![](/img/trans.png)
[英]How to compile Rust code to bare metal 32 bit x86 (i686) code? What compile target should I use?
[英]Rust custom bare metal compile target: linker expects "_start" symbol and discards unused ones: How can I specify a custom entry symbol?
I'm cross compiling bare metal 32-bit code for x86 with Rust and I'm facing the problem, that the final object file is empty, if the entry function is not exactly called _start
; linker 將所有代碼丟棄,因為它認為它已死。 我很熟悉_start
是一個眾所周知的入口點名稱,但問題仍然是:
Rust、LLVM 或 Linker 中的哪個部分強制執行此操作? 像extern "C" fn...
、 #[no_mangle]
或#[export_name = "foobar"]
這樣的屬性也不起作用(被鏈接器丟棄)。 我的猜測是,它不是 Rust 編譯器,而是 linker。 如您所見,在我的例子中,我使用rust-lld
作為 linker 和ld.lld
作為鏈接器風格(見下文)。
_start
-來自哪里? 為什么 linker 會丟棄我的其他代碼?x86-unknown-bare_metal.json
{
"llvm-target": "i686-unknown-none",
"data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32",
"arch": "x86",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "+soft-float,+sse"
}
我每晚使用 Rust 1.54.0 並將其構建在 Linux 5.8.0 系統上。
我花了一些時間在互聯網上搜索並找到了討論,Rust 最終應該得到一個#[entrypoint="foobar
注釋或類似的東西,但不幸的是我沒有找到可用的解決方案。
我的嘗試是 append
"pre-link-args": {
"ld.lld": [
"-e,foobar"
]
}
到目標定義(也稱為 foobar 的函數),但 object 文件仍然是空的。 另一種嘗試是保留所有死代碼。 這可行,但此解決方案很臟。
最小代碼示例:
// disable rust standard library
#![no_std]
// disables Rust runtime init,
#![no_main]
// see https://docs.rust-embedded.org/embedonomicon/smallest-no-std.html
#![feature(lang_items)]
// see https://docs.rust-embedded.org/embedonomicon/smallest-no-std.html
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
use core::panic::PanicInfo;
use core::sync::atomic;
use core::sync::atomic::Ordering;
#[no_mangle]
/// The name **must be** `_start`, otherwise the compiler doesn't output anything
/// to the object file. I don't know why it is like this.
/// Also `pub` or `pub extern "C"` doesn't work
fn _start() -> ! {
loop {}
}
#[inline(never)]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {
atomic::compiler_fence(Ordering::SeqCst);
}
}
新答案 [解決方案]
真正的解決方案非常簡單,但很難找到,因為在這個相對無證的領域中很難挖掘出可能的選擇和解決方案。 我發現llvm-ld
使用與GNU ld
相同的選項。 所以我檢查了GNU ld
鏈接選項並找到了解決方案。 它一定要是
"pre-link-args": {
"ld.lld": [
"--entry=entry_32_bit"
]
}
值為文件中function的名稱。 function必須用#[no_mangle]
注釋。
另見: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
老答案:
一個快速且非常骯臟的解決方案是
#[no_mangle]
/// The name **must be** `_start`, otherwise the compiler doesn't output anything
/// to the object file. I don't know it is like this.
fn _start() -> ! {
entry_32_bit();
}
#[no_mangle]
#[inline(never)]
fn entry_32_bit() -> ! {
loop {}
}
這樣,可以直接從匯編中跳轉到符號entry_32_bit
。 但是這種“解決方案”遠非理想,尤其是當您想將多個垃圾箱鏈接在一起時。 會有名字沖突。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.