日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux C: 内嵌汇编语法

發布時間:2024/10/14 linux 77 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux C: 内嵌汇编语法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? 學內嵌匯編首先知道編譯器的編譯流程,內嵌匯編就是嵌套在高級程序語言中的匯編語言。在cpp 文件轉成 .s 匯編文件時,內嵌匯編保持不動,只有高級程序語言會編譯成匯編合成在.s文件中。下面的鏈接將了C的源碼是怎么變成匯編碼:

? ? 《Linux C:匯編碼的生成 》https://blog.csdn.net/superSmart_Dong/article/details/115920429

目錄

一、基本匯編

二、擴展匯編

1)占位符和操作數變量:

2)輸出操作數:

3)輸入操作數:

4)Clobbers:

5)GotoLabel:

三、擴展匯編的轉義

四、多匯編方言模板

五、常用的操作數類型

六、給C代碼命名一個asm匯編變量名


?

?

一、基本匯編

? ? ? 基本匯編就是純匯編語言,而擴展匯編在基本匯編上加了些功能,例如可用占位符實現從C程序中向內嵌匯編中傳遞/輸出變量值,而不用去分析當前代碼的堆棧結構。也可以不用關心具體用哪些寄存器合適。先來看看基本的內嵌匯編

int main(){int aaa = 1 ,bbb=2;__asm__ __volatile__ ("movl $88,-12(%ebp) \n\t""movl $66,-16(%ebp) \n\t");cout<<aaa<<" "<<bbb; //輸出 88 66return 0; }

? ? ? ? 內嵌匯編用? asm() 關鍵字來表明括號內寫的是匯編碼,每段匯編碼當用字符串引號來引起來,在編譯時直接套在編譯后的匯編文件中。由于計算機的原因,大多數系統用換行符作為匯編語言一條語句的結束符,而有些系統用分號';'表示,而也有些系統的分號是作為注釋符號。所以每個系統下的匯編語言語法可能并不統一

? ? ? ? 在上述代碼的匯編代碼塊中,%ebp 表示 ebp寄存器中對應的內存地址,而-12(%ebp)表示ebp寄存器中對應的內存地址再往低地址偏移12個字節。在我的系統中該地址對應的變量是aaa的地址值。上段代碼在我的WINDOWS上可以正常執行而在我的Linux上執行會出現段錯誤,代碼要改成如下方式才有同樣的效果。之所以無法兼容,是因為每個系統編譯出來的堆棧情況可能會不一樣,用的寄存器也不一樣。

#include "iostream"using namespace std; int main(){int aaa = 1 ,bbb=2;__asm__ __volatile__ ("movl $88,-8(%rbp) \n\t""movl $66,-4(%rbp) \n\t");cout<<aaa<<" "<<bbb;return 0; }

對應的匯編碼

.....pushq %rbpmovq %rsp, %rbpsubq $16, %rspmovl $1, -8(%rbp)movl $2, -4(%rbp) #APP # 9 "main.cpp" 1movl $88,-8(%rbp)movl $66,-4(%rbp)# 0 "" 2 #NO_APPmovl -8(%rbp), %eaxmovl %eax, %esi.....

? ? 可以看出不同系統下的寄存器可能不同,例如fp,bp,ebp,rbp都是不同系統下功能類似的寄存器。也可以看出堆棧情況的表達方式也和WINDOWS下的不一樣了。基本內嵌匯編可以寫在函數體外部,但在不同系統的寄存器,匯編語法,堆棧分配情況不一樣,用相同代碼的兼容性問題就要考慮非常多,并且操作起來也十分的不方便。擴展內嵌匯編有些許的改善,雖然它必須寫在C的函數體中。

二、擴展匯編

asm asm-qualifiers ( AssemblerTemplate : OutputOperands : InputOperands : Clobbers : GotoLabels )

asm-qualifiers :? __volatile__修飾詞就不需要多講了,不加volatile 編譯器會幫你優化一些操作,刪除一些沒用的代碼。 goto修飾詞,用來配合內容中的GotoLabel

在小括號內的文本如果發現冒號‘:’則該語句塊視為擴展匯編。內容由5部分組成:

1)用來寫代碼的匯編代碼模板?AssemblerTemplate,

2)替換掉代碼中的占位符的輸出變量OutputOperands,

3)替換掉代碼中的占位符的輸入變量 InputOperands ,

