Linux下的彙編程序設計

By IPOz(於2002-11-5發表)
引言:

彙編語言是低級語言,與硬件和操作系統緊密聯繫。個人電腦以前都是用DOS,現在發展成了WINDOWS, 而另一個操作系統Linux也正在崛起。下面比較一下這三個操作系統:

DOS       較穩定,速度快 無法充分發揮計算機性能,沒有圖形界面
WINDOWS   操作簡便,應用軟件多,硬件兼容性好  不穩定,經常死機,速度慢
Linux     性能優秀,非常穩定,界面美觀,操作簡便缺乏軟件廠商支持,應用軟件少


由以上的比較可知,Linux操作系統本身具有較大優勢,它的普及應該只是時間問題,所以如何在Linux下 開發軟件是我們計算機系學生必須學習與研究的一個課題。

Linux下的主要編程語言是C,同時Linux還支持其他許多編程語言,彙編語言作爲最重要的編程語言之一, 當然也包括在內。它能夠完成許多其他語言所不能完成的功能。要學習Linux編程,就必須要學習Linux下 的彙編程序設計。下面我就來介紹一下Linux下的彙編程序設計。

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使用手冊。

結論:

我認爲不論是在Windows/DOS下還是在Linux下完完全全用匯編編一個大型程序已經是不可能了,也不會有 人願意去這樣做。在windows下我們可以用VC,在Linux/Xwindows下我們可以用C甚至C++ Builder,但是像 VC、C++ Builder之類的工具儘量隱藏了底層的調用,同時也阻隔了成爲高手的機會,因爲編出來的程序無 法瞭解它的執行過程也就使編程中最重要的“可預測”性變得很低。正因爲如此彙編纔有它存在的必要性 ,同時還有一個更重要的原因,正如《超級解霸》的作者樑肇新所說:“編程序的重點不是“編”,而是調試程序,理論上的完美在實現的時候會遇到很多細節問題,這些問題必須調試才能解決。我的編程習慣 是一天寫五天調試,《超級解霸》是調試出來的,而不是寫出來的。調試就涉及到彙編的問題,不進行彙編級的調試是不徹底的,也不能讓人放心。 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章