標籤:att 組合語言 作業系統
前言:組合語言,對下取決於體繫結構;對上取決於彙編器。在linux下,GCC編譯出來的彙編預設為ATT文法的彙編,本文主要介紹ATT彙編:運算元長度、立即數表示方法,寄存器引用,運算元順序,符號常量,記憶體引用等。
1,運算元的長度
運算元的長度用加在指令後的符號表示 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“
2. 立即數
使用立即數,要在數前面加符號$, 如“movl $0x04, %ebx”或者:
para = 0x04
movl $para, %ebx
3.寄存器引用
引用寄存器要在寄存器號前加百分比符號%,如“movl %eax, %ebx”。
80386 有如下寄存器:8 個 32-bit 寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;
8 個 16-bit 寄存器,它們事實上是上面 8 個 32-bit 寄存器的低 16 位:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp;
8 個 8-bit 寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。它們事實上是寄存器%ax,%bx,%cx,%dx 的高 8 位和低 8 位;
6 個段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs;
3 個控制寄存器:%cr0,%cr2,%cr3;
6 個 debug 寄存器:%db0,%db1,%db2,%db3,%db6,%db7;
2 個測試寄存器:%tr6,%tr7;
8 個浮點寄存器棧:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),%st(7).
4. 運算元順序
運算元排列是從源(左)到目的(右),如“movl %eax(源), %ebx(目的)”
5, 符號常數
符號常數直接引用 如value: .long 0x12a3f2de
movl value , %ebx
指令執行的結果是將常數 0x12a3f2de 裝入寄存器 ebx。
引用符號地址在符號前加符號$, 如“movl $value, % ebx”則是將符號 value 的地址裝入寄存器 ebx。
6. 記憶體引用
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)。