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

Linking to a static library does not always include exported symbols #99721

Open
mkroening opened this issue Jul 25, 2022 · 8 comments
Open

Linking to a static library does not always include exported symbols #99721

mkroening opened this issue Jul 25, 2022 · 8 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@mkroening
Copy link
Contributor

mkroening commented Jul 25, 2022

Similarly to #47384, statics in a static library that are marked as used are not included in the resulting binary if a non-inlined function is used in the same module.

Example

This code can be found at mkroening/rust-issue-99721.

staticlib.rs:

mod note {
    #[used]
    #[link_section = ".note.my-note"]
    static MY_NOTE: u8 = 0;

    #[inline(always)]
    pub fn dummy() {}
}

#[no_mangle]
pub extern "C" fn staticlib() {
    note::dummy();
}

bin.rs:

fn main() {
    extern "C" {
        fn staticlib();
    }

    unsafe {
        staticlib();
    }
}

Build using:

rustc --crate-type staticlib staticlib.rs
rustc -L native=. -l static=staticlib bin.rs

Display static library notes:

$ readelf -Wn libstaticlib.a
[...]
File: libstaticlib.a(staticlib.staticlib.68b5aa53-cgu.0.rcgu.o)

Displaying notes found in: .note.my-note
  Owner                Data size 	Description
readelf: Warning: Corrupt note: only 1 byte remains, not enough for a full note
[...]

Display binary notes:

$ readelf -Wn bin
Displaying notes found in: .note.gnu.property
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0	      Properties: x86 ISA needed: x86-64-baseline

Displaying notes found in: .note.gnu.build-id
  Owner                Data size 	Description
  GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)	   Build ID: 258d83311faf1a32cb84dd090ccc57abdbb1cb38

Displaying notes found in: .note.ABI-tag
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_ABI_TAG (ABI version tag)	    OS: Linux, ABI: 4.4.0

If note::dummy is made inline(never), the symbol is included in the resulting binary:

$ readelf -Wn bin
Displaying notes found in: .note.gnu.property
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0	      Properties: x86 ISA needed: x86-64-baseline

Displaying notes found in: .note.gnu.build-id
  Owner                Data size 	Description
  GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)	   Build ID: 72d6efcf61e2b33563094c3f179ebcc511db7485

Displaying notes found in: .note.ABI-tag
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_ABI_TAG (ABI version tag)	    OS: Linux, ABI: 4.4.0

Displaying notes found in: .note.my-note
  Owner                Data size 	Description
readelf: Warning: Corrupt note: only 1 byte remains, not enough for a full note
@mkroening mkroening added the C-bug Category: This is a bug. label Jul 25, 2022
@mkroening
Copy link
Contributor Author

CC: @nbdd0121 @petrochenkov

@nbdd0121
Copy link
Contributor

That's the nature of static library; there's not much we can do about it unless we squeeze everything into one single object file or reference all object files from every single one of them.

@mkroening
Copy link
Contributor Author

That makes sense.

I just found that you can force link the symbol with -Clink-arg=--undefined=<symbol_name> when building the binary. I was hoping there would be some general way of doing this that does not require modifying the binary.

I'll resort to using the inline(never) approach in the meantime, although that is really not a nice way of forcing a reference into the object file.

@carbotaniuman
Copy link
Contributor

You need [used(linker)] for this to work. That has spotty availability sadly, but there are workarounds.

@nbdd0121
Copy link
Contributor

You need [used(linker)] for this to work. That has spotty availability sadly, but there are workarounds.

That won't work either. Object file inside static libs will not participate in linker if it does not provide any undefined symbol. SHF_GNU_RETAIN are not special in this regard.

@mkroening
Copy link
Contributor Author

You need [used(linker)] for this to work. That has spotty availability sadly, but there are workarounds.

Yeah, that does not work unfortunately.

@petrochenkov
Copy link
Contributor

There's a similar issue that can be fixed.

You link a staticlib (written in C, or Rust, or whatever) to a binary, and you want to preserve some symbol from it.

// bin.rs

#[link(name = "my_staticlib")]
extern "C" {
    #[used(linker)]
    fn some_symbol_from_my_staticlib_that_needs_to_be_kept();

   #[used(linker)]
   static SAME_BUT_STATIC: u8;
}

Unfortunately, #[used] attributes do not work on foreign items, but it probably should.
(It should also work on (foreign) functions too, but this is what #94348 is about.)

If it worked it would refer to the symbol in question from symbols.o thus keeping the corresponding object file during linking.

@mkroening
Copy link
Contributor Author

Interesting!

Since in our use case we want to distribute the static library, this won't work. It's great that you can use --undefined from within Rust, though. For our problem I have now resorted to having a macro in the excluded module to define the static in the rood module while keeping the logic separate.

@fmease fmease added A-linkage Area: linking into static, shared libraries and binaries T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-discussion Category: Discussion or questions that doesn't represent real issues. and removed C-bug Category: This is a bug. needs-triage-legacy labels Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants