如何通過asm關(guān)鍵字嵌入?yún)R編語言代碼?
4. test5.c 聲明改動(dòng)的寄存器
在 test4.c 中,我們沒有聲明改動(dòng)的寄存器,所以編譯器可以任意選擇使用哪些寄存器。從生成的匯編代碼 test4.s 中可以看到,gcc 使用了 %edx 寄存器。
那么我們來測(cè)試一下:告訴 gcc 不要使用 %edx 寄存器。
#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)
: "%edx");
printf("data3 = %d ", data3);
return 0;
}
代碼中,asm 指令最后部分 "%edx" ,就是用來告訴 gcc 編譯器:在內(nèi)聯(lián)匯編代碼中,我們會(huì)使用到 %edx 寄存器,你就不要用它了。
生成匯編代碼指令:
gcc -m32 -S -o test5.s test5.c
來看一下生成的匯編代碼 test5.s:
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl -20(%ebp), %eax
movl -16(%ebp), %ecx
movl %eax, %ebx
#APP
# 10 "test5.c" 1
movl %ebx, %eax
addl %ecx, %eax
# 0 "" 2
#NO_APP
movl %eax, -12(%ebp)
可以看到,在內(nèi)聯(lián)匯編代碼之前,gcc 沒有選擇使用寄存器 %edx。
三、使用占位符來代替寄存器名稱
在上面的示例中,只使用了 2 個(gè)寄存器來操作 2 個(gè)局部變量,如果操作數(shù)有很多,那么在內(nèi)聯(lián)匯編代碼中去寫每個(gè)寄存器的名稱,就顯得很不方便。
因此,擴(kuò)展 asm 格式為我們提供了另一種偷懶的方法,來使用輸出和輸入操作數(shù)列表中的寄存器:占位符!
占位符有點(diǎn)類似于批處理腳本中,利用 2...來引用輸入?yún)?shù)一樣,內(nèi)聯(lián)匯編代碼中的占位符,從輸出操作數(shù)列表中的寄存器開始從 0 編號(hào),一直編號(hào)到輸入操作數(shù)列表中的所有寄存器。
還是看例子比較直接!
1. test6.c 使用占位符代替寄存器#include <stdio.h>
int main()
{
int data1 = 1;
int data2 = 2;
int data3;
asm("addl %1, %2 "
"movl %2, %0"
: "=r"(data3)
: "r"(data1),"r"(data2));
printf("data3 = %d ", data3);
return 0;
}
代碼說明:
輸出操作數(shù)列表"=r"(data3):約束使用字符 r, 也就是說不指定寄存器,由編譯器來選擇使用哪個(gè)寄存器來存儲(chǔ)結(jié)果,最后復(fù)制到局部變量 data3中;
輸入操作數(shù)列表"r"(data1),"r"(data2):約束字符r, 不指定寄存器,由編譯器來選擇使用哪 2 個(gè)寄存器來接收局部變量 data1 和 data2;
輸出操作數(shù)列表中只需要一個(gè)寄存器,因此在內(nèi)聯(lián)匯編代碼中的 %0 就代表這個(gè)寄存器(即:從 0 開始計(jì)數(shù));
輸入操作數(shù)列表中有 2 個(gè)寄存器,因此在內(nèi)聯(lián)匯編代碼中的 %1 和 %2 就代表這 2 個(gè)寄存器(即:從輸出操作數(shù)列表的最后一個(gè)寄存器開始順序計(jì)數(shù));
生成匯編代碼指令:
gcc -m32 -S -o test6.s test6.c
匯編代碼如下 test6.s:
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl -20(%ebp), %eax
movl -16(%ebp), %edx
#APP
# 10 "test6.c" 1
addl %eax, %edx
movl %edx, %eax
# 0 "" 2
#NO_APP
movl %eax, -12(%ebp)
可以看到,gcc 編譯器選擇了 %eax 來存儲(chǔ)局部變量 data1,%edx 來存儲(chǔ)局部變量 data2 ,然后操作結(jié)果也存儲(chǔ)在 %eax 寄存器中。
是不是感覺這樣操作就方便多了?不用我們來指定使用哪些寄存器,直接交給編譯器來選擇。
在內(nèi)聯(lián)匯編代碼中,使用 %0、%1 、%2 這樣的占位符來使用寄存器。
別急,如果您覺得使用編號(hào)還是麻煩,容易出錯(cuò),還有另一個(gè)更方便的操作:擴(kuò)展 asm 格式還允許給這些占位符重命名,也就是給每一個(gè)寄存器起一個(gè)別名,然后在內(nèi)聯(lián)匯編代碼中使用別名來操作寄存器。
還是看代碼!
2. test7.c 給寄存器起別名#include <stdio.h>
int main()
{
int data1 = 1;
int data2 = 2;
int data3;
asm("addl %[v1], %[v2] "
"movl %[v2], %[v3]"
: [v3]"=r"(data3)
: [v1]"r"(data1),[v2]"r"(data2));
printf("data3 = %d ", data3);
return 0;
}
代碼說明:
輸出操作數(shù)列表:給寄存器(gcc 編譯器選擇的)取了一個(gè)別名 v3;
輸入操作數(shù)列表:給寄存器(gcc 編譯器選擇的)取了一個(gè)別名 v1 和 v2;
起立別名之后,在內(nèi)聯(lián)匯編代碼中就可以直接使用這些別名( %[v1], %[v2], %[v3])來操作數(shù)據(jù)了。
生成匯編代碼指令:
gcc -m32 -S -o test7.s test7.c
再來看一下生成的匯編代碼 test7.s:
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl -20(%ebp), %eax
movl -16(%ebp), %edx
#APP
# 10 "test7.c" 1
addl %eax, %edx
movl %edx, %eax
# 0 "" 2
#NO_APP
movl %eax, -12(%ebp)
這部分的匯編代碼與 test6.s 中完全一樣!
四、使用內(nèi)存位置
在以上的示例中,輸出操作數(shù)列表和輸入操作數(shù)列表部分,使用的都是寄存器(約束字符:a, b, c, d, r等等)。
我們可以指定使用哪個(gè)寄存器,也可以交給編譯器來選擇使用哪些寄存器,通過寄存器來操作數(shù)據(jù),速度會(huì)更快一些。
如果我們?cè)敢獾脑,也可以直接使用變量的?nèi)存地址來操作變量,此時(shí)就需要使用約束字符 m。
1. test8.c 使用內(nèi)存地址來操作數(shù)據(jù)#include <stdio.h>
int main()
{
int data1 = 1;
int data2 = 2;
int data3;
asm("movl %1, %%eax "
"addl %2, %%eax "
"movl %%eax, %0"
: "=m"(data3)
: "m"(data1),"m"(data2));
printf("data3 = %d ", data3);
return 0;
}
代碼說明:
輸出操作數(shù)列表 "=m"(data3):直接使用變量 data3 的內(nèi)存地址;
輸入操作數(shù)列表 "m"(data1),"m"(data2):直接使用變量 data1, data2 的內(nèi)存地址;
在內(nèi)聯(lián)匯編代碼中,因?yàn)樾枰M(jìn)行相加計(jì)算,因此需要使用一個(gè)寄存器(%eax),計(jì)算這個(gè)環(huán)節(jié)是肯定需要寄存器的。
在操作那些內(nèi)存地址中的數(shù)據(jù)時(shí),使用的仍然是按順序編號(hào)的占位符。
生成匯編代碼指令:
gcc -m32 -S -o test8.s test8.c
生成的匯編代碼如下 test8.s:
movl $1, -24(%ebp)
movl $2, -20(%ebp)
#APP
# 10 "test8.c" 1
movl -24(%ebp), %eax
addl -20(%ebp), %eax
movl %eax, -16(%ebp)
# 0 "" 2
#NO_APP
movl -16(%ebp), %eax
可以看到:在進(jìn)入內(nèi)聯(lián)匯編代碼之前,把 data1 和 data2 的值放在了棧中,然后直接把棧中的數(shù)據(jù)與寄存器 %eax 進(jìn)行操作,最后再把操作結(jié)果(%eax),復(fù)制到棧中 data3 的位置(-16(%ebp))。
五、總結(jié)
通過以上 8 個(gè)示例,我們把內(nèi)聯(lián)匯編代碼中的關(guān)鍵語法規(guī)則進(jìn)行了講解,有了這個(gè)基礎(chǔ),就可以在內(nèi)聯(lián)匯編代碼中編寫更加復(fù)雜的指令了。
希望以上內(nèi)容對(duì)您能有所幫助!謝謝!

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
3月27日立即報(bào)名>> 【工程師系列】汽車電子技術(shù)在線大會(huì)
-
4月30日立即下載>> 【村田汽車】汽車E/E架構(gòu)革新中,新智能座艙挑戰(zhàn)的解決方案
-
5月15-17日立即預(yù)約>> 【線下巡回】2025年STM32峰會(huì)
-
即日-5.15立即報(bào)名>>> 【在線會(huì)議】安森美Hyperlux™ ID系列引領(lǐng)iToF技術(shù)革新
-
5月15日立即下載>> 【白皮書】精確和高效地表征3000V/20A功率器件應(yīng)用指南
-
5月16日立即參評(píng) >> 【評(píng)選啟動(dòng)】維科杯·OFweek 2025(第十屆)人工智能行業(yè)年度評(píng)選
推薦專題
- 1 UALink規(guī)范發(fā)布:挑戰(zhàn)英偉達(dá)AI統(tǒng)治的開始
- 2 北電數(shù)智主辦酒仙橋論壇,探索AI產(chǎn)業(yè)發(fā)展新路徑
- 3 降薪、加班、裁員三重暴擊,“AI四小龍”已折戟兩家
- 4 “AI寒武紀(jì)”爆發(fā)至今,五類新物種登上歷史舞臺(tái)
- 5 國產(chǎn)智駕迎戰(zhàn)特斯拉FSD,AI含量差幾何?
- 6 光計(jì)算迎來商業(yè)化突破,但落地仍需時(shí)間
- 7 東陽光:2024年扭虧、一季度凈利大增,液冷疊加具身智能打開成長(zhǎng)空間
- 8 地平線自動(dòng)駕駛方案解讀
- 9 封殺AI“照騙”,“淘寶們”終于不忍了?
- 10 優(yōu)必選:營收大增主靠小件,虧損繼續(xù)又逢關(guān)稅,能否乘機(jī)器人東風(fēng)翻身?