Hi! Apologies if this is a silly question or if I've got anything wrong. This is definitely not my aread of expertise:
I'm currently trying to some work with Rust using an ARM7v embedded device. The device in question is a bit odd, in that you send a binary over the network, where it's then dynamically linked and loaded — so we need to target bare metal, but produce a dynamically linked-executable!
This has worked fine, until I tried to update to Rust nightly-2025-02-20 (yay, Rust 2024!), where the binary now starts exporting some weak symbols from compiler-builtins, like __aeabi_uidivmod
. The binary loader on the device doesn't currently cope with this and fails.
I've pinned this down to a change between nightly-2024-12-12 and nightly-2024-12-13, but I'm not quite sure what's causing it, or where to go for here.
Cargo.toml:
[package]
name = "example"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[profile.release]
codegen-units = 1
opt-level = 2
lto = true
src/lib.rs
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[unsafe(no_mangle)]
extern "C" fn div_euclid(x: i64) -> i64 {
x.div_euclid(123)
}
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
I'm then compiling the whole thing with the following command (well, not IRL, but for this example!):
env RUSTFLAGS=-Crelocation-model=pic cargo +nightly-2024-12-13 build --target=armv7a-none-eabihf -Zbuild-std=core --release
ld.lld -shared target/armv7a-none-eabihf/release/libexample.a --entry div_euclid -x -o out.elf
On 2024-12-12, the binary exports the following symbols:
$ nm -g out.elf
00114f8 T div_euclid
But on 2024-12-13, it exports:
$ nm -g out.elf
00011668 W __aeabi_idivmod
00011680 W __aeabi_ldivmod
00011628 W __aeabi_uidivmod
00011644 W __aeabi_uldivmod
000115e8 T div_euclid
If I compare the original libexample.a
file, this appears to be because the visibility of these symbols has changed from HIDDEN
to DEFAULT
, but it's not clear why to me — the version of compiler-builtins is the same.
Does anyone know what might have changed in Rust to cause this, and if there's any good ways to prevent this? Ideally I'd like to strip the weak marker from all symbols (either in the Rust lib, or in the final link step), but most existing tooling (e.g. objcopy
) is only interested in making symbols more weak, and don't think there's any linker flags to ignore the weak marker.
My current workaround is to mark symbols as hidden (llvm-objcopy --localize-symbols=(llvm-readelf -s libexample.a | grep "WEAK DEFAULT" | awk '{ print $8 }' | psub) libexample.a
), but this does not feel like a good long-term solution.