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

#[link_section] is only usable from the root crate #67209

Open
jfrimmel opened this issue Dec 10, 2019 · 7 comments
Open

#[link_section] is only usable from the root crate #67209

jfrimmel opened this issue Dec 10, 2019 · 7 comments
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@jfrimmel
Copy link
Contributor

Consider the following MNWE (minimal non-working example 😄):

~ $ mkdir mwe
~ $ cd mwe
~/mwe $ cargo new a
     Created binary (application) `a` package
~/mwe $ cargo new --lib b
     Created library `b` package
~/mwe $ cat <<EOF > b/src/lib.rs 
> #[used]
> #[link_section = ".mysection"]
> static X: u32 = 0;
> EOF
~/mwe $ echo 'b = { path="../b" }' >> a/Cargo.toml 
~/mwe $ cat <<EOF > a/src/main.rs 
> extern crate b; // link the crate
> 
> fn main() {}
> EOF
~/mwe $ cd a
~/mwe $ cat <<EOF > link.x
> ENTRY(main)
> 
> SECTIONS {
>     .mysection : ALIGN(8) {
>         _START_ = .;
>         KEEP(*(.mysection))
>         _END_ = .;
>     }
> }
> 
> ASSERT(_END_ != _START_, "Section empty");
> EOF
~/mwe $ mkdir .cargo
~/mwe $ cat <<EOF > .cargo/config
> [build]
> rustflags = ["-C", "link-arg=-Tlink.x"]
> EOF
~/mwe/a $ cargo build
   Compiling a v0.1.0 (/home/jfrimmel/mwe/a)
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" [long output omitted (libb-<hash>.rlib included)] -T../link.x"
  = note: /usr/bin/ld: Section empty

The setup contains two crates: the binary a and the dependent crate b. A custom linker script is used in order to put the contents of .mysection in a section with the same name. The assert statement makes the error visible: the static variable X should be moved into that section, making the section 4 bytes in size, but the section is empty.

If the static X is defined in crate a, everything works fine:

~/mwe/a $ cat <<EOF > src/main.rs
#[used]

#[link_section = ".mysection"]

static X: u32 = 0;
fn main() {}
EOF
~/mwe/a $ cargo build
   Compiling a v0.1.0 (/home/jfrimmel/mwe/a)
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s

So the behavior is different when the #[used] #[link_section] static is placed in a dependency or in the currently build crate.

Am I doing something wrong (in which case it should be documented more clearly) or is there really a bug in the linker?

@jonas-schievink jonas-schievink added A-attributes Area: Attributes (`#[…]`, `#![…]`) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 10, 2019
@Amanieu
Copy link
Member

Amanieu commented Dec 11, 2019

Can you try using pub static in the dependency crate? Maybe it's a visibility issue (although #[used] should force it to be emitted regardless)

@Amanieu
Copy link
Member

Amanieu commented Dec 11, 2019

Also, could you check the .rlib file generated for the dependency crate? Make sure it has a non-empty .mysection section (use readelf -a on it).

@jfrimmel
Copy link
Contributor Author

Sorry, I had both information pieces already available, but forget to write them down...

Can you try using pub static in the dependency crate? Maybe it's a visibility issue (although #[used] should force it to be emitted regardless)

The visibility of the static (or any parent module) doesn't change the behavior.

Also, could you check the .rlib file generated for the dependency crate? Make sure it has a non-empty .mysection section (use readelf -a on it).

I had a look at the file and it contains the section with its contents:
I extracted the .o-file of the libb-[...].rlib archive and looked at the section headers:

Section Headers:
  [Nr] Name              Type             Address           Offset         Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000       0000000000000000  0000000000000000           0     0     0
  [ 1] .strtab           STRTAB           0000000000000000  000003d0       0000000000000104  0000000000000000           0     0     1
  [ 2] .text             PROGBITS         0000000000000000  00000040       0000000000000000  0000000000000000  AX       0     0     4
  [ 3] .mysection        PROGBITS         0000000000000000  00000040       0000000000000004  0000000000000000   A       0     0     4

As you can see, the section is present and has the size expected (4 bytes of the u32).

So the linker should have all required information about the section and its data.

@jfrimmel
Copy link
Contributor Author

I did some more investigation: when using the system linker ld (GNU ld (GNU Binutils) 2.33.1) the section is included both if

  • an object file with the section attribute is used and
  • a static library containing the object file above.

Reproduction:

mkdir mwe-asm
cd mwe-asm/
cat <<EOF > b.s
.section .mysection
.align 4
.global X
X:
    .word 42
EOF
cat <<EOF > a.s
.comm X, 4, 4

.global main
main:
    ret
EOF
as -o a.o a.s
as -o b.o b.s
cat <<EOF > link.x
ENTRY(main)

SECTIONS {
    .mysection : ALIGN(8) {
        _START_ = .;
        KEEP(*(.mysection))
        _END_ = .;
    }
}

ASSERT(_END_ != _START_, "Section empty");
EOF
# link directly
ld -o archive-no.elf a.o b.o -Tlink.x --gc-sections
# create archive and link
ar rcs libb.a b.o
ld -o archive-yes.elf a.o b.o -Tlink.x -lb -L. --gc-sections

Both archive-no.elf and archive-yes.elf contain the section .mysection.
If I'm not mistaken, this should be the same setup as the Rust one from above (except for the different linker).

Has anybody an idea how to proceed?

@BaderSZ
Copy link

BaderSZ commented Jul 28, 2022

A bit outdated, but I found that updating my toolchain seems to have fixed a similar issue I have (works on 2022-05-01, but not 2022-01-01 or earlier).

@jfrimmel
Copy link
Contributor Author

Confirmed fixed with the toolchain 1.62.1! When redoing the steps in the issue description, the current toolchain 1.62.1 produce the desired result:

~/mwe/a$ cargo build --target x86_64-unknown-linux-musl
~/mwe/a$ readelf -S target/x86_64-unknown-linux-musl/debug/a | grep -A1 .mysection
  [703] .mysection        PROGBITS         00000000000478d0  000488d0
       0000000000000004  0000000000000000   A       0     0     8

As you can see in the last output line, the section is now non-empty and has a size of 4 (a single u32).

Seems like this bug was fixed by accident 😉

@Amanieu should we add a test to the Rust repo, so that this doesn't break accidentally? Or should this bug simply be closed as fixed?

@BaderSZ
Copy link

BaderSZ commented Jul 28, 2022

Confirmed fixed with the toolchain 1.62.1! When redoing the steps in the issue description, the current toolchain 1.62.1 produce the desired result:

~/mwe/a$ cargo build --target x86_64-unknown-linux-musl
~/mwe/a$ readelf -S target/x86_64-unknown-linux-musl/debug/a | grep -A1 .mysection
  [703] .mysection        PROGBITS         00000000000478d0  000488d0
       0000000000000004  0000000000000000   A       0     0     8

As you can see in the last output line, the section is now non-empty and has a size of 4 (a single u32).

Seems like this bug was fixed by accident wink

@Amanieu should we add a test to the Rust repo, so that this doesn't break accidentally? Or should this bug simply be closed as fixed?

Possibly related to #95604?

@bjorn3 bjorn3 added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Jul 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. 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

5 participants