]>
Commit | Line | Data |
---|---|---|
8bb4bdeb | 1 | # `lang_items` |
92a42be0 | 2 | |
8bb4bdeb | 3 | The tracking issue for this feature is: None. |
92a42be0 | 4 | |
8bb4bdeb | 5 | ------------------------ |
92a42be0 | 6 | |
8bb4bdeb XL |
7 | The `rustc` compiler has certain pluggable operations, that is, |
8 | functionality that isn't hard-coded into the language, but is | |
9 | implemented in libraries, with a special marker to tell the compiler | |
10 | it exists. The marker is the attribute `#[lang = "..."]` and there are | |
11 | various different values of `...`, i.e. various different 'lang | |
12 | items'. | |
13 | ||
14 | For example, `Box` pointers require two lang items, one for allocation | |
15 | and one for deallocation. A freestanding program that uses the `Box` | |
16 | sugar for dynamic allocations via `malloc` and `free`: | |
17 | ||
18 | ```rust,ignore | |
19 | #![feature(lang_items, box_syntax, start, libc, core_intrinsics)] | |
20 | #![no_std] | |
21 | use core::intrinsics; | |
22 | ||
23 | extern crate libc; | |
24 | ||
25 | #[lang = "owned_box"] | |
26 | pub struct Box<T>(*mut T); | |
27 | ||
28 | #[lang = "exchange_malloc"] | |
29 | unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { | |
30 | let p = libc::malloc(size as libc::size_t) as *mut u8; | |
31 | ||
32 | // Check if `malloc` failed: | |
33 | if p as usize == 0 { | |
34 | intrinsics::abort(); | |
35 | } | |
36 | ||
37 | p | |
38 | } | |
39 | ||
40 | #[lang = "exchange_free"] | |
41 | unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { | |
42 | libc::free(ptr as *mut libc::c_void) | |
43 | } | |
44 | ||
45 | #[lang = "box_free"] | |
46 | unsafe fn box_free<T: ?Sized>(ptr: *mut T) { | |
47 | deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr)); | |
48 | } | |
49 | ||
50 | #[start] | |
51 | fn main(argc: isize, argv: *const *const u8) -> isize { | |
52 | let x = box 1; | |
53 | ||
54 | 0 | |
55 | } | |
56 | ||
57 | #[lang = "eh_personality"] extern fn rust_eh_personality() {} | |
58 | #[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } } | |
59 | # #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} | |
60 | # #[no_mangle] pub extern fn rust_eh_register_frames () {} | |
61 | # #[no_mangle] pub extern fn rust_eh_unregister_frames () {} | |
62 | ``` | |
63 | ||
64 | Note the use of `abort`: the `exchange_malloc` lang item is assumed to | |
65 | return a valid pointer, and so needs to do the check internally. | |
66 | ||
67 | Other features provided by lang items include: | |
68 | ||
69 | - overloadable operators via traits: the traits corresponding to the | |
70 | `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all | |
71 | marked with lang items; those specific four are `eq`, `ord`, | |
72 | `deref`, and `add` respectively. | |
73 | - stack unwinding and general failure; the `eh_personality`, | |
74 | `eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items. | |
75 | - the traits in `std::marker` used to indicate types of | |
76 | various kinds; lang items `send`, `sync` and `copy`. | |
77 | - the marker types and variance indicators found in | |
78 | `std::marker`; lang items `covariant_type`, | |
79 | `contravariant_lifetime`, etc. | |
80 | ||
81 | Lang items are loaded lazily by the compiler; e.g. if one never uses | |
82 | `Box` then there is no need to define functions for `exchange_malloc` | |
83 | and `exchange_free`. `rustc` will emit an error when an item is needed | |
84 | but not found in the current crate or any that it depends on. | |
85 | ||
86 | Most lang items are defined by `libcore`, but if you're trying to build | |
87 | an executable without the standard library, you'll run into the need | |
88 | for lang items. The rest of this page focuses on this use-case, even though | |
89 | lang items are a bit broader than that. | |
3157f602 XL |
90 | |
91 | ### Using libc | |
92 | ||
8bb4bdeb XL |
93 | In order to build a `#[no_std]` executable we will need libc as a dependency. |
94 | We can specify this using our `Cargo.toml` file: | |
3157f602 XL |
95 | |
96 | ```toml | |
97 | [dependencies] | |
5bcae85e | 98 | libc = { version = "0.2.14", default-features = false } |
3157f602 XL |
99 | ``` |
100 | ||
101 | Note that the default features have been disabled. This is a critical step - | |
102 | **the default features of libc include the standard library and so must be | |
103 | disabled.** | |
104 | ||
105 | ### Writing an executable without stdlib | |
106 | ||
107 | Controlling the entry point is possible in two ways: the `#[start]` attribute, | |
108 | or overriding the default shim for the C `main` function with your own. | |
92a42be0 SL |
109 | |
110 | The function marked `#[start]` is passed the command line parameters | |
111 | in the same format as C: | |
112 | ||
5bcae85e | 113 | ```rust,ignore |
32a655c1 | 114 | #![feature(lang_items, core_intrinsics)] |
92a42be0 SL |
115 | #![feature(start)] |
116 | #![no_std] | |
32a655c1 | 117 | use core::intrinsics; |
92a42be0 | 118 | |
476ff2be | 119 | // Pull in the system libc library for what crt0.o likely requires. |
92a42be0 SL |
120 | extern crate libc; |
121 | ||
476ff2be | 122 | // Entry point for this program. |
92a42be0 SL |
123 | #[start] |
124 | fn start(_argc: isize, _argv: *const *const u8) -> isize { | |
125 | 0 | |
126 | } | |
127 | ||
5bcae85e | 128 | // These functions are used by the compiler, but not |
92a42be0 SL |
129 | // for a bare-bones hello world. These are normally |
130 | // provided by libstd. | |
5bcae85e SL |
131 | #[lang = "eh_personality"] |
132 | #[no_mangle] | |
9e0c209e SL |
133 | pub extern fn rust_eh_personality() { |
134 | } | |
135 | ||
136 | // This function may be needed based on the compilation target. | |
137 | #[lang = "eh_unwind_resume"] | |
138 | #[no_mangle] | |
139 | pub extern fn rust_eh_unwind_resume() { | |
5bcae85e SL |
140 | } |
141 | ||
142 | #[lang = "panic_fmt"] | |
143 | #[no_mangle] | |
144 | pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, | |
145 | _file: &'static str, | |
041b39d2 XL |
146 | _line: u32, |
147 | _column: u32) -> ! { | |
32a655c1 | 148 | unsafe { intrinsics::abort() } |
5bcae85e | 149 | } |
92a42be0 SL |
150 | ``` |
151 | ||
152 | To override the compiler-inserted `main` shim, one has to disable it | |
153 | with `#![no_main]` and then create the appropriate symbol with the | |
154 | correct ABI and the correct name, which requires overriding the | |
155 | compiler's name mangling too: | |
156 | ||
5bcae85e | 157 | ```rust,ignore |
32a655c1 | 158 | #![feature(lang_items, core_intrinsics)] |
92a42be0 SL |
159 | #![feature(start)] |
160 | #![no_std] | |
161 | #![no_main] | |
32a655c1 | 162 | use core::intrinsics; |
92a42be0 | 163 | |
476ff2be | 164 | // Pull in the system libc library for what crt0.o likely requires. |
92a42be0 SL |
165 | extern crate libc; |
166 | ||
476ff2be | 167 | // Entry point for this program. |
92a42be0 | 168 | #[no_mangle] // ensure that this symbol is called `main` in the output |
5bcae85e | 169 | pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 { |
92a42be0 SL |
170 | 0 |
171 | } | |
172 | ||
9e0c209e | 173 | // These functions are used by the compiler, but not |
5bcae85e SL |
174 | // for a bare-bones hello world. These are normally |
175 | // provided by libstd. | |
176 | #[lang = "eh_personality"] | |
177 | #[no_mangle] | |
9e0c209e SL |
178 | pub extern fn rust_eh_personality() { |
179 | } | |
180 | ||
181 | // This function may be needed based on the compilation target. | |
182 | #[lang = "eh_unwind_resume"] | |
183 | #[no_mangle] | |
184 | pub extern fn rust_eh_unwind_resume() { | |
5bcae85e SL |
185 | } |
186 | ||
187 | #[lang = "panic_fmt"] | |
188 | #[no_mangle] | |
189 | pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, | |
190 | _file: &'static str, | |
041b39d2 XL |
191 | _line: u32, |
192 | _column: u32) -> ! { | |
32a655c1 | 193 | unsafe { intrinsics::abort() } |
5bcae85e | 194 | } |
92a42be0 SL |
195 | ``` |
196 | ||
3b2f2976 XL |
197 | In many cases, you may need to manually link to the `compiler_builtins` crate |
198 | when building a `no_std` binary. You may observe this via linker error messages | |
199 | such as "```undefined reference to `__rust_probestack'```". Using this crate | |
200 | also requires enabling the library feature `compiler_builtins_lib`. You can read | |
201 | more about this [here][compiler-builtins-lib]. | |
202 | ||
203 | [compiler-builtins-lib]: library-features/compiler-builtins-lib.html | |
204 | ||
9e0c209e | 205 | ## More about the language items |
5bcae85e SL |
206 | |
207 | The compiler currently makes a few assumptions about symbols which are | |
208 | available in the executable to call. Normally these functions are provided by | |
209 | the standard library, but without it you must define your own. These symbols | |
210 | are called "language items", and they each have an internal name, and then a | |
211 | signature that an implementation must conform to. | |
92a42be0 | 212 | |
9e0c209e | 213 | The first of these functions, `rust_eh_personality`, is used by the failure |
7453a54e SL |
214 | mechanisms of the compiler. This is often mapped to GCC's personality function |
215 | (see the [libstd implementation][unwind] for more information), but crates | |
216 | which do not trigger a panic can be assured that this function is never | |
9e0c209e SL |
217 | called. The language item's name is `eh_personality`. |
218 | ||
3157f602 | 219 | [unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs |
5bcae85e | 220 | |
9e0c209e | 221 | The second function, `rust_begin_panic`, is also used by the failure mechanisms of the |
5bcae85e SL |
222 | compiler. When a panic happens, this controls the message that's displayed on |
223 | the screen. While the language item's name is `panic_fmt`, the symbol name is | |
224 | `rust_begin_panic`. | |
9e0c209e SL |
225 | |
226 | A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume` | |
227 | flag is set in the options of the compilation target. It allows customizing the | |
228 | process of resuming unwind at the end of the landing pads. The language item's name | |
229 | is `eh_unwind_resume`. | |
abe05a73 XL |
230 | |
231 | ## List of all language items | |
232 | ||
233 | This is a list of all language items in Rust along with where they are located in | |
234 | the source code. | |
235 | ||
236 | - Primitives | |
237 | - `i8`: `libcore/num/mod.rs` | |
238 | - `i16`: `libcore/num/mod.rs` | |
239 | - `i32`: `libcore/num/mod.rs` | |
240 | - `i64`: `libcore/num/mod.rs` | |
241 | - `i128`: `libcore/num/mod.rs` | |
242 | - `isize`: `libcore/num/mod.rs` | |
243 | - `u8`: `libcore/num/mod.rs` | |
244 | - `u16`: `libcore/num/mod.rs` | |
245 | - `u32`: `libcore/num/mod.rs` | |
246 | - `u64`: `libcore/num/mod.rs` | |
247 | - `u128`: `libcore/num/mod.rs` | |
248 | - `usize`: `libcore/num/mod.rs` | |
249 | - `f32`: `libstd/f32.rs` | |
250 | - `f64`: `libstd/f64.rs` | |
251 | - `char`: `libstd_unicode/char.rs` | |
252 | - `slice`: `liballoc/slice.rs` | |
253 | - `str`: `liballoc/str.rs` | |
254 | - `const_ptr`: `libcore/ptr.rs` | |
255 | - `mut_ptr`: `libcore/ptr.rs` | |
256 | - `unsafe_cell`: `libcore/cell.rs` | |
257 | - Runtime | |
258 | - `start`: `libstd/rt.rs` | |
259 | - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC) | |
260 | - `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU) | |
261 | - `eh_personality`: `libpanic_unwind/seh.rs` (SEH) | |
262 | - `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU) | |
263 | - `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC) | |
264 | - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH) | |
265 | - `panic`: `libcore/panicking.rs` | |
266 | - `panic_bounds_check`: `libcore/panicking.rs` | |
267 | - `panic_fmt`: `libcore/panicking.rs` | |
268 | - `panic_fmt`: `libstd/panicking.rs` | |
269 | - Allocations | |
270 | - `owned_box`: `liballoc/boxed.rs` | |
271 | - `exchange_malloc`: `liballoc/heap.rs` | |
272 | - `box_free`: `liballoc/heap.rs` | |
273 | - Operands | |
274 | - `not`: `libcore/ops/bit.rs` | |
275 | - `bitand`: `libcore/ops/bit.rs` | |
276 | - `bitor`: `libcore/ops/bit.rs` | |
277 | - `bitxor`: `libcore/ops/bit.rs` | |
278 | - `shl`: `libcore/ops/bit.rs` | |
279 | - `shr`: `libcore/ops/bit.rs` | |
280 | - `bitand_assign`: `libcore/ops/bit.rs` | |
281 | - `bitor_assign`: `libcore/ops/bit.rs` | |
282 | - `bitxor_assign`: `libcore/ops/bit.rs` | |
283 | - `shl_assign`: `libcore/ops/bit.rs` | |
284 | - `shr_assign`: `libcore/ops/bit.rs` | |
285 | - `deref`: `libcore/ops/deref.rs` | |
286 | - `deref_mut`: `libcore/ops/deref.rs` | |
287 | - `index`: `libcore/ops/index.rs` | |
288 | - `index_mut`: `libcore/ops/index.rs` | |
289 | - `add`: `libcore/ops/arith.rs` | |
290 | - `sub`: `libcore/ops/arith.rs` | |
291 | - `mul`: `libcore/ops/arith.rs` | |
292 | - `div`: `libcore/ops/arith.rs` | |
293 | - `rem`: `libcore/ops/arith.rs` | |
294 | - `neg`: `libcore/ops/arith.rs` | |
295 | - `add_assign`: `libcore/ops/arith.rs` | |
296 | - `sub_assign`: `libcore/ops/arith.rs` | |
297 | - `mul_assign`: `libcore/ops/arith.rs` | |
298 | - `div_assign`: `libcore/ops/arith.rs` | |
299 | - `rem_assign`: `libcore/ops/arith.rs` | |
300 | - `eq`: `libcore/cmp.rs` | |
301 | - `ord`: `libcore/cmp.rs` | |
302 | - Functions | |
303 | - `fn`: `libcore/ops/function.rs` | |
304 | - `fn_mut`: `libcore/ops/function.rs` | |
305 | - `fn_once`: `libcore/ops/function.rs` | |
306 | - `generator_state`: `libcore/ops/generator.rs` | |
307 | - `generator`: `libcore/ops/generator.rs` | |
308 | - Other | |
309 | - `coerce_unsized`: `libcore/ops/unsize.rs` | |
310 | - `drop`: `libcore/ops/drop.rs` | |
311 | - `drop_in_place`: `libcore/ptr.rs` | |
312 | - `clone`: `libcore/clone.rs` | |
313 | - `copy`: `libcore/marker.rs` | |
314 | - `send`: `libcore/marker.rs` | |
315 | - `sized`: `libcore/marker.rs` | |
316 | - `unsize`: `libcore/marker.rs` | |
317 | - `sync`: `libcore/marker.rs` | |
318 | - `phantom_data`: `libcore/marker.rs` | |
319 | - `freeze`: `libcore/marker.rs` | |
320 | - `debug_trait`: `libcore/fmt/mod.rs` | |
321 | - `non_zero`: `libcore/nonzero.rs` |