如何通過asm關(guān)鍵字嵌入?yún)R編語言代碼?
4. test5.c 聲明改動的寄存器
在 test4.c 中,我們沒有聲明改動的寄存器,所以編譯器可以任意選擇使用哪些寄存器。從生成的匯編代碼 test4.s 中可以看到,gcc 使用了 %edx 寄存器。
那么我們來測試一下:告訴 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)匯編代碼中,我們會使用到 %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 個寄存器來操作 2 個局部變量,如果操作數(shù)有很多,那么在內(nèi)聯(lián)匯編代碼中去寫每個寄存器的名稱,就顯得很不方便。
因此,擴展 asm 格式為我們提供了另一種偷懶的方法,來使用輸出和輸入操作數(shù)列表中的寄存器:占位符!
占位符有點類似于批處理腳本中,利用 2...來引用輸入?yún)?shù)一樣,內(nèi)聯(lián)匯編代碼中的占位符,從輸出操作數(shù)列表中的寄存器開始從 0 編號,一直編號到輸入操作數(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, 也就是說不指定寄存器,由編譯器來選擇使用哪個寄存器來存儲結(jié)果,最后復制到局部變量 data3中;
輸入操作數(shù)列表"r"(data1),"r"(data2):約束字符r, 不指定寄存器,由編譯器來選擇使用哪 2 個寄存器來接收局部變量 data1 和 data2;
輸出操作數(shù)列表中只需要一個寄存器,因此在內(nèi)聯(lián)匯編代碼中的 %0 就代表這個寄存器(即:從 0 開始計數(shù));
輸入操作數(shù)列表中有 2 個寄存器,因此在內(nèi)聯(lián)匯編代碼中的 %1 和 %2 就代表這 2 個寄存器(即:從輸出操作數(shù)列表的最后一個寄存器開始順序計數(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 來存儲局部變量 data1,%edx 來存儲局部變量 data2 ,然后操作結(jié)果也存儲在 %eax 寄存器中。
是不是感覺這樣操作就方便多了?不用我們來指定使用哪些寄存器,直接交給編譯器來選擇。
在內(nèi)聯(lián)匯編代碼中,使用 %0、%1 、%2 這樣的占位符來使用寄存器。
別急,如果您覺得使用編號還是麻煩,容易出錯,還有另一個更方便的操作:擴展 asm 格式還允許給這些占位符重命名,也就是給每一個寄存器起一個別名,然后在內(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 編譯器選擇的)取了一個別名 v3;
輸入操作數(shù)列表:給寄存器(gcc 編譯器選擇的)取了一個別名 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等等)。
我們可以指定使用哪個寄存器,也可以交給編譯器來選擇使用哪些寄存器,通過寄存器來操作數(shù)據(jù),速度會更快一些。
如果我們愿意的話,也可以直接使用變量的內(nèi)存地址來操作變量,此時就需要使用約束字符 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)匯編代碼中,因為需要進行相加計算,因此需要使用一個寄存器(%eax),計算這個環(huán)節(jié)是肯定需要寄存器的。
在操作那些內(nèi)存地址中的數(shù)據(jù)時,使用的仍然是按順序編號的占位符。
生成匯編代碼指令:
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
可以看到:在進入內(nèi)聯(lián)匯編代碼之前,把 data1 和 data2 的值放在了棧中,然后直接把棧中的數(shù)據(jù)與寄存器 %eax 進行操作,最后再把操作結(jié)果(%eax),復制到棧中 data3 的位置(-16(%ebp))。
五、總結(jié)
通過以上 8 個示例,我們把內(nèi)聯(lián)匯編代碼中的關(guān)鍵語法規(guī)則進行了講解,有了這個基礎(chǔ),就可以在內(nèi)聯(lián)匯編代碼中編寫更加復雜的指令了。
希望以上內(nèi)容對您能有所幫助!謝謝!
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個字
最新活動更多
-
即日-11.13立即報名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月20日火熱報名中>> 2024 智能家居出海論壇
-
11月28日立即報名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會議
-
12月19日立即報名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍皮書》
推薦專題
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市