diff options
| author | bors <bors@rust-lang.org> | 2017-04-07 04:56:45 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-04-07 04:56:45 +0000 |
| commit | b9c5197d4878253804d91e0c30ed92e0a965b663 (patch) | |
| tree | bed96e3ef538a1ae2cb866b371745b517da1ae00 /src/doc | |
| parent | 2277f4bdcc1195a5f6c9c96d8d1fb32482cbd673 (diff) | |
| parent | 98037ca43d4d96f93e73e1eb3df8e64372d8f929 (diff) | |
| download | rust-b9c5197d4878253804d91e0c30ed92e0a965b663.tar.gz rust-b9c5197d4878253804d91e0c30ed92e0a965b663.zip | |
Auto merge of #39987 - japaric:used, r=arielb1
#[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
Diffstat (limited to 'src/doc')
| -rw-r--r-- | src/doc/unstable-book/src/SUMMARY.md | 1 | ||||
| -rw-r--r-- | src/doc/unstable-book/src/used.md | 153 |
2 files changed, 154 insertions, 0 deletions
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4..20812de524a 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -205,6 +205,7 @@ - [unwind_attributes](unwind-attributes.md) - [update_panic_count](update-panic-count.md) - [use_extern_macros](use-extern-macros.md) +- [used](used.md) - [utf8_error_error_len](utf8-error-error-len.md) - [vec_remove_item](vec-remove-item.md) - [windows_c](windows-c.md) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md new file mode 100644 index 00000000000..75a8b2774f4 --- /dev/null +++ b/src/doc/unstable-book/src/used.md @@ -0,0 +1,153 @@ +# `used` + +The tracking issue for this feature +is: [40289](https://github.com/rust-lang/rust/issues/40289). + +------------------------ + +The `#[used]` attribute can be applied to `static` variables to prevent the Rust +compiler from optimizing them away even if they appear to be unused by the crate +(appear to be "dead code"). + +``` rust +#![feature(used)] + +#[used] +static FOO: i32 = 1; + +static BAR: i32 = 2; + +fn main() {} +``` + +If you compile this program into an object file, you'll see that `FOO` makes it +to the object file but `BAR` doesn't. Neither static variable is used by the +program. + +``` text +$ rustc -C opt-level=3 --emit=obj used.rs + +$ nm -C used.o +0000000000000000 T main + U std::rt::lang_start +0000000000000000 r used::FOO +0000000000000000 t used::main +``` + +Note that the *linker* knows nothing about the `#[used]` attribute and will +remove `#[used]` symbols if they are not referenced by other parts of the +program: + +``` text +$ rustc -C opt-level=3 used.rs + +$ nm -C used | grep FOO +``` + +"This doesn't sound too useful then!" you may think but keep reading. + +To preserve the symbols all the way to the final binary, you'll need the +cooperation of the linker. Here's one example: + +The ELF standard defines two special sections, `.init_array` and +`.pre_init_array`, that may contain function pointers which will be executed +*before* the `main` function is invoked. The linker will preserve symbols placed +in these sections (at least when linking programs that target the `*-*-linux-*` +targets). + +``` rust,ignore +#![feature(used)] + +extern "C" fn before_main() { + println!("Hello, world!"); +} + +#[link_section = ".init_array"] +#[used] +static INIT_ARRAY: [extern "C" fn(); 1] = [before_main]; + +fn main() {} +``` + +So, `#[used]` and `#[link_section]` can be combined to obtain "life before +main". + +``` text +$ rustc -C opt-level=3 before-main.rs + +$ ./before-main +Hello, world! +``` + +Another example: ARM Cortex-M microcontrollers need their reset handler, a +pointer to the function that will executed right after the microcontroller is +turned on, to be placed near the start of their FLASH memory to boot properly. + +This condition can be met using `#[used]` and `#[link_section]` plus a linker +script. + +``` rust,ignore +#![feature(lang_items)] +#![feature(used)] +#![no_main] +#![no_std] + +extern "C" fn reset_handler() -> ! { + loop {} +} + +#[link_section = ".reset_handler"] +#[used] +static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; + +#[lang = "panic_fmt"] +fn panic_fmt() {} +``` + +``` text +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} + +SECTIONS +{ + .text ORIGIN(FLASH) : + { + /* Vector table */ + LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */ + KEEP(*(.reset_handler)); + + /* Omitted: The rest of the vector table */ + + *(.text.*); + } > FLASH + + /DISCARD/ : + { + /* Unused unwinding stuff */ + *(.ARM.exidx.*) + } +} +``` + +``` text +$ xargo rustc --target thumbv7m-none-eabi --release -- \ + -C link-arg=-Tlink.x -C link-arg=-nostartfiles + +$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app +./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm + + +Disassembly of section .text: + +08000000 <app::RESET_HANDLER-0x4>: + 8000000: 20005000 .word 0x20005000 + +08000004 <app::RESET_HANDLER>: + 8000004: 08000009 .... + +08000008 <app::reset_handler>: + 8000008: e7fe b.n 8000008 <app::reset_handler> +``` |
