在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

在Rust中使用內(nèi)聯(lián)匯編

jf_wN0SrCdH ? 來(lái)源:Rust語(yǔ)言中文社區(qū) ? 2023-05-04 09:54 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

自 Rust 1.59 以降,在 Rust 代碼中內(nèi)聯(lián)匯編代碼的語(yǔ)言特性已然 stable^1。參考知乎上一篇文章^3,我用 Rust 的內(nèi)聯(lián)匯編實(shí)現(xiàn)了有棧協(xié)程^4。在此過(guò)程中學(xué)到了一些知識(shí)。

本文假設(shè)讀者對(duì) x86 匯編有基礎(chǔ)了解。

局部?jī)?nèi)聯(lián)匯編與自動(dòng)分配寄存器

Rust 的內(nèi)聯(lián)匯編一開(kāi)始是對(duì)標(biāo) GCC 的內(nèi)聯(lián)匯編設(shè)計(jì)的,長(zhǎng)得像這樣^(guān)5:


	

asm!("mov $4, %eax cpuid mov %eax, $0 mov %ebx, $1 mov %ecx, $2 mov %edx, $3" : "=r"(a), "=r"(b), "=r"(c), "=r"(d) : "m"(info) : "eax", "ebx", "ecx", "edx" )

后來(lái)才變成如今富有 Rust 特色的樣子^(guān)6:


	

asm!( "mov edi, ebx", "cpuid", "xchg edi, ebx", in("eax") info, lateout("eax") a, out("edi") b, out("ecx") c, out("edx") d, )

與 GCC 內(nèi)聯(lián)匯編語(yǔ)法一樣,Rust 希望即使需要手寫(xiě)匯編,程序員也能將一部分工作交給編譯器來(lái)高效完成,這部分工作就是寄存器分配,畢竟只有編譯器了解內(nèi)聯(lián)匯編前后的上下文,知道該怎么分配寄存器最合適。

asm宏的inoutinoutlateoutinlateout參數(shù)就是為了讓編譯器幫助分配寄存器的。

in表示將變量的值傳給寄存器,編譯器生成的匯編代碼會(huì)使得在內(nèi)聯(lián)匯編代碼中讀取相應(yīng)的寄存器,就得到了傳入的變量的值;

out表示將寄存器的值寫(xiě)到變量中,在內(nèi)聯(lián)匯編代碼中寫(xiě)入相應(yīng)寄存器,編譯器在內(nèi)聯(lián)匯編之后生成的匯編代碼會(huì)使得相應(yīng)變量具有寫(xiě)入相應(yīng)寄存器的值;

late則是代表編譯器可以采取進(jìn)一步的策略來(lái)優(yōu)化寄存器分配:默認(rèn)的分配策略給每個(gè)參數(shù)分配不同的寄存器,使用lateoutinlateout的參數(shù)則允許編譯器復(fù)用某個(gè)in參數(shù)的寄存器,只要內(nèi)聯(lián)匯編代碼中先讀完所有的in寄存器,再輸出lateoutinlateout寄存器即可。

具體細(xì)節(jié)以及此處沒(méi)講到的option可參考^1。

全局內(nèi)聯(lián)匯編與名稱(chēng)修飾(Name Mangling)

除了需要寫(xiě)在函數(shù)體中的asm宏,還有需要寫(xiě)在函數(shù)之外的global_asm宏,其作用與獨(dú)立的匯編代碼相差不大,一切全由程序員掌控,沒(méi)有上節(jié)所述寄存器自動(dòng)分配之功能,還需要手動(dòng)管理參數(shù)傳遞,棧對(duì)齊等等。

global_asm我們可以寫(xiě)出源代碼完全是匯編代碼的函數(shù),函數(shù)名就是匯編代碼中的標(biāo)簽,函數(shù)參數(shù)和返回值需要按照 ABI 約定來(lái)處理^7:


	

use std::global_asm; extern "C" { fn my_asm_add(a: i32, b: i32) -> i32; } global_asm!{ "my_asm_add:", "mov eax, edi", "add eax, esi", "ret", } fn main() { let a = 114; let b = 514; let x = unsafe { my_asm_add(a, b) }; dbg!(x); }

這段代碼在x86_64-unknown-linux-gnu的目標(biāo),也就是 Rust Playground 的運(yùn)行環(huán)境下會(huì)通過(guò)編譯并輸出正確結(jié)果 628,但在 64 位 Windows 下則會(huì)得到錯(cuò)誤的結(jié)果,因?yàn)?64 位 Windows 所用的 C ABI 和 64 位 Linux 不一樣,雖然都是通過(guò)寄存器傳遞參數(shù),但 64 位 Windows 的 C ABI 的第一二參數(shù)是用 RCX 和 RDX 傳遞,而非示例中的 RDI 和 RSI。

而在MacOS上編譯,結(jié)果是編譯不過(guò)——雖然和 64 位 Linux 一樣使用 System V AMD64 ABI,但 MacOS 進(jìn)行 C 語(yǔ)言函數(shù)名名稱(chēng)修飾時(shí)會(huì)在函數(shù)名前加一個(gè)下劃線(xiàn),所以編譯器會(huì)試圖尋找_my_asm_add符號(hào),結(jié)果找不到。在匯編代碼中把"my_asm_add:"改成"_my_asm_add:"即可編譯通過(guò)。

由此可見(jiàn)匯編語(yǔ)言的不可移植性:即使是同一架構(gòu),甚至同一 ABI 約定的匯編代碼也相當(dāng)不可移植。

在代碼編寫(xiě)過(guò)程中,我發(fā)現(xiàn)一個(gè)技巧可以規(guī)避掉名稱(chēng)修飾的影響。asmglobal_asm宏可以接受格式為sym SYMBOL的參數(shù)來(lái)引用符號(hào),其中SYMBOL是函數(shù)或者靜態(tài)變量,這種參數(shù)的目的是在匯編語(yǔ)言中直接引用 Rust 函數(shù)或靜態(tài)變量的符號(hào),盡管 Rust 的名稱(chēng)修飾算法尚未 stable,但代碼中可以不寫(xiě)出來(lái)而由編譯器來(lái)計(jì)算。這個(gè)功能也可以用在extern符號(hào)上,因此可以這樣寫(xiě):


	

global_asm!{ ".extern {0}", "{0}:", "mov eax, edi", "add eax, esi", "ret", sym my_asm_add, }

這樣在編譯 x86_64-unknown-linux-gnu 目標(biāo)時(shí)生成的匯編代碼中的標(biāo)簽是my_asm_add,而對(duì)于x86_64-apple-darwin目標(biāo),生成的標(biāo)簽則是_my_asm_add

這樣的技巧不夠方便,更直觀(guān)的寫(xiě)法是 naked function^9,這種函數(shù)從外部看來(lái)就是一個(gè) unsafe 函數(shù),而內(nèi)部只允許有一個(gè)asm宏調(diào)用,編譯器不生成一般函數(shù)中會(huì)有的各種上下文代碼,函數(shù)本體完全由該 asm 宏調(diào)用生成。

程序重定位與位置無(wú)關(guān)代碼

為了加載動(dòng)態(tài)鏈接庫(kù)或者避免被黑客利用固定程序地址攻擊,操作系統(tǒng)加載程序時(shí)會(huì)將其載入到隨機(jī)的內(nèi)存地址,這個(gè)過(guò)程就是程序重定位。

對(duì)于 32 位 x86 程序,需要在加載時(shí)修改程序中所有的絕對(duì)地址,包括函數(shù)的和數(shù)據(jù)的。在匯編語(yǔ)言中可以直接將標(biāo)號(hào)作為常量使用,但最好不要寫(xiě)mov eax, LABEL這樣的語(yǔ)句,因?yàn)檫@樣的語(yǔ)句加載器不會(huì)識(shí)別和修改。應(yīng)該寫(xiě)lea eax, LABEL

x86_64 支持相對(duì) RIP 尋址,Rust 編譯器默認(rèn)將代碼編譯為使用這項(xiàng)特性的位置無(wú)關(guān)可執(zhí)行程序(PIE),因此在 Rust 的內(nèi)聯(lián)匯編中取符號(hào)地址需要寫(xiě)成lea rax, [rip+SYMBOL]

示例,x86_64 平臺(tái)下給 static 變量X加 1 的函數(shù)用匯編語(yǔ)言實(shí)現(xiàn)[11]:


	

use std::global_asm; static mut X: usize = 0; extern "C" { fn incr_x(); } global_asm!{ "{0}:", "add dword ptr [rip+{X}], 1", "ret", sym incr_x, X = sym X, } fn main() { unsafe { incr_x(); dbg!(X); incr_x(); dbg!(X); } }

