彙編基本語法簡介

轉載 http://www.360doc.com/content/10/0926/12/1317564_56492037.shtmlhtml

彙編基本語法簡介
在 AT&T 彙編格式中,寄存器名要加上 '%' 做爲前綴;而在 Intel 彙編格式中,寄存器名不須要加前綴。例如:
AT&T 格式
 Intel 格式
 
pushl %eax
 push eax
 學習

在 AT&T 彙編格式中,用 '$' 前綴表示一個當即操做數;而在 Intel 彙編格式中,當即數的表示不用帶任何前綴。例如:
AT&T 格式
 Intel 格式
 
pushl $1
 push 1
 指針

AT&T 和 Intel 格式中的源操做數和目標操做數的位置正好相反。在 Intel 彙編格式中,目標操做數在源操做數的左邊;而在 AT&T 彙編格式中,目標操做數在源操做數的右邊。例如:
AT&T 格式
 Intel 格式
 
addl $1, %eax
 add eax, 1
 orm

在 AT&T 彙編格式中,操做數的字長由操做符的最後一個字母決定,後綴'b'、'w'、'l'分別表示操做數爲字節(byte,8 比特)、字(word,16 比特)和長字(long,32比特);而在 Intel 彙編格式中,操做數的字長是用 "byte ptr" 和 "word ptr" 等前綴來表示的。例如:
AT&T 格式
 Intel 格式
 
movb val, %al
 mov al, byte ptr val
 htm

在 AT&T 彙編格式中,絕對轉移和調用指令(jump/call)的操做數前要加上'*'做爲前綴,而在 Intel 格式中則不須要。
遠程轉移指令和遠程子調用指令的操做碼,在 AT&T 彙編格式中爲 "ljump" 和 "lcall",而在 Intel 彙編格式中則爲 "jmp far" 和 "call far",即:
AT&T 格式 Intel 格式
ljump $section, $offset
 jmp far section:offset
 
lcall $section, $offset
 call far section:offset
 內存

與之相應的遠程返回指令則爲:
AT&T 格式
 Intel 格式
 
lret $stack_adjust
 ret far stack_adjust
 文檔

在 AT&T 彙編格式中,內存操做數的尋址方式是
AT&T 格式
 Intel 格式
 
section:disp(base, index, scale)
 section:[base + index*scale + disp]
 字符串

因爲 Linux 工做在保護模式下,用的是 32 位線性地址,因此在計算地址時不用考慮段基址和偏移量,而是採用以下的地址計算方法:disp + base + index * scale
下面是一些內存操做數的例子:
AT&T 格式
 Intel 格式
 
movl -4(%ebp), %eax
 mov eax, [ebp - 4]
 
movl array(, %eax, 4), %eax
 mov eax, [eax*4 + array]
 
movw array(%ebx, %eax, 4), %cx
 mov cx, [ebx + 4*eax + array]
 
movb $4, %fs:(%eax)
 mov fs:eax, 4
 編譯器

內嵌彙編格式簡介
內嵌彙編語法以下:
__asm__(彙編語句模板: 輸出部分: 輸入部分: 破壞描述部分)
 it

其中,asm 和 __asm__是徹底同樣的。共四個部分:彙編語句模板,輸出部分,輸入部分,破壞描述部分,各部分使用「:」格開,彙編語句模板必不可少,其餘三部分可選,若是使用了後面的部分,而前面部分爲空,也須要用「:」格開,相應部份內容爲空。例如:
__asm__ __volatile__("cli": : :"memory")
 

 
一、彙編語句模板
    彙編語句模板由彙編語句序列組成,語句之間使用 「;」、「\\n」或「\\n\\t」分開。指令中的操做數可使用佔位符引用C語言變量,操做數佔位符最多10個,名稱以下:%0,%1,…,%9。指令中使用佔位符表示的操做數,總被視爲long型(4個字節),但對其施加的操做根據指令能夠是字或者字節,當把操做數看成字或者字節使用時,默認爲低字或者低字節。對字節操做能夠顯式的指明是低字節仍是次字節。方法是在%和序號之間插入一個字母,「b」表明低字節,「h」表明高字節,例如:%h1。
 
二、輸出部分
    輸出部分描述輸出操做數,不一樣的操做數描述符之間用逗號格開,每一個操做數描述符由限定字符串和C 語言變量組成。每一個輸出操做數的限定字符串必須包含「=」表示他是一個輸出操做數。
例:
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) )
 

描述符字符串表示對該變量的限制條件,這樣GCC 就能夠根據這些條件決定如何分配寄存器,如何產生必要的代碼處理指令操做數與C表達式或C變量之間的聯繫。
 
