GNU 內聯彙編

2022-09-10 07:42:13 字數 4090 閱讀 7374

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 ...