Week 0034 - Fun with UEFI linker errors

« Home

Created 2022-11-14, last updated 2022-11-20 20:43:44 UTC


I discovered that the new disted i686-unknown-uefi target hits linker errors when you try to use it. Filed an issue for that and started looking into it.

There are a few issues that need to be solved. First up, an asm issue:

Asm files aren't getting a special symbol needed by the linker when safe SEH is enabled. It might be possible to solve that with some extra compilation flags, except those flags are asm-specific and clang doesn't like it when you pass the flag to C files. Since compiler_builtins uses a single cc::Build object for all files, we can't easily pass asm-specific flags.

For now I solved this in compiler-builtins by just disabling the asm implementations on UEFI: PR. I also filed an issue in cc-rs suggesting adding a way to set asm-specific flags. That got a quick response indicating that a patch would be welcome. I put together a PR implementing that, which got reviewed and merged in about a half hour, which is a really nice response time :)

The second issue is that the dist script for the UEFI targets is defaulting to gcc for the C files in compiler builtins. That causes us to end up with a compiler-builtins rlib that contains a mix of PE objects (from the Rust code) and ELF objects (from the C code). That doesn't actually cause an error when building compiler-builtins or Rust, which is why we didn't notice it. However, if you try to actually reference one of the symbols in an ELF object you get a linker error.

To solve this we can switch the dist to use clang, but that exposes another issue: one of the C files in compiler-rt that compiler-builtins uses tries to include stdlib.h. That is not really compatible with compiling with -ffreestanding, and can lead to incompatible type definition errors.

My first attempt to solve this was to just skip including that file (PR), but that was wrong because the file defines functions that are used in other files. Easy to miss because again, you don't find out that it's wrong until you actually call something that (transitively) uses the missing symbol.

Then I realized we could just provide an empty stdlib.h file since nothing actually needs to be declared for the C file to compile in our case. Made a new PR for that.

The two compiler_builtins PRs were merged and included in the 0.1.84 release.

Next I put up a PR in Rust to update to the new version of compiler_builtins and switch the C compiler for the UEFI targets to clang. I got some feedback requesting some kind of test to ensure that the rlibs all contain just COFF objects, so I spent a little time figuring that out and updated the PR.

That's the status as of Sunday; once the PR is merged the next nightly should contain much more functional UEFI prebuilts.

I also want to enable CI for the aarch64 and i686 UEFI targets. For i686 that might require updating the Dockerfile to a newer version of Ubuntu that has the ovmf-ia32 package. Haven't looked at the aarch64 part yet.


© 2024 Nicholas BishopHomeRepo
Unless otherwise noted, content is licensed under CC BY 4.0. Code blocks are additionally available under CC0 and Apache License version 2.0 at your option.