訂閱
糾錯(cuò)
加入自媒體

如何通過(guò)asm關(guān)鍵字嵌入?yún)R編語(yǔ)言代碼?

查看 test2.s 中內(nèi)聯(lián)匯編代碼之前的部分,可以看到:

.file "test2.c"
.globl a
.data
.a(chǎn)lign 4
.type a, @object
.size a, 4
a:
.long 1
.globl b
.a(chǎn)lign 4
.type b, @object
.size b, 4
b:
.long 2
.comm c,4,4

變量 a, b 被 .globl 修飾,c 被 .comm 修飾,相當(dāng)于是把它們導(dǎo)出為全局的,所以可以在匯編代碼中使用。

那么問(wèn)題來(lái)了:如果是一個(gè)局部變量,在匯編代代碼中就不會(huì)用 .globl 導(dǎo)出,此時(shí)在內(nèi)聯(lián)匯編指令中,還可以直接使用嗎?

眼見(jiàn)為實(shí),我們把這 3 個(gè)變量放到 main 函數(shù)的內(nèi)部,作為局部變量來(lái)試一下。

4. test3.c 嘗試操作局部變量#include <stdio.h>
int main()

   int a = 1;
   int b = 2;
   int c;
   asm("movl a, %eax "
       "addl b, %eax "
       "movl %eax, c");
   printf("c = %d ", c);
   return 0;

生成匯編代碼指令:

gcc -m32 -S -o test3.s test3.c

在 test3.s 中可以看到?jīng)]有 a, b, c 的導(dǎo)出符號(hào),a 和 b 沒(méi)有其他地方使用,因此直接把他們的數(shù)值復(fù)制到?臻g中了:

movl $1, -20(%ebp)
movl $2, -16(%ebp)

我們來(lái)嘗試編譯成可執(zhí)行程序:

$ gcc -m32 -o test3 test3.c
/tmp/ccuY0TOB.o: In function `main':
test3.c:(.text+0x20): undefined reference to `a'
test3.c:(.text+0x26): undefined reference to `b'
test3.c:(.text+0x2b): undefined reference to `c'
collect2: error: ld returned 1 exit status

編譯報(bào)錯(cuò):找不到對(duì) a,b,c 的引用!那該怎么辦,才能使用局部變量呢?擴(kuò)展 asm 格式!

二、擴(kuò)展 asm 格式

 1. 指令格式

asm [volatile] ("匯編指令" : "輸出操作數(shù)列表" : "輸入操作數(shù)列表" : "改動(dòng)的寄存器")

格式說(shuō)明

匯編指令:與基本asm格式相同;

輸出操作數(shù)列表:匯編代碼如何把處理結(jié)果傳遞到 C 代碼中;

輸入操作數(shù)列表:C 代碼如何把數(shù)據(jù)傳遞給內(nèi)聯(lián)匯編代碼;

改動(dòng)的寄存器:告訴編譯器,在內(nèi)聯(lián)匯編代碼中,我們使用了哪些寄存器;

“改動(dòng)的寄存器”可以省略,此時(shí)最后一個(gè)冒號(hào)可以不要,但是前面的冒號(hào)必須保留,即使輸出/輸入操作數(shù)列表為空。

關(guān)于“改動(dòng)的寄存器”再解釋一下:gcc 在編譯 C 代碼的時(shí)候,需要使用一系列寄存器;我們手寫(xiě)的內(nèi)聯(lián)匯編代碼中,也使用了一些寄存器。

為了通知編譯器,讓它知道: 在內(nèi)聯(lián)匯編代碼中有哪些寄存器被我們用戶(hù)使用了,可以在這里列舉出來(lái),這樣的話(huà),gcc 就會(huì)避免使用這些列舉出的寄存器

2. 輸出和輸入操作數(shù)列表的格式

在系統(tǒng)中,存儲(chǔ)變量的地方就2個(gè):寄存器和內(nèi)存。因此,告訴內(nèi)聯(lián)匯編代碼輸出和輸入操作數(shù),其實(shí)就是告訴它:

向哪些寄存器或內(nèi)存地址輸出結(jié)果;

從哪些寄存器或內(nèi)存地址讀取輸入數(shù)據(jù);

這個(gè)過(guò)程也要滿(mǎn)足一定的格式:

"[輸出修飾符]約束"(寄存器或內(nèi)存地址)

(1)約束

