絕大多數
linux
程式設計師以前只接觸過
dos/windows
下的組合語言,這些彙編**都是
intel
風格的。但在
unix
和linux
系統中,更多採用的還是
at&t
格式,兩者在語法格式上有著很大的不同: 在
at&t
彙編格式中,暫存器名要加上
' %'
作為字首;而在
intel
彙編格式中,暫存器名不需要加字首。例如:
at&t 格式
intel 格式
pushl %eax
push eax 在
at&t
彙編格式中,用
'$'
字首表示乙個立即運算元;而在
intel
彙編格式中,立即數的表示不用帶任何字首。例如:
at&t 格式
intel 格式
pushl $1
push 1
at&t
和intel
格式中的源運算元和目標運算元的位置正好相反。在
intel
彙編格式中,目標運算元在源運算元的左邊;而在
at&t
彙編格式中,目標運算元在源運算元的右邊。例如:
at&t 格式
intel 格式
addl $1, %eax
add eax, 1 在
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 在
at&t
彙編格式中,絕對轉移和呼叫指令(
jump/call
)的運算元前要加上
'*'作為字首,而在
intel
格式中則不需要。
遠端轉移指令和遠端子呼叫指令的操作碼,在
at&t
彙編格式中為
"ljump"
和"lcall"
,而在intel
彙編格式中則為
"jmp far"
和"call far"
,即: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 在
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
hello world!
真不知道打破這個傳統會帶來什麼樣的後果,但既然所有程式語言的第乙個例子都是在螢幕上列印乙個字串
"hello world!"
,那我們也以這種方式來開始介紹
linux
下的組合語言程式設計。
在linux
作業系統中,你有很多辦法可以實現在螢幕上顯示乙個字串,但最簡潔的方式是使用
linux
核心提供的系統呼叫。使用這種方法最大的好處是可以直接和作業系統的核心進行通訊,不需要鏈結諸如
libc
這樣的函式庫,也不需要使用
elf
直譯器,因而**尺寸小且執行速度快。
linux
是乙個執行在保護模式下的
32 位作業系統,採用
flat memory
模式,目前最常用到的是
elf
格式的二進位制**。乙個
elf
格式的可執行程式通常劃分為如下幾個部分:
.text
、.data
和.bss
,其中.text
是唯讀的**區,
.data
是可讀可寫的資料區,而
.bss
則是可讀可寫且沒有初始化的資料區。**區和資料區在
elf
中統稱為
section
,根據實際需要你可以使用其它標準的
section
,也可以新增自定義
section
,但乙個
elf
可執行程式至少應該有乙個
.text
部分。下面給出我們的第乙個匯程式設計序,用的是
at&t
組合語言格式:
例
1.at&t
格式#hello.s
.data
# 資料段宣告
msg : .string "hello, world!//n" #
要輸出的字串
len = . - msg#
字串長度
.text#
**段宣告
.global _start#
指定入口函式
_start:#
在螢幕上顯示乙個字串
movl $len, %edx#
引數三:字串長度
movl $msg, %ecx#
引數二:要顯示的字串
movl $1, %ebx#
引數一:檔案描述符
(stdout)
movl $4, %eax#
系統呼叫號
(sys_write)
int$0x80#
呼叫核心功能
# 退出程式
movl $0,%ebx#
引數一:退出**
movl $1,%eax#
系統呼叫號
(sys_exit)
int$0x80#
呼叫核心功能
初次接觸到
at&t
格式的彙編**時,很多程式設計師都認為太晦澀難懂了,沒有關係,在
linux
平台上你同樣可以使用
intel
格式來編寫匯程式設計序:
例
2.intel
格式; hello.asm
section .data;
資料段宣告
msg db "hello, world!", 0xa
; 要輸出的字串
len equ $ - msg;
字串長度
section .text;
**段宣告
global _start;
指定入口函式
_start:;
在螢幕上顯示乙個字串
mov edx, len;
引數三:字串長度
mov ecx, msg;
引數二:要顯示的字串
mov ebx, 1;
引數一:檔案描述符
(stdout)
mov eax, 4;
系統呼叫號
(sys_write)
int 0x80;
呼叫核心功能
; 退出程式
mov ebx, 0;
引數一:退出**
mov eax, 1;
系統呼叫號
(sys_exit)
int 0x80;
呼叫核心功能
上面兩個匯程式設計序採用的語法雖然完全不同,但功能卻都是呼叫
linux
核心提供的
sys_write
來顯示乙個字串,然後再呼叫
sys_exit
退出程式。在
linux
核心原始檔
include/asm-i386/unistd.h
中,可以找到所有系統呼叫的定義。
AT T彙編語法格式
1.暫存器的引用要在暫存器前加 如mov eax,ebx 2.運算元排列是左源右目的,如上例表示把值從eax暫存器mov到ebx暫存器 3.常數 立即數前面要加 如mov 4,ebx 4.對於變數加 表示取位址。如mov value,ebx表示傳值給ebx,而mov value,ebx表示傳位址給e...
Linux下AT T彙編語法格式簡介
一 at t 格式linux 彙編語法格式 在 at t 彙編格式中,暫存器名要加上 作為字首 而在 intel 彙編格式中,暫存器名不需要加字首。例如 at t格式 intel格式 pushl eax push eax 在 at t 彙編格式中,用 字首表示乙個立即運算元 而在 intel 彙編格...
Linux下AT T彙編語法格式簡介
絕大多數linux程式設計師以前只接觸過dos windows下的組合語言,這些彙編 都是intel風格的。但在unix和linux系統中,更多採用的還是at t格式,兩者在語法格式上有著很大的不同 在at t彙編格式中,暫存器名要加上 作為字首 而在intel彙編格式中,暫存器名不需要加字首。例如...