Linux彙編簡介:
一、組合語言的優缺點:
由於Linux是用C寫的,所以C自然而然的就成為了Linux的標準程式設計語言。大部分人都把彙編給忽略了,甚至在網際網路上找資料都是非常的困難,很多問題都需要靠自己來嘗試。我認為這樣對待組合語言是不公平的,不能只看到它的缺點,當然也不能只看到它的優點,下面把它的優缺點作一個比較:
優點:組合語言可以表達非常底層的東西
.可以直接存取寄存器和I/O
.編寫的代碼可以非常精確的被執行
.可以編寫出比一般編譯系統高效的代碼
.可以作為不同語言或不同標準的介面
缺點:組合語言是一個非常低級的語言
.非常冗長單調,在DOS下編程時就可以體會到
.易出BUG,且調試困難
.代碼不易維護
.相容性不好,與硬體關係非常緊密
總的來說,組合語言要用在必須的地方,盡量少用彙編編寫大型程式,多採用inline模式。
二、組合語言工具:
DOS下常用的工具MASM和TASM到Linux下就用不起來了,Linux有自己的彙編工具,而且種類非常的多。其中
gas可以算是標準配置,每一種Linux中都包括有gas,但是GAS採用的不是我們通常在DOS下採用的彙編文法 ,它採用的是AT&T的文法格式,與intel文法格式有很大的不同。
如果要採用與DOS接近的文法格式,就必須用另一種彙編工具NASM,NASM基本與MASM相同,但也有不少地方有較大區別,特別涉及到作業系統原理時,與DOS可以說是截然不同。
Linux組譯工具設計:
一、Hello,world!
幾乎所有的語言入門篇都是以“Hello,world!”為例,那麼我也以Hello,world!為例開始。
;-------------NASM’s standalone Hello-World.asm for Linux --------
section .text
extern puts
global main
main:
push
dword msg ;stash the location of msg on the stack.
call puts ;call the
"puts" routine (libc?)
add esp, byte 4 ;clean the stack?
ret
;exit.
msg:
db "Hello World!",0
編譯:
nasm –f elf
hello.asm
gcc –o hello hello.o
說明:這個程式實際上是調用了,Linux系統的puts函數,原理與調用DOS下C語言的函數相同,先用extern聲明puts是外部函數,再把參數(即msg的地址)壓入堆棧,最後call函數實現輸出。
我們再來看一個程式:
section .text
global main
main:
mov
eax,4 ;4號調用
mov ebx,1 ;ebx送1表示stdout
mov ecx,msg ;字串的首地址送入ecx
mov edx,14 ;字串的長度送入edx
int 80h ;輸出字串
mov eax,1 ;1號調用
int 80h ;結束
msg:
db "Hello World!",0ah,0dh
(編譯同上一個程式)
這個程式與DOS程式十分相似,它用的是linux中的80h中斷,相當於DOS下的21h中斷,只是因為Linux是32位作業系統,所以採用了EAX、EBX等寄存器。但是Linux作為一個多使用者的作業系統與DOS又是有著非常大的區別的。要寫出有特色的程式,不瞭解作業系統和硬體是不行的。下面我介紹一下Linux作業系統。
二、Linux作業系統簡介:
作業系統實際是抽象資源操作到具體硬體操作細節之間的介面。對Linux這樣的多使用者作業系統來說,它需要避免使用者對硬體的直接存取,並防止使用者之間的互相干擾。所以Linux接管了BIOS調用和連接埠輸入輸出,
關於連接埠輸入輸出方面請參閱Linux IO-Port-Programming HOWTO。而要通過Linux對硬體硬體進行訪問就需要用到System
Call,實際上是許多C的函數,可以在組譯工具中調用,調用方法與DOS下的彙編完全相同 ,而且用ASM彙編時不用連結額外的庫函數。
Linux與DOS的主要區別在於記憶體管理、進程(DOS下無進程概念)、檔案系統,其中記憶體管理和進程與彙編 編程的關係比較密切:
1、記憶體管理:
對任一台電腦而言,其記憶體以及其他資源都是有限的。為了讓有限的實體記憶體滿足應用程式對記憶體的大
需求量,Linux採用了稱為“虛擬記憶體”的記憶體管理方式。Linux將記憶體劃分為容易處理的“記憶體頁”,在
系統運行過程中,應用程式對記憶體的需求大於實體記憶體時,Linux可將暫時不用的記憶體頁交換到硬碟上,這
樣,閒置記憶體頁可以滿足應用程式的記憶體需求,而應用程式卻不會注意到記憶體交換的發生。
2、進程
進程實際是某特定應用程式的一個運行實體。在Linux系統中,能夠同時運行多個進程,Linux通過在短的
時間間隔內輪流程執行這些進程而實現“多任務”。這一短的時間間隔稱為“時間片”,讓進程輪流程執行的
方法稱為“調度”,完成調度的程式稱為發送器。通過多任務機制,每個迸程可認為只有自己獨佔計算
機,從而簡化程式的編寫,每個進程有自己單獨的地址空間,並且只能由這一進程訪問,這樣,作業系統 避免了進程之間的互相干擾以及“壞”程式對系統可能造成的危害。
為了完成某特定任務,有時需要綜合兩個程式的功能,例如一個程式輸出文本,而另一個程式對文本進行
排序。為此,作業系統還提供進程間的通訊機制來協助完成這樣的任務。Linux中常見的進程間通訊機制有 訊號、管道、共用記憶體、訊號量和通訊端等。
三、Linux下的彙編工具:
Linux下的彙編工具可謂百家爭鳴,不像DOS下都要給MASM和TASM給控制了。但是Linux下每一種彙編工具都
有很大的區別,要想全部掌握幾乎是不可能的,下面我介紹幾種常用的彙編工具,重點介紹NASM及其使用 和文法。
1、GCC
GCC其實是GNU的C語言產品,但它支援Inline Assemble,在GCC中inline
assemble使用就像宏一樣,但它比宏能更清楚更準確的表達機器的工作狀態。
C是彙編編程的一個高度概括,它可以減少許多彙編中的麻煩,特別是在GCC這個C編譯器中,assemble似乎 起不了多大的作用。
2、GAS
GAS是Linux各版本中基本的彙編工具,但它採用的是AT&T的文法標準與Intel的文法標準有很大的不同,對
於DOS編程的我們來說,學習起來是非常困難的。當然如果要精通Linux下的彙編編程,學習GAS也是非常必 要的,具體的文法標準可以參看Using GNU
Assembler。
3、GASP
GASP是GAS的擴充,它增強了GAS對宏的支援。
4、NASM
NASM是linux中文法與DOS最為相像的一種彙編工具。雖說如此,它與MASM也是有著很大區別的。
.NASM的使用格式如下:
nasm –f -o
例如:
nasm -f elf
hello.asm
將把hello.asm彙編成ELF object檔案,而
nasm -f bin hello.asm -o
hello.com
會把hello.asm彙編成二進位可執行檔hello.com
nasm –h
將會列出NASM命令列的完整說明。
NASM不會有任何輸出,除非有錯誤發生。
-f
在Linux下主要有aout和ELF兩種,如果你不確定你的Linux系統應該用AOUT還是ELF,可以在NASM目錄中 輸入 file nasm ,如果輸出nasm: ELF 32-bit LSB executable i386 (386 and
up) Version 1表示是ELF ,如果輸出nasm: Linux/i386 demand-paged executable
(QMAGIC)表示是aout。
.NASM與MASM的主要不同:
首先與linux系統一樣,nasm是區分大小寫,Hello與hello將是不同的標識符,如果要彙編到DOS或OS/2
,需要加入UPPERCASE參數。
其次,nasm中記憶體運算元都是以[ ]表示。
在MASM中
foo equ
1
bar dw 2
mov ax,foo
mov ax,bar
將被彙編成完全不同的指令,雖然它們在MASM中的表達方式完全一樣。而NASM完全避免了這種混亂,它使用的是這樣的規則:所有對記憶體的操作都必須通過[ ]來實現。例如上例中對bar的操作就要寫成如下形式
mov
ax,[bar]。由此可見,nasm中對offset的使用也是沒有必要的(nasm中無offset)。nasm對[ ]的使用 與masm也有所不同,所有的運算式都必須寫在[
]中,下面舉兩個例子來說明:
masm nasm
mov
ax,table[di] mov ax,[table+di]
mov
ax,es:[di] mov ax,[es:di]
mov
ax,[di]+1 mov ax,[di+1]
nasm 中不儲存變數類型,原因很簡單masm中通過[
]定址方式的變數也必須要指定類型。nasm中不支援 LODS, MOVS, STOS, SCAS, CMPS, INS,
OUTS,只支援lodsb、lodsw等已經指定類型的操作。nasm中不再有 assume操作,段地址完全取決於存入段寄存器的值。
關於NASM的使用方法及文法還可以參閱NASM使用手冊。