歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> GCC內嵌AT&T匯編語法

GCC內嵌AT&T匯編語法

日期:2017/3/1 9:50:09   编辑:Linux編程

一 基本語法

1 寄存器引用

引用寄存器要在寄存器號前加百分號%,如“movl %eax, %ebx”。

80386有如下寄存器:

  • 1、8個32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;
  • 2、8個16-bit寄存器,它們事實上是上面8個32-bit寄存器的低16位:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp;
  • 3、8個8-bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。它們事實上是寄存器%ax,%bx,%cx,%dx的高8位和低8位;
  • 4、6個段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs;
  • 5、3個控制寄存器:%cr0,%cr2,%cr3;
  • 6、6個debug寄存器:%db0,%db1,%db2,%db3,%db6,%db7;
  • 7、2個測試寄存器:%tr6,%tr7;
  • 8、8個浮點寄存器棧:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7)。

2 操作數順序

操作數排列是從源(左)到目的(右),如“movl %eax(源), %ebx(目的)”

3 立即數

使用立即數,要在數前面加符號$, 如“movl $0x04, %ebx”

或者:

para = 0x04

movl $para, %ebx

指令執行的結果是將立即數04h裝入寄存器ebx。

4 符號常數

符號常數直接引用 如

value : .long 0x12a3f2de

movl value , %ebx

指令執行的結果是將常數0x12a3f2de裝入寄存器ebx。

5 操作數的長度

操作數的長度用加在指令後的符號表示b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits),如“movb %al, %bl”,“movw %ax, %bx”,“movl %eax, %ebx ”。

如果沒有指定操作數長度的話,編譯器將按照目標操作數的長度來設置。比如指令“mov %ax, %bx”,由於目標操作數bx的長度為word,那麼編譯器將把此指令等同於“movw %ax, %bx”。同樣道理,指令“mov $4, %ebx”等同於指令“movl $4, %ebx”,“push %al”等同於“pushb %al”。對於沒有指定操作數長度,但編譯器又無法猜測的指令,編譯器將會報錯,比如指令“push $4”。

引用符號地址在符號前加符號$, 如“movl $value, %ebx”則是將符號value的地址裝入寄存器ebx。

6 符號擴展和零擴展指令

絕大多數面向80386的AT&T匯編指令與Intel格式的匯編指令都是相同的,符號擴展指令和零擴展指令則是僅有的不同格式指令。符號擴展指令和零擴展指令需要指定源操作數長度和目的操作數長度,即使在某些指令中這些操作數是隱含的。

在AT&T語法中,符號擴展和零擴展指令的格式為,基本部分"movs"和"movz"(對應Intel語法的movsx和movzx),後面跟上源操作數長度和 目的操作數長度。movsbl意味著movs (from)byte (to)long;movbw意味著movs (from)byte (to)word;movswl意味著movs (from)word (to)long。對於movz指令也一樣。比如指令“movsbl %al, %edx”意味著將al寄存器的內容進行符號擴展後放置到edx寄存器中。

其它的Intel格式的符號擴展指令還有:

cbw -- sign-extend byte in %al to word in %ax;

cwde -- sign-extend word in %ax to long in %eax;

cwd -- sign-extend word in %ax to long in %dx:%ax;

cdq -- sign-extend dword in %eax to quad in %edx:%eax;

對應的AT&T語法的指令為cbtw,cwtl,cwtd,cltd。

7 調用和跳轉指令

段內調用和跳轉指令為"call","ret"和"jmp",段間調用和跳轉指令為"lcall","lret"和"ljmp"。

段間調用和跳轉指令的格式為“lcall/ljmp $SECTION, $OFFSET”,而段間返回指令則為“lret $STACK-ADJUST”。

8 前綴

操作碼前綴被用在下列的情況:

  • 1、字符串重復操作指令(rep,repne);
  • 2、指定被操作的段(cs,ds,ss,es,fs,gs);
  • 3、進行總線加鎖(lock);
  • 4、指定地址和操作的大小(data16,addr16);

在AT&T匯編語法中,操作碼前綴通常被單獨放在一行,後面不跟任何操作數。例如,對於重復scas指令,其寫法為:

repne

scas

上述操作碼前綴的意義和用法如下:

指定被操作的段前綴為cs,ds,ss,es,fs,和gs。在AT&T語法中,只需要按照section:memory-operand的格式就指定了相應的段前綴。比如:lcall %cs:realmode_swtch

操作數/地址大小前綴是“data16”和"addr16",它們被用來在32-bit操作數/地址代碼中指定16-bit的操作數/地址。

總線加鎖前綴“lock”,它是為了在多處理器環境中,保證在當前指令執行期間禁止一切中斷。這個前綴僅僅對ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD,XCHG指令有效,如果將Lock前綴用在其它指令之前,將會引起異常。

字符串重復操作前綴"rep","repe","repne"用來讓字符串操作重復“%ecx”次。

9 內存引用

Intel語法的間接內存引用的格式為:

section:[base+index*scale+displacement]

而在AT&T語法中對應的形式為:

section:displacement(base,index,scale)

其中,base和index是任意的32-bit base和index寄存器。scale可以取值1,2,4,8。如果不指定scale值,則默認值為1。section可以指定任意的段寄存器作為段前綴,默認的段寄存器在不同的情況下不一樣。如果你在指令中指定了默認的段前綴,則編譯器在目標代碼中不會產生此段前綴代碼。

下面是一些例子:

-4(%ebp):base=%ebp,displacement=-4,section沒有指定,由於base=%ebp,所以默認的section=%ss,index,scale沒有指定,則index為0。

foo(,%eax,4):index=%eax,scale=4,displacement=foo。其它域沒有指定。這裡默認的section=%ds。

foo(,1):這個表達式引用的是指針foo指向的地址所存放的值。注意這個表達式中沒有base和index,並且只有一個逗號,這是一種異常語法,但卻合法。

%gs:foo:這個表達式引用的是放置於%gs段裡變量foo的值。

如果call和jump操作在操作數前指定前綴“*”,則表示是一個絕對地址調用/跳轉,也就是說jmp/call指令指定的是一個絕對地址。如果沒有指定"*",則操作數是一個相對地址。

任何指令如果其操作數是一個內存操作,則指令必須指定它的操作尺寸(byte,word,long),也就是說必須帶有指令後綴(b,w,l)。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-12/93636p2.htm

Copyright © Linux教程網 All Rights Reserved