Skip to content

Support cross-compilation of bare-metal binaries? #269

Description

@jonathanpallant

The README notes:

Embedded platforms where you cannot spare a byte should not add anything in the executable. Instead they should record the hash of every executable in a database and associate the hash with its Cargo.lock, compiler and LLVM version, build date, etc.

However, ELF executables (the format typically used produced by rustc when building bare-metal code) has the concept of a 'NOLOAD' section - this would leave the audit data in the ELF file, but it would not take up any space on the microcontroller. We already use this trick for debug info, defmt logs, etc, so it seems an ideal place to store dependency information.

I naively tried to just build a thumbv8m.main-none-eabi binary with cargo auditable build on my macOS machine, and I got a linker error:

= note: rust-lld: error: unknown argument '-Wl,-u,AUDITABLE_VERSION_INFO'

Activity

  1. bjorn3 commented on Sep 30, 2026

    @bjorn3

    cargo-auditable already omits SHF_ALLOC on ELF.

    = note: rust-lld: error: unknown argument '-Wl,-u,AUDITABLE_VERSION_INFO'

    It failed to detect that you are using a bare linker. It looks at the -Clinker argument passed, not at target defaults:

    /// Normally `rustc` uses a C compiler such as `cc` or `clang` as linker,
    /// and arguments to the actual linker need to be passed prefixed with `-Wl,`.
    /// But it is possible to configure Cargo and rustc to call a linker directly,
    /// and the breakage it causes is subtle enough that people just roll with it
    /// and complain when cargo-auditable doesn't support this configuration:
    /// <https://github.com/rust-secure-code/cargo-auditable/issues/202>
    ///
    /// This function can tell you if a bare linker is in use
    /// and whether you need to prepend `-Wl,` or not.
    ///
    /// Such setups are exceptionally rare and frankly it's a misconfiguration
    /// that will break more than just `cargo auditable`, but I am feeling generous.
    pub fn bare_linker(&self) -> bool {
    let linker_flag = self.codegen.iter().find(|s| s.starts_with("linker="));
    if let Some(linker_flag) = linker_flag {
    let linker = linker_flag.strip_prefix("linker=").unwrap();
    if linker.ends_with("ld") {
    return true;
    }
    }
    false
    }
    }

  2. jonathanpallant commented on Sep 30, 2026

    @jonathanpallant
    Author

    Ah.

    Adding linker = "rust-lld" to .cargo/config.toml allowed the build to work, but it's not ideal (and most people won't have that set).

    $ cargo audit bin ../target/thumbv8m.main-none-eabi/release/standalone-hello
        Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
          Loaded 1277 security advisories (from /Users/jonathan/.cargo/advisory-db)
        Updating crates.io index
           Found 'cargo auditable' data in ../target/thumbv8m.main-none-eabi/release/standalone-hello (59 dependencies)
    Crate:     bare-metal
    Version:   0.2.5
    Warning:   unmaintained
    Title:     bare-metal is deprecated
    Date:      2026-04-23
    ID:        RUSTSEC-2026-0110
    URL:       https://rustsec.org/advisories/RUSTSEC-2026-0110
    
    warning: 1 allowed warning found in ../target/thumbv8m.main-none-eabi/release/standalone-hello

    /// Such setups are exceptionally rare and frankly it's a misconfiguration
    /// that will break more than just cargo auditable, but I am feeling generous.

    I mean, basically all the Rust bare-metal targets are configured to use rust-lld directly, so it's not that rare.

    Unfortunately I don't know how to work out that rustc is using a bare linker, beyond holding a big database of target strings that will often be slightly out of date.

  3. Shnatsel commented on Sep 30, 2026

    @Shnatsel
    Member

    I think there are two options to get this info from rustc. One is this:

    rustc +nightly -Z unstable-options \
      --target x86_64-unknown-linux-gnu \
      --print target-spec-json |
      jq -r '."linker-flavor"'
    

    Requires nightly, but we can just pass RUSTC_BOOTSTRAP=1, and if it breaks then all non-bare-metal platforms will keep working so it's probably fine.

    Technically we also have this on stable:

    rustc --print link-args main.rs --target x86_64-unknown-linux-gnu
    

    But the output is not machine-readable, and it actually compiles and links a small binary, which is pretty slow.

    I'll try to implement the RUSTC_BOOTSTRAP JSON option and see if that works.

    However, ELF executables (the format typically used produced by rustc when building bare-metal code) has the concept of a 'NOLOAD' section - this would leave the audit data in the ELF file, but it would not take up any space on the microcontroller.

    cargo-auditable already omits SHF_ALLOC on ELF.

    It would be great news if we happened to already pass the correct flags! I would like to get an experimental confirmation of this, however. @jonathanpallant now that you got it working, do you think you could measure the flashed binary size before and after to see if the audit info is correctly omitted?

  4. jonathanpallant commented on Sep 30, 2026

    @jonathanpallant
    Author
    $ cargo build --release --bin standalone-hello && rust-size ./target/thumbv8m.main-none-eabi/release/standalone-hello
        Finished `release` profile [optimized + debuginfo] target(s) in 11.09s
       text	   data	    bss	    dec	    hex	filename
       5524	     56	   1032	   6612	   19d4	./target/thumbv8m.main-none-eabi/release/standalone-hello
    $ cargo auditable build --release --bin standalone-hello && rust-size ./target/thumbv8m.main-none-eabi/release/standalone-hello
        Finished `release` profile [optimized + debuginfo] target(s) in 0.62s
       text	   data	    bss	    dec	    hex	filename
       5524	     56	   1032	   6612	   19d4	./target/thumbv8m.main-none-eabi/release/standalone-hello

    No change in code size. But here's the section:

    $ cargo auditable build --release --bin standalone-hello && rust-size -Ax ./target/thumbv8m.main-none-eabi/release/standalone-hello
        Finished `release` profile [optimized + debuginfo] target(s) in 0.04s
    ./target/thumbv8m.main-none-eabi/release/standalone-hello  :
    section                size         addr
    .vector_table         0x258    0x8000000
    .text                0x10ac    0x8000258
    .rodata               0x290    0x8001304
    .data                  0x38   0x20000000
    .gnu.sgstubs              0    0x80015e0
    .bss                    0x8   0x20000038
    .uninit               0x400   0x20000040
    .defmt                  0x4            0
    .debug_abbrev        0x2407            0
    .debug_info         0x558e5            0
    .debug_aranges       0x24e0            0
    .debug_ranges       0x140e0            0
    .debug_str          0x88753            0
    .comment               0xa1            0
    .ARM.attributes        0x32            0
    .debug_frame         0x7230            0
    .debug_line         0x2a101            0
    .debug_loc           0x7149            0
    .dep-v0               0x38c            0 <<<<< it's this one
    Total              0x130cb0
  5. Shnatsel commented on Oct 2, 2026

    @Shnatsel
    Member

    Done in #270

    Release as v0.7.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions