当前位置: 首页 > 知识库问答 >
问题:

如何排除rust标准库符号中的cargo/rustc链接的故障,即使使用no_std?

居乐池
2023-03-14

我试图创建一个嵌入友好的可执行文件(占用空间小且不依赖于Rust标准库),它使用的库(wasmi)已经支持no_std构建。对于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 {}
}

即:

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

编译此文件的货物文件如下所示:

[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

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

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

rustc --release --verbose -- -C link-arg=-nostartfiles
   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

出现错误:

error[E0152]: duplicate lang item found: panic_impl.
  --> src/main.rs:31:1
   |
31 | / pub extern fn panic(_info: &PanicInfo) -> ! {
32 | |     loop {}
33 | | }
   | |_^
   |
   = note: first defined in crate `std`.

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

我想帮助理解为什么和理解如何防止它。

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

我看到的示例符号是:

my_home@my_puter:~/wasmi_embed/driver/target/release$ nm --demangle -A -a -B -s --line-number test_2018 2>/dev/null | grep std
driver:00000000000264c0 t rust_begin_unwind  /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:311
driver:00000000000264a0 t rust_oom   /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/alloc.rs:203
driver:000000000001f490 t rust_panic /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:524
driver:0000000000025aa0 t _$LT$std..panicking..continue_panic_fmt..PanicPayload$LT$$u27$a$GT$$u20$as$u20$core..panic..BoxMeUp$GT$::get::he4f810e299a2e0b4    /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:372
driver:00000000000259a0 t _$LT$std..panicking..continue_panic_fmt..PanicPayload$LT$$u27$a$GT$$u20$as$u20$core..panic..BoxMeUp$GT$::box_me_up::hd8430725259668a8     /rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/panicking.rs:367
driver:0000000000021520 t _$LT$std..sys_common..process..DefaultEnvKey$u20$as$u20$core..borrow..Borrow$LT$std..ffi..os_str..OsStr$GT$$GT$::borrow::hbacd0cd7d7fbf1c1/rustc/8e2063d02062ee9f088274690a97826333847e17//src/libstd/sys_common/process.rs:27
driver:0000000000021570 t _$LT$std..error..$LT$impl$u20$core..convert..From$LT$alloc..string..String$GT$$u20$for$u20$alloc..boxed..Box$LT$$LP$dyn$u20$std..error..Err
... plus more

dep目录下的任何rlib文件(包括libwasmi)中都找不到上述符号,在不调用libwasmi代码的驱动程序可执行文件中也找不到上述符号。

我也读过类似的问题(因此在cargo.toml中有test=falsebench=false),但这没有帮助。我尝试用Rustc构建不同的命令(不包括Cargo),但错误是一样的。我试图将wasmi编译为一个静态库(ar)并将其链接进来,但作为Rust的新手,我花了很多时间试图将其链接进来,但没有成功。

共有1个答案

慕凌
2023-03-14

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

>

  • 我尝试使用货物树来列出依赖项,以列出所有板条箱依赖项:

    wasmi V0.4.3(/HOME/JLB6740/GITHUB_DEV/wasmi)
    ──byteorder V1.3.1(/HOME/JLB6740/GITHUB_DEV/byteorder)
    ──hashbrown V0.1.8(/HOME/JLB6740/GITHUB_DEV/hashbrown)
    \──byteorder V1.3.1(/HOME/JLB6740/GITHUB_DEV/hashbrown)
    \──byteorder>──memory_units v0.3.0
    ──parity-wasm v0.31.0(/home/JLB6740/GITHUB_DEV/parity-wasm)
    ──byteorder v1.3.1(/home/JLB6740/GITHUB_DEV/byteorder)()

    我尝试使用cargo Rustc--verbose……但此时verbose并不表示任何使用默认特性的东西,其中可能包括使用std

    我尝试使用cargo元数据…这产生了一长串很难解析的依赖关系,但我确实看到了一些情况,其中scopeguard和byteorder具有需要std支持的默认特性。我下载了所有这些板条箱和硬编码属性,以便板条箱只能在no_std支持下构建。

    我尝试查看deps/output,并对所有RLIB进行nm操作,以查看是否有库使用了STD中的符号。我找不到情况是这样的。我认为rlib就像静态库,它们使用的任何东西都将包含在rlib中,但显然不是。

    我看了货物锈c---c---print-link-args来检查链接器标志,但我没有发现任何明显的东西告诉我它带来了std lib。

    这些事情都没有帮助我确定是什么引入了性病库。最终,rust论坛的建议是对一个根本不允许std lib的目标使用货物检查。那些在这里列出*的:这里输入链接描述只有核心支持。我尝试了一下,运行--target=thumbv7m-none-eabi并看到:

    错误[E0463]:找不到板条箱
    ->/home/jlb6740/github_dev/hashbrown/src/lib.rs:44:144外部板条箱std为alloc;
    ^^^^^^^^^^^^^^^^^^^找不到板条箱

    原来是hashbrown,它是我的可执行文件的依赖项的依赖项。默认情况下,它构建no_std,但有一个外部std以不同的名称链接,并由一个名为“nightly”的特性保护。在我努力不构建任何东西但no_std时,守卫被禁用。在这之前,我没有试过让我注意到板条箱是负责任的。似乎应该有一个更好的方法来获得比货运树提供的更全面的板条箱依赖列表,但是更改wasmi货运以确保设置了夜间功能解决了我的问题。

  •  类似资料:
    • 完整的pom.xml 如果我通过IDEA runner(TestNG config)运行project-一切都100%正常。我不知道为什么mvn builder在某个时候不想执行configfactory.create()并且找不到任何运行过Maven+owner的人。 附加信息:如果我运行上面的config方法,但将-durl={url}指定为arg,那么不是从Environment.class

    • 初始设置 在创建并启动新的 Serene 应用程序之后,不能显示登录页,而当你打开浏览器控制台,却得到一条错误消息:找不到 Template.LoginPanel: 你可能使用了无效的解决方案名称,如 MyProject.Something (包含点’.’)。 当项目以这种方式命名时,模板系统将不能定位模板。 请不要在解决方案名称中使用点符号(’.’),如果必须使用点符号,可在创建解决方案之后再重

    • 当使用 Gradle 时, 你肯定会碰到许多问题. 解决遇到的问题 如果你碰到了问题, 首先要确定你使用的是最新版本的 Gradle. 我们会经常发布新版本, 解决一些 bug 并加入新的功能. 所以你遇到的问题可能就在新版本里解决了. 如果你正在使用 Gradle Daemon, 先暂时关闭 daemon (你可以使用 switch —no-daemon 命令). 在第19章我们可以了解到更多关

    • 在Debian和Ubuntu上,当您安装标准的FreeRADIUS软件包时,FreeRADIUS服务器二进制文件称为freeradius而不是radiusd。 您可以创建将使用较慢服务器的ldap模块的命名实例。 然后,您可以使用冗余部分替换authorize部分中的ldap条目,该冗余部分首先使用快速LDAP服务器列出模块,然后使用较慢的部分使用ldap模块实例。 #ldap redundant

    • Mount 5 Error mount 5 错误通常是 MDS 服务器滞后或崩溃导致的。要确保至少有一个 MDS 是启动且运行的,集群也要处于 active+healthy 状态。 Mount 12 Error mount 12 错误显示 cannot allocate memory ,常见于 Ceph 客户端和 Ceph 存储集群版本不匹配。用以下命令检查版本: ceph -v 如果 Ceph

    • 从 Vert.x 3.4.0 开始,Vert.x 已经弃用 JGoups 实现,已经由 [infinispan]|(/clustering/Infinispan.md) 。不建议在生产或测试环境中使用 JGroups Cluster Manager 在构建工具中添加依赖即可: Maven(pom.xml) <dependency> <groupId>io.vertx</groupId> <