diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index eb9e2b24ac9..f5dd92f5a3d 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -29,7 +29,12 @@ and will be able to understand most Rust code and write more complex programs. In a similar fashion to "Intermediate," this section is full of individual, deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on the most complex features, as well as some things that -are only available in upcoming versions of Rust. +chapters focus on the most complex features, -After reading "Advanced," you'll be a Rust expert! +

Unstable

+ +In a similar fashion to "Intermediate," this section is full of individual, +deep-dive chapters, which stand alone and can be read in any order. + +This chapter contains things that are only available on the nightly channel of +Rust. diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 70c74825a07..140086e32d0 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -36,6 +36,12 @@ * [FFI](ffi.md) * [Unsafe Code](unsafe.md) * [Advanced Macros](advanced-macros.md) +* [Unstable Rust](unstable.md) * [Compiler Plugins](plugins.md) + * [Inline Assembly](inline-assembly.md) + * [No stdlib](no-stdlib.md) + * [Intrinsics](intrinsics.md) + * [Lang items](lang-items.md) + * [Link args](link-args.md) * [Conclusion](conclusion.md) * [Glossary](glossary.md) diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md index 86279f7f1a1..fef458caaaf 100644 --- a/src/doc/trpl/advanced-macros.md +++ b/src/doc/trpl/advanced-macros.md @@ -206,8 +206,6 @@ the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton within Rust's macro system. ```rust -#![feature(trace_macros)] - macro_rules! bct { // cmd 0: d ... => ... (0, $($ps:tt),* ; $_d:tt) @@ -229,13 +227,6 @@ macro_rules! bct { ( $($ps:tt),* ; ) => (()); } - -fn main() { - trace_macros!(true); -# /* just check the definition - bct!(0, 0, 1, 1, 1 ; 1, 0, 1); -# */ -} ``` Exercise: use macros to reduce duplication in the above definition of the diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 695279e2d5b..3dff72b3794 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -366,31 +366,6 @@ A few examples of how this model can be used are: On OSX, frameworks behave with the same semantics as a dynamic library. -## The `link_args` attribute - -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. - # Unsafe blocks Some operations, like dereferencing unsafe pointers or calling functions that have been marked diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md new file mode 100644 index 00000000000..1a4592f980f --- /dev/null +++ b/src/doc/trpl/inline-assembly.md @@ -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. + diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md new file mode 100644 index 00000000000..25f7c544931 --- /dev/null +++ b/src/doc/trpl/intrinsics.md @@ -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(x: T) -> U; + + fn offset(dst: *const T, offset: isize) -> *const T; +} +``` + +As with any other FFI functions, these are always `unsafe` to call. + diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md new file mode 100644 index 00000000000..30ab59cc029 --- /dev/null +++ b/src/doc/trpl/lang-items.md @@ -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(*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. diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md new file mode 100644 index 00000000000..ee5159afb8e --- /dev/null +++ b/src/doc/trpl/link-args.md @@ -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. + diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md new file mode 100644 index 00000000000..539a0729ba3 --- /dev/null +++ b/src/doc/trpl/no-stdlib.md @@ -0,0 +1,168 @@ +% No stdlib + +By default, `std` is linked to every Rust crate. In some contexts, +this is undesirable, and can be avoided with the `#![no_std]` +attribute attached to the crate. + +```ignore +// a minimal library +#![crate_type="lib"] +#![feature(no_std)] +#![no_std] +# // fn main() {} tricked you, rustdoc! +``` + +Obviously there's more to life than just libraries: one can use +`#[no_std]` with an executable, controlling the entry point is +possible in two ways: the `#[start]` attribute, or overriding the +default shim for the C `main` function with your own. + +The function marked `#[start]` is passed the command line parameters +in the same format as C: + +``` +#![feature(lang_items, start, no_std)] +#![no_std] + +// Pull in the system libc library for what crt0.o likely requires +extern crate libc; + +// Entry point for this program +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +// These functions and traits are used by the compiler, but not +// for a bare-bones hello world. These are normally +// provided by libstd. +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + +To override the compiler-inserted `main` shim, one has to disable it +with `#![no_main]` and then create the appropriate symbol with the +correct ABI and the correct name, which requires overriding the +compiler's name mangling too: + +```ignore +#![feature(no_std)] +#![no_std] +#![no_main] +#![feature(lang_items, start)] + +extern crate libc; + +#[no_mangle] // ensure that this symbol is called `main` in the output +pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# // fn main() {} tricked you, rustdoc! +``` + + +The compiler currently makes a few assumptions about symbols which are available +in the executable to call. Normally these functions are provided by the standard +library, but without it you must define your own. + +The first of these three functions, `stack_exhausted`, is invoked whenever stack +overflow is detected. This function has a number of restrictions about how it +can be called and what it must do, but if the stack limit register is not being +maintained then a thread always has an "infinite stack" and this function +shouldn't get triggered. + +The second of these three functions, `eh_personality`, is used by the +failure mechanisms of the compiler. This is often mapped to GCC's +personality function (see the +[libstd implementation](../std/rt/unwind/index.html) for more +information), but crates which do not trigger a panic can be assured +that this function is never called. The final function, `panic_fmt`, is +also used by the failure mechanisms of the compiler. + +## Using libcore + +> **Note**: the core library's structure is unstable, and it is recommended to +> use the standard library instead wherever possible. + +With the above techniques, we've got a bare-metal executable running some Rust +code. There is a good deal of functionality provided by the standard library, +however, that is necessary to be productive in Rust. If the standard library is +not sufficient, then [libcore](../core/index.html) is designed to be used +instead. + +The core library has very few dependencies and is much more portable than the +standard library itself. Additionally, the core library has most of the +necessary functionality for writing idiomatic and effective Rust code. + +As an example, here is a program that will calculate the dot product of two +vectors provided from C, using idiomatic Rust practices. + +``` +#![feature(lang_items, start, no_std)] +#![no_std] + +# extern crate libc; +extern crate core; + +use core::prelude::*; + +use core::mem; + +#[no_mangle] +pub extern fn dot_product(a: *const u32, a_len: u32, + b: *const u32, b_len: u32) -> u32 { + use core::raw::Slice; + + // Convert the provided arrays into Rust slices. + // The core::raw module guarantees that the Slice + // structure has the same memory layout as a &[T] + // slice. + // + // This is an unsafe operation because the compiler + // cannot tell the pointers are valid. + let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { + mem::transmute(( + Slice { data: a, len: a_len as usize }, + Slice { data: b, len: b_len as usize }, + )) + }; + + // Iterate over the slices, collecting the result + let mut ret = 0; + for (i, j) in a_slice.iter().zip(b_slice.iter()) { + ret += (*i) * (*j); + } + return ret; +} + +#[lang = "panic_fmt"] +extern fn panic_fmt(args: &core::fmt::Arguments, + file: &str, + line: u32) -> ! { + loop {} +} + +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} +# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } +# fn main() {} +``` + +Note that there is one extra lang item here which differs from the examples +above, `panic_fmt`. This must be defined by consumers of libcore because the +core library declares panics, but it does not define it. The `panic_fmt` +lang item is this crate's definition of panic, and it must be guaranteed to +never return. + +As can be seen in this example, the core library is intended to provide the +power of Rust in all circumstances, regardless of platform requirements. Further +libraries, such as liballoc, add functionality to libcore which make other +platform-specific assumptions, but continue to be more portable than the +standard library itself. + diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index 33f0893466d..9eb22a7f698 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -1,29 +1,5 @@ % Compiler Plugins -
- -

