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

Tracking issue for the #[used] attribute #40289

Closed
japaric opened this issue Mar 6, 2017 · 16 comments · Fixed by #51363
Closed

Tracking issue for the #[used] attribute #40289

japaric opened this issue Mar 6, 2017 · 16 comments · Fixed by #51363
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@japaric
Copy link
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
@japaric japaric added the B-unstable Blocker: Implemented in the nightly compiler and unstable. label Mar 6, 2017
@est31
Copy link
Member

est31 commented Apr 29, 2017

cc #41628

@acmcarther
Copy link

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
Copy link
Member Author

japaric commented Apr 3, 2018

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

@phil-opp
Copy link
Contributor

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
Copy link
Member Author

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
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
Copy link
Member Author

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
Copy link
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
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
Copy link
Contributor

Centril commented May 27, 2018

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

@liigo
Copy link
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
Copy link
Member

@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 Relevant to the language team, which will review and decide on the PR/issue. label Jun 25, 2018
@cramertj
Copy link
Member

Trying again w/ a lang tag...

@rfcbot fcp merge

@rfcbot
Copy link

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 rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jun 25, 2018
@rfcbot
Copy link

rfcbot commented Aug 29, 2018

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

@rfcbot rfcbot added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Aug 29, 2018
@rfcbot rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Aug 29, 2018
@rfcbot rfcbot added the finished-final-comment-period The final comment period is finished for this PR / Issue. label Sep 8, 2018
@rfcbot
Copy link

rfcbot commented Sep 8, 2018

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

@rfcbot rfcbot removed the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Sep 8, 2018
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
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
@MaskRay
Copy link
Contributor

MaskRay commented Mar 2, 2021

Note: __attribute__((used)) has different behaviors on ELF and non-ELF targets. I recently added __attribute__((retain)) to Clang: https://reviews.llvm.org/D97447

See https://reviews.llvm.org/D97448 for the llvm.used change (SHF_GNU_RETAIN) on ELF targets.

See:
https://clang.llvm.org/docs/AttributeReference.html#used
https://clang.llvm.org/docs/AttributeReference.html#retain

@comex
Copy link
Contributor

comex commented Mar 7, 2021

Argh, why did GCC do that?

Apparently there's still some active debate about it: https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565418.html

I can sort of understand why one might want used and retain to be different, but I don't see any reason they can't have more analogous behavior across different targets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.