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

document #[used] #74

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@
* [Final Code](vec-final.md)
* [Implementing Arc and Mutex](arc-and-mutex.md)
* [FFI](ffi.md)
* [Application Binary Interface](abi.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo "application binary interface" is less a term than ABI is these days, so I'd call this section ABI (just as its neighbour is FFI). One of them there acronyms that's losts its meaning.

* [#[used]](used.md)
9 changes: 9 additions & 0 deletions src/abi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Application Binary Interface (ABI)

This section documents (or will document) features that affect the ABI of a Rust program / binary,
rlib, dylib, etc. A (likely incomplete) list of such features is shown below:

- #[used]
- #[no_mangle]
- #[link_section]
- extern "$ABI" fn
66 changes: 66 additions & 0 deletions src/used.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## #[used]

The #[used] attribute forces the *compiler* to keep a `static` variable in the output object file.
This is useful for placing data at specific memory locations: for example, placing the vector table
(interrupt table) in the memory location required by the ARM Cortex-M ABI: `0x0000_0000`.

It's important to note that, on its own, `#[used]` has no effect on the behavior of the *linker*.
That is the linker is free to drop a variable marked as `#[used]` when linking object files; thus,
*a `#[used]` variable may not necessarily make it into the final binary / executable*.

The guaranteed way to keep a variable in the final binary is to pair `#[used]` with the `EXTERN`
linker script command. Linkers are lazy: once they have found all the symbols needed by the first /
root object file they will stop looking at the other object files in their list of arguments.
`EXTERN` forces the linker to look into the other object files until it finds the `EXTERN`-ed
symbol.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this universal? Only for *nix? Is this concept also applicable to windows?


Below is an example that shows that both `#[used]` and `EXTERN` are required to keep `static`
variables in an executable.

``` rust
#![feature(panic_implementation)]
#![feature(used)]
#![no_main]
#![no_std]

use core::panic::PanicInfo;

// `#[no_mangle]` makes it easier to `EXTERN` this variable / symbol in the
// linker script
// `pub` is required to make this symbol *external*; the linker ignores
// *internal* symbols when looking for an `EXTERN`-ed symbol
#[no_mangle]
#[used]
pub static FOO: u32 = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am of the soft opinion that foo/bar/baz are subpar names to use in example code. I'd prefer descriptive names like: USED_AND_EXTERN, JUST_USED, TOTALLY_DEAD


// kept by the compiler, but dropped by the linker
#[used]
static BAR: u32 = 0;

// dropped by the compiler
#[allow(dead_code)]
static BAZ: u32 = 0;

#[panic_implementation]
fn panic(_: &PanicInfo) -> ! {
loop {}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This panic stuff seems like a big distraction, what's the deal? Just trying to make the smallest number of symbols possible? How bad is it if you don't do this?

```

``` console
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text should ideally say what this block is. Linux?

$ echo 'EXTERN(FOO);' > link.x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls comment this to explain what this is, something like "create a linker script for our EXTERN declarations".


$ rustc -O -C lto \
-C panic=abort -C relocation-model=static \
-C link-arg=-nostartfiles -C link-arg=-Wl,-Tlink.x \
--emit=link,obj \
foo.rs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To maximize readability can you make this one -C per line?


$ nm -C foo.o
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't expect a reader to have any idea what nm is, some exposition would be desirable.

0000000000000000 R FOO
0000000000000000 r foo::BAR

$ nm -C foo
0000000000000024 R FOO
0000000000000028 r _GLOBAL_OFFSET_TABLE_
```