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

Tracking issue for the `#[used]` attribute #40289

Closed
japaric opened this Issue Mar 6, 2017 · 14 comments

Comments

Projects
None yet
9 participants
@japaric
Member

japaric commented Mar 6, 2017

Added in PR #39987.
RFC for stabilization: rust-lang/rfcs#2386 (merged)

This is an experimental feature and requires an RFC before it goes through the stabilization process.

Usage

Preserves static variables up to the object file level. This feature doesn't affect link time garbage collections of unused symbols / sections.

// foo.rs
#![crate_type = "lib"]
#![feature(used)]

#[used]
static FOO: u32 = 0;
$ rustc -C opt-level=3 --emit=obj foo.rs

$ nm -C foo.o
0000000000000000 r foo::FOO::h367266b77811307c
@est31

This comment has been minimized.

Contributor

est31 commented Apr 29, 2017

cc #41628

@acmcarther

This comment has been minimized.

acmcarther commented Dec 1, 2017

Is there anything besides the task of creating an RFC that blocks stabilization of this feature? This feature is a cornerstone in a library I wrote and use, and I'd love to be able to use the library on a stable toolchain.

@japaric

This comment has been minimized.

Member

japaric commented Apr 3, 2018

I have opened an RFC to stabilize this: rust-lang/rfcs#2386

@japaric japaric referenced this issue Apr 3, 2018

Closed

Embedded development on stable #42

5 of 6 tasks complete
@phil-opp

This comment has been minimized.

Contributor

phil-opp commented Apr 20, 2018

There is still an open bug where an used static is optimized away if the surrounding module is not used by any code: #47384.

@japaric

This comment has been minimized.

Member

japaric commented Apr 25, 2018

Needs to be done before stabilizing this: #[used] should only be allowed on static variables. Right now you can put it on functions (which has no effect) and the compiler won't complain -- that should be an error.

kennytm added a commit to kennytm/rust that referenced this issue Apr 30, 2018

Rollup merge of rust-lang#50330 - japaric:used, r=nagisa
check that #[used] is used only on statics

this attribute has no effect on other items. This makes the implementation match what's described in the RFC.

cc rust-lang#40289

r? @nagisa
@japaric

This comment has been minimized.

Member

japaric commented May 1, 2018

@phil-opp

There is still an open bug where an used static is optimized away if the surrounding module is not used by any code: #47384.

That's not a problem with #[used] AFAICT. The symbol is in the libfoo.rlib., which is the only thing #[used] guarantees. See below

#![feature(used)]

mod foo {
    // private and non-reachable
    #[no_mangle]
    #[used]
    static STATIC: [u32; 10] = [1; 10];
}
$ cargo build
$ nm -C target/debug/libfoo.rlib

foo-d351a64747b10042.18cd33xhzunvqw3h.rcgu.o:
0000000000000000 r STATIC

$ cargo build --release
$ nm -C target/release/libfoo.rlib

foo-f1e69902e2c50980.foo0-f8ffab837addfc521cde53270051d9b7.rs.rcgu.o:
0000000000000000 r STATIC

You are not getting the behavior you want for other reasons, mainly due to link-time visibility: you want STATIC to be an exported symbol (it should show up as R in the output of nm, not as r).

Also KEEP does not guarantee that a symbol will be in the output binary: the linker will stop inspecting inputs as soon as all undefined symbols are resolved so it may not get to libfoo.rlib, or the linker may look into libfoo.rlib but it may not look into the object file that contains STATIC -- these days .rlibs contain several object files due to parallel codegen.

To make your example work I would rewrite it like this:

// foo/src/lib.rs

#![feature(used)]
#![no_std] // not required but I'm using thumbv7m-none-eabi as the example target

pub mod foo {
    // `STATIC` needs to be an *exported* symbol; they only way to do that right now is to make the
    // item *both* public and reachable
    #[doc(hidden)] // don't show this in the API docs
    #[export_name = "STATIC"] // or you could use `no_mangle` and rename the item, same thing
    #[used] // required or the compiler will drop this symbol when optimizations are enabled
    pub static __HIDDEN: [u32; 10] = [1; 10];
}
// src/main.rs
#![feature(lang_items)]
#![no_std]
#![no_main]

extern crate foo;

#[lang = "panic_fmt"]
fn panic_fmt() {}
/* link.x */
EXTERN(STATIC); /* Forces the linker to look into libfoo.rlib */
/* In general this makes the linker continue looking into the inputs until it finds this symbol */

SECTIONS
{
    /* put STATIC in the .static linker section */
    .static : ALIGN(4)
    {
        KEEP(*(.rodata.STATIC));
    }
}
$ cargo rustc --target thumbv7m-none-eabi -- -C linker=arm-none-eabi-ld -Z linker-flavor=ld -C link-arg=-Tlink.x

$ # note exported symbol: "R"
$ arm-none-eabi-nm -C target/thumbv7m-none-eabi/debug/deps/libfoo-739fb2098c2fa823.rlib
foo-739fb2098c2fa823.18cd33xhzunvqw3h.rcgu.o:
00000000 N
00000041 N
00000050 N
00000066 N
0000006a N
00000073 N
00000077 N
00000080 N
00000000 R STATIC

$ arm-none-eabi-objdump -Cd -j.static target/thumbv7m-none-eabi/debug/bar

target/thumbv7m-none-eabi/debug/bar:     file format elf32-littlearm


Disassembly of section .static:

00000000 <STATIC>:
   0:   01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00     ................
  10:   01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00     ................
  20:   01 00 00 00 01 00 00 00                             ........

I think EXTERN was the main thing you were missing. Without it the linker doesn't even look into libfoo.rlib (then visibility doesn't even matter). Without EXTERN the linker will only look into libfoo.rlib if it's looking for other symbols -- this is why you got STATIC in the output binary when there were calls into functions defined in foo (the linker was looking for the function foo::hello and it happened to find STATIC). But it's not certain that will work because of parallel codegen: foo::hello may end in the first object file in libfoo.rlib then the linker won't bother to look into the second object file which could happen to contain STATIC.

Visibility is important too: if STATIC wasn't an exported symbol the linker would ignore it and you would end with an undefined reference to STATIC in your binary (U STATIC in the output of nm).

@phil-opp

This comment has been minimized.

Contributor

phil-opp commented May 4, 2018

@japaric Thanks so much for the detailed explanation! The behavior makes sense to me now and I agree that this has nothing to do with the used attribute.

phil-opp added a commit to embed-rs/stm32f7-discovery that referenced this issue May 4, 2018

Mark `EXCEPTIONS` and `INTERRUPTS` as `EXTERN` in the linker script
This is required because otherwise the linker finishes as soon as all unresolved symbols are found. If it stumbles upon one of them by accident (because it looked at the file to find other symbols), the symbol is kept. If not, it is discarded. The `EXTERN` declaration tells the linker that it should look for the passed symbol.

This also explains why our workaround worked: If the EXCEPTIONS static is alone in a separate module, it wasn't found because the linker didn't look at the module file to find other symbols.

For more details, see rust-lang/rust#40289 (comment)
@Centril

This comment has been minimized.

Contributor

Centril commented May 27, 2018

The stabilization RFC is now merged. Anyone writing up the stabilization PR?

japaric added a commit to japaric/rust that referenced this issue Jun 5, 2018

@liigo

This comment has been minimized.

Contributor

liigo commented Jun 6, 2018

#[used] item is misleading. It's used until linking, but not used at writing or compiling code.
should be #[to_be_used] or #[maybe_useful], or #[useful] for short?
useful also implies: compiler, don't dismiss this item, it's useful for later use, i.e. linking.
cc #51363

@cramertj

This comment has been minimized.

Member

cramertj commented Jun 25, 2018

@rfcbot fcp merge

I propose that we stabilize this feature. The #[used] attribute, which can only be applied to static variables, forces the compiler to keep the variable in the output object file (.o, .rlib, etc.) even if the variable is not used, or referenced, by any other item in the crate.

See the latest RFC here.

@cramertj cramertj added the T-lang label Jun 25, 2018

@cramertj

This comment has been minimized.

Member

cramertj commented Jun 25, 2018

Trying again w/ a lang tag...

@rfcbot fcp merge

@rfcbot

This comment has been minimized.

rfcbot commented Jun 25, 2018

Team member @cramertj has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot

This comment has been minimized.

rfcbot commented Aug 29, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot

This comment has been minimized.

rfcbot commented Sep 8, 2018

The final comment period, with a disposition to merge, as per the review above, is now complete.

japaric added a commit to japaric/rust that referenced this issue Sep 9, 2018

bors added a commit that referenced this issue Sep 11, 2018

Auto merge of #51363 - japaric:stable-used, r=cramertj
stabilize #[used]

closes #40289

RFC for stabilization: rust-lang/rfcs#2386

r? @Centril

Where should this be documented? Currently the documentation is in the unstable book

@bors bors closed this in #51363 Sep 11, 2018

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