有時候需要在c語言裡使用組合語言,或者是提高效能,或者是因為某些功能不能由系統呼叫實現。而在核心裡,c語言裡嵌入彙編是非常普遍的。如何在c語言裡嵌入組合語言呢?
intmain()
使用__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
紅色的部分就是我們嵌入的**。
上面的指令確實執行了我們嵌入的兩條指令,可是這兩條指令只是執行了。沒給我們任何結果。如果我們想用彙編實現兩個記憶體數的相加,怎麼辦?
intmain()
中間要怎麼填呢?
__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」 等。
全域性變數
如果使用全域性變數就不用這麼麻煩了。
inta,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 ...