gnu的c編譯器使用asm關鍵字:asm段格式如下:
asm ("assembly code");
一些彙編器使用製表符字元縮排指令以便區分和標籤。gnu編譯器不需要這樣做,單為保持一致使用這樣方式。
asm("mov $1, %eax\n\tmov $0, %ebx\n\tint $0x80");
這樣格式有些混亂,下面這樣方式書寫:
asm("mov $1, %eax\n\t"
"mov $0, %ebx\n\t"
"int $0x80");
將asm放入到**中例如:
#include int main()
基本內聯彙編**,可以使用程式定義的全域性c變數。
#include int a = 10;
int b = 20;
int result
int main()
注意
:資料變數必須被宣告為全域性的,不能在asm段中使用區域性變數。
使用volatile修飾符的新增不希望優化這個**段。
asm volatile("assembly code");
ansi c規範把關鍵字asm用於其他用途,不能用於內聯彙編。ansi c想使用內聯彙編,則使用__asm__
關鍵字替代asm
__asm__("assembly code");
基本asm有其侷限性:
gnu彙編器提供asm段的擴充套件格式來幫助解決這些問題。asm擴充套件版的格式如下:
asm("assembly code"
:ouput locations
:input operands
:changed registers);
有4個部分組成,使用冒號組成:
其中,輸入和輸出可以為空,只有最後乙個冒號可以省略。
擴充套件格式,可以從暫存器和記憶體位置給輸入
值和輸出
值賦值。輸入值和輸出值列表的格式是:
"constraint" (variable)
其中:約束描述a
使用%eax,%ax或者%al暫存器
b使用%ebx,%bx或者%bl暫存器
c使用%ecx,%cx或者%cl暫存器
d使用%edx,%dx或者%dl暫存器
s使用%esi或者%si暫存器
d使用%edi或者%di暫存器
r使用任何通用的暫存器
q使用%eax,%ebx,%ecx,或者%edx暫存器之一
a對於64位值使用%eax和%ebx暫存器
f使用浮點暫存器
t使用第乙個(頂部的)浮點暫存器
u使用第二個浮點暫存器
m使用變數的記憶體位置
o使用偏移記憶體位置
v只是用直接記憶體位置
i使用立即整數值
n使用值已知的立即整數值
g使用任何可用的暫存器或者記憶體位置
除了約束之外,輸出值包含約束修飾符,指示編譯器如何處理輸出值,可以使用如下來修飾輸出值:
輸出修飾符描述+
可以讀取和寫入運算元
=只能寫入運算元
%如果必要,運算元可以和下乙個運算元切換
&在內聯函式完成之前,可以刪除或者重新使用運算元
例如:asm("assembly code" : "=a"(result) :"d"(data1), "c"(data2));
注意
:輸入是c變數給暫存器,而輸出是暫存器給c變數。
如果輸入和輸出都給暫存器,幾乎和平常一樣使用暫存器,需注意的是擴充套件asm中,在彙編**中引用暫存器,必須使用兩個百分號符號。
#include int main()
movs指令輸入值包含輸出位置,volatile很重要,編譯器因為沒有輸出值,認為這個asm沒有必要而刪除asm段:
#include int main()
; char output[30];
int length = 25;
asm volatile (
"cld\n\t"
"rep movsb"
::"s"(input), "d"(output), "c"(length)
);printf("%s", output)
return 0;
}
很多輸入和輸出的情況,可以使用佔位符(placeholder)。佔位符是前面加上百分號的數字。按照內聯彙編**中列出的每個輸入值和輸出值在列表中的位置。每個值被賦予乙個從零開始的數字。然後可以在彙編**中使用佔位符表示值。
asm("assembly code"
:"=r"(result)
:"r"(data1), "r"(data2));
其中:
注意
:佔位符提供在內聯彙編**中利用暫存器和記憶體位置的方法。彙編**中使用佔位符只作為原始的資料:
imull %1, %2
movl %2, %0
示例如下:
#include int main()
gdb除錯:info reg
整個asm被看作為一條語句,使用stepi來除錯asm彙編
如果內聯彙編**中的輸入值和輸出值共享程式中相同的c變數,可以指定使用佔位符作為約束值。
修改上面個彙編**如下:
asm("imull %1, %0"
:"=r"(data2)
:"r"(data1),"0"(data2));
如果很多佔位符,就會混亂。從gnu3.1開始允許宣告替換名稱作為佔位符。格式如下:%[name]"constraint"(variable)
定義的值name成為內聯彙編**中的變數新的佔位符識別符號,下面例子:
asm("imull %[value1], %[value2]"
:[value2]"=r"(data2)
:[value1]"r"(data1),"0"(data2));
使用佔位替換佔位符名稱的方式和使用普通的佔位符相同。
改動暫存器列表:如果改動了不在輸入和輸出列表中的暫存器,要進行申明這些暫存器。
#include int main()
讓編譯器正確避免使用eax暫存器,因為在內聯彙編**中宣告了要使用它。
在改動暫存器列表中使用memory,通知編譯器這個記憶體位置在內聯彙編**中被改動。
雖然內聯彙編**使用暫存器比較快,但也可以使用c變數的記憶體位置。約束m
用於引用輸入和輸出值中的記憶體位置。要求使用暫存器的彙編指令,仍然必須使用暫存器,所以不許不得不定義儲存資料的中間暫存器。
#include int main()
內聯彙編**中是使用標籤有兩個限制。
#include int main()
#include int main()
backward和forward
和對待c巨集函式一樣,可以宣告包含內聯彙編的巨集函式。內聯彙編**必須使用擴充套件asm格式,便於輸入正確的輸入值和輸出值。
定義乙個內聯彙編巨集函式的乙個例子:
#define greater(a, b, result) ()
GNU內聯彙編
組合語言 gcc內聯彙編 gcc支援在c c 中嵌入彙編 這些 被稱作是 gcc inline asm gcc內聯彙編 一 基本內聯彙編 gcc中基本的內聯彙編非常易懂,格式如下 asm volatile instruction list 其中,1.asm 它是gcc定義的關鍵字asm的巨集定義 d...
彙編 div Solidity內聯彙編
在用solidity開發以太坊智慧型合約時,使用彙編可以直接與evm互動,降低gas開銷成本,更精細的控制智慧型合約的行為,因此值得solidity開發者學習並加以利用。本文是solidity彙編開發的簡明教程,旨在幫助你快速熟悉如何在solidity智慧型合約 中嵌入彙編 以太坊虛擬機器evm有自...
ARM彙編和Gnu彙編的轉換
將 arm ads 下的彙編碼移植到 gcc for arm 編譯器時,有如下規則 1,注釋行以 或 代替 2,get 或 include include 如 get option.a include option.a 3,equ equ tclk2 equ pb25 equ tclk2,pb25 ...