即使在使用 no_std 的情况下,如何解决为什么在 rust 标准库符号中的 cargo/rustc 链接?

jlb*_*740 5 rust rust-cargo

我正在尝试创建一个嵌入友好的可执行文件(占用空间小且不依赖于 Rust 标准库),它使用一个已经支持no_std构建的库 (wasmi) 。Rust 的新手,我只是将说明拼凑在一起,但其要点似乎是按照步骤操作

对于可执行文件:

#![no_std]
#![no_main]

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn _start(_argc: isize, _argv: *const *const u8) -> ! {
    interpret(_argc, _argv);
    loop {}
}
Run Code Online (Sandbox Code Playgroud)

即:

  • 包括 #![no_std]
  • 定义我们的条目(不是main因为我们没有调用它的运行时)
  • 并定义一个恐慌处理程序,因为不包含 Rust 标准库来为我们定义它。

我要编译的 Cargo 文件如下所示:

[package]
 name = "driver"
 version = "0.1.0"
 edition = "2018"

[dependencies.wasmi]
 path = "../../github_dev/wasmi" 
 features = ["core"]
 default-features = false
 test=false
 bench=false

 [profile.release]
 panic = "abort"
 lto = true
 incremental=false
 debug=true
 opt-level = "z"
 test=false
 bench=false
Run Code Online (Sandbox Code Playgroud)

并生成一个非常小的二进制文件,排除任何标准库符号(nm用于检查)并按预期运行。

当我实际尝试从 wasmi 库调用函数时会出现问题。它是no_std通过features=core线路构建的。nm对文件执行操作release/deps/libwasmi-*.rlib显示没有标准库符号。但是,当使用此命令进行链接时:

#![no_std]
#![no_main]

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn _start(_argc: isize, _argv: *const *const u8) -> ! {
    interpret(_argc, _argv);
    loop {}
}
Run Code Online (Sandbox Code Playgroud)

它导致:

[package]
 name = "driver"
 version = "0.1.0"
 edition = "2018"

[dependencies.wasmi]
 path = "../../github_dev/wasmi" 
 features = ["core"]
 default-features = false
 test=false
 bench=false

 [profile.release]
 panic = "abort"
 lto = true
 incremental=false
 debug=true
 opt-level = "z"
 test=false
 bench=false
Run Code Online (Sandbox Code Playgroud)

并发生错误:

rustc --release --verbose -- -C link-arg=-nostartfiles
Run Code Online (Sandbox Code Playgroud)

似乎 Rust 试图链接标准库支持至少用于紧急处理,但我不知道为什么。

我想帮助了解原因并了解如何预防它。

如果我删除该panic_impl属性,那么我的可执行文件会编译,但它包含许多我试图阻止的标准库符号。

我看到的示例符号是:

   Compiling driver v0.1.0 (/home/my_home/wasmi_embed/driver)
     Running rustc --edition=2018 --crate-name driver src/main.rs --color always --crate-type bin --emit=dep-info,link -C opt-level=3 -C panic=abort -C lto -C link-arg=-nostartfiles -C metadata=957eda2e590447ba -C extra-filename=-957eda2e590447ba --out-dir /home/my_home/wasmi_embed/driver/target/release/deps -L dependency=/home/my_home/wasmi_embed/driver/target/release/deps --extern libc=/home/my_home/wasmi_embed/driver/target/release/deps/liblibc-f7fb773c7b059a14.rlib --extern wasmi=/home/my_home/wasmi_embed/driver/target/release/deps/libwasmi-534aef1926b4eb6c.rlib
Run Code Online (Sandbox Code Playgroud)

dep包括libwasmi在内的目录下的任何rlib文件中都没有发现上述符号,在不调用libwasmi代码时的驱动程序可执行文件中也没有发现这些符号。

我读过一个类似的问题(因此是我的test=falsebench=falseCargo.toml 中的),但这没有帮助。我尝试rustc使用不同的命令(不包括 Cargo)进行构建,但错误是相同的。我曾尝试将 wasmi 编译为静态库 (ar) 并将其链接,但是作为 Rust 的新手,我花了很多时间尝试将其链接,但它并没有发生。

