1. 程式人生 > >AT&T彙編簡介

AT&T彙編簡介

AT&T彙編簡介

Intel 386彙編與AT&T區別

AT&T語法與Intel彙編程式使用的語法很不一樣,他們之間的主要區別有以下幾點:

  • AT&T語法中立即運算元前面要加一個字元$,暫存器運算元前要加%;絕對跳轉運算元前面要加星號*。而Intel彙編語法沒有這些限制

  • AT&T語法與Intel語法使用的源和目的運算元次序正好相反。AT&T的源和目的運算元是從左到右。例如Intel的語句add eax, 4對於AT&T的add $4, %eax

  • AT&T語法中記憶體運算元的長度(寬度)由操作碼最後一個字元來確定。操作碼字尾b、w、l

    分別指示記憶體引用寬度魏8位位元組(byte)、16位字(word)和32位長字(long)。Intel語法則通過在記憶體運算元前使用字首byte ptrword ptrdword ptr來達到同樣目的。Intel的語句mov al, byte ptr foo對應於AT&T的語句movb $foo, %al

  • AT&T語法中立即形式的遠跳轉和遠呼叫為ljmp/lcall $section, $offset,而Intel的是jmp/call far section:offset。同樣,AT&T語法中遠返回指令lret $stack-adjust對應Intel的ret far stack-adjust

  • 間接定址的一般格式,兩者區別如下:

    • SecTION:[BASE + INDEX * SCALE + DISP] (Intel格式)
    • SECTION:disp(base, index, scale) (AT&T格式)

    這種定址方式常常用於在資料結構陣列中訪問特定元素內的一個欄位,base為陣列的起始地址,scale為每個陣列元素的大小,index為下標。如果陣列元素是資料結構,則disp為具體欄位在結構中的偏移。

  • AT&T彙編器不提供對多程式碼段程式的支援,類UNIX作業系統要求所有程式碼在一個段中

現代的彙編工具吸收了C語言預處理的功能,在彙編之前加上了一趟預處理,而預處理之前的檔案則已.S

為字尾。此類.S檔案也和C程式一樣,可以使用#include、#ifdef等等。對於.s檔案則不回進行預處理。

AT&T彙編基礎

符號、語句、常數

符號是由字元組成的識別符號,包括大小寫字符集、數字和三個字元_.$。符號不允許用數字字元開始,並且大小寫含義不同。

語句以換行符或者行分割字元;作為結束。檔案最後語句必須以換行符作為結束

語句由零個或多個標號(Label)開始,後面可以跟隨一個確定語句型別的關鍵符號。標號由符號後面跟隨一個冒號:構成。關鍵符號確定了語句餘下部分的語義。如果該關鍵符號以一個.開始,那麼當前語句就是一個彙編命令(或稱為偽指令、指示符)。如果關鍵符號以一個字母開始,那麼當前語句就是一條組合語言指令語句。因此一條語句的通用格式為:

標號: 彙編命令  註釋部分(可選)
或
標號: 指令助記符  運算元1, 運算元2     註釋部分(可選)

常數是一個數字,可分為字元常數和數字常數兩類。字元常數還可分為字串和單個字元;數字常數分為整數和浮點數。

指令語句、運算元和定址

一條指令語句可以含有0個或最多3個用逗號分開的運算元。對於具有兩個運算元的指令語句,第1個是源運算元,第2個是目的運算元,指令操作結果儲存在目的運算元中。

運算元可以是立即數、暫存器或記憶體。一個間接運算元含有實際運算元的地址值。AT&T語法通過在運算元前加一個*字元來指定一個間接運算元。

  • 立即運算元加$字首
  • 暫存器名前需要加%字首
  • 記憶體運算元由變數名或者含有變數地址的一個暫存器指定。變數名隱含指出了變數的地址,並指示CPU引用該地址處記憶體的內容

記憶體引用

mov var, %eax               #把記憶體地址var處的內容放入暫存器eax中

mov %cs:var, %eax           #把程式碼段中記憶體地址var處的內容放入暫存器eax中

movb $0x0a, %es:(%ebx)      #位元組值0x0a放入到es段偏移ebx中

movl $var, %eax             #var地址放入eax

movl array(%esi), %eax      #array + esi地址的內容放入到eax

movl (%ebx, %esi, 4), %eax  #ebx + 4 * esi地址內容放入eax

movl array(%ebx, %esi, 4), %eax  #array + ebx + 4 * esi地址內容放入eax

movl -4(%ebp), %eax         #ebp - 4地址內容放入eax

movl foo(, %eax, 5), %eax   #foo + 5 * eax地址內容放入eax

跳轉指令

直接跳轉和間接跳轉,條件跳轉只能是直接跳轉,對於直接跳轉,跳轉的目標地址作為指令的一部分直接編碼進跳轉指令中;間接跳轉,跳轉的目的位置來自於某個暫存器或某個記憶體位置中。

jmp *%eax          #間接跳轉,eax內容是跳轉的目標位置  
jmp *(%eax)        #間接跳轉,eax地址內容是跳轉的目標位置

彙編命令

  • .align abs-expr1, abs-expr2, abs-expr3

    • 第一個代表對其位元組數(2 ^ expr1)
    • abs-expr2代表填充位元組值
    • abs-expr3代表對其操作允許跳過的最大位元組數,如果超過這個值,對其操作取消
  • .ascii "string"
    從位置計數器當前位置為字串分配空間並存儲字串。.ascii "Hello World", "My Assembler"

  • .asciz "string"
    該彙編命令與.ascii類似,但是每個字串後面會自動新增NULL字元

  • .byte expressions
    該彙編命令定義定義0個或多個用逗號分開的自己值。每個表示式的值是一個位元組

  • .comm symbol,length
    在bss區中宣告一個命名的公共區域。在ld連線過程中,某個目標檔案中的一個公共符號會與其他目標檔案中同名的公共符號合併。

  • .data subsection
    通知編譯器把隨後的語句彙編到編號為subsection的data子區中。

  • .global symbol(.globl symbol)
    使得連結器ld能看見符號symbol。如果在檔案中定義了symbol,那麼他的值能被連結過程中的其它目標檔案使用。

  • .org new_lc,fill
    這個彙編命令會把當前區的位置計數器設定為new_lc。fill代表跳過的填充自己數。位置計數器都是同區的。