![](/img/trans.png)
[英]GCC/x86 inline asm: How do you tell gcc that inline assembly section will modify %esp?
[英]How to use address constants in GCC x86 inline assembly
GCC工具鏈默認使用AT&T匯編語法,但可通過.intel_syntax
指令獲得對Intel語法的支持。
此外,AT&T和Intel語法都有prefix
和noprefix
版本,不同之處在於它們是否需要使用%
sigil為寄存器名稱添加前綴。
根據存在的指令,地址常量的格式會發生變化。
我們考慮以下C代碼
*(int *)0xdeadbeef = 0x1234;
使用objdump -d
,我們發現它被編譯為以下匯編程序指令
movl $0x1234,0xdeadbeef
由於沒有涉及寄存器,這是.att_syntax prefix
和.att_syntax noprefix
的正確語法,即。 嵌入在C代碼中,它們看起來像這樣
__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeef");
__asm__(".att_syntax noprefix");
__asm__("movl $0x1234,0xdeadbeef");
您可以選擇用括號括起地址常量,即。
__asm__("movl $0x1234,(0xdeadbeef)");
也會奏效。
將sigil添加到普通地址常量時,代碼將無法復制
__asm__("movl $0x1234,$0xdeadbeef"); // won't compile
當用paranthesis圍繞這個表達式時,編譯器將發出錯誤的代碼而不發出警告,即
__asm__("movl $0x1234,($0xdeadbeef)"); // doesn't warn, but doesn't work!
這將錯誤地發出指令
movl $0x1234,0x0
在Intel模式下,如果可能存在歧義,則地址常量必須以段寄存器為前綴,以及操作數大小和PTR
標志。 在我的機器上(采用Windows XP和當前MinGW和Cygwin GCC版本的英特爾雙核筆記本電腦),默認情況下使用寄存器ds
。
常量周圍的方括號是可選的。 如果省略了段寄存器,但是括號存在,也可以正確識別地址常量。 但是,忽略寄存器會在我的系統上發出警告。
在prefix
模式中,段寄存器必須以%
為前綴,但僅使用括號仍然有效。 這些是生成正確指令的不同方法:
__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!
__asm__(".intel_syntax prefix");
__asm__("mov DWORD PTR %ds:0xdeadbeef,0x1234");
__asm__("mov DWORD PTR %ds:[0xdeadbeef],0x1234");
__asm__("mov DWORD PTR [0xdeadbeef],0x1234"); // works, but warns!
省略段寄存器和括號將無法編譯
__asm__("mov DWORD PTR 0xdeadbeef,0x1234"); // won't compile
我將此問題標記為社區維基 ,所以如果你有任何有用的東西可以添加,請隨意這樣做。
noprefix
/ prefix
指令僅控制寄存器是否需要%
前綴(*)(至少看起來如此,這是文檔提到的唯一區別)。 值文字在AT&T語法中始終需要$
前綴,而在Intel語法中從不需要。 以下是有效的:
__asm__(".intel_syntax prefix");
__asm__("MOV [DWORD PTR 0xDEADBEEF], 0x1234");
如果您真的傾向於在使用GCC編譯的C代碼中使用英特爾語法內聯匯編並與GAS匯編,請不要忘記在它之后添加以下內容,以便匯編器可以查看由其生成的其余(AT&T語法)匯編。 GCC:
__asm__(".att_syntax prefix");
我看到前綴/ noprefix區別的原因是,對於AT&T語法,英特爾架構上的寄存器並不真正需要%
前綴,因為寄存器是命名的。 但是為了統一,它可以存在,因為一些其他體系結構(即SPARC)已經編號注冊,在這種情況下,單獨指定一個低數字對於是否意味着存儲器地址或寄存器是不明確的。
這是我自己的結果:
*(int *)0xdeadbeaf = 0x1234; // reference implementation
// AT&T: addresses without sigil; parentheses are optional
__asm__(".att_syntax prefix");
__asm__("movl $0x1234,0xdeadbeaf"); // works
__asm__("movl $0x1234,(0xdeadbeaf)"); // works
__asm__("movl $0x1234,($0xdeadbeaf)"); // doesn't work, doesn't warn!
//__asm__("movl $0x1234,$0xdeadbeaf"); // doesn't compile
//__asm__("movl 0x1234,0xdeadbeaf"); // doesn't compile
//__asm__("movl 0x1234,(0xdeadbeaf)"); // doesn't compile
__asm__(".att_syntax noprefix");
// same as above: no registers used!
// Intel: addresses with square brackets or segment register prefix
// brackets without prefix will warn
__asm__(".intel_syntax noprefix");
__asm__("mov DWORD PTR ds:0xdeadbeaf,0x1234"); // works
__asm__("mov DWORD PTR ds:[0xdeadbeaf],0x1234"); // works
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234"); // works, but warns!
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234"); // doesn't compile
// `prefix` will add % to register names
__asm__(".intel_syntax prefix");
__asm__("mov DWORD PTR %ds:0xdeadbeaf,0x1234"); // works
__asm__("mov DWORD PTR %ds:[0xdeadbeaf],0x1234"); // works
__asm__("mov DWORD PTR [0xdeadbeaf],0x1234"); // works, but warns!
//__asm__("mov DWORD PTR 0xdeadbeaf,0x1234"); // doesn't compile
__asm__(".att_syntax prefix");
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.