鍍金池/ 教程/ Java/ 內(nèi)聯(lián)匯編
哲學(xué)家就餐問題
鏈接進階
名詞中英文對照
測試
引用和借用
泛型
方法語法
函數(shù)
不安全代碼
并發(fā)
裝箱語法和模式
注釋
棧和堆
運算符與重載
語法索引
文檔
固有功能
所有權(quán)
循環(huán)
通用函數(shù)調(diào)用語法
不定長類型
<code>const</code> 和 <code>static</code>
迭代器
其他語言中的 Rust
枚舉
詞匯表
If語句
猜猜看
錯誤處理
生命周期
編譯器插件
發(fā)布途徑
閉包
trait 對象
不使用標(biāo)準(zhǔn)庫
關(guān)聯(lián)常量
外部函數(shù)接口(FFI)
類型轉(zhuǎn)換
原生類型
匹配
參考文獻(xiàn)
Rust 編程語言
內(nèi)聯(lián)匯編
條件編譯
選擇你的保證
學(xué)習(xí) Rust
`type`別名
自定義內(nèi)存分配器
屬性
if let
高效 Rust
可變性
語法和語義
模式
基準(zhǔn)測試
結(jié)構(gòu)體
變量綁定
語言項
切片模式
<code>Deref</code> 強制多態(tài)
關(guān)聯(lián)類型
裸指針
<code>Borrow</code> 和 <code>AsRef</code>
準(zhǔn)備
Rust 開發(fā)版
字符串

內(nèi)聯(lián)匯編

inline-assembly.md
commit 024aa9a345e92aa1926517c4d9b16bd83e74c10d

為了極端底層操作和性能要求,你可能希望直接控制 CPU。Rust 通過asm!宏來支持使用內(nèi)聯(lián)匯編。語法大體上與 GCC 和 Clang 相似:

asm!(assembly template
   : output operands
   : input operands
   : clobbers
   : options
   );

任何asm的使用需要功能通道(需要在包裝箱上加上#![feature(asm)]來允許使用)并且當(dāng)然也需要寫在unsafe塊中

注意:這里的例子使用了 x86/x86-64 匯編,不過所有平臺都受支持。

匯編模板

assembly template是唯一需要的參數(shù)并且必須是原始字符串(就是""

#![feature(asm)]

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn foo() {
    unsafe {
        asm!("NOP");
    }
}

// other platforms
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn foo() { /* ... */ }

fn main() {
    // ...
    foo();
    // ...
}

feature(asm)#[cfg]從現(xiàn)在開始將被忽略。)

輸出操作數(shù),輸入操作數(shù),覆蓋和選項都是可選的,然而如果你要省略它們的話,你必選加上正確數(shù)量的:

# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax"
    :
    :
    : "{eax}"
   );
# } }

有空格在中間也沒關(guān)系:

# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
asm!("xor %eax, %eax" ::: "{eax}");
# } }

操作數(shù)

輸入和輸出操作數(shù)都有相同的格式:: "constraints1"(expr1), "constraints2"(expr2), ..."。輸出操作數(shù)表達(dá)式必須是可變的左值,或還未賦值的:

# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
    let c: i32;
    unsafe {
        asm!("add $2, $0"
             : "=r"(c)
             : "0"(a), "r"(b)
             );
    }
    c
}
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
# fn add(a: i32, b: i32) -> i32 { a + b }

fn main() {
    assert_eq!(add(3, 14159), 14162)
}

如果你想在這里使用真正的操作數(shù),然而,要求你在你想使用的寄存器上套上大括號{},并且要求你指明操作數(shù)的大小。這在非常底層的編程中是很有用的,這時你使用哪個寄存器是很重要的:

# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# unsafe fn read_byte_in(port: u16) -> u8 {
let result: u8;
asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
result
# }

覆蓋(Clobbers)

一些指令修改的寄存器可能保存有不同的值,所以我們使用覆蓋列表來告訴編譯器不要假設(shè)任何裝載在這些寄存器的值是有效的。

# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
// Put the value 0x200 in eax
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "{eax}");
# } }

輸入和輸出寄存器并不需要列出因為這些信息已經(jīng)通過給出的限制溝通過了。因此,任何其它的被使用的寄存器應(yīng)該隱式或顯式的被列出。

如果匯編修改了代碼狀態(tài)寄存器cc則需要在覆蓋中被列出,如果匯編修改了內(nèi)存,memory也應(yīng)被指定。

選項(Options)

最后一部分,options是 Rust 特有的。格式是逗號分隔的基本字符串(也就是說,:"foo", "bar", "baz")。它被用來指定關(guān)于內(nèi)聯(lián)匯編的額外信息:

目前有效的選項有:

  1. volatile - 相當(dāng)于 gcc/clang 中的__asm__ __volatile__ (...)
  2. alignstack - 特定的指令需要棧按特定方式對齊(比如,SSE)并且指定這個告訴編譯器插入通常的棧對齊代碼
  3. intel - 使用 intel 語法而不是默認(rèn)的 AT&T 語法
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() {
let result: i32;
unsafe {
   asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
}
println!("eax is currently {}", result);
# }

更多信息

目前asm!的實現(xiàn)是一個LLVM內(nèi)聯(lián)匯編表達(dá)式的直接綁定,所以請確保充分的閱讀他們的文檔來獲取關(guān)于覆蓋,限制等概念的更多信息。