-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New section of the book: nightly rust
Now that feature flags are only on nightly, it's good to split this stuff out.
- Loading branch information
1 parent
1501f33
commit c153fc1
Showing
12 changed files
with
542 additions
and
597 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
% Inline Assembly | ||
|
||
For extremely low-level manipulations and performance reasons, one | ||
might wish to control the CPU directly. Rust supports using inline | ||
assembly to do this via the `asm!` macro. The syntax roughly matches | ||
that of GCC & Clang: | ||
|
||
```ignore | ||
asm!(assembly template | ||
: output operands | ||
: input operands | ||
: clobbers | ||
: options | ||
); | ||
``` | ||
|
||
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the | ||
crate to allow) and of course requires an `unsafe` block. | ||
|
||
> **Note**: the examples here are given in x86/x86-64 assembly, but | ||
> all platforms are supported. | ||
## Assembly template | ||
|
||
The `assembly template` is the only required parameter and must be a | ||
literal string (i.e. `""`) | ||
|
||
``` | ||
#![feature(asm)] | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
fn foo() { | ||
unsafe { | ||
asm!("NOP"); | ||
} | ||
} | ||
// other platforms | ||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] | ||
fn foo() { /* ... */ } | ||
fn main() { | ||
// ... | ||
foo(); | ||
// ... | ||
} | ||
``` | ||
|
||
(The `feature(asm)` and `#[cfg]`s are omitted from now on.) | ||
|
||
Output operands, input operands, clobbers and options are all optional | ||
but you must add the right number of `:` if you skip them: | ||
|
||
``` | ||
# #![feature(asm)] | ||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
# fn main() { unsafe { | ||
asm!("xor %eax, %eax" | ||
: | ||
: | ||
: "eax" | ||
); | ||
# } } | ||
``` | ||
|
||
Whitespace also doesn't matter: | ||
|
||
``` | ||
# #![feature(asm)] | ||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
# fn main() { unsafe { | ||
asm!("xor %eax, %eax" ::: "eax"); | ||
# } } | ||
``` | ||
|
||
## Operands | ||
|
||
Input and output operands follow the same format: `: | ||
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand | ||
expressions must be mutable lvalues: | ||
|
||
``` | ||
# #![feature(asm)] | ||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
fn add(a: i32, b: i32) -> i32 { | ||
let mut c = 0; | ||
unsafe { | ||
asm!("add $2, $0" | ||
: "=r"(c) | ||
: "0"(a), "r"(b) | ||
); | ||
} | ||
c | ||
} | ||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] | ||
# fn add(a: i32, b: i32) -> i32 { a + b } | ||
fn main() { | ||
assert_eq!(add(3, 14159), 14162) | ||
} | ||
``` | ||
|
||
## Clobbers | ||
|
||
Some instructions modify registers which might otherwise have held | ||
different values so we use the clobbers list to indicate to the | ||
compiler not to assume any values loaded into those registers will | ||
stay valid. | ||
|
||
``` | ||
# #![feature(asm)] | ||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
# fn main() { unsafe { | ||
// Put the value 0x200 in eax | ||
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); | ||
# } } | ||
``` | ||
|
||
Input and output registers need not be listed since that information | ||
is already communicated by the given constraints. Otherwise, any other | ||
registers used either implicitly or explicitly should be listed. | ||
|
||
If the assembly changes the condition code register `cc` should be | ||
specified as one of the clobbers. Similarly, if the assembly modifies | ||
memory, `memory` should also be specified. | ||
|
||
## Options | ||
|
||
The last section, `options` is specific to Rust. The format is comma | ||
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to | ||
specify some extra info about the inline assembly: | ||
|
||
Current valid options are: | ||
|
||
1. *volatile* - specifying this is analogous to | ||
`__asm__ __volatile__ (...)` in gcc/clang. | ||
2. *alignstack* - certain instructions expect the stack to be | ||
aligned a certain way (i.e. SSE) and specifying this indicates to | ||
the compiler to insert its usual stack alignment code | ||
3. *intel* - use intel syntax instead of the default AT&T. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
% Intrinsics | ||
|
||
> **Note**: intrinsics will forever have an unstable interface, it is | ||
> recommended to use the stable interfaces of libcore rather than intrinsics | ||
> directly. | ||
These are imported as if they were FFI functions, with the special | ||
`rust-intrinsic` ABI. For example, if one was in a freestanding | ||
context, but wished to be able to `transmute` between types, and | ||
perform efficient pointer arithmetic, one would import those functions | ||
via a declaration like | ||
|
||
``` | ||
# #![feature(intrinsics)] | ||
# fn main() {} | ||
extern "rust-intrinsic" { | ||
fn transmute<T, U>(x: T) -> U; | ||
fn offset<T>(dst: *const T, offset: isize) -> *const T; | ||
} | ||
``` | ||
|
||
As with any other FFI functions, these are always `unsafe` to call. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
% Lang items | ||
|
||
> **Note**: lang items are often provided by crates in the Rust distribution, | ||
> and lang items themselves have an unstable interface. It is recommended to use | ||
> officially distributed crates instead of defining your own lang items. | ||
The `rustc` compiler has certain pluggable operations, that is, | ||
functionality that isn't hard-coded into the language, but is | ||
implemented in libraries, with a special marker to tell the compiler | ||
it exists. The marker is the attribute `#[lang="..."]` and there are | ||
various different values of `...`, i.e. various different 'lang | ||
items'. | ||
|
||
For example, `Box` pointers require two lang items, one for allocation | ||
and one for deallocation. A freestanding program that uses the `Box` | ||
sugar for dynamic allocations via `malloc` and `free`: | ||
|
||
``` | ||
#![feature(lang_items, box_syntax, start, no_std)] | ||
#![no_std] | ||
extern crate libc; | ||
extern { | ||
fn abort() -> !; | ||
} | ||
#[lang = "owned_box"] | ||
pub struct Box<T>(*mut T); | ||
#[lang="exchange_malloc"] | ||
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { | ||
let p = libc::malloc(size as libc::size_t) as *mut u8; | ||
// malloc failed | ||
if p as usize == 0 { | ||
abort(); | ||
} | ||
p | ||
} | ||
#[lang="exchange_free"] | ||
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { | ||
libc::free(ptr as *mut libc::c_void) | ||
} | ||
#[start] | ||
fn main(argc: isize, argv: *const *const u8) -> isize { | ||
let x = box 1; | ||
0 | ||
} | ||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {} | ||
#[lang = "eh_personality"] extern fn eh_personality() {} | ||
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } | ||
``` | ||
|
||
Note the use of `abort`: the `exchange_malloc` lang item is assumed to | ||
return a valid pointer, and so needs to do the check internally. | ||
|
||
Other features provided by lang items include: | ||
|
||
- overloadable operators via traits: the traits corresponding to the | ||
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all | ||
marked with lang items; those specific four are `eq`, `ord`, | ||
`deref`, and `add` respectively. | ||
- stack unwinding and general failure; the `eh_personality`, `fail` | ||
and `fail_bounds_checks` lang items. | ||
- the traits in `std::marker` used to indicate types of | ||
various kinds; lang items `send`, `sync` and `copy`. | ||
- the marker types and variance indicators found in | ||
`std::marker`; lang items `covariant_type`, | ||
`contravariant_lifetime`, etc. | ||
|
||
Lang items are loaded lazily by the compiler; e.g. if one never uses | ||
`Box` then there is no need to define functions for `exchange_malloc` | ||
and `exchange_free`. `rustc` will emit an error when an item is needed | ||
but not found in the current crate or any that it depends on. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
% Link args | ||
|
||
There is one other way to tell rustc how to customize linking, and that is via | ||
the `link_args` attribute. This attribute is applied to `extern` blocks and | ||
specifies raw flags which need to get passed to the linker when producing an | ||
artifact. An example usage would be: | ||
|
||
``` no_run | ||
#![feature(link_args)] | ||
#[link_args = "-foo -bar -baz"] | ||
extern {} | ||
# fn main() {} | ||
``` | ||
|
||
Note that this feature is currently hidden behind the `feature(link_args)` gate | ||
because this is not a sanctioned way of performing linking. Right now rustc | ||
shells out to the system linker, so it makes sense to provide extra command line | ||
arguments, but this will not always be the case. In the future rustc may use | ||
LLVM directly to link native libraries in which case `link_args` will have no | ||
meaning. | ||
|
||
It is highly recommended to *not* use this attribute, and rather use the more | ||
formal `#[link(...)]` attribute on `extern` blocks instead. | ||
|
Oops, something went wrong.