x86匯編一直存在兩種不同的語法,在intel的官方文檔中使用intel語法,Windows也使用intel語法,而UNIX平台的匯編器一直使用AT&T語法。
AT&T 和 Intel 匯編語言的語法區別主要體現在操作數前綴、賦值方向、間接尋址語法、操作碼的后綴上,而就具體的指令而言,在同一平台上,兩種匯編語言是一致的。下面僅列出這兩種匯編語言在語法上的不同點。
操作數前綴
在 Intel 的匯編語言語法中,寄存器和和立即數都沒有前綴。但是在 AT&T 中,寄存器前冠以“%”,而立即數前冠以“$”。在 Intel 的語法中,十六進制和二進制立即數后綴分別
冠以“h”和“b”,而在 AT&T 中,十六進制立即數前冠以“0x”:
Intel 語法 |
AT&T 語法 |
Mov eax,8 |
movl $8,%eax |
Mov ebx,0ffffh |
movl $0xffff,%ebx |
int 80h |
int $0x80 |
源/目的操作數順序
Intel 匯編語言的指令與 AT&T的指令操作數的方向上正好相反:在 Intel 語法中,第一個操作數是目的操作數,第二個操作數源操作數。而在 AT&T 中,第一個數是源操作數,第二個數是目的操作數。
Intel 語法 |
AT&T 語法 |
MOV EAX,8 |
movl $8,%eax |
尋址方式
與 Intel 的語法比較,AT&T 間接尋址方式可能更晦澀難懂一些。 Intel 的指令格式是segreg: [base+index*scale+disp],而 AT&T 的格式是%segreg:disp(base,index,scale)。其中index/scale/disp/segreg 全部是可選的, 完全可以簡化掉。如果沒有指定 scale 而指定了 index,則 scale 的缺省值為 1。 segreg 段寄存器依賴於指令以及應用程序是運行在實模式還是保護模式下,在實模式下,它依賴於指令,而在保護模式下, segreg 是多余的。在 AT&T 中,當立即數用在 scale/disp 中時, 不應當在其前冠以“$”前綴, 而且 scale,disp 不需要加前綴“&”。另外在 Intel 中基地址使用“[”、“]”,而在 AT&T 中則使用“(”、“)
Intel 語法 |
AT&T 語法 |
Instr foo,segreg: [base+index*scale+disp] |
instr %segreg: disp(base,index,scale),foo |
[eax] |
(%eax) |
[eax + _variable] |
_variable(%eax) |
[eax*4 + _array] |
_array(,%eax,4) |
[ebx + eax*8 + _array] |
_array(%ebx,%eax,8) |
標識長度的操作碼前綴和后綴
在 AT&T 匯編中遠程跳轉指令和子過程調用指令的操作碼使用前綴“l”,分別為 ljmp,lcall,與之相應的返回指令偽 lret。例如:
Intel 語法 |
AT&T 語法 |
LL SECTION:OFFSET |
lcall $secion:$offset |
FAR SECTION:OFFSET |
ljmp $secion:$offset |
FAR STACK_ADJUST |
lret $stack_adjust |
在 AT&T 的操作碼后面有時還會有一個后綴,其含義就是指出操作碼的大小。“l”表示
長整數(32 位),“w”表示字(16 位),“b”表示字節(8 位)。而在 Intel 的語法中,則要
在內存單元操作數的前面加上 byte ptr、 word ptr,和 dword ptr,“dword”對應“long”。
Intel 語法 |
AT&T 語法 |
Mov al,bl |
movb %bl,%al |
Mov ax,bx |
movw %bx,%ax |
Mov eax,ebx |
movl %ebx,%eax |
Mov eax, dword ptr [ebx] |
movl (%ebx),%eax |