linux汇编和x86汇编,linux平台学x86汇编(四):从“hello world!”开始
【版權(quán)聲明:尊重原創(chuàng),轉(zhuǎn)載請保留出處:blog.csdn.net/shallnet,文章僅供學(xué)習(xí)交流,請勿用于商業(yè)用途】
匯編語言程序由定義好的段構(gòu)成,每個(gè)段有各自的目的。三個(gè)最常用的的段如下:數(shù)據(jù)段、bss段、文本段。文本段是可執(zhí)行程序內(nèi)聲明指令碼的地方,所有匯編程序都必須有文本段,數(shù)據(jù)段和bss段是可選的,但是在程序中經(jīng)常使用。數(shù)據(jù)段聲明帶有初始值的變量,bss段聲明使用0值初始化的數(shù)據(jù)元素,這些元素常用作匯編程序的緩沖區(qū)。下圖為匯編語言程序的布局。
GNU匯編器使用.section命令語句聲明段。.section語句只有一個(gè)參數(shù)——段類型。上圖的布局是匯編程序安排段的一般方式。bss段總是在文本段之前,數(shù)據(jù)段可以在文本段之后,但將其放在前面更容易閱讀和理解。
如其它高級語言一樣,匯編語言程序在鏈接為可執(zhí)行程序時(shí),鏈接器必須要知道程序中的起點(diǎn)是什么,就像c語言中的main函數(shù)一樣。GNU匯編器使用一個(gè)默認(rèn)標(biāo)簽_start作為應(yīng)用程序的入口點(diǎn),如果鏈接器找不到這個(gè)標(biāo)簽就會(huì)生成錯(cuò)誤消息。如果編寫被外部匯編語言或C語言程序使用的一組工具,需要使用.globl命令聲明每個(gè)函數(shù)段標(biāo)簽,.globl命令是聲明外部程序可以訪問的程序標(biāo)簽。所以,一般編寫匯編語言的基礎(chǔ)模板是這樣的:
.section.data
.section.bss
.section.text
.globl _start
_start:
有了模板之后就可以開始創(chuàng)建匯編語言程序,我們也像學(xué)習(xí)高級語言一樣,從最簡單的程序開始。
編寫匯編語言主要工作在編寫.text部分,該部分主要編寫要實(shí)現(xiàn)應(yīng)用程序的指令碼。匯編語言允許程序員使用助記符表示指令碼,助記符使程序員可以使用英語樣式的詞表示各個(gè)指令碼,匯編器可以很容易地把匯編語言助記符轉(zhuǎn)換為原始指令碼。這樣使得匯編程序員不必了解指令碼每個(gè)字節(jié)表示什么,子需要使用更加容易記憶的助記符(如push、mov、sub、call)來表示指令碼。比如下面這個(gè)指令碼例子:
55
89 E5
83 EC 08
C7 45 FC 01 00 00 00
83 EC 0C
6A 00
E8 D1 FE FF FF
可以寫為如下的匯編代碼:
push %ebp
mov %esp, %ebp
sub $0x8, %esp
movl $0x1, -4(%ebp)
sub $0xc, %esp
push $0x0
call 8048348
數(shù)據(jù)段
和高級語言一樣,編寫匯編語言程序都需要管理某種類型的變量,在匯編語言中數(shù)據(jù)段和bss段都提供了定義變量的方法。數(shù)據(jù)段是最常見的定義變量的位置。
在數(shù)據(jù)段中定義變量需要兩個(gè)語句:一個(gè)符號、一個(gè)命令。
符號類似于C語言程序中變量的名稱,它只是匯編器試圖訪問內(nèi)存位置時(shí)用作引用指針的一個(gè)位置。
命令實(shí)現(xiàn)為符號引用的數(shù)據(jù)元素保留多少字節(jié),類似于高級語言指定數(shù)據(jù)類型。匯編語言使用如下的命令:.ascii、.asciz、.byte、.double、.float、.int、.long、.octa、.quad、.short、.single。例如定義變量如下:
.section .data
msg:
.ascii “This is a test message”
數(shù)據(jù)段主要用于定義變量數(shù)據(jù),不過也可以使用命令.equ定義靜態(tài)數(shù)據(jù)符號,類似于高級語言的定義常量。例如:
.equ var 3
引用靜態(tài)數(shù)據(jù)時(shí),需要在變量名稱前加$符號,比如把var的值傳送到EAX寄存器:
movl $var, %eax
bss段
在bss段中定義數(shù)據(jù)元素和在數(shù)據(jù)段中定義有些不同,不需要指定特定數(shù)據(jù)類型。
GNU匯編器使用兩個(gè)命令聲明緩沖區(qū),.comm命令聲明未初始化的數(shù)據(jù)的通用內(nèi)存區(qū)域;.lcomm命令聲明未初始化的數(shù)據(jù)本地通用內(nèi)存區(qū)域,該區(qū)域不允許從本地匯編代碼之外進(jìn)行訪問。其使用格式為:
.comm symbol, length
symbol是賦給內(nèi)存區(qū)域的符號,length是內(nèi)存區(qū)域中包含的字節(jié)數(shù)量。
在bss段中聲明數(shù)據(jù)的一個(gè)好處是數(shù)據(jù)不包含在可執(zhí)行程序中,在數(shù)據(jù)段中定義數(shù)據(jù)必須包含在可執(zhí)行程序中。
下面來看看匯編語言的hello world 程序:
#hello.s sample program to print hello world information
.section .data #數(shù)據(jù)段聲明
msg:
.ascii "hello world!\n" #要輸出的字符串
len=.-msg #字符串長度
.section .text #代碼段聲明
# .global main
# main:
.global _start #指定入口函數(shù)
_start: #函數(shù)在屏幕上輸出hello world!
movl $len, %edx #第三個(gè)參數(shù): 字符串長度
movl $msg, %ecx #第二個(gè)參數(shù): hello world!字符串
movl $1, %ebx #第一個(gè)參數(shù): 輸出文件描述符
movl $4, %eax #系統(tǒng)調(diào)用號sys_write
int $0x80 #調(diào)用內(nèi)核功能
#下面為退出程序代碼
movl $0, %ebx #第一個(gè)參數(shù): 退出返回碼
movl $1, %eax #系統(tǒng)調(diào)用sys_exit
int $0x80 #調(diào)用內(nèi)核功能
編譯執(zhí)行結(jié)果如下:
$ as -o hello.o hello.s
$ ld -o hello hello.o
$ ./hello hello world!$
Linux 下的系統(tǒng)調(diào)用是通過中斷(int 0x80)來實(shí)現(xiàn)的。在執(zhí)行 int 0X80 指令時(shí),寄存器 eax 中存放的是系統(tǒng)調(diào)用號,而傳給系統(tǒng)調(diào)用的參數(shù)則必須按順序放到寄存器 ebx,ecx,edx,esi,edi 中,當(dāng)系統(tǒng)調(diào)用完成之后,返回值可以在寄存器 eax 中獲得。系統(tǒng)調(diào)用號4對應(yīng)的函數(shù)調(diào)用是
sys_write,在應(yīng)用上其函數(shù)定義如下:
ssize_t write(int fd, const void *buf, size_t count);
參數(shù) fd、buf 和 count 分別存在寄存器 ebx、ecx 和 edx 中,而系統(tǒng)調(diào)用號 SYS_write 則放在寄存器 eax 中,當(dāng) int 0x80 指令執(zhí)行完畢后,返回值可以從寄存器 eax 中獲得。
注意,如果使用gcc編譯的話有一個(gè)問題,gcc查找main標(biāo)簽而不是_start標(biāo)簽,所以把程序中的_start改為main直接使用gcc編譯鏈接就沒有問題了。
總結(jié)
以上是生活随笔為你收集整理的linux汇编和x86汇编,linux平台学x86汇编(四):从“hello world!”开始的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言加取址符的作用,C语言中指针和取地
- 下一篇: linux下apk包名查看,使用adb命