ATT 彙編語法

2021-06-07 19:48:20 字數 4053 閱讀 1795

在研華的pc104上使用看門狗要使用彙編。使用彙編來修改cmos裡面的引數。也就是內聯彙編。

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 t通用暫存器 %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 位;

但有的有特殊的用途:ax為累加器,cx為計數器,bx,bp為基址暫存器,si,di為變址暫存器,bp還可以是基指標,sp為堆疊指標。

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)。

1,內聯彙編。

兩種內聯彙編的格式。

一、基本內聯彙編的格式是

__asm__ __volatile__("instruction list");

二、帶有 c/c++表示式的內聯彙編格式為:

__asm__ __volatile__("instruction list" : output : input : clobber/modify);

規則:1,這 4 個部分都不是必須的,任何乙個部分都可以為空。

2,如 果 clobber/modify 為 空 , 則 其 前 面 的 冒 號 (:) 必 須 省 略 。 比 如 __asm__("mov %

%eax, %%ebx" : "=b"(foo) : "a"(inp) : ) 就 是 非 法 的 寫 法 ; 而 __asm__("mov %

%eax, %%ebx" : "=b"(foo) : "a"(inp) )則是正確的。

3,"instruction list"中的暫存器寫法要遵守相關規定,比如暫存器前必須使用兩個百分號(%%),

而不是像基本彙編格式一樣在暫存器前只使用乙個百分號(%)。比如 __asm__( " mov %%eax, %%ebx" : : );

__asm__( " mov %%eax, %%ebx" : ) 和 __asm__( " mov %eax, %ebx" ) 都 是 正 確 的 寫 法 , 而

__asm__( " mov %eax, %ebx" : : );__asm__( " mov %eax, %ebx" : )和__asm__(

" mov %%eax, %%ebx" )都是錯誤的寫法。

4,區分乙個內聯彙編是基本格式的還是帶有 c/c++表示式格式的,其規則在於在"instruction list"後

是否有冒號(:)的存在,如果沒有則是基本格式的,否則,則是帶有 c/c++表示式格式的。

5,ouput:

例子:

int

func

(void

)

我們可以很清楚得看到這個輸出操作由兩部分組成:括號括住 的部分 (b)和引號引

住的部分"=a"。這兩部分都是每乙個輸出操作必不可少的。其中括號裡面的是c/c++

表示式,而且只能是左值表示式。而右值來自於引用部分。引號中的內容,被稱作

「操作約束」(operation constraint),在這個例子中操作約束為"=a",它包含兩個約束:

等號(=)和字母 a,其中等號(=)說明括號中左值表示式b是乙個 write-only 的,只能夠

被作為當前內聯彙編的輸入,而不能作為輸入。而字母 a 是暫存器 eax / ax / al 的

簡寫,說明 cr0 的值要從 eax 暫存器中獲取,也就是說b = eax。

6,input.

理解了output,再來理解input很容易。

__asm__("movl %0, %%db7" : : "a" (cpu->db7));

括號裡面的是c/c++表示式,可以是左值,也可以是右值。

引號裡面的是暫存器。暫存器作為左值。

**:

AT T彙編語法格式

1.暫存器的引用要在暫存器前加 如mov eax,ebx 2.運算元排列是左源右目的,如上例表示把值從eax暫存器mov到ebx暫存器 3.常數 立即數前面要加 如mov 4,ebx 4.對於變數加 表示取位址。如mov value,ebx表示傳值給ebx,而mov value,ebx表示傳位址給e...

AT T彙編語法簡介

引用自 ps 這段時間在研究linux源 遇到了at t彙編,故轉貼個不錯的at t彙編貼。就像軟體的真諦 給我乙個標準,我用我的邏輯舞動世界 一樣,at t彙編是組合語言裡的另一種標準,這是相對於鼎鼎大名的intel的x86彙編來說。即使對於電子專業的學生來說,一旦掌握了c51微控制器的彙編,x8...

AT T下彙編語法

mov long 32bits mov word 16bits mov byte 8bits 取有效位址 偏移量 lea ignore int,edx 表示把ignore int處的有效位址傳給edx note 是去ignore int處的偏移量,而不是ignore int處儲存的內容 使用方法 l...