4)排除掉InputOperands 和OutputOperands 中自動匹配寄存器規則中的寄存器集合。

5)GotoLabels,替換掉代碼中的跳轉標簽,通常用“ %l ” 開頭

看看下述代碼:

int test(){ cout<<" test call \t";return 20;} int main(){int aaa = 1 ,bbb=2;__asm__ __volatile__ ("popl %%eax \n\t""pushl %[asmlabel] \n\t""call *%2 \n\t""movl %1 ,%0\n\t":"=rm" (aaa):"r" (bbb),"b"(test),[asmlabel]"A"(2):"%eax");cout<<aaa<<" "<<bbb;return 0; }

1)占位符和操作數變量:

擴展匯編從輸出操作數,輸入操作數,gotolabel中去替代asm依次代碼中的占位符,從%0開始。?"=r" (aaa) 替代了 %0 ,? "r"(bbb)替代了%1? ,? “b”(test)替代了 %2 , “A”(2)替代了%3...依次類推。用占位符實現代碼塊外部向asm內部傳遞值。如果覺得數數字麻煩,可以給操作數命名一個變量,用%[操作數變量名] 來代替占位符中的部分。

2)輸出操作數:

格式為 [操作數變量] “約束”(變量值)。操作數變量,這個可缺省。何為約束?由于匯編命令通常需要用寄存器或者內存地址來進行運算,而不是變量名。所以當C程序向asm內部傳遞數值時,需要指明該變量用哪些寄存器或者內存去存放這個值。其中 “r”代表寄存器的泛型,“m”代表內存的泛型, “rm”就是從寄存器或者內存中挑出任意一個來存儲變量值。輸出操作數的約束必須要有前綴,前綴有兩種,“=”代表asm的操作會覆蓋原先的變量值(相當于引用傳遞),“+”單純的讀寫寄存器或內存,不去主動覆蓋原來的變量值。當然,原先變量存在寄存器中,結果asm把該寄存器的原數據丟失則另說。

3)輸入操作數:

格式為 [操作數變量] “約束”(表達式)。操作數變量稍后再講,這個可缺省。它沒有"+"或者“=”這樣的前綴。只負責傳值。

4)Clobbers:

在輸出/輸入操作數中如果存在泛型,則Clobbers的作用就是編譯器在挑選具體的寄存器時,將Clobbers中的寄存器列表排除在挑選規則之外。例如上述程序指定了“%eax” 那么, 在輸出/輸入操作數 中的 "r" 就不會去選擇 eax寄存器了。

5)GotoLabel:

?由于ASM語句塊中看不見其他塊中的Label標簽,標簽名可能會在編譯中發生變化。所以直接在基礎匯編代碼中直接寫標簽名會造成標簽名不一致情況。gcc可以對列出的標簽集合,實現C程序和Asm之間的跳轉。