-Warning: Plugins are an advanced, unstable feature! For many details, -the only available documentation is the libsyntax and librustc API docs, or even the source -code itself. These internal compiler APIs are also subject to change at any -time. -

- -

-For defining new syntax it is often much easier to use Rust's built-in macro system. -

- -

-The code in this document uses language features not covered in the Rust -Guide. See the Reference Manual for more -information. -

- -
- # Introduction `rustc` can load compiler plugins, which are user-provided libraries that diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md new file mode 100644 index 00000000000..bc337f30515 --- /dev/null +++ b/src/doc/trpl/tracing-macros.md @@ -0,0 +1,90 @@ +% Tracing Macros + +The `trace_macros` feature allows you to use a special feature: tracing macro +invocations. + +In the advanced macros chapter, we defined a `bct` macro: + +```rust +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} +``` + +This is pretty complex! we can see the output + + ```rust +#![feature(trace_macros)] + +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} + +fn main() { + trace_macros!(true); + + bct!(0, 0, 1, 1, 1 ; 1, 0, 1); +} + +This will print out a wall of text: + +```text +bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 } +bct! { 1 , 1 , 1 , 0 , 0 ; 1 } +bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 } +bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 } +bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 } +bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 } +bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 } +bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 } +bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 } +``` + +And eventually, error: + +```text +18:45 error: recursion limit reached while expanding the macro `bct` + => (bct!($($ps),*, 1, $p ; $($ds),*)); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +The `trace_macros!` call is what produces this output, showing how we match +each time. diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index dbf0cae6f4b..3ca3cfd0588 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -181,539 +181,3 @@ code: that clean-up is always run, even when the thread panics. - ensure that any data stored behind a raw pointer is destroyed at the appropriate time. - -As an example, we give a reimplementation of owned boxes by wrapping -`malloc` and `free`. Rust's move semantics and lifetimes mean this -reimplementation is as safe as the `Box` type. - -``` -# #![feature(libc)] -#![feature(unsafe_destructor)] - -extern crate libc; -use libc::{c_void, size_t, malloc, free}; -use std::mem; -use std::ptr; - -// Define a wrapper around the handle returned by the foreign code. -// Unique has the same semantics as Box -// -// NB: For simplicity and correctness, we require that T has kind Send -// (owned boxes relax this restriction). -pub struct Unique { - // It contains a single raw, mutable pointer to the object in question. - ptr: *mut T -} - -// Implement methods for creating and using the values in the box. - -impl Unique { - pub fn new(value: T) -> Unique { - unsafe { - let ptr = malloc(mem::size_of::() as size_t) as *mut T; - // we *need* valid pointer. - assert!(!ptr.is_null()); - // `*ptr` is uninitialized, and `*ptr = value` would - // attempt to destroy it `overwrite` moves a value into - // this memory without attempting to drop the original - // value. - ptr::write(&mut *ptr, value); - Unique{ptr: ptr} - } - } - - // the 'r lifetime results in the same semantics as `&*x` with - // Box - pub fn borrow<'r>(&'r self) -> &'r T { - // By construction, self.ptr is valid - unsafe { &*self.ptr } - } - - // the 'r lifetime results in the same semantics as `&mut *x` with - // Box - pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T { - unsafe { &mut *self.ptr } - } -} - -// A key ingredient for safety, we associate a destructor with -// Unique, making the struct manage the raw pointer: when the -// struct goes out of scope, it will automatically free the raw pointer. -// -// NB: This is an unsafe destructor; rustc will not normally allow -// destructors to be associated with parameterized types (due to -// historically failing to check them soundly). Note that the -// `#[unsafe_destructor]` feature gate is currently required to use -// unsafe destructors. -#[unsafe_destructor] -impl Drop for Unique { - fn drop(&mut self) { - unsafe { - // Copy the object out from the pointer onto the stack, - // where it is covered by normal Rust destructor semantics - // and cleans itself up, if necessary - ptr::read(self.ptr); - - // clean-up our allocation - free(self.ptr as *mut c_void) - } - } -} - -// A comparison between the built-in `Box` and this reimplementation -fn main() { - { - let mut x = Box::new(5); - *x = 10; - } // `x` is freed here - - { - let mut y = Unique::new(5); - *y.borrow_mut() = 10; - } // `y` is freed here -} -``` - -Notably, the only way to construct a `Unique` is via the `new` -function, and this function ensures that the internal pointer is valid -and hidden in the private field. The two `borrow` methods are safe -because the compiler statically guarantees that objects are never used -before creation or after destruction (unless you use some `unsafe` -code...). - -# 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. - -# Avoiding the standard library - -By default, `std` is linked to every Rust crate. In some contexts, -this is undesirable, and can be avoided with the `#![no_std]` -attribute attached to the crate. - -```ignore -// a minimal library -#![crate_type="lib"] -#![feature(no_std)] -#![no_std] -# // fn main() {} tricked you, rustdoc! -``` - -Obviously there's more to life than just libraries: one can use -`#[no_std]` with an executable, controlling the entry point is -possible in two ways: the `#[start]` attribute, or overriding the -default shim for the C `main` function with your own. - -The function marked `#[start]` is passed the command line parameters -in the same format as C: - -``` -# #![feature(libc)] -#![feature(lang_items, start, no_std)] -#![no_std] - -// Pull in the system libc library for what crt0.o likely requires -extern crate libc; - -// Entry point for this program -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} - -// These functions and traits are used by the compiler, but not -// for a bare-bones hello world. These are normally -// provided by libstd. -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - -To override the compiler-inserted `main` shim, one has to disable it -with `#![no_main]` and then create the appropriate symbol with the -correct ABI and the correct name, which requires overriding the -compiler's name mangling too: - -```ignore -# #![feature(libc)] -#![feature(no_std)] -#![no_std] -#![no_main] -#![feature(lang_items, start)] - -extern crate libc; - -#[no_mangle] // ensure that this symbol is called `main` in the output -pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { - 0 -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# // fn main() {} tricked you, rustdoc! -``` - - -The compiler currently makes a few assumptions about symbols which are available -in the executable to call. Normally these functions are provided by the standard -library, but without it you must define your own. - -The first of these three functions, `stack_exhausted`, is invoked whenever stack -overflow is detected. This function has a number of restrictions about how it -can be called and what it must do, but if the stack limit register is not being -maintained then a thread always has an "infinite stack" and this function -shouldn't get triggered. - -The second of these three functions, `eh_personality`, is used by the -failure mechanisms of the compiler. This is often mapped to GCC's -personality function (see the -[libstd implementation](../std/rt/unwind/index.html) for more -information), but crates which do not trigger a panic can be assured -that this function is never called. The final function, `panic_fmt`, is -also used by the failure mechanisms of the compiler. - -## Using libcore - -> **Note**: the core library's structure is unstable, and it is recommended to -> use the standard library instead wherever possible. - -With the above techniques, we've got a bare-metal executable running some Rust -code. There is a good deal of functionality provided by the standard library, -however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/index.html) is designed to be used -instead. - -The core library has very few dependencies and is much more portable than the -standard library itself. Additionally, the core library has most of the -necessary functionality for writing idiomatic and effective Rust code. - -As an example, here is a program that will calculate the dot product of two -vectors provided from C, using idiomatic Rust practices. - -``` -# #![feature(libc, core)] -#![feature(lang_items, start, no_std)] -#![no_std] - -# extern crate libc; -extern crate core; - -use core::prelude::*; - -use core::mem; - -#[no_mangle] -pub extern fn dot_product(a: *const u32, a_len: u32, - b: *const u32, b_len: u32) -> u32 { - use core::raw::Slice; - - // Convert the provided arrays into Rust slices. - // The core::raw module guarantees that the Slice - // structure has the same memory layout as a &[T] - // slice. - // - // This is an unsafe operation because the compiler - // cannot tell the pointers are valid. - let (a_slice, b_slice): (&[u32], &[u32]) = unsafe { - mem::transmute(( - Slice { data: a, len: a_len as usize }, - Slice { data: b, len: b_len as usize }, - )) - }; - - // Iterate over the slices, collecting the result - let mut ret = 0; - for (i, j) in a_slice.iter().zip(b_slice.iter()) { - ret += (*i) * (*j); - } - return ret; -} - -#[lang = "panic_fmt"] -extern fn panic_fmt(args: &core::fmt::Arguments, - file: &str, - line: u32) -> ! { - loop {} -} - -#[lang = "stack_exhausted"] extern fn stack_exhausted() {} -#[lang = "eh_personality"] extern fn eh_personality() {} -# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } -# fn main() {} -``` - -Note that there is one extra lang item here which differs from the examples -above, `panic_fmt`. This must be defined by consumers of libcore because the -core library declares panics, but it does not define it. The `panic_fmt` -lang item is this crate's definition of panic, and it must be guaranteed to -never return. - -As can be seen in this example, the core library is intended to provide the -power of Rust in all circumstances, regardless of platform requirements. Further -libraries, such as liballoc, add functionality to libcore which make other -platform-specific assumptions, but continue to be more portable than the -standard library itself. - -# Interacting with the compiler internals - -> **Note**: this section is specific to the `rustc` compiler; these -> parts of the language may never be fully specified and so details may -> differ wildly between implementations (and even versions of `rustc` -> itself). -> -> Furthermore, this is just an overview; the best form of -> documentation for specific instances of these features are their -> definitions and uses in `std`. - -The Rust language currently has two orthogonal mechanisms for allowing -libraries to interact directly with the compiler and vice versa: - -- intrinsics, functions built directly into the compiler providing - very basic low-level functionality, -- lang-items, special functions, types and traits in libraries marked - with specific `#[lang]` attributes - -## 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(x: T) -> U; - - fn offset(dst: *const T, offset: isize) -> *const T; -} -``` - -As with any other FFI functions, these are always `unsafe` to call. - -## 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(libc)] -#![feature(lang_items, box_syntax, start, no_std)] -#![no_std] - -extern crate libc; - -extern { - fn abort() -> !; -} - -#[lang = "owned_box"] -pub struct Box(*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.