Linux 下用匯編語言編寫的代碼具有兩種不同的形式。第一種是完全的彙編代碼,指的是整個程序全部用匯編語言編寫。儘管是完全的彙編代碼,Linux 平臺下的彙編工具也吸收了 C 語言的長處,使得程序員可以使用 #include、#ifdef 等預處理指令,並能夠通過宏定義來簡化代碼。第二種是內嵌的彙編代碼,指的是可以嵌入到C語言程序中的彙編代碼片段。雖然 ANSI 的 C 語言標準中沒有關於內嵌彙編代碼的相應規定,但各種實際使用的 C 編譯器都做了這方面的擴充,這其中當然就包括 Linux 平臺下的 GCC。
一 Linux彙編語法格式
絕大多數 Linux 程序員以前只接觸過DOS/Windows 下的彙編語言,這些彙編代碼都是 Intel 風格的。但在 Unix 和 Linux 系統中,更多采用的還是 AT&T 格式,兩者在語法格式上有着很大的不同.
二 Hello World的編寫
在 Linux 操作系統中,你有很多辦法可以實現在屏幕上顯示一個字符串,但最簡潔的方式是使用 Linux 內核提供的系統調用。使用這種方法最大的好處是可以直接和操作系統的內核進行通訊,不需要鏈接諸如 libc 這樣的函數庫,也不需要使用 ELF 解釋器,因而代碼尺寸小且執行速度快。
Linux 是一個運行在保護模式下的 32 位操作系統,採用 flat memory 模式,目前最常用到的是 ELF 格式的二進制代碼。一個 ELF 格式的可執行程序通常劃分爲如下幾個部分:.text、.data 和 .bss,其中 .text 是隻讀的代碼區,.data 是可讀可寫的數據區,而 .bss 則是可讀可寫且沒有初始化的數據區。代碼區和數據區在 ELF 中統稱爲 section,根據實際需要你可以使用其它標準的 section,也可以添加自定義 section,但一個 ELF 可執行程序至少應該有一個 .text 部分。 下面給出我們的第一個彙編程序,用的是 AT&T 彙編語言格式:
例: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 # 調用內核功能
例: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 中,可以找到所有系統調用的定義。
三 Linux 彙編工具
1.彙編器
彙編器(assembler)的作用是將用匯編語言編寫的源程序轉換成二進制形式的目標代碼。Linux 平臺的標準彙編器是 GAS,它是 GCC 所依賴的後臺彙編工具,通常包含在 binutils 軟件包中。GAS 使用標準的 AT&T 彙編語法,可以用來彙編用 AT&T 格式編寫的程序:
panlu@ThinkPad:~/彙編語言$ as -o hello.o helloWorld.s
Linux 平臺上另一個經常用到的彙編器是 NASM,它提供了很好的宏指令功能,並能夠支持相當多的目標代碼格式,包括 bin、a.out、coff、elf、rdf 等。NASM 採用的是人工編寫的語法分析器,因而執行速度要比 GAS 快很多,更重要的是它使用的是 Intel 彙編語法,可以用來編譯用 Intel 語法格式編寫的彙編程序:
panlu@ThinkPad:~/彙編語言$ nasm -f elf hello.asm
2.鏈接器
由彙編器產生的目標代碼是不能直接在計算機上運行的,它必須經過鏈接器的處理才能生成可執行代碼。鏈接器通常用來將多個目標代碼連接成一個可執行代碼,這樣可以先將整個程序分成幾個模塊來單獨開發,然後纔將它們組合(鏈接)成一個應用程序。 Linux 使用 ld 作爲標準的鏈接程序,它同樣也包含在 binutils 軟件包中。彙編程序在成功通過 GAS 或 NASM 的編譯並生成目標代碼後,就可以使用 ld 將其鏈接成可執行程序了:
panlu@ThinkPad:~/彙編語言$ ld -s -o hello hello.o
3 運行
panlu@ThinkPad:~/彙編語言$ ./hello
Hello World!
四 Intel格式
1、在ubuntu上安裝nasm方法
首先在網站http://www.nasm.us/pub/nasm/releasebuilds/2.10.07/下面去下載2.10.07.tar.gz這個版本(一般在ubuntu上面都是使用這個壓縮形式的)。如果要下其他版本的nasm可以通過http://www.nasm.us/來進行選擇進行下載。
2、安裝方法:使用如下的命令:
解壓:tar zxvf nasm-2.10.07.tar.gz
進入剛解壓的目錄 cd 解壓後的目錄
然後執行命令:./configure
make
sudo make install
通過以上的步驟nasm就在ubuntu上安裝好了。也可以通過使用命令:nasm -version來查看是否安裝成功。如果出現了nasm的版本信息則說明安裝成功,否則還需進一步安裝。
panlu@ThinkPad:~/彙編語言$ nasm -version
NASM version 2.10.07 compiled on Sep 29 2015
3 編譯運行
nasm -f elf64(elf32) hello.asm (注意這裏使用elf64還是elf32要看操作系統的位數來決定)
gcc -o hello hello.o
./hello
輸出Hello World便成功了.