絕大多數 Linux 程序員以前只接觸過DOS/Windows 下的彙編語言,這些彙編代碼都是Intel 風格的。但在 Unix 和 Linux 系統中,更多采用的還是 AT&T 格式,兩者在語法格式上有着很大的不同:
|
1.在 AT&T 彙編格式中,寄存器名要加上 '%' 作爲前綴;而在 Intel 彙編格式中,寄存器名不需要加前綴。例如:
AT&T 格式 |
Intel 格式 |
pushl %eax |
push eax |
2.在 AT&T 彙編格式中,用 '$' 前綴表示一個立即操作數;而在 Intel 彙編格式中,立即數的表示不用帶任何前綴。例如:
AT&T 格式 |
Intel 格式 |
pushl $1 |
push 1 |
3.AT&T 和 Intel 格式中的源操作數和目標操作數的位置正好相反。在 Intel 彙編格式中,目標操作數在源操作數的左邊;而在 AT&T 彙編格式中,目標操作數在源操作數的右邊。例如:
AT&T 格式 |
Intel 格式 |
addl $1, %eax |
add eax, 1 |
4.在 AT&T 彙編格式中,操作數的字長由操作符的最後一個字母決定,後綴'b'、'w'、'l'分別表示操作數爲字節(byte,8 比特)、字(word,16 比特)和長字(long,32比特);而在 Intel 彙編格式中,操作數的字長是用 "byte ptr" 和 "word ptr" 等前綴來表示的。例如:
AT&T 格式 |
Intel 格式 |
movb val, %al |
mov al, byte ptr val |
5. 在 AT&T 彙編格式中,絕對轉移和調用指令(jump/call)的操作數前要加上'*'作爲前綴,而在 Intel 格式中則不需要。
6.遠程轉移指令和遠程子調用指令的操作碼,在 AT&T 彙編格式中爲 "ljump" 和 "lcall",而在 Intel 彙編格式中則爲 "jmp far" 和 "callfar",即:
AT&T 格式 |
Intel 格式 |
ljump $section, $offset |
jmp far section:offset |
lcall $section, $offset |
call far section:offset |
與之相應的遠程返回指令則爲:
AT&T 格式 |
Intel 格式 |
lret $stack_adjust |
ret far stack_adjust |
7.在 AT&T 彙編格式中,內存操作數的尋址方式是
section:disp(base, index, scale) |
而在 Intel 彙編格式中,內存操作數的尋址方式爲:
section:[base + index*scale + disp] |
由於 Linux 工作在保護模式下,用的是 32 位線性地址,所以在計算地址時不用考慮段基址和偏移量,而是採用如下的地址計算方法:
disp + base + index * scale |
下面是一些內存操作數的例子:
AT&T 格式 |
Intel 格式 |
movl -4(%ebp), %eax |
mov eax, [ebp - 4] |
movl array(, %eax, 4), %eax |
mov eax, [eax*4 + array] |
movw array(%ebx, %eax, 4), %cx |
mov cx, [ebx + 4*eax + array] |
movb $4, %fs:(%eax) |
mov fs:eax, 4 |