Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined symbols when linking i686-unknown-uefi without using -Zbuild-std #104326

Closed
nicholasbishop opened this issue Nov 12, 2022 · 3 comments · Fixed by #104622
Closed

Undefined symbols when linking i686-unknown-uefi without using -Zbuild-std #104326

nicholasbishop opened this issue Nov 12, 2022 · 3 comments · Fixed by #104622
Assignees
Labels
C-bug Category: This is a bug.

Comments

@nicholasbishop
Copy link
Contributor

nicholasbishop commented Nov 12, 2022

Simple repro:

# rust_toolchain.toml
[toolchain]
channel = "nightly"
targets = ["i686-unknown-uefi"]
// src/main.rs:
#![no_main]
#![no_std]

#[panic_handler]
fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

#[export_name = "efi_main"]
pub extern "C" fn main(_h: *mut core::ffi::c_void, _st: *mut core::ffi::c_void) -> usize {
    panic!();
}

Compile with cargo build --target i686-unknown-uefi. This fails with undefined symbols ___udivdi3 and ___umoddi3.

Full output
   Compiling tmp-i686-test v0.1.0 (/var/home/nbishop/src/tmp-i686-test)
error: linking with `rust-lld` failed: exit status: 1
  |
  = note: "rust-lld" "-flavor" "link" "/NOLOGO" "/entry:efi_main" "/subsystem:efi_application" "/tmp/rustcf3Esr7/symbols.o" "/var/home/nbishop/src/tmp-i686-test/target/i686-unknown-uefi/debug/deps/tmp_i686_test-e070b2b3d9570a0b.4r7w5v2t9imd2qsu.rcgu.o" "/LIBPATH:/var/home/nbishop/src/tmp-i686-test/target/i686-unknown-uefi/debug/deps" "/LIBPATH:/var/home/nbishop/src/tmp-i686-test/target/debug/deps" "/LIBPATH:/var/home/nbishop/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-uefi/lib" "/var/home/nbishop/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-uefi/lib/librustc_std_workspace_core-87aa5ecf680885c4.rlib" "/var/home/nbishop/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-uefi/lib/libcore-078ea958aaba8579.rlib" "/var/home/nbishop/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-uefi/lib/libcompiler_builtins-a6f227741d962a9d.rlib" "/NXCOMPAT" "/LIBPATH:/var/home/nbishop/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/i686-unknown-uefi/lib" "/OUT:/var/home/nbishop/src/tmp-i686-test/target/i686-unknown-uefi/debug/deps/tmp_i686_test-e070b2b3d9570a0b.efi" "/OPT:REF,NOICF" "/DEBUG" "/NODEFAULTLIB"
  = note: rust-lld: error: undefined symbol: ___udivdi3
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/num/dec2flt/decimal.rs:126
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::num::dec2flt::decimal::Decimal::left_shift::hdaf1b75087ea64fb)
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/num/dec2flt/decimal.rs:137
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::num::dec2flt::decimal::Decimal::left_shift::hdaf1b75087ea64fb)
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/num/flt2dec/strategy/dragon.rs:295
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::num::flt2dec::strategy::dragon::format_exact::h6e53ee3200af73e2)
          >>> referenced 40 more times
          
          rust-lld: error: undefined symbol: ___umoddi3
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/fmt/num.rs:501
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::fmt::num::parse_u64_into::h6ca2586fb1d1d6c4)
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/fmt/num.rs:502
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::fmt::num::parse_u64_into::h6ca2586fb1d1d6c4)
          >>> referenced by /rustc/e75aab045fc476f176a58c408f6b06f0e275c6e1/library/core/src/fmt/num.rs:503
          >>>               libcore-078ea958aaba8579.rlib(core-078ea958aaba8579.core.3b584330-cgu.0.rcgu.o):(core::fmt::num::parse_u64_into::h6ca2586fb1d1d6c4)
          >>> referenced 2 more times

Interestingly, the error does not reproduce when using -Zbuild-std. Compiling with cargo build --target i686-unknown-uefi -Zbuild-std=core,compiler_builtins is successful.

Meta

rustc --version --verbose:

rustc 1.67.0-nightly (e75aab045 2022-11-09)
binary: rustc
commit-hash: e75aab045fc476f176a58c408f6b06f0e275c6e1
commit-date: 2022-11-09
host: x86_64-unknown-linux-gnu
release: 1.67.0-nightly
LLVM version: 15.0.4
@nicholasbishop nicholasbishop added the C-bug Category: This is a bug. label Nov 12, 2022
@nicholasbishop
Copy link
Contributor Author

@rustbot claim

@nicholasbishop
Copy link
Contributor Author

nicholasbishop commented Nov 14, 2022

It looks like there are two issues here, which I will start working on PRs for.

The first issue is that we aren't setting clang as the C compiler used when disting the UEFI targets. Presumably it's just defaulting to gcc, with the end result that C code gets compiled into ELF objects instead of PE. You can see this by running objdump -t path/to/libcompiler_builtins.rlib, which will show a mix of formats like:

compiler_builtins-c71194a2c8a54b35.compiler_builtins.86fabcdc-cgu.0.rcgu.o:     file format pe-x86-64
[...]
compiler_builtins-c71194a2c8a54b35.compiler_builtins.86fabcdc-cgu.1.rcgu.o:     file format pe-x86-64
[...]
absvdi2.o:     file format elf64-x86-64
[...]
absvsi2.o:     file format elf64-x86-64
[...]

This mix of formats doesn't cause an error until you actually try to use one of the functions in an ELF object, at which point you'll get a linker error.

The second issue relates to compiler_builtins using optimized assembly for some builtins: https://github.com/rust-lang/compiler-builtins/blob/0.1.83/build.rs#L302. When clang compiles these asm files, it doesn't add a @feat.00 symbol like it does for C files, so we get SEH errors from the linker. There doesn't seem to be any flag to change that behavior, so the simplest solution for now is probably to modify compiler_builtins to not add the .S files for any UEFI target.

Edit: the @feat.00 could be added with -Wa,-defsym,@feat.00=1, but then we'd need a way to only pass that flag for asm targets. Filed a cc feature request for that: rust-lang/cc-rs#751

@nicholasbishop
Copy link
Contributor Author

The necessary fixes in compiler_builtins have been made and released in 0.1.84. Next step is #104561

Manishearth added a commit to Manishearth/rust that referenced this issue Nov 22, 2022
…r=Mark-Simulacrum

Use clang for the UEFI targets

This fixes an issue where the C and asm sources built by compiler_builtins were being compiled as ELF objects instead of PE objects. This wasn't noticed before because it doesn't cause compiler_builtins or rustc to fail to build. You only see a failure when a program is built that references one of the symbols in an ELF object.

Compiling with clang fixes this because the cc crate converts the UEFI targets into Windows targets that clang understands, causing it to produce PE objects.

Also update compiler_builtins to 0.1.84 to pull in some necessary fixes for compiling the UEFI targets with clang.

Fixes rust-lang#104326
@bors bors closed this as completed in eafe61d Nov 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant