[英]Converting [symbol + constant] Intel syntax addressing mode to AT&T syntax?
我只是無法弄清楚如何在移動值時向目標添加偏移量,特別是在我擁有的英特爾語法中:
MOV [gdtr + 2], EAX
對於 AT&T 語法,我嘗試將其轉換為:
movl %eax, gdtr(2,1)
junk '(2,1)' after expression
時會出錯,但僅使用gdtr(,1)
可以正常工作。
我不明白為什么我不能使用基本偏移,而只能使用比例因子。
簡單地寫
movl %eax, gdtr+2
基偏移尋址僅在偏移為寄存器時才有效。 使用尋址模式將兩個常量相加是沒有意義的。 其工作方式(無論語法如何)是匯編程序/linker 將symbol+constant
解析為指令編碼的位移字段的單個數字。
就是gdtr+2
gdtr(2,1)
[給出錯誤] 但僅使用gdtr(,1)
工作正常。
AT&T 尋址模式中()
括號內的內容只能是寄存器(和比例因子): disp(base, index, scale)
。 基數和索引是可選的,所以空是可以的,但無效(非注冊)不是。
當您指定一個沒有基數或索引的比例時,顯然您必須只使用一個逗號: (,,1)
是關於空比例因子的錯誤。
您可以將其寫為gdtr+2(,1)
以顯式不使用寄存器。
+2 是尋址模式中位移的一部分,而不是基址或索引寄存器,無論語法如何。 請參閱有關 [base + index*scale + disp] 或 Intel 或 AMD 的有關尋址模式如何編碼的手冊的幾個問題。 (就如何將其編碼為機器代碼而言,您正在做的是[disp32]
或[disp16]
尋址模式。)
正如 Nate 所指出的,linker 負責將匯編時文字常量 + 鏈接時常量符號地址轉換為機器代碼中的最終地址,編碼為disp32
(或disp16
用於 16 位地址大小)。 或用於 x86-64 的 RIP 相對rel32
。
有趣的事實:一些 AT&T 匯編器接受(gdtr)
作為gdtr
的替代品,但不接受2(gdtr)
。
通常,如果您卡在 NASM -> AT&T 上,您可以組裝 NASM 源代碼(例如nasm -felf
)並使用 AT&T 反匯編程序(如objdump -drwC
)進行反匯編。 但這對符號尋址模式語法沒有幫助,因為充其量objdump -dr
只是用符號名稱信息注釋數字尋址模式。
因此,在這種情況下,您最好的選擇是讓 GCC 或 clang 發出使用符號名稱和數字常量的指令,如下所示
char gdtr[1024]; // global var so it has a symbol
char foo() { return gdtr[2]; } // load from global symbol + constant.
在 Godbolt 編譯器資源管理器上使用gcc9.3 -O2 -m32
編譯到這個 asm:
foo:
movzbl gdtr+2, %eax
ret
gdtr:
.zero 1024
有你的尋址模式,作為獎勵,帶有字節源的 movzx 的 AT&T 助記符。 當然,您可以擺弄類型。
編譯器是有用的資源; 在編譯簡單的 C 函數時,他們知道如何以“正常方式”做很多事情,並且他們知道調用約定和類型寬度。 包括 function 指針在內的所有內容的 AT&T 語法。 如果您遇到困難,請詢問編譯器。 基本上,您唯一無法讓編譯器向您展示的是jmp far
的語法(AT&T ljmp
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.