-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add a used attribute #1459
Add a used attribute #1459
Conversation
Note that rust-lang/rust#30830 fixes this, and I consider the current behaviour to be a bug. However, there's a bit of an unresolved question around whether the type should need to be marked |
That issue is somewhat related but doesn't fix this.
|
I also don't agree with the patch that was merged. Items should be aggressively removed if they are not used. I'm not sure what your patch does exactly, but if it allows completely unused items to be present in the executable, then it should be reverted. |
Erm I was a bit confused, sorry, let's make a graph! #![feature(linkage)]
#![allow(dead_code)]
#[link_section = ".init_array"] #[linkage = "external"]
static F_STATIC_EXT: extern fn() = f_static_external;
#[link_section = ".init_array"] #[linkage = "external"]
pub static F_PUB_STATIC_EXT: extern fn() = f_pub_static_external;
#[link_section = ".init_array"]
static F_STATIC: extern fn() = f_static;
#[link_section = ".init_array"]
pub static F_PUB_STATIC: extern fn() = f_pub_static;
extern fn f_static() {
println!("static");
}
extern fn f_static_external() {
println!("static external");
}
extern fn f_pub_static_external() {
println!("pub static external");
}
extern fn f_pub_static() {
println!("pub static");
}
fn main() { }
|
I don't think it is. Otherwise LLVM wouldn't have a separate mechanism for |
Linkage has really nothing to do with this RFC. |
Ah, fair, I wasn't aware llvm had a construct for that! |
This seems like a reasonable thing to me, modulo bikeshedding the name. I feel like the name should be less generic, perhaps include something about "link" in it :) |
@nikomatsakis This is the name used by gcc/clang and llvm for this feature. I don't know what else you'd call it. |
Yes rust-lang/rust#30830 is different than this RFC as that largely just has to do with LTO. As @mahkoh indicated it is indeed the case that LLVM's For example, a #![feature(linkage)]
#[export_name = "llvm.used"]
#[linkage = "appending"]
static mut _FOO: [*const u8; 1] = [
&FOO_ADDR as *const _ as *const _
];
static FOO_ADDR: fn() = foo;
fn foo() {}
fn main() { } If you take a look at the generated object file: $ rustc foo.rs --emit obj
$ nm -g foo.o
0000000000000000 T main
U _ZN2rt10lang_start20h81372bffc43d2081zkyE
$ nm -a foo.o
0000000000000000 a foo.0.rs
0000000000000000 T main
0000000000000000 t .text.main
0000000000000000 t .text._ZN3foo20hea4f1d23bdee9020vaaE
0000000000000000 t .text._ZN4main20h7bc0c385e27c0783yaaE
U _ZN2rt10lang_start20h81372bffc43d2081zkyE
0000000000000000 t _ZN3foo20hea4f1d23bdee9020vaaE
0000000000000000 t _ZN4main20h7bc0c385e27c0783yaaE
0000000000000000 d _ZN8FOO_ADDR20hc3c6a3fb783d8c08saaE Here we can see that Another difference, I believe, is that LLVM has different optimization heuristics (such as inlining) for internal functions rather than external ones. In my testing, however, I was surprised that this may not be as useful as originally appearing. One might expect that if the above program is compiled into a binary that it would indeed have the relevant symbols in the binary (but as private), it in fact does not. The reason for this is that we still pass (note dynamic linkage is used here to reduce the number of stripped symbols $ rustc -C prefer-dynamic -O foo.rs -C link-args=-Wl,--print-gc-sections
INFO:rustc_trans::back::link: LinkMeta { crate_name: "foo", crate_hash: Svh { hash: "d9f16434537bb629" } }
INFO:rustc_trans::back::link: preparing dylib? (false) from ["foo.0.o"] to "foo"
INFO:rustc_trans::back::linker: linking with ld.gold
INFO:rustc_trans::back::link: "cc" "-Wl,--as-needed" "-m64" "-L" "/home/alex/.multirust/toolchains/nightly/lib/rustlib/x86_64-unknown-linux-gnu/lib" "foo.0.o" "-o" "foo" "-Wl,--gc-sections" "-pie" "-Wl,-O1" "-nodefaultlibs" "-L" "/home/alex/.multirust/toolchains/nightly/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "-L" "/home/alex/.multirust/toolchains/nightly/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-l" "std-17a8ccbd" "-l" "dl" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-fuse-ld=gold" "-Wl,--print-gc-sections" "-l" "compiler-rt"
INFO:rustc_trans::back::link: linker stderr:
/usr/bin/ld.gold: removing unused section from '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld.gold: removing unused section from '.text' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/crtbeginS.o'
/usr/bin/ld.gold: removing unused section from '.text' in file 'foo.0.o'
/usr/bin/ld.gold: removing unused section from '.data' in file 'foo.0.o'
/usr/bin/ld.gold: removing unused section from '.bss' in file 'foo.0.o'
/usr/bin/ld.gold: removing unused section from '.text._ZN3foo20hea4f1d23bdee9020vaaE' in file 'foo.0.o'
/usr/bin/ld.gold: removing unused section from '.data.rel.ro.local._ZN8FOO_ADDR20hc3c6a3fb783d8c08saaE' in file 'foo.0.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)'
/usr/bin/ld.gold: removing unused section from '.text' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/crtendS.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/crtendS.o'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/crtendS.o'
/usr/bin/ld.gold: removing unused section from '.text' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o' Here we see that our "used symbol" This seems like it's at least a downside of this RFC, although it's one that I think it would also be interesting to explore if we could fix as well. The current state of affairs is that we've also stabilized very little with respect to this sort of fine-grained control over linkage and symbol names, which is relatively intentional. That's not to say the set could expand, though! This largely just means that there's not many other pieces of the system we need to consider the interaction with, but that set may grow over time. I'd personally probably be mostly interested in pursuing this as a nightly feature for now. I'm sure if there are that many use cases for an attribute like this (it looks like |
@alexcrichton My mistake was that I misunderstood this part of the LLVM docs:
I thought this referred to LLVM itself emitting such a directive on certain targets but maybe it is the code that generates the IR that has to do this. I'll investigate what clang does here. |
Oh interesting, so according to the docs as well:
I wonder if we're perhaps invoking the linker in a weird way? Or maybe it's just not designed to work in tandem with It looks like LLVM also has a |
Both GCC and clang throw If you're using a linker script you can tell the linker to keep a specific section. I haven't found a way to keep a section via a command line option. |
I don't think there are many uses for symbols are are not referenced anywhere at the linking stage. As long as this this behavior is documented, there shouldn't be an issue. |
Agreed. The main purpose of the attribute would be to ensure that an internal symbol makes it all the way to the linker. At that point it's free to throw it out if it's truly unused; the linker script is what determines that. |
It's possible to keep them by putting them all in a section that is used: #![feature(linkage)]
#[export_name = "llvm.used"]
#[linkage = "appending"]
static mut _FOO: [*const u8; 1] = [
&foo as *const _ as *const _
];
#[link_section = ".text"]
fn foo() {}
#[link_section = ".text"]
fn main() { } This is probably good enough for those rare cases that want this behavior. |
I'd personally still be a bit wary to give this such a small name like |
What is "it"?
The same can be done with a #[used] attribute. What one might do is make #[used] more general (here called #[preserved]):
|
I like |
I'd be a little wary to overdesign a feature like this as it may be difficult to actually guarantee that all the various combinations and such actually work. I'd also want to have a strong motivation for each one before we added it. I do agree, however, that |
Updated. |
I too prefer On Sat, Jan 16, 2016 at 6:37 PM, mahkoh notifications@github.com wrote:
|
The RFC uses the imperative form because it is also used for inline. |
Updated. |
Sorry if it's not entirely on topic, but could the |
That's an orthogonal issue that can already be solved with fences. |
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
None. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this drawbacks section should probably at least mention that "may be discarded by the linker" can in some cases be confusing. In annotating a symbol as #[preserve]
one might expect it to be preserved but it may not make it all the way through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One might expect that #[inline]
inlines the function but that's not true either.
Updated. |
🔔 This RFC is now entering its final comment period 🔔 The tools team discussed this RFC yesterday and the current feeling is that we're likely to not merge this for now. While a number of possibilities have all been discussed here they all suffer from one complication or another unfortunately, and the general story around what symbols end up as what in Rust is relatively vague today as well (so it's tough to provide attributes to control them at an even finer grain). |
I don't have much opinion on this. It looks reasonable to me. |
I don't feel strongly whether we should merge or not, however, istm that most of the sentiment on the thread has been positive and that there is clearly some need for something in this space. So, if we don't merge, I think we should make some effort to spec the details that need to be spec'ed so that our symbol story is not "relatively vague" and we can then progress either merging this RFC or a new one. |
Ok, the tools team got a chance to talk about this RFC the other day, and the conclusion was that we're going to close this for now. Overall our symbol story is pretty vague today and is largely "best effort", so it's difficult to extend it as there's not already a set of documented guarantees. Additionally, once LTO is thrown into the mix, it adds quite a few complications to our symbol visibility story as well. This RFC is also lacking some details with the relationship to LTO and such, so it's not quite fully fleshed out as-is. Today we approximate symbol visibility on a "best-effort" kind of basis with In other words, though, we should have existing mechanisms to guarantee a symbols makes it to the linker such as:
Given all that, to merge an RFC like this we felt that there would want to be a more comprehensive design for our symbols story before adding pieces here and there, so closing. |
I've send a PR implementing this in rust-lang/rust#39987. I'd like to hear about what use cases people have in mind for this (apart from the one mentioned in the PR description). Please leave a comment on that PR. |
[RFC] #[used] attribute (For an explanation of what this feature does, read the commit message) I'd like to propose landing this as an experimental feature (experimental as in: no clear stabilization path -- like `asm!`, `#[linkage]`) as it's low maintenance (I think) and relevant to the "Usage in resource-constrained environments" exploration area. The main use case I see is running code before `main`. This could be used, for instance, to cheaply initialize an allocator before `main` where the alternative is to use `lazy_static` to initialize the allocator on its first use which it's more expensive (atomics) and doesn't work on ARM Cortex-M0 microcontrollers (no `AtomicUsize` on that platform) Here's a `std` example of that: ``` rust unsafe extern "C" fn before_main_1() { println!("Hello"); } unsafe extern "C" fn before_main_2() { println!("World"); } static INIT_ARRAY: [unsafe extern "C" fn(); 2] = [before_main_1, before_main_2]; fn main() { println!("Goodbye"); } ``` ``` $ rustc -C lto -C opt-level=3 before_main.rs $ ./before_main Hello World Goodbye ``` In general, this pattern could be used to let *dependencies* run code before `main` (which sounds like it could go very wrong in some cases). There are probably other use cases; I hope that the people I have cc-ed can comment on those. Note that I'm personally unsure if the above pattern is something we want to promote / allow and that's why I'm proposing this feature as experimental. If this leads to more footguns than benefits then we can just axe the feature. cc @nikomatsakis ^ I know you have some thoughts on having a process for experimental features though I'm fine with writing an RFC before landing this. - `dead_code` lint will have to be updated to special case `#[used]` symbols. - Should we extend `#[used]` to work on non-generic functions? cc rust-lang/rfcs#1002 cc rust-lang/rfcs#1459 cc @dpc @JinShil
[RFC] #[used] attribute (For an explanation of what this feature does, read the commit message) I'd like to propose landing this as an experimental feature (experimental as in: no clear stabilization path -- like `asm!`, `#[linkage]`) as it's low maintenance (I think) and relevant to the "Usage in resource-constrained environments" exploration area. The main use case I see is running code before `main`. This could be used, for instance, to cheaply initialize an allocator before `main` where the alternative is to use `lazy_static` to initialize the allocator on its first use which it's more expensive (atomics) and doesn't work on ARM Cortex-M0 microcontrollers (no `AtomicUsize` on that platform) Here's a `std` example of that: ``` rust unsafe extern "C" fn before_main_1() { println!("Hello"); } unsafe extern "C" fn before_main_2() { println!("World"); } static INIT_ARRAY: [unsafe extern "C" fn(); 2] = [before_main_1, before_main_2]; fn main() { println!("Goodbye"); } ``` ``` $ rustc -C lto -C opt-level=3 before_main.rs $ ./before_main Hello World Goodbye ``` In general, this pattern could be used to let *dependencies* run code before `main` (which sounds like it could go very wrong in some cases). There are probably other use cases; I hope that the people I have cc-ed can comment on those. Note that I'm personally unsure if the above pattern is something we want to promote / allow and that's why I'm proposing this feature as experimental. If this leads to more footguns than benefits then we can just axe the feature. cc @nikomatsakis ^ I know you have some thoughts on having a process for experimental features though I'm fine with writing an RFC before landing this. - `dead_code` lint will have to be updated to special case `#[used]` symbols. - Should we extend `#[used]` to work on non-generic functions? cc rust-lang/rfcs#1002 cc rust-lang/rfcs#1459 cc @dpc @JinShil
(For an explanation of what this feature does, read the commit message) I'd like to propose landing this as an experimental feature (experimental as in: no clear stabilization path -- like `asm!`, `#[linkage]`) as it's low maintenance (I think) and relevant to the "Usage in resource-constrained environments" exploration area. The main use case I see is running code before `main`. This could be used, for instance, to cheaply initialize an allocator before `main` where the alternative is to use `lazy_static` to initialize the allocator on its first use which it's more expensive (atomics) and doesn't work on ARM Cortex-M0 microcontrollers (no `AtomicUsize` on that platform) Here's a `std` example of that: ``` rust unsafe extern "C" fn before_main_1() { println!("Hello"); } unsafe extern "C" fn before_main_2() { println!("World"); } static INIT_ARRAY: [unsafe extern "C" fn(); 2] = [before_main_1, before_main_2]; fn main() { println!("Goodbye"); } ``` ``` $ rustc -C lto -C opt-level=3 before_main.rs $ ./before_main Hello World Goodbye ``` In general, this pattern could be used to let *dependencies* run code before `main` (which sounds like it could go very wrong in some cases). There are probably other use cases; I hope that the people I have cc-ed can comment on those. Note that I'm personally unsure if the above pattern is something we want to promote / allow and that's why I'm proposing this feature as experimental. If this leads to more footguns than benefits then we can just axe the feature. cc @nikomatsakis ^ I know you have some thoughts on having a process for experimental features though I'm fine with writing an RFC before landing this. - `dead_code` lint will have to be updated to special case `#[used]` symbols. - Should we extend `#[used]` to work on non-generic functions? cc rust-lang/rfcs#1002 cc rust-lang/rfcs#1459 cc @dpc @JinShil
(For an explanation of what this feature does, read the commit message) I'd like to propose landing this as an experimental feature (experimental as in: no clear stabilization path -- like `asm!`, `#[linkage]`) as it's low maintenance (I think) and relevant to the "Usage in resource-constrained environments" exploration area. The main use case I see is running code before `main`. This could be used, for instance, to cheaply initialize an allocator before `main` where the alternative is to use `lazy_static` to initialize the allocator on its first use which it's more expensive (atomics) and doesn't work on ARM Cortex-M0 microcontrollers (no `AtomicUsize` on that platform) Here's a `std` example of that: ``` rust unsafe extern "C" fn before_main_1() { println!("Hello"); } unsafe extern "C" fn before_main_2() { println!("World"); } static INIT_ARRAY: [unsafe extern "C" fn(); 2] = [before_main_1, before_main_2]; fn main() { println!("Goodbye"); } ``` ``` $ rustc -C lto -C opt-level=3 before_main.rs $ ./before_main Hello World Goodbye ``` In general, this pattern could be used to let *dependencies* run code before `main` (which sounds like it could go very wrong in some cases). There are probably other use cases; I hope that the people I have cc-ed can comment on those. Note that I'm personally unsure if the above pattern is something we want to promote / allow and that's why I'm proposing this feature as experimental. If this leads to more footguns than benefits then we can just axe the feature. cc @nikomatsakis ^ I know you have some thoughts on having a process for experimental features though I'm fine with writing an RFC before landing this. - `dead_code` lint will have to be updated to special case `#[used]` symbols. - Should we extend `#[used]` to work on non-generic functions? cc rust-lang/rfcs#1002 cc rust-lang/rfcs#1459 cc @dpc @JinShil
#[used] attribute (For an explanation of what this feature does, read the commit message) I'd like to propose landing this as an experimental feature (experimental as in: no clear stabilization path -- like `asm!`, `#[linkage]`) as it's low maintenance (I think) and relevant to the "Usage in resource-constrained environments" exploration area. The main use case I see is running code before `main`. This could be used, for instance, to cheaply initialize an allocator before `main` where the alternative is to use `lazy_static` to initialize the allocator on its first use which it's more expensive (atomics) and doesn't work on ARM Cortex-M0 microcontrollers (no `AtomicUsize` on that platform) Here's a `std` example of that: ``` rust unsafe extern "C" fn before_main_1() { println!("Hello"); } unsafe extern "C" fn before_main_2() { println!("World"); } #[link_section = ".init_arary"] #[used] static INIT_ARRAY: [unsafe extern "C" fn(); 2] = [before_main_1, before_main_2]; fn main() { println!("Goodbye"); } ``` ``` $ rustc -C lto -C opt-level=3 before_main.rs $ ./before_main Hello World Goodbye ``` In general, this pattern could be used to let *dependencies* run code before `main` (which sounds like it could go very wrong in some cases). There are probably other use cases; I hope that the people I have cc-ed can comment on those. Note that I'm personally unsure if the above pattern is something we want to promote / allow and that's why I'm proposing this feature as experimental. If this leads to more footguns than benefits then we can just axe the feature. cc @nikomatsakis ^ I know you have some thoughts on having a process for experimental features though I'm fine with writing an RFC before landing this. - `dead_code` lint will have to be updated to special case `#[used]` symbols. - Should we extend `#[used]` to work on non-generic functions? cc rust-lang/rfcs#1002 cc rust-lang/rfcs#1459 cc @dpc @JinShil
Add a
used
attribute to prevent symbols from being discarded.