32 位 x86 代碼下則需要把匯編代碼改成:


	

global_asm!{ "{0}:", "lea eax, {X}", "add dword ptr[eax], 1", "ret", sym incr_x, X = sym X, }

審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4895

    瀏覽量

    70543
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1661

    瀏覽量

    50114
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    233

    瀏覽量

    7053

原文標(biāo)題:在 Rust 中使用內(nèi)聯(lián)匯編

文章出處:【微信號(hào):Rust語(yǔ)言中文社區(qū),微信公眾號(hào):Rust語(yǔ)言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何在Rust中使用Memcached

    Memcached協(xié)議的實(shí)現(xiàn),使得開(kāi)發(fā)者可以Rust中使用Memcached。 基礎(chǔ)用法 創(chuàng)建連接 使用Rust語(yǔ)言Memcached需要先創(chuàng)建一個(gè)連接。可以使用 memcached
    的頭像 發(fā)表于 09-19 16:30 ?1496次閱讀

    RealView MDK中使內(nèi)聯(lián)函數(shù)時(shí)需要注意的問(wèn)題

    的文件中申明為extern類(lèi)型。原因是MDK中使用的__inline函數(shù)時(shí)和標(biāo)準(zhǔn)C++中的inline函數(shù)有相同的語(yǔ)義。C++標(biāo)準(zhǔn)中,一個(gè)內(nèi)聯(lián)函數(shù)在用到它的每個(gè)解釋單元需要相同的定義,這樣看來(lái)只有內(nèi)部
    發(fā)表于 08-02 10:10

    如何編寫(xiě)內(nèi)聯(lián)匯編MAC指令?

    我使用的是DSPIC33 FJ。我所有的代碼都是用C編寫(xiě)的,但是考慮到應(yīng)用程序的復(fù)雜性,我不得不使用內(nèi)聯(lián)匯編指令。我的C代碼中,我有三個(gè)變量foo,bar和foo bar,其中foo bar
    發(fā)表于 08-01 09:38

    內(nèi)聯(lián)函數(shù)和匯編指令疑問(wèn)

    我想用內(nèi)聯(lián)函數(shù)來(lái)取兩個(gè)int型變量(32位)的較大值,看了一下內(nèi)聯(lián)函數(shù)有_max2和_max4,和匯編指令MAX2和 MAXU4 但是他們的用法比較奇特,他們用法是把32位的int型變量拆成4個(gè)8位
    發(fā)表于 10-22 15:28

    如何使用內(nèi)聯(lián)函數(shù)法調(diào)用匯編函數(shù)?

    從C/C++中調(diào)用匯編代碼中的函數(shù)使用內(nèi)聯(lián)函數(shù)法調(diào)用匯編函數(shù)從C/C++中調(diào)用匯編代碼中的變量或者常量
    發(fā)表于 04-02 06:57

    哪幾種情況中必須使用內(nèi)聯(lián)匯編或嵌入型匯編

    。Linux驅(qū)動(dòng)入門(mén)可以一起交流。一、gcc 內(nèi)聯(lián)匯編內(nèi)聯(lián)匯編即在C中直接使用匯編語(yǔ)句進(jìn)行編程,使程序可以C程序中實(shí)現(xiàn)C語(yǔ)言不能完成的一些
    發(fā)表于 12-20 08:00

    Rust代碼中加載靜態(tài)庫(kù)時(shí),出現(xiàn)錯(cuò)誤 ` rust-lld: error: undefined symbol: malloc `怎么解決?

    “ [i]malloc ”、“ [i]exit ”。我驗(yàn)證了使用 ` [i]nm ` 命令。 問(wèn)題是我打算使用 ffi rust 中使用這個(gè)靜態(tài)庫(kù)。當(dāng)我嘗試我的
    發(fā)表于 06-09 08:44

    內(nèi)聯(lián)匯編的技巧

      有時(shí)我們的程序需要一些很高的執(zhí)行效率或者執(zhí)行系統(tǒng)底層的功能模塊,這些關(guān)鍵的部分我們可以采用內(nèi)聯(lián)匯編直接插入匯編指令來(lái)達(dá)到我們的要求,以下是幾個(gè)技巧與大家共同
    發(fā)表于 08-29 10:20 ?962次閱讀

    內(nèi)聯(lián)匯編和嵌入型匯編的使用

    編譯器中的匯編器。使用它可以C/C++程序中實(shí)現(xiàn)C/C++語(yǔ)言不能完成的一些工作。例如,在下面幾種情況中必須使用內(nèi)聯(lián)匯編或嵌入型匯編。 程
    發(fā)表于 10-19 09:30 ?0次下載

    Rust相比Go的優(yōu)劣勢(shì)

    Rust可以做內(nèi)聯(lián)匯編,Go不行(Rust的SIMD庫(kù)也開(kāi)發(fā)中,這種事情你不會(huì)用Go做)。
    發(fā)表于 06-29 11:19 ?4279次閱讀

    哪幾種情況中必須使用內(nèi)聯(lián)匯編或嵌入型匯編

    ARM系列文章,請(qǐng)點(diǎn)擊以下匯總鏈接:《從0學(xué)arm合集》一、gcc 內(nèi)聯(lián)匯編內(nèi)聯(lián)匯編即在C中直接使用匯編語(yǔ)句進(jìn)行編程,使程序可以C程序中實(shí)
    的頭像 發(fā)表于 12-24 12:55 ?1229次閱讀

    C和匯編如何互相調(diào)用?

    一、gcc 內(nèi)聯(lián)匯編 內(nèi)聯(lián)匯編即在C中直接使用匯編語(yǔ)句進(jìn)行編程,使程序可以C程序中實(shí)現(xiàn)C語(yǔ)言不
    的頭像 發(fā)表于 12-25 15:50 ?3240次閱讀

    C中直接使用匯編語(yǔ)句進(jìn)行編程

    ? 一、gcc 內(nèi)聯(lián)匯編 內(nèi)聯(lián)匯編即在C中直接使用匯編語(yǔ)句進(jìn)行編程,使程序可以C程序中實(shí)現(xiàn)C語(yǔ)
    的頭像 發(fā)表于 11-16 09:26 ?8938次閱讀

    移動(dòng)端arm cpu優(yōu)化學(xué)習(xí)筆記第4彈--內(nèi)聯(lián)匯編入門(mén)(上)

    本文主要內(nèi)容是介紹ARMv7和v8內(nèi)聯(lián)匯編的一些基礎(chǔ)知識(shí),并且會(huì)結(jié)合兩個(gè)具體例子去看下如何用內(nèi)聯(lián)匯編來(lái)改寫(xiě)原來(lái)的代碼。 作者:梁德澎首...
    發(fā)表于 02-07 11:03 ?0次下載
    移動(dòng)端arm cpu優(yōu)化學(xué)習(xí)筆記第4彈--<b class='flag-5'>內(nèi)聯(lián)</b><b class='flag-5'>匯編</b>入門(mén)(上)

    Rust的內(nèi)部工作原理

    Rust匯編:了解 Rust 的內(nèi)部工作原理 非常好的Rust系列文章,通過(guò)生成的匯編代碼,讓你了解很多
    的頭像 發(fā)表于 06-14 10:34 ?1012次閱讀
    <b class='flag-5'>Rust</b>的內(nèi)部工作原理
    主站蜘蛛池模板: 欧美人成绝费网站色www吃脚 | 亚洲乱码卡一卡二卡三永久 | 九色精品在线 | 四虎在线电影 | 黄视频在线播放 | 中国高清性色生活片 | 亚洲视频免费一区 | 精品伊人久久大线蕉色首页 | 5566在线观看 | 全免费一级毛片在线播放 | 国产一级片免费看 | 欧美亚洲一区二区三区在线 | 日本黄色免费观看 | 日本亚洲在线 | 国产香蕉在线视频 | 色婷婷亚洲十月十月色天 | 亚洲一区二区视频在线观看 | 欧美三级色图 | 无夜精品久久久久久 | 四虎精品影院2022 | 国产女人小便视频 | 中文字幕在线看精品乱码 | 亚洲一区二区三区精品视频 | avtt天堂网永久资源 | 国产精品一区二区三区四区五区 | 亚洲a网 | 一本到视频在线 | 伊人久久大香线蕉综合网站 | 天天操天天干天天拍 | 国模吧2021新入口 | 四虎影院免费视频 | 亚洲香蕉影视在线播放 | 男女爱爱是免费看 | 国产乱码免费卡1卡二卡3卡四 | 人人揉揉香蕉大青草 | 日本理论午夜中文字幕第一页 | 国产色视频在线 | 深爱激情小说网 | 四虎影视大全免费入口 | 九九视频这里只有精品 | aaa在线观看高清免费 |