int main(){int aaa = 1 ,bbb=2;__asm__ __volatile__ goto("cmp %1,%0 \n\t""jne %l2": //goto不可以由輸出操作數:"r"(aaa),"r"(bbb):"cc":Lable);cout<<"adadadada\n";Lable:cout<<aaa<<" "<<bbb;return 0; }

?

三、擴展匯編的轉義

? ? ?由于%被當成占位符去用了。如果想直接引用寄存器,那么需要輸出兩個“%”

擴展匯編符對應的基本匯編符
%%%
%==
%{{
%|?

|

%}}

四、多匯編方言模板

之前說過,因為每個機器上的匯編語法可能會不一樣。所以可以提供多種模板給編譯器挑選。模板的非共同部分用花括號括起來{} ,每個模板直接用豎線"|"分割。? ?例如

?// 等價的intel 寫法__asm__ __volatile__ (...."bt %[Base],%[Offset] \n\t"...);//att寫法__asm__ __volatile__ (...."btl %[Offset], %[Base] \n\t"...);//合并起來就是__asm__ __volatile__ (...."bt {l %[Offset],%[Base] | %[Base],%[Offset]} \n\t"... );

五、常用的操作數類型

?

代碼

操作數

m任意內存
r

任意寄存器

i整數立即數
Efloat立即數
o可偏移的內存地址,通常與'<'或'>' 搭配,m的子集
V不可偏移的內存地址,即偏移地址后訪問不合法的內存地址。m的子集
g 常用寄存器,內存,整數立即數
X任何操作數

?

六、給C代碼命名一個asm匯編變量名

? ? ?命名方式是在聲明后 加上 asm("asm變量名")的形式進行命名。而命名必須是全局或者靜態的.聲明完后,就可以asm代碼中直接訪問變量名。

#include "iostream" using namespace std; int test()asm("test"); int test() { cout<<" test call \t";return 20;}int main(){static int aaa asm("myvar") = 1;int bbb=2;__asm__ __volatile__ ("call test \n\t" "movl %1 ,%0 \n\t" //movl $2, %r"add $10,%0 \n\t" //add $10,%r ,此時寄存器值為12"movl %0,myvar\n\t" // 此時 myvar 的內存值是12"add myvar,%0" // add myvar,%0 , 此時寄存器值是24,內存值是12:"=r" (aaa) //執行完模板后,%0對應的寄存器替換成aaa,值為24:"r" (bbb),"r0"(test),[asmlabel]"A"(3):"%eax");cout<<aaa<<" "<<bbb; //24 2return 0; }

?

總結

以上是生活随笔為你收集整理的Linux C: 内嵌汇编语法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久久99精品成人片直播 | 1000部国产精品成人观看 | avtt男人天堂 | 色婷婷综合在线 | 色香色香欲天天天影视综合网 | 免费观看黄色一级视频 | 欧美jizz欧美性大全 | 一本色道久久亚洲综合精品蜜桃 | 流白浆视频| 日本视频网站在线观看 | 欧美日韩午夜 | 日本精品在线一区 | 日本黄网免费 | 精品精品| 射在线 | 中文字幕精品三区 | 丁香激情五月少妇 | 国产av一区不卡 | 国产精品久久久久久久免费看 | 夜间福利网站 | 国产人妖网站 | 蜜臀久久99精品久久久画质超高清 | 国产无遮挡呻吟娇喘视频 | 91漂亮少妇露脸在线播放 | 日韩精品视频三区 | 免费av电影网站 | 西西人体大胆4444ww张筱雨 | 夜夜夜操| 91视频导航 | 亚洲视频图片 | 91香焦视频 | 精品国产制服丝袜高跟 | 综合国产视频 | 午夜播放 | 91激情视频在线 | 四虎看黄 | www.色妞| 精品日韩在线视频 | 97成人精品视频在线观看 | 国产精品免费无码 | 97精品人妻麻豆一区二区 | 免费观看黄色网页 | 这里只有精品视频在线观看 | 9l视频自拍蝌蚪9l视频成人 | 黑人巨大猛烈捣出白浆 | 又黄又爽又刺激的视频 | 黄色91| 日本成人一二三区 | 久久成年视频 | 我要看免费毛片 | 黑人一区二区三区四区五区 | 神马午夜一区 | 日韩欧美亚洲国产精品字幕久久久 | 国产麻豆网 | 丰满少妇毛片 | 老鸭窝一区二区 | 毛片视频在线免费观看 | 在线观看日韩欧美 | 麻豆视频免费版 | 青青草视频观看 | 性高跟鞋xxxxhd国产电影 | 99福利影院| 日本人xxxⅹ18hd19hd | 麻豆视频免费版 | 亚洲av无码片一区二区三区 | 国产日韩精品中文字无码 | 四虎在线看片 | 三级伦理视频 | 国产中文视频 | 134vcc影院免费观看 | 久久成人a | 日韩女同互慰一区二区 | 涩涩av| 久色成人 | 日本黄色特级片 | 亚洲欧美另类视频 | 欧美精品久久久久久久自慰 | 四虎av网站| 91吃瓜今日吃瓜入口 | 青青草原影视 | 三级视频网站 | 两个小y头稚嫩紧窄h文 | 在线播放视频高清在线观看 | 亚洲视频免费看 | 捆绑裸体绳奴bdsm亚洲 | 肉大捧一进一出免费视频 | 少妇淫片 | 中年夫妇啪啪高潮 | 亚洲成年 | 邵氏电影《金莲外传2》免费观看 | 国产盗摄精品一区二区酒店 | 免费一级特黄 | 国产国拍精品亚洲 | 中文第一页 | 在线天堂资源 | 美脚の诱脚舐め脚视频播放 | 国产精品久久久久影院老司 | 中文字幕在线视频不卡 | 亚洲操操操 |