about summary refs log tree commit diff
path: root/src/doc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-07 04:56:45 +0000
committerbors <bors@rust-lang.org>2017-04-07 04:56:45 +0000
commitb9c5197d4878253804d91e0c30ed92e0a965b663 (patch)
treebed96e3ef538a1ae2cb866b371745b517da1ae00 /src/doc
parent2277f4bdcc1195a5f6c9c96d8d1fb32482cbd673 (diff)
parent98037ca43d4d96f93e73e1eb3df8e64372d8f929 (diff)
downloadrust-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.md1
-rw-r--r--src/doc/unstable-book/src/used.md153
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>
+```