在 Zig 中使用匯編輸出 Hello- World-
Zig 中的內聯彙編
儘管現代高級語言的特性已經非常豐富,但我們仍需要彙編語言的幫助,在某些特殊的場景下,彙編語言可以發揮出比高級語言更好的性能,這是因爲彙編語言更加接近硬件,它允許我們對硬件直接進行操作。
一般是在以下場景下,纔會涉及到使用匯編語言:
-
時效性高的程序,例如工業控制的程序。
-
驅動程序,這需要直接操控硬件,由於高級語言的抽象層次過高,導致其不如彙編語言來的方便。
-
內核的開發,現代化內核編寫時均會使用匯編來完成一些初始化工作,如 bootloader,分段分頁,中斷處理等。
-
程序的優化,高級語言的編譯器並不是完美的,它有時會做出反而使程序變慢的 “優化”。
對於 x86 和 x86_64 ,當前彙編語法爲 AT&T 語法,而不是更流行的 Intel 語法。這是由於技術限制,彙編解析由 LLVM 提供,其對 Intel 語法的支持存在 bug 且測試 結果並不理想。
原文地址:https://zigcc.github.io/zig-course/advanced/assembly.html
以下簡單介紹一下兩種在 Zig 中使用匯編的方式:
全局彙編
Zig 支持在容器中使用 comptime
+ asm
包裹表達式,以此聲明一段全局彙編,可以通過此方法直接引入彙編代碼。
以下是一段通過全局彙編功能實現在 x86_64-linux
下輸出 "Hello, World!\n" 的代碼:
comptime {
asm (
\\ msg:
\\ .ascii "Hello, World!\n"
\\ len = . - msg
\\
\\.global hello;
\\.type hello, @function;
\\hello:
\\ # write syscall
\\ mov $1, %rax
\\ # file descriptor (stdout)
\\ mov $1, %rdi
\\ # address of string to output
\\ lea msg(%rip), %rsi
\\ # length of string to output
\\ mov $len, %rdx
\\ syscall
\\ retq
);
}
extern fn hello() usize;
pub fn main() !void {
_ = hello();
}
在以上代碼中,我們通過使用 .global
聲明一個全局符號,使用 .type
聲明一個 hello
函數,隨後便是爲 syscall
提供參數,rax
寄存器保存系統調用號, rdi
, rsi
, rdx
, r10
, r8
, r9
則存儲參數。
完整的系統調用號信息可以在此處查詢:Linux System Call Table[1] 。
我們使用 1 號系統調用,並按照以下順序傳遞參數:標準輸出 1、字符串地址(使用 lea
指令獲取到有效地址)、字符串長度。
內聯彙編
內聯彙編給予了我們可以將 low-level
的彙編代碼和高級語言相組合,實現更加高效或者更直白的操作。
Zig 的內聯彙編語法所採用的是 GNU 語法,並且約束語義採取的是類似 LLVM 和 GCC 的方案。
以下是實現代碼:
const str = "Hello, World!\n";
pub fn main() !void {
_ = asm volatile ("syscall"
: [ret] "={rax}" (-> usize),
: [number] "{rax}" (1),
[arg1] "{rdi}" (1),
[arg2] "{rsi}" (str),
[arg3] "{rdx}" (str.len),
: "rcx", "r11"
);
}
很簡單地通過 asm
定義了一個內聯彙編,使用 ret
作爲返回值的標識符(number
、arg1
、arg2
、arg3
同理),將執行完 syscall
指令後 rax
寄存器的值作爲返回值,隨後將參數分別賦值給對應的寄存器,在最後的約束中rcx
、r11
表示會被使用的寄存器(syscall
會將下一條指令地址存入 rcx
,將 rflags
存入 r11
)。
更多的內聯彙編約束語義,可以參考:LLVM documentation[2]、GCC documentation[3]。
參考資料
[1]
Linux System Call Table: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86_64-64_bit
[2]
LLVM documentation: http://releases.llvm.org/10.0.0/docs/LangRef.html#inline-asm-constraint-string
[3]
GCC documentation: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/benRXj7CMSyDDyXOdEimag