jlb*_*740 -1

我在 Rust 论坛寻求一些帮助后解决了这个问题。在此输入链接描述。具体来说,无法确定是什么原因导致 rust std lib 链接到我的可执行文件中......是板条箱问题还是货物问题还是 rustc 问题还是链接器问题。我不知道问题出在哪里,但根据提交的类似错误,我认为不知何故正在编译一个板条箱以引入意外的 std lib。事实证明,尽管错误消息相同,但此处的错误输入链接描述并不相关。我没有遇到来自不同类型依赖项(开发依赖项和构建依赖项)的意外传播的问题。我尝试了所有这些技术来查明 std lib 中引入的内容:

\n\n
    \n
  1. 我尝试使用货物树列出依赖项以列出所有板条箱\n依赖项:

    \n\n

    wasmi v0.4.3 (/home/jlb6740/github_dev/wasmi)
    \n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 字节顺序 v1.3.1 (/home/jlb6740/github_dev/byteorder) \
    n \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 hashbrown v0.1.8 (/home/jlb6740/github_dev/hashbrown)
    \n\xe2\x94\x82\xe2\x94\x9c\xe2\x94 \x80\xe2\x94\x80 字节顺序 v1.3.1 (/home/jlb6740/github_dev/byteorder) ( )
    \n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 scopeguard v0.3.3 (/home/jlb6740/github_dev/scopeguard)
    \n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 libm v0.1.2
    \n\xe2\x94\x9c\xe2\x94 \x80\xe2\x94\x80 memory_units v0.3.0
    \n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 parity-wasm v0.31.0 (/home/jlb6740/github_dev/parity-wasm)
    \n \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 字节顺序 v1.3.1 (/home/jlb6740/github_dev/byteorder) (
    )

  2. \n
  3. 我尝试使用 Cargo rustc --verbose \xe2\x80\xa6 但此时 verbose 并不表明任何内容正在使用默认功能,其中可能包括使用 std

  4. \n
  5. 我尝试使用货物元数据 \xe2\x80\xa6 这生成了一长串难以解析的\n依赖项,但我确实看到了一些实例\n其中scopeguard和byteorder具有需要std\n支持的默认功能。我下载了所有这些板条箱并只是硬编码\nattributes,以便这些板条箱只能在 no_std 支持的情况下构建。

  6. \n
  7. 我尝试查看 deps/ 输出,并对所有\nrlibs 执行 nm 以查看是否有任何库使用了 std 中找到的符号。我发现情况并非如此。我认为 rlib 就像静态库,它们使用的任何内容都将包含在 rlib 中,但显然不是。

  8. \n
  9. 我查看了 Cargo rustc -- -C --print-link-args 来检查链接器\n标志,但我找不到任何明显的东西告诉我它\n引入了标准库。

  10. \n
\n\n

这些事情都没有帮助我查明是什么引入了 std lib。最终,Rust 论坛的建议是对根本不允许 std lib 的目标使用货物检查。此处列出的*在此处输入链接描述仅具有核心支持。我尝试过,与--target=thumbv7m-none-eabi看到:

\n\n

错误[E0463]:可以\ xe2 \ x80 \ x99t找到分配的箱子
\ n \ xe2 \ x80 \ x93> /home/jlb6740/github_dev/hashbrown/src/lib.rs:44:1
\n|
\n44 | extern crate std 作为 alloc;
\n| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 可以\xe2\x80\x99t找到箱子

\n\n

事实证明它是 hashbrown,它是我的可执行文件的依赖项的依赖项。它默认构建 no_std,但有一个以不同名称链接的外部 std,并由名为 \xe2\x80\x9cnightly\xe2\x80\x9d 的功能保护。在我努力不建造除 no_std 之外的任何东西时,守卫被禁用了。我\xe2\x80\x99d 尝试过的任何事情都没有提醒我注意在此之前负责的板条箱。似乎应该有一种更好的方法来获得比货物树提供的更全面的板条箱依赖项列表,但是更改 wasmi 货物以确保设置夜间功能解决了我的问题。

\n