Sự khác nhau giữa toán tử ADDR và OFFSET
Tranz by NhatPhuongLe
Sự khác nhau giữa toán tử ADDR và OFFSET
Trong những ngày đầu khi tôi mới bắt đầu viết các chương trình assemlby. Tôi không phân biệt được khi nào sử dụng ADDR, và khi nào sử dụng OFFSET trong chương trình. Bài viết này sẽ cố gắng làm rõ các vấn đề thắc mắc của các lập trình viên asm, hay cũng có nghĩa là cách sử dụng của ADDR và OFFSET
Đầu tiên và trước nhất, mục đích của việc sử dụng ADDR hoặc là OFFSET là để lấy địa chỉ bộ nhớ của biến trong lúc chương trình thực thi.
Bây giờ, chúng ta biết rằng các biến trong các chương trình hợp ngữ có 2 loại, biến cục bộ và toàn cục
Trong khi các biến toàn cục tồn tại trong bộ nhớ trong suốt quá trình thực thi của chương trình, còn biến cục bộ chỉ tồn tại trong quá trình thực thi của các hàm mà nó được khai báo và sẽ được remov khỏi bộ nhớ stack ngay khi hàm mà chúng được khai báo đã hoàn thành việc thực thi.
Khi các biến toàn cục tồn tại trong bộ nhớ trong suốt quá trình thực thi của chương trình, địa chỉ bộ nhớ của các biến toàn cục đó được cấp phát trong suốt thời gian biên dịch chương trình bởi trình hợp dịch. Trình hợp dịch biết chính xác vị trí của địa chỉ bộ nhớ của các biến toàn cục trong suốt quá trình biên dịch.
Trong trường hợp nó là biến cục bộ, trình hợp dịch sẽ không biết địa chỉ của biến bởi vì địa chỉ của nó được cấp phát trong thời gian thực thi chương trình trên bộ nhớ stack và khi hàm mà nó đựơc khai báo, thực thi.
Bây giờ hãy trở lại các chỉ thị của trình hợp dịch, OFFSET sẽ lấy địa chỉ của một biến mà nó đã được cấp phát địa chỉ. Điều này có nghĩa là là OFFSET có thể đựơc sử dụng để lấy địa chỉ chỉ của các biến toàn cục. Chúng ta không thể lấy được địa chỉ của các biến cục bộ bằng cách sử dụng OFFSET bởi vì địa chỉ của các biến cục bộ không được quyết định lúc biên dịch.
Để khắc phục điều này, chúng ta có chỉ thị ADDR. Chỉ này có thể đựơc sử dụng nếu như chúng ta muốn lấy địa chỉ của một biến cục bộ
Bây giờ, một câu hỏi được đặt ra là làm thế nào để ADDR biết địa chỉ của 1 biến cục bộ trong khi OFFSET không thể. Àh, thậm chí ADDR không biết địa chỉ thực của 1 biến cục bộ khi nó được sử dụng trong quá trình bên dịch. Những gì mà toán tử ADDR làm đơn giản chỉ là một phép toán thay thế trong mã lệnh như sau, điều này chỉ xảy ra trước khi hàm thực thi
lea eax, localvar
push eax
Điều này thực sự có nghĩa là ADDR sẽ tạo ra địa chỉ của biến cục bộ mà nó được khởi tạo trong quá trình thực thi sau đó trả về địa chỉ. LEA được sử dụng để tham chiếu tới bộ nhớ stack. LEA có nghĩa là Load Effective Address. Nó được sử dụng để nạp địa chỉ của các biến vào stack
Nếu bạn vẫn không lấy được địa chỉ của biến, thì hãy tưởng tưởng một tình huống như sau:
Tôi đang đứng ở một nơi nào đó trên đường và bạn đến gặp tôi để tìm địa chỉ của một cô gái xinh đẹp mà bạn biết rằng tôi biết. Vì vậy, việc bạn hỏi tôi địa chỉ được xem như là lúc biên dịch chương trình, bạn là một chương trình hợp ngữ để tìm địa chỉ của cô gái và tôi là một trình hợp dịch.
Giả sử nếu như tôi biết chính xác địa chỉ của cô gái ấy, tôi sẽ đưa nó cho bạn: địa chỉ đường, số nhà, ... Điều này chính là những gì mà toán tử OFFSET thực hiện
Ngược lại, nếu như tôi không biết nơi cô ấy sống, nhưng tôi biết một ai đó mà tôi quen, biết địa chỉ của cô gái đó, sau đó tôi sẽ đưa địa chỉ của người đó và yêu cầu bạn đến đó để hỏi địa chỉ của cô gái mà bạn đang tìm. Đó chính là những gì mà toán tử ADDR thực hiện.
Bây giờ bạn đã phân biệt được khi nào sử dụng ADDR và khi nào sử dụng OFFSET chưa? Một câu hỏi khác được đặt ra là chúng ta có thể sử dụng toán tử ADDR để nạp địa chỉ của biến toàn cục hay không?
Vâng, dĩ nhiên là được. Nếu như bạn tham chiếu tới biến toàn cục bằng cách sử dụng toán tử ADDR, sau đó ADDR đơn giản sẽ thay thế chúng như sau:
mov eax, 3000h
Địa chỉ 3000h chính là địa chỉ thực sự của biến toàn cục. Hãy nhớ rằng địa chỉ của 1 biến toàn cục sẽ luôn luôn biết đựơc trong suốt quá trình biên dịch và thực thi.
Nhưng sau đó, tại sau ADDR lại sử dụng LEA thay vì là MOV trong trường hợp của biến cục bộ. Àh, lý do đơn giản là
mov eax,ebp+2
Đó là một chỉ thị không hợp lệ của CPU. Chú ý rằng, EBP đựơc biết đến là địa chỉ cơ sở trong thanh ghi đựơc sử dụng để truy cập stack, và nó chỉ ở trên stack nơi mà biến cục bộ được lưu trữ.
Do đó, LEA được sử dụng bởi ADDR trong trường hợp là các biến cục bộ.
Vì vậy, rõ ràng là toán tử OFFSET được sử dụng cho biến toàn cục và ADDR cho biến cục bộ. ADDR cũng có thể được sử dụng để tham chiếu tới biến toàn cục, nhưng toán tử OFFSET không được sử dụng để tham chiếu tới biến cục bộ.