Linux 匯編語(yǔ)言開發(fā)指南詳解
大?。?/span>0.5 MB 人氣: 2017-11-02 需要積分:1
推薦 + 挑錯(cuò) + 收藏(0) + 用戶評(píng)論(0)
標(biāo)簽:Linux(205935)匯編語(yǔ)言(34963)
匯編語(yǔ)言的優(yōu)點(diǎn)是速度快,可以直接對(duì)硬件進(jìn)行操作,這對(duì)諸如圖形處理等關(guān)鍵應(yīng)用是非常重要的。Linux 是一個(gè)用 C 語(yǔ)言開發(fā)的操作系統(tǒng),這使得很多程序員開始忘記在 Linux 中還可以直接使用匯編這一底層語(yǔ)言來優(yōu)化程序的性能。本文為那些在Linux 平臺(tái)上編寫匯編代碼的程序員提供指南,介紹 Linux 匯編語(yǔ)言的語(yǔ)法格式和開發(fā)工具,并輔以具體的例子講述如何開發(fā)實(shí)用的Linux 匯編程序。一、簡(jiǎn)介
作為最基本的編程語(yǔ)言之一,匯編語(yǔ)言雖然應(yīng)用的范圍不算很廣,但重要性卻勿庸置疑,因?yàn)樗軌蛲瓿稍S多其它語(yǔ)言所無法完成的功能。就拿 Linux 內(nèi)核來講,雖然絕大部分代碼是用 C 語(yǔ)言編寫的,但仍然不可避免地在某些關(guān)鍵地方使用了匯編代碼,其中主要是在 Linux 的啟動(dòng)部分。由于這部分代碼與硬件的關(guān)系非常密切,即使是 C 語(yǔ)言也會(huì)有些力不從心,而匯編語(yǔ)言則能夠很好揚(yáng)長(zhǎng)避短,最大限度地發(fā)揮硬件的性能。
大多數(shù)情況下 Linux 程序員不需要使用匯編語(yǔ)言,因?yàn)榧幢闶怯布?qū)動(dòng)這樣的底層程序在 Linux 操作系統(tǒng)中也可以用完全用 C 語(yǔ)言來實(shí)現(xiàn),再加上 GCC 這一優(yōu)秀的編譯器目前已經(jīng)能夠?qū)ψ罱K生成的代碼進(jìn)行很好的優(yōu)化,的確有足夠的理由讓我們可以暫時(shí)將匯編語(yǔ)言拋在一邊了。但實(shí)現(xiàn)情況是 Linux 程序員有時(shí)還是需要使用匯編,或者不得不使用匯編,理由很簡(jiǎn)單:精簡(jiǎn)、高效和 libc 無關(guān)性。假設(shè)要移植 Linux 到某一特定的嵌入式硬件環(huán)境下,首先必然面臨如何減少系統(tǒng)大小、提高執(zhí)行效率等問題,此時(shí)或許只有匯編語(yǔ)言能幫上忙了。
匯編語(yǔ)言直接同計(jì)算機(jī)的底層軟件甚至硬件進(jìn)行交互,它具有如下一些優(yōu)點(diǎn):
能夠直接訪問與硬件相關(guān)的存儲(chǔ)器或 I/O 端口;
能夠不受編譯器的限制,對(duì)生成的二進(jìn)制代碼進(jìn)行完全的控制;
能夠?qū)﹃P(guān)鍵代碼進(jìn)行更準(zhǔn)確的控制,避免因線程共同訪問或者硬件設(shè)備共享引起的死鎖;
能夠根據(jù)特定的應(yīng)用對(duì)代碼做最佳的優(yōu)化,提高運(yùn)行速度;
能夠最大限度地發(fā)揮硬件的功能。
同時(shí)還應(yīng)該認(rèn)識(shí)到,匯編語(yǔ)言是一種層次非常低的語(yǔ)言,它僅僅高于直接手工編寫二進(jìn)制的機(jī)器指令碼,因此不可避免地存在一些缺點(diǎn):
編寫的代碼非常難懂,不好維護(hù);
很容易產(chǎn)生 bug,難于調(diào)試;
只能針對(duì)特定的體系結(jié)構(gòu)和處理器進(jìn)行優(yōu)化;
開發(fā)效率很低,時(shí)間長(zhǎng)且單調(diào)。
Linux 下用匯編語(yǔ)言編寫的代碼具有兩種不同的形式。第一種是完全的匯編代碼,指的是整個(gè)程序全部用匯編語(yǔ)言編寫。盡管是完全的匯編代碼,Linux 平臺(tái)下的匯編工具也吸收了 C 語(yǔ)言的長(zhǎng)處,使得程序員可以使用 #include、#ifdef 等預(yù)處理指令,并能夠通過宏定義來簡(jiǎn)化代碼。第二種是內(nèi)嵌的匯編代碼,指的是可以嵌入到C語(yǔ)言程序中的匯編代碼片段。雖然 ANSI 的 C 語(yǔ)言標(biāo)準(zhǔn)中沒有關(guān)于內(nèi)嵌匯編代碼的相應(yīng)規(guī)定,但各種實(shí)際使用的 C 編譯器都做了這方面的擴(kuò)充,這其中當(dāng)然就包括 Linux 平臺(tái)下的 GCC。
二、Linux 匯編語(yǔ)法格式
絕大多數(shù) Linux 程序員以前只接觸過DOS/Windows 下的匯編語(yǔ)言,這些匯編代碼都是 Intel 風(fēng)格的。但在 Unix 和 Linux 系統(tǒng)中,更多采用的還是 AT&T 格式,兩者在語(yǔ)法格式上有著很大的不同:
在 AT&T 匯編格式中,寄存器名要加上 ‘%’ 作為前綴;而在 Intel 匯編格式中,寄存器名不需要加前綴。例如:
AT&T 格式Intel 格式
pushl %eaxpush eax
在 AT&T 匯編格式中,用 ‘$’ 前綴表示一個(gè)立即操作數(shù);而在 Intel 匯編格式中,立即數(shù)的表示不用帶任何前綴。例如:
AT&T 格式Intel 格式
pushl $1push 1
AT&T 和 Intel 格式中的源操作數(shù)和目標(biāo)操作數(shù)的位置正好相反。在 Intel 匯編格式中,目標(biāo)操作數(shù)在源操作數(shù)的左邊;而在 AT&T 匯編格式中,目標(biāo)操作數(shù)在源操作數(shù)的右邊。例如:
AT&T 格式Intel 格式
addl $1, %eaxadd eax, 1
在 AT&T 匯編格式中,操作數(shù)的字長(zhǎng)由操作符的最后一個(gè)字母決定,后綴‘b’、‘w’、‘l’分別表示操作數(shù)為字節(jié)(byte,8 比特)、字(word,16 比特)和長(zhǎng)字(long,32比特);而在 Intel 匯編格式中,操作數(shù)的字長(zhǎng)是用 “byte ptr” 和 “word ptr” 等前綴來表示的。例如:
AT&T 格式Intel 格式
movb val, %almov al, byte ptr val
在 AT&T 匯編格式中,絕對(duì)轉(zhuǎn)移和調(diào)用指令(jump/call)的操作數(shù)前要加上‘*’作為前綴,而在 Intel 格式中則不需要。
遠(yuǎn)程轉(zhuǎn)移指令和遠(yuǎn)程子調(diào)用指令的操作碼,在 AT&T 匯編格式中為 “l(fā)jump” 和 “l(fā)call”,而在 Intel 匯編格式中則為 “jmp far” 和 “call far”,即:
AT&T 格式Intel 格式
ljump $section, $offsetjmp far section:offset
lcall $section, $offsetcall far section:offset
與之相應(yīng)的遠(yuǎn)程返回指令則為:
AT&T 格式Intel 格式
lret $stack_adjustret far stack_adjust
在 AT&T 匯編格式中,內(nèi)存操作數(shù)的尋址方式是
section:disp(base, index, scale)
而在 Intel 匯編格式中,內(nèi)存操作數(shù)的尋址方式為:
section:[base + index*scale + disp]
由于 Linux 工作在保護(hù)模式下,用的是 32 位線性地址,所以在計(jì)算地址時(shí)不用考慮段基址和偏移量,而是采用如下的地址計(jì)算方法:
disp + base + index * scale
下面是一些內(nèi)存操作數(shù)的例子:
AT&T 格式Intel 格式
movl -4(%ebp), %eaxmov eax, [ebp - 4]
movl array(, %eax, 4), %eaxmov eax, [eax*4 + array]
movw array(%ebx, %eax, 4), %cxmov cx, [ebx + 4*eax + array]
movb $4, %fs:(%eax)mov fs:eax, 4
三、Hello World!
真不知道打破這個(gè)傳統(tǒng)會(huì)帶來什么樣的后果,但既然所有程序設(shè)計(jì)語(yǔ)言的第一個(gè)例子都是在屏幕上打印一個(gè)字符串 “Hello World!”,那我們也以這種方式來開始介紹 Linux 下的匯編語(yǔ)言程序設(shè)計(jì)。
在 Linux 操作系統(tǒng)中,你有很多辦法可以實(shí)現(xiàn)在屏幕上顯示一個(gè)字符串,但最簡(jiǎn)潔的方式是使用 Linux 內(nèi)核提供的系統(tǒng)調(diào)用。使用這種方法最大的好處是可以直接和操作系統(tǒng)的內(nèi)核進(jìn)行通訊,不需要鏈接諸如 libc 這樣的函數(shù)庫(kù),也不需要使用 ELF 解釋器,因而代碼尺寸小且執(zhí)行速度快。
Linux 是一個(gè)運(yùn)行在保護(hù)模式下的 32 位操作系統(tǒng),采用 flat memory 模式,目前最常用到的是 ELF 格式的二進(jìn)制代碼。一個(gè) ELF 格式的可執(zhí)行程序通常劃分為如下幾個(gè)部分:.text、.data 和 .bss,其中 .text 是只讀的代碼區(qū),.data 是可讀可寫的數(shù)據(jù)區(qū),而 .bss 則是可讀可寫且沒有初始化的數(shù)據(jù)區(qū)。代碼區(qū)和數(shù)據(jù)區(qū)在 ELF 中統(tǒng)稱為 section,根據(jù)實(shí)際需要你可以使用其它標(biāo)準(zhǔn)的 section,也可以添加自定義 section,但一個(gè) ELF 可執(zhí)行程序至少應(yīng)該有一個(gè) .text 部分。
非常好我支持^.^
(0) 0%
不好我反對(duì)
(0) 0%
下載地址
Linux 匯編語(yǔ)言開發(fā)指南詳解下載
相關(guān)電子資料下載
- uboot的基本概念和啟動(dòng)流程分析 49
- Windows11上Linux安裝教程 22
- 多路徑和iSCSI SAN存儲(chǔ)技術(shù)介紹 56
- 探討嵌入式系統(tǒng)的軟硬件框架 29
- 浩辰CAD Linux版 2024全球發(fā)布 274
- 如何使用pthread_barrier_xxx系列函數(shù)來實(shí)現(xiàn)多線程之間的同步? 29
- 馬斯克曾說特斯拉堅(jiān)不可摧,卻敗在Kali Linux手下 559
- 火遍童年的FC游戲是使用什么語(yǔ)言編寫的 330
- 為T507-H開發(fā)板配置Samba服務(wù),高效實(shí)現(xiàn)跨系統(tǒng)的文件共享 250
- DNS的各種玩法:程序編譯到進(jìn)程的過程解析 23