-
Notifications
You must be signed in to change notification settings - Fork 271
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
document #[used] #74
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 {} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To maximize readability can you make this one |
||
|
||
$ nm -C foo.o | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't expect a reader to have any idea what |
||
0000000000000000 R FOO | ||
0000000000000000 r foo::BAR | ||
|
||
$ nm -C foo | ||
0000000000000024 R FOO | ||
0000000000000028 r _GLOBAL_OFFSET_TABLE_ | ||
``` |
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.
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.