天天看點

Linux Debugging(二): 熟悉AT&T彙編語言1 AT&T與Intel彙編文法對比 2 求一個數組最大數

    沒想到《linux debugging:使用反彙編了解c++程式函數調用棧》發表了收到了大家的歡迎。但是有網友留言說不熟悉彙編,是以本書列了彙編的基礎文法。這些對于我們平時的調試應該是夠用了。

    大學時候大家學的基本上都是intel的8086彙編語言,微軟采用的就是這種格式的彙編。gcc采用的是at&t的彙編格式, 也叫gas格式(gnu asembler gnu彙編器)。

1、寄存器命名不同

at&t

intel

說明

%eax

eax

intel的不帶百分号

2、操作數順序不同

movl %eax, %ebx

mov ebx, eax

intel的目的操作數在前,源操作數在後;at&t相反

3、常數/立即數的格式不同

movl $_value,%ebx

mov eax,_value

intel的立即數前面不帶$符号

movl $0xd00d,%ebx

mov ebx,0xd00d

規則同樣适用于16進制的立即數

4、操作數長度辨別

movw %ax,%bx

mov bx,ax

intel的彙編中, 操作數的長度并不通過指令符号來辨別。

at&t的格式中, 每個操作都有一個字元字尾, 表明操作數的大小. 例如:mov指令有三種形式:

movb  傳送位元組

movw  傳送字

movl   傳送雙字

如果沒有指定操作數長度的話,編譯器将按照目标操作數的長度來設定。比如指令“mov %ax, %bx”,由于目标操作數bx的長度為word,那麼編譯器将把此指令等同于“movw %ax, %bx”。

5、尋址方式

imm32(basepointer,

indexpointer,

indexscale)

[basepointer + indexpointer*indexscale + imm32)

兩種尋址的實際結果都應該是

imm32 + basepointer + indexpointer*indexscale

例如: 下面是一些尋址的例子:

mov 4(%ebp), %eax

mov eax, [ebp + 4]

基址尋址(base pointer addressing mode),用于通路結構體成員比較友善,例如一個結構體的基位址儲存在<code>eax</code>寄存器中,其中一個成員在結構體内的偏移量是4位元組,要把這個成員讀上來就可以用這條指令

<code>data_items(,%edi,4)</code>

[data_items+edi*4

變址尋址(indexed addressing mode),通路數組

movl $addr, %eax

mov eax, addr

直接尋址(direct addressing mode)

<code>movl (%eax), %ebx</code>

mov ebx, [eax]

間接尋址(indirect addressing mode),把<code>eax</code>寄存器的值看作位址,把記憶體中這個位址處的32位數傳送到<code>ebx</code>寄存器

mov $12, %eax

mov eax, 12

立即數尋址(immediate mode)

寄存器尋址(register addressing mode

6.跳轉方式不同

at&amp;t 彙編格式中,絕對轉移和調用指令(jump/call)的操作數前要加上'*'作為字首,而在 intel 格式中則不需要。 

jmp *%eax

jmp %eax

用寄存器%eax中的值作為跳轉目标

jmp *(%eax)

jmp (%eax)

以%eax中的值作為讀入的位址, 從存儲器中讀出跳轉目标

通過求一個數組的最大數,來進一步學習at&amp;t的文法

[cpp]

view plaincopy

#purpose: this program finds the maximum number of a  

#     set of data items.  

#  

#variables: the registers have the following uses:  

# %edi - holds the index of the data item being examined  

# %ebx - largest data item found  

# %eax - current data item  

# the following memory locations are used:  

# data_items - contains the item data. a 0 is used  

# to terminate the data  

 .section .data #全局變量  

data_items:         #these are the data items  

 .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0  

 .section .text  

 .globl _start  

_start:  

 movl $0, %edi      # move 0 into the index register  

 movl data_items(,%edi,4), %eax # load the first byte of data  

 movl %eax, %ebx    # since this is the first item, %eax is  

            # the biggest  

start_loop:         # start loop  

 cmpl $0, %eax      # check to see if we've hit the end  

 je loop_exit  

 incl %edi      # load next value  

 movl data_items(,%edi,4), %eax  

 cmpl %ebx, %eax    # compare values  

 jle start_loop     # jump to loop beginning if the new  

            # one isn't bigger  

 movl %eax, %ebx    # move the value as the largest  

 jmp start_loop     # jump to loop beginning  

loop_exit:  

 # %ebx is the status code for the _exit system call  

 # and it already has the maximum number  

 movl $1, %eax      #1 is the _exit() syscall  

 int $0x80  

彙程式設計式中以<code>.</code>開頭的名稱并不是指令的助記符,不會被翻譯成機器指令,而是給彙編器一些特殊訓示,稱為彙編訓示(assembler directive)或僞操作(pseudo-operation),由于它不是真正的指令是以加個“僞”字。<code>.section</code>訓示把代碼劃分成若幹個段(section),程式被作業系統加載執行時,每個段被加載到不同的位址,作業系統對不同的頁面設定不同的讀、寫、執行權限。<code>.data</code>段儲存程式的資料,是可讀可寫的,相當于c++程式的全局變量。

<code>.text</code>段儲存代碼,是隻讀和可執行的,後面那些指令都屬于<code>.text</code>段。

<code>.long</code>訓示聲明一組數,每個數占32;.quad類似,占64位;.byte是8位;.word 是16位。<code>.ascii</code>,例如<code>.ascii "hello world"</code>,聲明11個數,取值為相應字元的ascii碼。

參考資料:

1. 

最簡單的彙程式設計式

2.

第二個彙程式設計式

3. http://blog.chinaunix.net/uid-27717694-id-3942757.html

最後複習一下lea指令:

mov 4(%ebp) %eax #将%ebp+4位址處所存的值,mov到%eax

leal 4(%ebp) %eax #将%ebp+4的位址值, mov到%eax

leal 可以被mov取代:

addl $4, %ebp

mov. %ebp, %eax

繼續閱讀