三、輸入部分
輸入部分描述輸入操做數,不一樣的操做數描述符之間使用逗號格開,每一個操做數描述符由限定字符串和C語言表達式或者C語言變量組成。
例1 :
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
 

例二(bitops.h):
Static __inline__ void __set_bit(int nr, volatile void * addr)
{
        __asm__(
                         "btsl %1,%0"
                        :"=m" (ADDR)
                        :"Ir" (nr));
}
 

後例功能是將(*addr)的第nr位設爲 1。第一個佔位符%0與C 語言變量ADDR對應,第二個佔位符%1與C語言變量nr對應。所以上面的彙編語句代碼與下面的僞代碼等價:btsl nr, ADDR,該指令的兩個操做數不能全是內存變量,所以將nr的限定字符串指定爲「Ir」,將nr 與當即數或者寄存器相關聯,這樣兩個操做數中只有ADDR爲內存變量。
 
四、限制字符
   4.一、限制字符列表
   限制字符有不少種,有些是與特定體系結構相關,此處僅列出經常使用的限定字符和i386中可能用到的一些經常使用的限定符。它們的做用是指示編譯器如何處理其後的C語言變量與指令操做數之間的關係。
分類
 限定符
 描述
 
 
 
 
 
 
 
 
通用寄存器
 a
 將輸入變量放入eax這裏有一個問題:假設eax已經被使用,那怎麼辦?其實很簡單:由於GCC 知道eax 已經被使用,它在這段彙編代碼的起始處插入一條語句pushl %eax,將eax 內容保存到堆棧,而後在這段代碼結束處再增長一條語句popl %eax,恢復eax的內容
 
b
 將輸入變量放入ebx
 
c
 將輸入變量放入ecx
 
d
 將輸入變量放入edx
 
s
 將輸入變量放入esi
 
d
 將輸入變量放入edi
 
q
 將輸入變量放入eax,ebx,ecx,edx中的一個
 
r
 將輸入變量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一個
 
A
 把eax和edx合成一個64 位的寄存器(use long longs)
 
 
 
 
內存
 m
 內存變量
 
o
 操做數爲內存變量,可是其尋址方式是偏移量類型,也便是基址尋址,或者是基址加變址尋址
 
V
 操做數爲內存變量,但尋址方式不是偏移量類型
 
「」
 操做數爲內存變量,但尋址方式爲自動增量
 
p
 操做數是一個合法的內存地址(指針)
 
寄存器或內存
 g
 將輸入變量放入eax,ebx,ecx,edx中的一個或者做爲內存變量
 
X
 操做數能夠是任何類型
 
 
 
 
當即數
 I
 0-31之間的當即數(用於32位移位指令)
 
J
 0-63之間的當即數(用於64位移位指令)
 
N
 0-255之間的當即數(用於out指令)
 
i
 當即數
 
n
 當即數,有些系統不支持除字之外的當即數,這些系統應該使用「n」而不是「i」
 
 
 
匹配
 0
 表示用它限制的操做數與某個指定的操做數匹配,
 
1
 也即該操做數就是指定的那個操做數,例如「0」
 
9
 去描述「%1」操做數,那麼「%1」引用的其實就是「%0」操做數,注意做爲限定符字母的0-9 與指令中的「%0」-「%9」的區別,前者描述操做數,後者表明操做數。
 
 &
 該輸出操做數不能使用過和輸入操做數相同的寄存器
 
 
操做數類型
 =
 操做數在指令中是隻寫的(輸出操做數)
 
+
 操做數在指令中是讀寫類型的(輸入輸出操做數)
 
 
 
 
 
浮點數
 f
 浮點寄存器
 
t
 第一個浮點寄存器
 
u
 第二個浮點寄存器
 
G
 標準的80387浮點常數
 
%
 該操做數能夠和下一個操做數交換位置 例如addl的兩個操做數能夠交換順序(固然兩個操做數都不能是當即數)
 
#
 部分註釋,從該字符到其後的逗號之間全部字母被忽略
 
*
 表示若是選用寄存器,則其後的字母被忽略
 

五、破壞描述部分   破壞描述符用於通知編譯器咱們使用了哪些寄存器或內存,由逗號格開的字符串組成,每一個字符串描述一種狀況,通常是寄存器名;除寄存器外還有「memory」。例如:「%eax」,「%ebx」,「memory」等。感謝這篇文章是兩篇文章的綜合體,我只是把這兩篇文章綜合起來了,進行了一下簡單的排版,閱讀起來方便一點,舒服一點。兩位做者分別是肖文鵬和臨江仙,向他們表示感謝。後續我會根據相關資料,繼續改進該文檔,使之更全面。Mail:normalnotebook@126.com,互相學習。

相關文章
相關標籤/搜索