gcc嵌入彙編

2021-09-21 10:55:18 字數 3503 閱讀 4047

有時候需要在c語言裡使用組合語言,或者是提高效能,或者是因為某些功能不能由系統呼叫實現。而在核心裡,c語言裡嵌入彙編是非常普遍的。如何在c語言裡嵌入組合語言呢?

int

main() 

使用__asm__巨集就可以嵌入彙編,__volatile__指示不讓gcc優化下面的彙編**。

.file 

"gccasm.c"

.text 

.globl main 

.type main, @function

main: 

pushl %ebp 

movl %esp, %ebp 

# 3 "gccasm.c"

1 movl %eax,%ebx 

addl %eax,%ebx 

# 0 ""

2 movl $0, %eax 

popl %ebp 

ret 

紅色的部分就是我們嵌入的**。

上面的指令確實執行了我們嵌入的兩條指令,可是這兩條指令只是執行了。沒給我們任何結果。如果我們想用彙編實現兩個記憶體數的相加,怎麼辦?

int

main() 

中間要怎麼填呢?

__asm__ ( 

"addl %2,%1\n\tmovl %1,%0\n"

:"=m"

(sum) 

:"r"

(a),

"r"(b) 

); 上面的**是什麼意思呢?

實際上,嵌入彙編的標準格式是下面這個樣子:

__asm__(

彙編語句模板

: 輸出部分

: 輸入部分

: 破壞描述部分);

第乙個冒號前邊是彙編語句模版,%0,%1,%2被稱為佔位符,%0是下面出現的第乙個變數,%1是第二個,依次類推,一共可以有10個,%0-%9。下面的三個變數出現順序是sum,a,b,因此%0,%1,%2分表代表sum,a,b。

那是不是這兩句彙編就相當於addl b,a; movl a,sum?明顯不是,因為一條指令是不能出現兩個記憶體數的。

接下來就是輸出部分和輸入部分了。這兩部分主要就是說使用了哪些變數,一次列出,比如這裡就列出了sum,a,b,分別用%0,%1,%2表示,但是每個變數前邊還有個標誌,是告訴編譯器怎麼使用這些變數。

輸出部分前邊還要加個「=」。這些標誌是什麼意思呢?前邊如果是r,那麼這個變數要事先處理一下,先載入乙個暫存器,然後再使用我們嵌入的彙編,因此前邊要加乙個指令,例如a和b,都是暫存器數,前邊還需要新增movl a,%eax movl b, %ebx(r表示讓編譯器選暫存器,可以使用其他標誌選特定的暫存器)。而sum是記憶體數,直接使用即可。因此這段**實際上對應的彙編**是:

movl a, %eax

movl b, %ebx

addl %ebx,%eax

movl %eax, sum

前邊兩條是編譯器加上的。

輸出部分就是說,在這段彙編執行完後,需要把結果儲存到這個變數中。如果變數是記憶體數(=m),那就不用管了,但如果變數在彙編指令執行過程中使用了暫存器,那麼需要將這個暫存器的值存入變數,例如使用了eax,那麼這段彙編後需要加上一條指令 movl %eax, sum。

如果我們將sum也使用暫存器,"=r",那麼會多加兩條語句

movl sum,%ecx

movl a, %eax

movl b, %ebx

addl %ebx,%eax

movl %eax, %ecx

movl %ecx, sum

實際上只在最後加了一句movl %ebx, sum,前邊那一句理論上是應該加的,但是由於並沒有對它進行破壞,不需要加。

最後的破壞部分是指該嵌入彙編**段可能會影響哪些暫存器,也可以是記憶體,告訴編譯器要注意保護這些地方。由逗號格開的字串組成,每個字串描述一種情況,一般是暫存器名;除暫存器外還有 「memory」。例如:「%eax」,「%ebx」,「memory」 等。

全域性變數

如果使用全域性變數就不用這麼麻煩了。

int

a,b,sum; 

intmain() 

