gcc彙編格式及其與MS下彙編格式區別

2021-06-16 10:06:18 字數 3221 閱讀 6271

gcc採用的是at&t的彙編格式,ms採用intel的格式.

一 基本語法

語法上主要有以下幾個不同.

★ 暫存器命名原則

at&t: %eax              intel: eax

★源/目的運算元順序

at&t: movl %eax,%ebx    intel: mov ebx,eax

★常數/立即數的格式

at&t: movl $_value,%ebx intel: mov eax,_value

把_value的位址放入eax暫存器

at&t: movl $0xd00d,%ebx intel: mov ebx,0xd00d

★ 運算元長度標識

at&t: movw %ax,%bx      intel: mov bx,ax

★定址方式

at&t:   immed32(basepointer,indexpointer,indexscale)

intel:  [basepointer + indexpointer*indexscale + imm32)

linux工作於保護模式下,用的是32位線性位址,所以在計算位址時

不用考慮segment:offset的問題.上式中的位址應為:

imm32 + basepointer + indexpointer*indexscale

下面是一些例子:

★直接定址

at&t:   _booga ; _booga是乙個全域性的c變數

注意加上$是表示位址引用,不加是表示值引用.

注:對於區域性變數,可以通過堆疊指標引用.

intel: [_booga]

★暫存器間接定址

at&t:   (%eax)

intel: [eax]

★變址定址

at&t:   _variable(%eax)

intel: [eax + _variable]

at&t:   _array(,%eax,4)

intel:  [eax*4 + _array]

at&t:   _array(%ebx,%eax,8)

intel:  [ebx + eax*8 + _array]

二 基本的行內彙編

基本的行內彙編很簡單,一般是按照下面的格式

asm("statements");

例如:asm("nop"); asm("cli");

asm 和 __asm__是完全一樣的.

如果有多行彙編,則每一行都要加上 " "

例如:asm(    "pushl %eax "

"movl $0,%eax "

"popl %eax");

實際上gcc在處理彙編時,是要把asm(...)的內容"列印"到彙編

檔案中,所以格式控制字元是必要的.

再例如:

asm("movl %eax,%ebx");

asm("xorl %ebx,%edx");

asm("movl $0,_booga);

在上面的例子中,由於我們在行內彙編中改變了edx和ebx的值,但是

由於gcc的特殊的處理方法,即先形成彙編檔案,再交給gas去彙編,

所以gas並不知道我們已經改變了edx和ebx的值,如果程式的上下文

需要edx或ebx作暫存,這樣就會引起嚴重的後果.對於變數_booga也

存在一樣的問題.為了解決這個問題,就要用到擴充套件的行內彙編語法.

三 擴充套件的行內彙編

擴充套件的行內彙編類似於watcom.

基本的格式是:

asm ( "statements" : output_regs : input_regs : clobbered_regs);

clobbered_regs指的是被改變的暫存器.

下面是乙個例子(為方便起見,我使用全域性變數):

int count=1;

int value=1;

int buf[10];

void main()

得到的主要彙編**為:

movl count,%ecx

movl value,%eax

movl buf,%edi

cldrep

stosl

cld,rep,stos就不用多解釋了.

這幾條語句的功能是向buf中寫上count個value值.

冒號後的語句指明輸入,輸出和被改變的暫存器.

通過冒號以後的語句,編譯器就知道你的指令需要和改變哪些暫存器,

從而可以優化暫存器的分配.

其中符號"c"(count)指示要把count的值放入ecx暫存器

類似的還有:

a       eax

b       ebx

c       ecx

d       edx

s       esi

d       edi

i       常數值,(0 - 31)

q,r     動態分配的暫存器

g       eax,ebx,ecx,edx或記憶體變數

a       把eax和edx合成乙個64位的暫存器(use long longs)

我們也可以讓gcc自己選擇合適的暫存器.

如下面的例子:

asm("leal (%1,%1,4),%0"

: "=r" (x)

: "0" (x) );

這段**實現5*x的快速乘法.

得到的主要彙編**為:

movl x,%eax

leal (%eax,%eax,4),%eax

movl %eax,x

幾點說明:

1.使用q指示編譯器從eax,ebx,ecx,edx分配暫存器.

使用r指示編譯器從eax,ebx,ecx,edx,esi,edi分配暫存器.

2.我們不必把編譯器分配的暫存器放入改變的暫存器列表,因為暫存器

已經記住了它們.

3."="是標示輸出暫存器,必須這樣用.

4.數字%n的用法:

數字表示的暫存器是按照出現和從左到右的順序對映到用"r"或"q"請求

的暫存器.如果我們要重用"r"或"q"請求的暫存器的話,就可以使用它們.

5.如果強制使用固定的暫存器的話,如不用%1,而用ebx,則

asm("leal (%%ebx,%%ebx,4),%0"

: "=r" (x)

: "0" (x) );

注意要使用兩個%,因為乙個%的語法已經被%n用掉了.

AT T彙編格式與Intel彙編格式的比較

gcc採用的是at t的彙編格式,也叫gas格式 gnu asembler gnu彙編器 而微軟採用intel的彙編格式.一 基本語法 語法上主要有以下幾個不同.1 暫存器命名原則 at t intel 說明 eax eaxintel的不帶百分號 2 源 目的運算元順序 at t intel 說明m...

AT T彙編格式與Intel彙編格式的比較

gcc採用的是at t的彙編格式,也叫gas格式 gnu asembler gnu彙編器 而微軟採用intel的彙編格式.一 基本語法 語法上主要有以下幾個不同.1 暫存器命名原則 at t intel 說明 eax eaxintel的不帶百分號 2 源 目的運算元順序 at t intel 說明m...

AT T彙編格式與Intel彙編格式的比較

gcc採用的是at t的彙編格式,也叫gas格式 gnu asembler gnu彙編器 而微軟採用intel的彙編格式.一 基本語法 語法上主要有以下幾個不同.1 暫存器命名原則 at t intel 說明 eax eaxintel的不帶百分號 2 源 目的運算元順序 at t intel 說明m...