就是通過(guò)不同的字符,來(lái)告訴編譯器使用哪些寄存器,或者內(nèi)存地址。包括下面這些字符:

a: 使用 eax/ax/al 寄存器;

b: 使用 ebx/bx/bl 寄存器;

c: 使用 ecx/cx/cl 寄存器;

d: 使用 edx/dx/dl 寄存器;

r: 使用任何可用的通用寄存器;

m: 使用變量的內(nèi)存位置;

先記住這幾個(gè)就夠用了,其他的約束選項(xiàng)還有:D, S, q, A, f, t, u等等,需要的時(shí)候再查看文檔。

(2)輸出修飾符

顧名思義,它使用來(lái)修飾輸出的,對(duì)輸出寄存器或內(nèi)存地址提供額外的說(shuō)明,包括下面4個(gè)修飾符:

+:被修飾的操作數(shù)可以讀取,可以寫(xiě)入;

=:被修飾的操作數(shù)只能寫(xiě)入;

%:被修飾的操作數(shù)可以和下一個(gè)操作數(shù)互換;

&:在內(nèi)聯(lián)函數(shù)完成之前,可以刪除或者重新使用被修飾的操作數(shù);

語(yǔ)言描述比較抽象,直接看例子!

3. test4.c 通過(guò)寄存器操作局部變量#include <stdio.h>
int main()

   int data1 = 1;
   int data2 = 2;
   int data3;
   asm("movl %%ebx, %%eax "
       "addl %%ecx, %%eax"
       : "=a"(data3)
       : "b"(data1),"c"(data2));
   printf("data3 = %d ", data3);
   return 0;

有 2 個(gè)地方需要注意一下啊:

在內(nèi)聯(lián)匯編代碼中,沒(méi)有聲明“改動(dòng)的寄存器”列表,也就是說(shuō)可以省略掉(前面的冒號(hào)也不需要);

擴(kuò)展asm格式中,寄存器前面必須寫(xiě) 2 個(gè)%;

代碼解釋?zhuān)?/p>

"b"(data1),"c"(data2) ==> 把變量 data1 復(fù)制到寄存器 %ebx,變量 data2 復(fù)制到寄存器 %ecx。這樣,內(nèi)聯(lián)匯編代碼中,就可以通過(guò)這兩個(gè)寄存器來(lái)操作這兩個(gè)數(shù)了;

"=a"(data3) ==> 把處理結(jié)果放在寄存器 %eax 中,然后復(fù)制給變量data3。前面的修飾符等號(hào)意思是:會(huì)寫(xiě)入往 %eax 中寫(xiě)入數(shù)據(jù),不會(huì)從中讀取數(shù)據(jù);

通過(guò)上面的這種格式,內(nèi)聯(lián)匯編代碼中,就可以使用指定的寄存器來(lái)操作局部變量了,稍后將會(huì)看到局部變量是如何從經(jīng)過(guò)?臻g,復(fù)制到寄存器中的。

生成匯編代碼指令:

gcc -m32 -S -o test4.s test4.c

匯編代碼 test4.s 如下:

movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl -20(%ebp), %eax
movl -16(%ebp), %edx
movl %eax, %ebx
movl %edx, %ecx
#APP
# 10 "test4.c" 1
movl %ebx, %eax
addl %ecx, %eax
# 0 "" 2
#NO_APP
   movl %eax, -12(%ebp)

可以看到,在進(jìn)入手寫(xiě)的內(nèi)聯(lián)匯編代碼之前:

把數(shù)字 1 通過(guò)棧空間(-20(%ebp)),復(fù)制到寄存器 %eax,再?gòu)?fù)制到寄存器 %ebx;

把數(shù)字 2 通過(guò)棧空間(-16(%ebp)),復(fù)制到寄存器 %edx,再?gòu)?fù)制到寄存器 %ecx;

這 2 個(gè)操作正是對(duì)應(yīng)了內(nèi)聯(lián)匯編代碼中的“輸入操作數(shù)列表”部分:"b"(data1),"c"(data2)。

在內(nèi)聯(lián)匯編代碼之后(#NO_APP 之后),把 %eax 寄存器中的值復(fù)制到棧中的 -12(%ebp) 位置,這個(gè)位置正是局部變量 data3 所在的位置,這樣就完成了輸出操作。

聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

    掃碼關(guān)注公眾號(hào)
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號(hào)