注意:如果沒有出現%0,%1這樣的佔位符,暫存器就用%eax,%ebx,如果出現了,就用%%eax,%%ebx。

限制字元

限制字元有很多種,有些是與特定體系結構相關,此處僅列出常用的限定字元和i386中可能用到的一些常用的限定符。它們的作用是指示編譯器如何處理其後的 c 語言變數與指令運算元之間的關係。分類

限定符 描述

通用暫存器

「a」將輸入變數放入eax

「b」將輸入變數放入ebx

「c」將輸入變數放入ecx

「d」將輸入變數放入edx

「s」將輸入變數放入esi

「d」將輸入變數放入edi

「q」將輸入變數放入eax,ebx,ecx,edx中的乙個

「r」將輸入變數放入通用暫存器,即eax,ebx,ecx,edx,esi,edi之一

「a」把eax和edx合成乙個64

位的暫存器(use long longs) 記憶體

「m」記憶體變數

「o」運算元為記憶體變數,但其定址方式是偏移量型別,

也即基址定址

「v」運算元為記憶體變數,但定址方式不是偏移量型別

「 」運算元為記憶體變數,但定址方式為自動增量

「p」運算元是乙個合法的記憶體位址(指標)

暫存器或記憶體

「g」將輸入變數放入eax,ebx,ecx,edx之一,或作為記憶體變數

「x」運算元可以是任何型別

立即數「i」

0-31之間的立即數(用於32位移位指令)

「j」0-63之間的立即數(用於64位移位指令)

「n」0-255之間的立即數(用於out指令)

「i」立即數

「n」立即數,有些系統不支援除字以外的立即數,則應使用「n」而非

「i」

匹配「 0 」

表示用它限制的運算元與某個指定的運算元匹配

「1」 ...

也即該運算元就是指定的那個運算元,例如「0」

「9」去描述「%1」運算元,那麼「%1」引用的其實就是「%0」運算元,注意作為限定符字母的0-9

與指令中的「%0」-「%9」的區別,前者描述運算元,

後者代表運算元。 &

該輸出運算元不能使用過和輸入運算元相同的暫存器

運算元型別

「=」運算元在指令中是只寫的(輸出運算元)

「+」運算元在指令中是讀寫型別的(輸入輸出運算元)

浮點數「f」

浮點暫存器

「t」第乙個浮點暫存器

「u」第二個浮點暫存器

「g」標準的80387浮點常數

%該運算元可以和下乙個運算元交換位置,例如addl的兩個運算元可以交換順序(當然兩個運算元都不能是立即數)

#部分注釋,從該字元到其後的逗號之間所有字母被忽略

*表示如果選用暫存器,則其後的字母被忽略

GCC嵌入彙編

其中有一段精華如下 嵌入式彙編的一般形式 asm volatile output input modify 其中,asm 表示彙編 的開始,其後可以跟 volatile 這是可選項 其 含義是避免 asm 指令被刪除 移動或組合 然後就是小括弧,括弧中的內容是我們介 紹的重點 為彙編指令部分,例如,...

gcc嵌入彙編語法

以前學gcc嵌入彙編時的一些筆記,看一下對gcc的嵌入彙編比較有用處 1 格式 asm 以回車或分號分隔的彙編指令 以逗號分隔的輸出運算元 以逗號分隔的輸入運算元 以逗號分隔的受影響的暫存器或記憶體 2 輸出運算元表示彙編指令執行結果,輸入運算元表示彙編指令執行時的輸入值 3 每個輸出和輸入運算元都...

GCC內聯彙編

有時為了高效,有時為了直接控制硬體,有些模組我們不得不直接用組合語言來編寫,並且對外提供呼叫的介面,隱藏細節,這其實就是內聯彙編。如何使用內聯彙編?我們就以 gcc 為例,一窺其中奧秘!一 關鍵字 如何讓 gcc 知道 中內嵌的彙編呢?借助 關鍵字!來看下面的例子 asm volatile hlt ...