# LCRust ABI, Version 0 ## Preamble This document is a normative specification of version 0 of the lcrust ABI. This is not an abi defined by the rust lang team, and should not be considered portable to all rust implementations. For all purposes, you can rely on this ABI or a future version when compiling using lccc. Other implementations of rust may adopt this specification as well, at their option. This document is intended to mirror guarantees provided by the rust language team, and the Unsafe Coding Guidelines, in terms of abi. If a difference is observed, then for all purposes, this specification will override both the language team and the Unsafe Coding Guidelines while the particular version is in use, and a new version will be prepared and released with the correct ABI as required by both sources. * A minor change to the requirements of the Unsafe Coding Guidelines may not warrant an update to this abi, however a change adopted by the language team of rust will always result in an update. As the layout and abi of scalar types, types with the `repr(C)` layout, and types with the `repr(transparent)` layout are well defined, none of those types are documened here. ## Crate ABI Selection 1. An implementation shall support this version and any other implementation-defined versions. 2. An implementation should provide a mechanism to select it between the in-use version. 3. An implementation may use an implementation-defined version for proc-macro crates, and for the proc_macro standard library, even if a selection mechanism used above would select a different version. ### lccc _This section is not normative_ When building a crate, you can pass `-Zbuild-abi=0` (or `-frustc-abi=0`) to force lccc to build against abi version 0. This requires the standard library to be built with abi version 0. To detect incompatibilities from version 0 to the latest version, `-W abi-incompatibility=0` (or `-D abi-incompatibility=0` for deny) or `-Wabi-incompatibility=0` (or `-Werror=abi-incompatibility=0`) can be passed, or `#[warn(lccc::abi_incompatibility_0)]` (`#[deny]` likewise). To detect incompatibilities with prescribed layout and abi requirements with those included in this specification, `-W lang-abi-incompatibility` or `-Wlang-abi-incompatibility` may be used. This is enabled by default when `-Wabi-incompatibility` is used. It is an error to depend upon an rlib or dylib crate built with a different abi version. The implementation shall issue a diagnostic if such is requested. When linking against a `staticlib` crate built with a different abi version, other than a `#![no_std]` crate that does not contain an `extern crate` declaration naming `std`, the behaviour is undefined if either crate dynamic links against `std`. When linking a single crate with multiple source files, the behaviour is undefined if the source files were built with a different abi. A crate may opt-out of the abi guarantees herein by passing `-Z repr-rust-layout=randomize`or `-frust-struct-layout=randomize` to the compiler command line. When building a proc-macro crate, all functions declared `#[proc_macro]`, `#[proc_macro_derive]`, and `#[proc_macro_attribute]` will use the function call ABI of the latest implemented version (otherwise the abi will follow the selected version). ## Type Layout In this section, if a type is said to have the same layout as some other type, unless otherwise stated, it also has the same ABI as that type for the `extern"C"`, `extern"Rust"`, `extern"cdecl"`, `extern"stdcall"`, `extern"fastcall`, `extern"thiscall"`, `extern"vectorcall"`, `extern"win64"`, `extern"sysv64"`, and `extern"aapcs"` abis. If an implementation defines other platform-specific or unstable abis, whether or not types explicitly defined to have the same layout herein also have the same ABI for those abis is unspecified. ### `!` The type `!` shall have the same layout and ABI as `()`. A function returning `!` shall have the same abi as a `_Noreturn` function declared in C with a return type of `void`. ### repr(Rust) Structures The layout of a repr(Rust) structure shall be as follows: * Each field shall be sorted in descending order by the required alignment of the fields type. Fields with the same alignment requirement shall not be reordered relative to other such fields * After Sorting, the structure shall be layed out according to the equivalent definition of a C++ structure with the same fields in the sorted order with the same access specifier. * If the type is a unit struct, or a struct with no members other than ZSTs, then the type shall instead be layed out with a size of 0, but shall have the alignment it would have had according to the above definition. * For tuple structs, it shall be treated as if the same as an equivalent struct declaration where each field has an unspecified name. * Fields that have a type for which the alignment requirement depends on the instantiation of a generic parameter shall be treated as though it has the maximum fundamental alignment for the purposes of ordering fields as above * If a field's type, but not it's alignment requirement, depends on the instantiation of a generic parameter, then the guaranteed alignment of the field is used instead of the maximum fundamental alignment (For example, `PhantomData<T>`, where T is a generic parameter, uses alignment 1, but `[T;0]` uses alignment 16 on x86_64 when ordering members). * If the alignment requirement of a field that depends on a generic parameter has an upper bound determined by a `where` clause, that is less than the maximum fundamental alignment, that maximum alignment requirement is used for ordering instead of the maximum fundamental alignment. * For example, the `U` in `pub struct Foo<U>(U,u64,u8) where [();{4-core::mem::align_of::<U>()}]:` uses alignment 4 for field ordering purposes. * A field of a potentially unsized type (IE. `T: ?Sized`, or `[u8]`), shall be placed at the end of the structure, reguardless of the alignment requirement. * A field of a potentially unsized type shall not be reordered relative to any other field in the structure. ### repr(Rust) Unions A union declared `repr(Rust)` shall be equivalent to a union declared `repr(C)`. [Note: This implies that each field of a `repr(Rust)` union starts at offset 0.] ### repr(Rust) enums * An repr(Rust) enum declared with two variants, with at least one unit variant or a variant for which the Variant type of has size 0 and alignment 1 and the other variant is not a unit variant or a variant type does not have size 0 and alignment 1, and where the variant type of the other variant has at least one niche, shall be layed out as the the variant type below for the non-unit variant, but where a niche is removed and reserved for the unit or 1-ZST variant. * `char`, the discriminant type of an enum, `bool`, and any other type shall have a niches starting after it's maximum value and proceeding to the highest possible value for a type of the size. These niches shall be removed starting with the lowest niche value going to the highest. * The maximum value of `char` is 0xffffff, and the maximum value of `bool` is 1. The maximum value of the discriminant type of an enum is the largest discriminant assigned, implicitly or explicitly. * A reference type, `core::ptr::NonNull<T>`, `alloc::boxed::Box<T>`, `core::num::NonZeroU*`, and `core::num::NonZeroI*` shall all have exactly one niche with the bit pattern zero [Note: The alignment of references or Box is not used as a niche] * The `!` type shall have exactly one niche. `Option<!>` shall have the same layout as `()`. * An `UnsafeCell<T>` shall have no niches (reguardless of `T`). * An enum type shall have the same niches as it's discriminant type. * A union type shall have no niches * An aggregate type shall have niches for each of it's fields that have niches, which shall be filled in declaration order. * If an enum has two variants, both which have variant types that have size 0 and alignment 1, and exactly one of those variant types has a niche, the then enum type shall have the same layout as the other variant * If a enum has two variants, both of which are variants that have a variant field type (see below) that has size 0 and alignment 1, and both variant fields have at least one niche, then the enum type is uninhabited and shall have the same layout as `!`. * Otherwise, the discriminant field of the enum is determined as follows, which shall be designated `D`: * If the enum has no variants, the discriminant field has type `!`. * If an enum has exactly one variant, then the discriminant field has type `()`. * If the enum has exactly two variants, and neither variant has a user-provided discriminant values, then the discriminant field has type `bool`. * Otherwise, if all discriminant values are values of type `u8`, then the discriminant field has type `u8`. * Otherwise, if all discriminant values are values of type `i8`, then the discriminant field has type `i8` * Otherwise, if all discriminant values are values of type `u16`, then the discriminant field has type `u16`. * Otherwise, if all discriminant values are values of type `i16`, then the discriminant field has type `i16` * Otherwise, if all discriminant values are values of type `u32`, then the discriminant field has type `u32`. * Otherwise, if all discriminant values are values of type `i32`, then the discriminant field has type `i32` * Otherwise, if all discriminant values are values of type `u64`, then the discriminant field has type `u64`, * Otherwise, if all discriminant values are values of type `i64`, then the discriminant field has type `i64` * Otherwise, if all discriminant values are values of type `u128`, then the discriminant field has type `u128`, * Otherwise, if all discriminant values are values of type `i128`, then the discriminant field has type `i128` * Otherwise, this abi does not specify the type of the discriminant field. * The type of the variant field is determined as follows, which shall be designated as `V`: * If the variant is a unit variant, then there is no variant field. * If the variant is a tuple variant, and has exactly one field, then the variant field is of that type * Otherwise, the variant field is of an exposition-only structure type declared `#[repr(Rust)]` and that same declaration as the variant's declaration * Let the aggregate type, designated `A<Variant>`, of a variant be the following *exposition-only* declaration `#[repr(C)] struct /*variant*/(D,V);` (where `V` is not included if there is not variant field). The layout of a `repr(Rust)` enum declared as `#[repr(Rust)] enum Enum{Variant...}` is the union declaration `#[repr(Rust)] union Enum{(Variant: A<Variant>)...}`. * An enum with only unit variants has the same layout as `D` * For the purposes of the above, the type of the discriminant field of a `repr(C)` enum is implementation-defined, and the type of the discriminant field for a `repr(un)` or `repr(in)` enum is *u*n or *i*n. ### DST Pointer Layout * The layout of any pointer to a slice is given by the following *exposition-only* declaration: `#[repr(Rust)] struct Slice<T>{data: *mut T,len: usize}`. * The layout of a pointer to `dyn Trait + Marker`, where `Marker` consists of only auto traits, `?Sized`, and lifetime bounds, shall be given by the following *exposition-only* declaration: `#[repr(Rust)] struct TraitObject{data: *mut (),vtable: *mut ()}` * The layout of pointers `dyn A+B` where neither A nor B are marker traits, is not specified by version 0 of the abi. * The layout of pointers to structures with trailing unsized fields are the same as the layout of pointers to the trailing unsized field, except that the "data" pointer in all cases points to the structure, rather than the trailing field. #### Trait Object Vtable Layout The `vtable` of any trait object has the following layout: * Let `SingleTraitVtable` denote the following *exposition-only* struct declaration: `#[repr(C)] struct SingleTraitVtable{pub size: usize, pub align: usize, pub dtor: Option<fn(*mut ())>, pub reserved_dealloc: Option<fn(*mut ())>,pub vfns: ...}` * The layout of the vtable of a trait with no supertraits is exactly `SingleTraitVtable` where each `vfn` points to the implementation of the corresponding dyn-reciever function not bound by `Sized` in declaration order * The layout of a vtable of a trait with only one supertrait is the layout of the vtable of it's supertrait, appending the corresponding list of dyn-reciever functions not bound by `Sized` in declaration order [Note: This allows the supertrait vtable can be accessed by using a prefix of the subtrait vtable]. * The layout of a vtable of a trait with two or more supertraits is obtained by concatenating the vtables of each supertrait from Left to Right, then appending the corresponding list of dyn-reciever functions not bound by `Sized` in declaration order * [Note: This allows a supertrait vtable to be accessed using some subrange of the subtrait vtable]. * [Note: the prefix information in `SingleTraitVtable` will be duplicated for each direct supertrait] * The exposition only type `VTable<T>`, used by this abi, denotes the vtable of `T` if `T` is `dyn Trait` or `dyn Trait+Tail` where `Tail` consists only of marker traits and lifetimes. ##### Trait Object Vtable Definition The VTable for a trait impl of an object-safe trait shall be emitted as follows: * If the trait implementation is not generic, then the vtable shall be emitted in the translation unit that defines the implementation. * Otherwise, the vtable shall be emitted in each translation unit that performs an unsize coercion from that trait implementation. During linking, all such vtables shall be merged into a single vtable instance within a discrete linkable target (top-level executable or dylib). * If a VTable that contains a pointer to another VTable which requires the instantiation of a generic vtable, then any translation unit that emits the first vtable shall also emit the second vtable, as above. The Creation of the vtable of a type shall ODR use it's destructor, even if that destructor is trivial. A trait impl for an unsized type does not generate vtables, including for non-generic trait impls. The name of a vtable for a trait impl is given in [Name Mangling](#Name-Mangling) ### Tuple Layout * The unit tuple shall have size 0 and alignment 1. * A function returning `()` shall have the same abi as a function declared in C returning `void` * In all other positions, `()` shall have the same abi as the structure declaration `#[repr(Rust]] struct Unit();`. * [Note: In particular, on C ABIs that differentiate between different pointer types, `*mut ()` has pointer-to-struct ABI] * The 1-tuple `(T,)` is layed out identically to `T` * The *n*-tuple `(T1,T2,...Tn)`, for n>1, is layed out the same as the structure declaration `#[repr(Rust)] struct Tuple(T1,T2,...,Tn);` ### char type * The `char` type shall be compatible with the underlying type of `char32_t` under the C++ Standard if the implementation supports translating C++ programs and linking rust code into C++ programs, otherwise the it shall be compatible with the integer type which `char32_t` is defined as under the C Standard. ### Closure Type Layout * The layout of an fn-item type and a non-capturing closure is the same as `()`. * The layout of a closure with *n* captures is the same as the tuple type `(T1,...,Tn)`, where `T`*`k`* is given as follows for 1<=k<=n * Captures are ordered according to the declaration order of the captured entities in the context that declares the closure * For partially-captured values, the partial-captures of a particular aggregate value are ordered according to the declaration order in that aggregate type. * If the *k*th tuple is a by-reference capture of a value of type `U`, then the type `T`*`k`* is `&U` * If the *k*th tuple is a by-mutable reference capture of a value of type `U`, then the type `T`*`k`* is `&mut U` * If the *k*th tuple is a by-move or by-copy capture of a value of type `U`, then the type `T`*`k`* is `U` * A capture of a type that is at most the same size of a pointer, which implements Copy and which is neither borrowed nor mutated by the body of the closure is captured by-copy por the purposes of ABI, even if the closure would otherwise capture it by-reference. [ Note: Given the following code snipet ```rust= let x = 5; let y = String::new(); let mut z = Box::new(1337); let mut c = ||{ *z = 42; println!("{}: {}",{x},y); }; ``` The captures of c have types i32, &String, and `&mut Box<i32>`, respectively. ] ### DST by-value parameters A parameter that has a `!Sized` type shall be passed as an invisible pointer to the parameter. The pointer has the layout and ABI defined in [DST Pointer Layout](#DST-Pointer-Layout). ## Standard Library Type, Guaranteed Layouts The standard library implementation shall guarantee layout and abi compatibility of all of the following groups of types: * `Box<T,Global>`, `NonNull<T>`, `Option<Box<T,Global>>`, and `*mut T` * `alloc::vec::Vec<u8>`, `alloc::string::String`, `std::os::OsString`, `std::path::PathBuf`, `std::ffi::CString`, and a struct given by the following definition: `#[repr(Rust)] struct RawVec(NonNull<u8>,usize,usize)`. * `[u8]`, `str`, `std::ffi::CStr`, `std::os::OsStr`, and `std::path::Path`, as well as pointers to any such type. * `std::mem::ManuallyDrop<T>`, `std::mem::MaybeUninit<T>`, and `T`. * `std::ptr::DynMetadata<T>` and `&'static VTable<T>`, if `T` is `dyn Trait` or `dyn Trait+Tail`, where `Tail` consists only of marker traits and lifetimes. * The reference in this section may be validly dereference to a value of type `VTable<T>` * The ABI of `std::ptr::DynMetadata<T>` for any other such type `T` is unspecified. The Standard library implemention shall guarantee layout, but not necessarily ABI, compatibility of all of the following groups of types: * `Box<T,A>` and `Box<T,B>` such that `A` and `B`are both `1-ZST`s * `alloc::vec::Vec<u8,A>`, `alloc::string::String<A>`, `std::os::OsString<A>`, `std::path::PathBuf<A>`, and `std::ffi::CString<A>` where the implementations supports allocator_api for such types. * `Box<T,A>` and `Option<Box<T,A>>` * Where `E` is an enum, `std::mem::Discrimintant<E>` and `D<E>`, where `D<E>` is the type of the discriminant field for `E` The layouts of the following standard library structures are restricted to the following: * `TypeId` shall have the same layout as the tuple `(*const u8,usize)`. The first field shall be a pointer to a Null Termianted Multibyte String (NTMBS) encoded in UTF-8 which shall a pointer to the external-name of the type. The second field shall be an FNV-1a hash of that NTMBS, excluding the nul terminator byte. The size of the hash shall be smallest supported hash size that is at least the number of significant bits of `usize` (which shall be taken modulo `usize::MAX+1` if this size is not exactly that number of bits) * The trait `Any` shall have exactly 1 virtual function slot, with the signature `extern"Rust" fn(&self)->TypeId`, and no other virtual function slots. * The `Location` struct shall have the same layout as the following structure: ```rust= #[repr(Rust)] pub struct Location<'a>{ file: &'a str, line: u32, col: u32 }; ``` Beyond these rules, implementations SHOULD ensure that when breaking abi changes occur in the standard library, an error is issued when linking an rlib or dylib target built against an earlier abi version of the standard library. There are no further restrictions on the layout or ABI of types in the standard library ## Function ABI Parameters that have size 0 are ignored for the purposes of function call ABI. Return values that have size 0 shall be equivalent to a function returning `void` declared in C. `extern"Rust"` is treated identically to `extern"C"`, except as follows: * If the function has the `#[track_caller]` attribute, a pointer to the caller Location is passed as the last parameter. * This invisible parameter is not mangled * On Windows or PhantomOS, targetting i386, `extern"fastcall"` ABI is used instead of `extern"cdecl"` (which is the platform default for `extern"C"`) The `extern"rust-call"` abi is defined as follows: * An `extern"rust-call"` function with a single parameter of a tuple type has the abi equivalent to the `extern"Rust"` function with each parameter in order being the fields of the tuple. * An `extern"rust-call"` function with two parameters, where the second parameter has a tuple type has the abi equivalent to the `extern"Rust"` function with the first parameter preserved as-is, and the remaining parameters being the fields of the tuple in order. * The abi of an `extern"rust-call"` function with any other signature is not specified. There shall be a function declared with external linkage, which is the mangled form of the function `core::intrinsics::caller_location()` (Mangled as `_ZNSt10intrinsics15caller_locationEv`), which shall have the signature `extern"Rust" fn()->&'static Location<'static>` and which shall be defined as though with the `#[track_caller]` attribute. * [Note: Whether or not a call to `core::intrinsics::caller_location()` emits a call to this external symbol is unspecified] There shall additionally be a function declared with extern linkage, which is the mangled form of `core::panicking::panic_any(&dyn Any)->!` (Manged as `_ZNST9panicking9panic_anyERKu3dynI_ZNSt3any3AnyEE`). This function shall perform the steps indicated under the section entitled "panicking". ## Name Mangling The LCRust ABI uses itanium mangling for names. The first component of the mangled name is the crate name, optionally with a trailing disambiguator, which is implementation-defined, except that none of the`core`, `std`, `alloc`, or `proc_macro` crates shall have a trailing disambiguator. It is extended as follows: * Each fixed size integer type `iN` or `uN` is mangled shall be mangled identically to the mangling of the type `uintN_t` or `intN_t`, respectively * `isize` and `usize` shall be mangled identically to the mangling of the type `intptr_t` or `uintptr_t` respectively. * `f32` shall be mangled as `f` and `f64` shall be mangled as `d` * The unit type is mangled as the vendor-extended type `u4unit`, except that it is mangled as `v` when appearing unmodified in the return type position * Tuple types are mangled as `u5tuple`, with each template argument being the element type of the tuple * Slice types are mangled as `u5slice`, with exactly one template argument being the element type of the slice * The `str` type is mangled as `u5sliceIDuE` (IE. `[char8_t]`) * `dyn Trait+Tail`, where `Tail` consists of only marker traits and lifetime bounds is mangled as `u3dynI<TraitName><TailNames>`. * When mangling a lifetime, it shall be mangled as a generic parameter when bound, otherwise, it shall be mangled as `u4life` * A reference with a bound lifetime shall be mangled as the vendor-extended qualifier `U4life`, with a template arguement being the bound lifetime. * A HRTB type, shall be mangled with the vendor-extended qualifier `U<n>decl<number>`, where `<number>` is the number of declared generic parameters. `<n>` is the total length of the qualifier, including `<number>`. * For example, a type that includes 1 declared generic parameter, would mangle that as `U5decl1` * A fn-ptr type shall be mangled as a pointer to the function type * An fn-ptr type declared with any abi other than `extern"Rust"`, `extern"rust-call"`, or `extern"rust-intrinsic"` shall include the Y prefix. If the ABI is not `extern"C"` or `extern"Rust"` it shall be incldued in a vendor extended qualifier by that name, replacing any character that is not an alphanumeric character with `_`. * `extern"rust-call"` shall be mangled as the qualifier `U9rust_call` without the `Y` prefix. `extern"rust-intrinsic"` shall be mangled as the qualifier `U14rust_intrinsic` without the `Y` prefix * An fn-item type shall be mangled as `DtL_Z<encoding for fn>EE` * When mangling `impl Trait` in the return position, it shall be mangled as `Da`. * The path for the core, alloc, or std crates in the standard library shall be std (substituted as St). * The mangling of a trait impl item shall be that of `TraitName::$impl`, with the first template parameter being the type the trait is implemented for, and the remaining parameters being the type parameters of the trait impl. * The mangling of a VTable shall be as follows shall be the vtable name for the above type. ### Unnamed Bindings A const or static with the name `_` is an unnamed binding. The name of such an item is as follows: &lt;unnamed-binding-name&gt; := .Uv_ &lt;unnamed-binding-name&gt; := .Uv&lt;__seq-id__&gt;_ &lt;unqualified-name&gt; := &lt;__unnamed-binding-name__&gt; The first unnamed binding in a particular scope recieves the name `.Uv_`. Subsequent unnamed bindings use the form with a seq-id. ### Anonymous Block Scope Names For the purpose of mangling local names, an anonymous block scope (for example, a block expression used as the initializer for a static/const, or in a type) is as follows: &lt;anon-encoding&gt; := &lt;*data* __encoding__&gt;.LD_ &lt;anon-encoding&gt; := &lt;*data* __encoding__&gt;.LD&lt;__seq-id__&gt;_ &lt;anon-encoding&gt; := &lt;*type or template* __name__&gt;.LT_ &lt;anon-encoding&gt; := &lt;*type or template* __name__&gt;.LT&lt;__seq-id__&gt;_ &lt;local-name&gt; := Z&lt;__anon-encoding__&gt;E&lt;*entity* __name__&gt;[&lt;discriminator&gt;] &lt;local-name&gt; := Z&lt;__anon-encoding__&gt;Es[&lt;discriminator&gt;] When the block appears in the initializer or type of a static or const, the form with `.LD` is used. The *data* encoding is the encoding of the static/const that contains the type The first top-level block that contains a mangled name in the initializer uses the form with a seq-id, subsequent top-level blocks use the latter. When the block appears in a generic parameter for a type, the form with `.LT` is used. The *type or template* name is the name of the type or template is the type appears in the declaration of the type or an inherent `impl` naming the type. If the block appears in a trait impl, the `trait` impl name is used instead. If the block is introduced in a generic argument to the type, then the untemplated name is used. Otherwise, the full name of the type is used (for example, if the block appears in a where clause). Any block introduced in the type of the function (including a where clause) is mangled as though it is contained within the function itself. [Example 1 (crate name example): ```rust= pub static FOO: usize = { pub struct Bar; 0 } ``` Bar has the encoding `_ZN7example3FOO.LD_E3Bar` ] ### `track_caller` shims If a function defined with the `#[track_caller]` attribute is used as a function pointer type, or in the instantiation of the vtable of a trait implementation, where the trait declaration does not declare the defined function with the `#[track_caller]` attribute, a shim shall be emitted. The first shim in a particular instantiation location shall be of the form. &lt;shim-name&gt; := &lt;*function* __name__&gt;.CL&lt;*instantiation location* __encoding__&gt;__ &lt;shim-name&gt; := &lt;*function* __name__&gt;.CL&lt;*instantiation location* __encoding__&gt;_&lt;__seq-id__&gt;_ &lt;special-name&gt; := <__shim-name__> The first shim in a given instantiation location has no `seq-id`, the second shim in a given location has a seq-id of 0, etc. The instantiation location of a shim is as follows: - If the shim is emitted by an fn-item to fn-ptr coercion within a function, the instantiation location is the function containing the shim (such instantitions use the mangled name of the function as the name following `CL`) - If the shim is emitted by an fn-item to fn-ptr coercion within the initializer or type of a const or a static, the instantiation location is the name of the const or static (such instantitions use the mangled name of the static/const as the name following `CL`) - [Note: If the static/const is declared within the function and has internal linkage, the location is the function, not the static/const] - If the shim is emitted by a vtable instantiation, then the instantiation location is the vtable for the trait implementation (such instantiations use the mangled name of the Vtable). - If the trait implementation is generic, then all translation units that instantiate the vtable also instantiate the shim. During linking, each instantiation of the shim is merged into a single definition of the shim function. [Note: the seq-id for instantiations are unique for the location, not the shimmed function.] [Note: For example, in this code (for a crate name of `test`) ```rust= #[track_caller] fn bar(){} #[track_caller] fn baz(){} fn foo(){ let _: fn()->() = bar; let _: fn()->() = baz; } static FOO: fn()->() = bar; ``` There are 3 shims created: 1. `_ZN4test3barEv.CLNS_fooEv_` (`test::bar()->() {shim 0 for test::foo()}`), 2. `_ZN4test3bazEv.CLNS_3fooEv0_` (`test::baz()->() {shim 1 for test::foo()}`), and 3. `_ZN4test3barEv.CLNS_3FOOE_` (`test::bar()->() {shim 0 for test::FOO)`) ] The `track_caller` shim shall have the same abi as the the function type unless the function has an abi not specified by the Rust Programming Language or this ABI Specification, in which case the abi of the shim is unspecified. The parameter and return types of the shim shall be the parameter and return types of the function type. Calling the shim shall call the underlying function with the parameters to the function, and the implicit source location parameter being a static reference to a `Location<'static>` that represents the location of the trait method definition or the use of the function name that was coerced to an fn-pointer. ### Edition Specific Names Edition Specific Names (names of the form `edition#name`) are mangled with a suffix: The fully mangled name of the non-specific name is mangled as follows: `<edition-specific-suffix>` := `.DE<`*`edition `*__`number`__`>__` `<edition-specific-suffix>` := `.DE<`*`edition `*__`number`__`>_<`__`number`__`>_` The number at the end is given by the level the edition specific name applies to. levels are from last component forward, and ignore non-name components (such as template argument lists). The first level is mangled without a number, the second level is mangled with the number 0, third with 1, etc. [Note: For example, in the following code in the crate example: ```rust pub fn edition2021#foo(){} pub mod edition2018#bar{ pub fn baz(){} } ``` `foo` has the name `_ZN7example3foo.DE2021__Ev` and `bar::baz` has the name `_Zn7example3bar3baz.DE2018_0_` ] ## panicking * When targetting a hosted operating system, any time a panic is required to cause the program to abort, it shall call either `abort` from the C Standard Library or `std::terminate` from the C++ Standard Library. It is unspecified which is called. It is unspecified whether the associated message is printed as a result of the abort. * Otherwise, when a freestanding target is used, it is unspecified how the program aborts. * Unwinding shall occur using SEH when targetting the msvc toolchain or the mingw32 system. Otherwise, on targets that support it, unwinding shall occur using itanium unwind tables. Otherwise, the method of unwind is not specified * If the implementation supports neither of the above mechanisms, but supports exceptions in C++, it is recommended that the implementations implement panics using the same or a compatible mechanism. ### Itanium Unwinding * Normative Reference: This section may reference types and functions defined by the [Itanium Exception Handling ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html) * When building a proc-macro or libraries linked with a proc-macro, the content of the unwind struct is unspecified. * [ Note: This allows, for example, panics to be implemented as C++ exceptions directly, so that the implementation can catch the exception as it unwinds into the proc-macro handling code. The implementation shall ensure that the function `std::panic::catch_unwind` distinguishes between exceptions thrown from other foreign code. ] * Otherwise, the unwind structure shall be the following *exposition-only* type: ```rust= #[repr(C)] pub struct PanicUnwindInformation{ uw: _Unwind_Exception, abi_ver: u64, panic_origin: Location<'static>, message: Option<String>, impl_info: usize, tail_size: usize, } ``` * The value of impl_info is unspecified * The value of `tail_size` shall be the size of the remaining header following the PanicUnwindInformation structure. * The low order 4 bytes of `uw.exception_class` shall be the 4 bytes of the string "LCRS". * [Note: This name was chosen, rather than `Rust` to avoid conflicts with other implementations of rust panics atop Itanium Unwinding]. * The high 4 bytes of `uw.exception_class` are unspecified. * The value of `abi_ver` shall be the version of the abi implemented. * An implementation shall support unwinding as a result of and catching of exceptions of previous and subsequent abi versions, than the one implemented * message shall either be set to None or the result of applying `format!()` to the input to the `panic!()` macro. * If the panic occurs from an call to `unreachable!()`, `todo!()`, `unimplemented!()`, a nullary call to `panic!()`, or a call to `std::panic::panic_any`, the message is implementation-defined. * If the panic occurs within a program that is `#![no_std]` and that does not link the alloc crate, whether or not the message is `None` in any of the above cases is implementation-defined. ## Foreign Exceptions * The implementation shall support unwinding as a result of foreign exceptions that use the Unwinding System that this ABI specifies for use with rust panics on a particular target. * Whether or not it supports catching Foreign Exceptions, and whether it supports Foreign Exceptions that unwind through any other mechanism, is unspecified. * If Foreign Exceptions may be caught via `std::panic::catch_unwind`, then the resulting error returned by `catch_unwind` shall Downcast to an *exposition-only* type of `std::panic::foreign::ForeignPanic`. The operations on this type, other than to Drop the type, are unspecified. * If an implementation chooses to make this *exposition-only* type available, both the `std::panic::foreign` and the `ForeignPanic` type should be made available to the program under the feature `foreign_exceptions`. * panicking with a value of this type shall rethrow the original exception. * If a program panics while unwinding as a result of a foreign exception it is unspecified whether the program immediately aborts, but the program shall abort if a destructor run during unwinding exits with a panic or a foreign exception. * Panics from Rust code compiled by an implementation that does not support this abi shall be considered foreign exceptions by the implementation. * Panics from Rust code compiled by an implementation that does support this abi shall not be considered foreign by the implementation if they use the same unwinding mechanism. Otherwise, it is unspecified whether such panics are considered foreign executions. ## dylib ABI Info Each `dylib` crate shall be built by the compiler to include a section, which shall not be loaded at runtime, shall have the name `.note.lcrust.build-info`, and shall have an alignment within the image that equals or exceeds 8 bytes. The section shall contain a structure as follows: ```rust= #[repr(C,align(8))] struct ABIInfo{ abi_ver: i64, compiler_name_and_version: u32, codegen_opts: u32, crate_name: u32, padding: [u16;1], extra_length: u16, extra: [Extra;extra_length] }; ``` * `abi_ver` is the version of the abi which the dylib was created by, and, for compilers adhering to this specification, shall be exactly zero. Values less than 0 are reserved to be used with the options `-Zstruct-layout=randomize` or `-frust-struct-layout=randomize`, or another, *implementation-defined* use. * compile_name_and_version is an index into the dynamic string table which is the start of a null-terminated UTF-8 encoded string, with an implementation-defined value that represents the name of the implementation and the version (for example: `lccc v1.0 (abi verison 0)`) * `crate_name` is an index into the dynamic string table which is the start of a null-terminated UTF-8 encoded string, with the name of the crate with the disambiguator, if any, appended. * `codegen_opts` contains information about the build. The following bits have defined meaning, all other bits shall be set to zero and ignored * `0x000001oo` is set if the crate was built with LTO enabled. `oo` is the value of the crate optimization level, where for a value <4, `oo` is the value of the optimization level, for a value in `[4,240)`, such values shall not be produced by the implementation, and shall be treated as if the value `3`. * The value 250 indicates `-Og`, that is, optimize for debugging * The value 251 is reserved for an extended version of `-Og`, the implementation shall not produce this value and shall treat it as the value 250 when encountered. * The value 252 indicates `-Os`, that is, optimize for code size * The value 253 indicates `-Oz`, that is, optimize for code size reducing size further than the value 252 * The value 254 indicates `-Ofast`, that is, optimize like `-O3`, but permits performing math-based optimizations that can violate language standards. * The value 255 indicates `-Oextra`, that is, optimize like `-Ofast`, but also permits preforming additional pointer-related optimizations that can violate language standards. * Any other value in [240,256) is reserved. The implementation shall not produce such values and shall ignore such values when encountered. * `0x00000200` is set with `0x000001oo` to indicate that only thin LTO is enabled for the dylib. * `0x80000000` indicates that the crate was build with `-Z repr-rust-layout=randomize`. The abi_ver field shall be negative, and shall be the seed used to randomize struct layouts. If this bit is not set, the use of negative abi_ver fields is unspecified. * padding is reserved for future use, and shall be set to zero. Implementations shall ignore the content of these fields. * extra_len shall be set to the number of entries in the `extra` array * extra shall be an array of entries, which describe extra data reguarding the abi. The content of this array is not defined by the specification. The Extra structure shall be declared follows: ```rust #[repr(C,align(8))] pub struct Extra{ e_type: u32, e_size: u16, e_bytes: [u8] } ``` Where e_bytes is `e_size` trailing bytes, and `e_type` is an index in the binaries dynamic string table which is a null terminated multibyte string encoded in UTF-8 which represents the type of the Extra field. The valid type names, and there meanings, are unspecified. If a type name is not understood, the particular `Extra` field shall be ignored. * [Note: It is recommended that `e_type` values be expressed in a form which is unique, such as OID, UUID, or Resource Identifier (`<domain>:<path/...>`) form. However, this document does neither specifies nor constrains the choice of form, nor requires that an implementation document it's choice.]