Skip to content

Tracking issue for the #[used] attribute #40289

Closed

Description

@japaric

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

Activity

  1. added
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Mar 6, 2017
  2. est31 commented on Apr 29, 2017

    @est31
    Member
  3. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 22, 2017
  4. acmcarther commented on Dec 1, 2017

    @acmcarther
    Contributor

    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.

  5. japaric commented on Apr 3, 2018

    @japaric
    ContributorAuthor

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

  6. phil-opp commented on Apr 20, 2018

    @phil-opp
    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.

  7. japaric commented on Apr 25, 2018

    @japaric
    ContributorAuthor

    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.

  8. added a commit that references this issue on Apr 30, 2018
  9. japaric commented on May 1, 2018

    @japaric
    ContributorAuthor

    @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).

  10. phil-opp commented on May 4, 2018

    @phil-opp
    Contributor

    @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.

  11. Centril commented on May 27, 2018

    @Centril
    Contributor

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

  12. liigo commented on Jun 6, 2018

    @liigo
    Contributor

    #[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

  13. cramertj commented on Jun 25, 2018

    @cramertj
    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.

  14. 1 remaining item

  15. cramertj commented on Jun 25, 2018

    @cramertj
    Member

    Trying again w/ a lang tag...

    @rfcbot fcp merge

  16. rfcbot commented on Jun 25, 2018

    @rfcbot

    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.

  17. added
    proposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.
    disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.
    on Jun 25, 2018
  18. rfcbot commented on Aug 29, 2018

    @rfcbot

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

  19. added
    final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.
    and removed
    proposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.
    on Aug 29, 2018
  20. rfcbot commented on Sep 8, 2018

    @rfcbot

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

  21. removed
    final-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.
    on Sep 8, 2018
  22. added a commit that references this issue on Sep 9, 2018
    2fb5d5d
  23. added a commit that references this issue on Sep 11, 2018
    7ee7207
  24. MaskRay commented on Mar 2, 2021

    @MaskRay
    Contributor

    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

  25. comex commented on Mar 7, 2021

    @comex
    Contributor

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-langRelevant to the language teamdisposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions