From 8116b5e92e8aecc9776d1c7bf3bdee7401a95f16 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 22 Jul 2024 14:57:10 -0400 Subject: [PATCH 01/25] Start `abi` chapter. --- src/abi.md | 215 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 171 insertions(+), 44 deletions(-) diff --git a/src/abi.md b/src/abi.md index 09ff20b16..65bba0c52 100644 --- a/src/abi.md +++ b/src/abi.md @@ -1,21 +1,126 @@ # Application Binary Interface (ABI) -This section documents features that affect the ABI of the compiled output of -a crate. +r[abi] -See *[extern functions]* for information on specifying the ABI for exporting -functions. See *[external blocks]* for information on specifying the ABI for -linking external libraries. +## ABI Compatibility + +r[abi.compatibility] + +r[abi.compatibilty.type] +Two types, `T` and `U`, can be *abi compatible*. + +r[abi.compatibility.equivalence] +Two types `T` and `U` are *abi compatible* if: +* They are the same type, +* `U` is *abi compatible* with `T`, or +* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatuble* with `U`, + +> [!NOTE] +> These properties ensure that *abi compatibility* is an equivalence relation. + +r[abi.compatibility.integer] +Two integer types are *abi compatible* if they have the same size and the same signednes + +> [!NOTE] +> In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. +> Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. + +r[abi.compatibility.char] +The type `char`is *abi compatible* with the type `u32`. + +r[abi.compatibility.pointer] +Two pointer types, `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. + +> [!NOTE] +> With transitivity, this applies regardless of the mutability of either pointer type + +r[abi.compatibility.reference-box] +The types `&T`, `&mut T`, [`Box`][core::boxed::Box], and [`NonNull`][core::ptr::NonNull], are *abi compatible* with `*const T` + +> [!NOTE] +> With transitivity,t hey are also *abi compatible** with each other, and with `*mut T`, as well as references/`Box` to different types that have the same *metadata type*. + + +r[abi.compatibility.core] +The types [`MaybeUninit`][core::mem::MaybeUninit], [`UnsafeCell`][core::cell::UnsafeCell], and [`NonZero`][core::num::NonZero], are *abi compatible* with `T`. + +r[abi.compatibility.transparent] +A `struct` declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists + +r[abi.compatibilty.zst] +Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. + +r[abi.compatibility.option] +If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`Option`], [`Result`], and [`Result`]. + +r[abi.compatibility.fn-ptr] +An `fn`-ptr type `T` is compatible with an `fn`-ptr type `U` if `T` and `U` have *abi compatible* tags. + +r[abi.compatibility.extern-tag] +Two abi tags are *abi compatible* if: +* They are the same string, or +* One tag is `"X"`, and the other is `"X-unwind"` + +r[abi.compatibility.signature] +Two function signatures are compatible if: +* The abi tags of both signatures are *abi compatible*, +* They have the same number of parameters, excluding C-varargs, +* Each parameter of both signatures, in order, are *abi compatible*, and +* Either both signatures have C-varargs, or neither signature does. + +r[abi.compatibility.simd-abi] +A type has *simd abi requirements* if: +* It is a type declared with the standard-library repr-attrbute `simd`, +* It is a aggregate type, which has a type with *simd abi requirements* as a field. + +r[abi.compatibility.simd-target-feature] +A type with *simd abi requirements* may have one or more *salient target features* . In the case of an aggregate type, the set of *salient target features* is the union of the set of *salient target features* of each field with *simd abi requirements*. + +> [!TARGET-SPECIFIC] +> On x86 and x86-64, the *salient target features* of the `simd` types are: +> * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`]: `sse` +> * [`__m256`], [`__m256i`], [`__m256f`], and [`__m256d`]: `avx` +> * [`__m512`], [`__m512i`], [`__m512f`], and [`__m512d`]: `avx512f` and `avx512vl` + +r[abi.compatibility.call] +A call to a function `f` via a function item or function pointer with a given signature `S` is valid only if the signature of `f` is *compatible* with the signature `S`, and, if the type of any parameter, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each *salient target feature* of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. The behaviour a call that is not valid is undefined. + + +[`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html +[`__m128i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128i.html +[`__m128f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128f.html +[`__m128d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128d.html +[`__m256`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256.html +[`__m256i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256i.html +[`__m256f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256f.html +[`__m256d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256d.html +[`__m512`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512.html +[`__m512i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512i.html +[`__m512f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512f.html +[`__m512d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512d.html ## The `used` attribute -The *`used` attribute* can only be applied to [`static` items]. This [attribute] forces the -compiler to keep the variable in the output object file (.o, .rlib, etc. excluding final binaries) -even if the variable is not used, or referenced, by any other item in the crate. -However, the linker is still free to remove such an item. -Below is an example that shows under what conditions the compiler keeps a `static` item in the -output object file. +r[abi.used] + +```abnf +MetaItemUsed := "used" +``` + +r[abi.used.syntax] +The *`used` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. + +r[abi.used.restriction] +The `used` attribute shall only be applied to a `static` item. It shall not be applied to a `static` item declared within an [`extern` block]. + +r[abi.used.application] +A `static` item with the `used` attribute is an *exported item*. + +> [!NOTE] +> *exported items* will generally appear in the output when linking a library crate, and will generally be available when linking a binary crate as a global symbol. +> The `used` attribute does not give the `static` item a *linkage name*, and thus does not disable name mangling. It may be used to place data into a given section that is referenced by the linker via the input section, without regard to the name of the symbol. +> Due to toolchain limitations, it is not guaranteed that a `#[used]` static will appear in the final output when linking a binary, or when linking an rlib/staticlib crate into a `dylib` or `cdylib`. ``` rust // foo.rs @@ -57,31 +162,54 @@ $ nm -C foo.o 0000000000000000 T foo::quux ``` -## The `no_mangle` attribute +## Symbol naming -The *`no_mangle` attribute* may be used on any [item] to disable standard -symbol name mangling. The symbol for the item will be the identifier of the -item's name. +r[abi.symbol-name] -Additionally, the item will be publicly exported from the produced library or -object file, similar to the [`used` attribute](#the-used-attribute). +```abnf +MetaItemNoMangle := "no_mangle" +MetaItemExportName := "export_name" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL]) +``` + +r[abi.symbol-name.names] +The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. + +> [!NOTE] +> They may be applied to an associated `fn` of an `impl` block. + +r[abi.symbol-name.exported] +An item with either the *`no_mangle` attrbute* or the *`export_name` attribute* is an *exported item*. + +r[abi.symbol-name.no_mangle] +The *`no_mangle` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the declaration name of the item. + +r[abi.symbol-name.export_name] +The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. -This attribute is unsafe as an unmangled symbol may collide with another symbol -with the same name (or with a well-known symbol), leading to undefined behavior. -```rust -#[unsafe(no_mangle)] -extern "C" fn foo() {} -``` ## The `link_section` attribute -The *`link_section` attribute* specifies the section of the object file that a -[function] or [static]'s content will be placed into. It uses the -[_MetaNameValueStr_] syntax to specify the section name. +r[abi.link_section] + +```abnf +MetaItemLinkSection := "link_section" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL]) +``` + +r[abi.link_section.syntax] +The *`link_section` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. + +r[abi.link_section.restriction] +The *`link_section` attribute* shall be aplied to a `static` or `fn` item. -This attribute is unsafe as it allows users to place data and code into sections -of memory not expecting them, such as mutable data into read-only areas. +r[abi.link_section.def] +An item with the *`link_section` attribute* is placed in the specified section when linking. The section specified shall not violate the constraints on section names on the target, and shall not be invalid for the item type, no diagnostic is required. + +> [!NOTE] +> A section name may be invalid if it violates the requirements for the item type, for example, an `fn` item must be placed in an executable section, and a mutable static item (`static mut` or one containing an `UnsafeCell`) must be placed in a writable section. +> The required format and any restrictions on section names are target-specific. +> +> The result of using an invalid section name may be that the section is placed into the section but cannot be used as applicable, or that the section is given additional attributes that may be incompatible when linking. ```rust,no_run @@ -90,26 +218,25 @@ of memory not expecting them, such as mutable data into read-only areas. pub static VAR1: u32 = 1; ``` -## The `export_name` attribute - -The *`export_name` attribute* specifies the name of the symbol that will be -exported on a [function] or [static]. It uses the [_MetaNameValueStr_] syntax -to specify the symbol name. - -This attribute is unsafe as a symbol with a custom name may collide with another -symbol with the same name (or with a well-known symbol), leading to undefined -behavior. - -```rust -#[unsafe(export_name = "exported_symbol_name")] -pub fn name_in_rust() { } -``` - +> [!TARGET-SPECIFIC] +> On ELF Platforms, the standard section names, and their attributes are: +> * `.text`: Readable and Executable, +> * `.rodata`: Readable, +> * `.data`: Readable and Writable, +> * `.bss`: Readable and Writable - Uninitialized data, +> * `.tdata`: Readable and Writable - Thread-local, +> * `.tbss`: Readable and Writable - Uninitialized and Thread-local. +> +> This is not an exhaustive list, and generally extended versions of these section names such as `.text.foo`, are also defined with the same properties as the base section. +> +> + +[_MetaWord_]: attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md [attribute]: attributes.md [extern functions]: items/functions.md#extern-function-qualifier -[external blocks]: items/external-blocks.md +[`extern` block]: items/external-blocks.md [function]: items/functions.md [item]: items.md [static]: items/static-items.md From 48be95ad940678c2b246d4b0fa81031fc23337ff Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 11:01:40 -0400 Subject: [PATCH 02/25] Clarify that `extern "Rust"` is safe, even when simd types are used --- src/abi.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/abi.md b/src/abi.md index 65bba0c52..c322f087a 100644 --- a/src/abi.md +++ b/src/abi.md @@ -74,16 +74,23 @@ A type has *simd abi requirements* if: * It is a aggregate type, which has a type with *simd abi requirements* as a field. r[abi.compatibility.simd-target-feature] -A type with *simd abi requirements* may have one or more *salient target features* . In the case of an aggregate type, the set of *salient target features* is the union of the set of *salient target features* of each field with *simd abi requirements*. +A type with *simd abi requirements* may have one or more [*salient target features*][target_feature] . In the case of an aggregate type, the set of [*salient target features*][target_feature] is the union of the set of [*salient target features*][target_feature] of each field with *simd abi requirements*. > [!TARGET-SPECIFIC] -> On x86 and x86-64, the *salient target features* of the `simd` types are: +> On x86 and x86-64, the [*salient target features*][target_feature] of the `simd` types are: > * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`]: `sse` > * [`__m256`], [`__m256i`], [`__m256f`], and [`__m256d`]: `avx` > * [`__m512`], [`__m512i`], [`__m512f`], and [`__m512d`]: `avx512f` and `avx512vl` r[abi.compatibility.call] -A call to a function `f` via a function item or function pointer with a given signature `S` is valid only if the signature of `f` is *compatible* with the signature `S`, and, if the type of any parameter, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each *salient target feature* of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. The behaviour a call that is not valid is undefined. +A call to a function `f` via a function item or function pointer with a given signature `S` is valid only if the signature of `f` is *compatible* with the signature `S`, and: +* The ABI tag of the function is `extern "Rust"`, or +* If the type of any parameter, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature]of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. + +The behaviour a call that is not valid is undefined. + +> [!NOTE] +> the ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. [`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html @@ -101,7 +108,6 @@ A call to a function `f` via a function item or function pointer with a given si ## The `used` attribute - r[abi.used] ```abnf @@ -231,6 +237,8 @@ pub static VAR1: u32 = 1; > > + + [_MetaWord_]: attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md @@ -240,3 +248,4 @@ pub static VAR1: u32 = 1; [function]: items/functions.md [item]: items.md [static]: items/static-items.md +[target_feature]: attributes/codegen.md#the-target_feature-attribute \ No newline at end of file From fee9c23c0a1ad39f8b7385381db33b9f1cbb05f1 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 11:14:16 -0400 Subject: [PATCH 03/25] Cleanup styling of abi chapter --- src/abi.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/abi.md b/src/abi.md index c322f087a..0a3dedd9d 100644 --- a/src/abi.md +++ b/src/abi.md @@ -26,11 +26,14 @@ Two integer types are *abi compatible* if they have the same size and the same s > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. r[abi.compatibility.char] -The type `char`is *abi compatible* with the type `u32`. +The type `char` is *abi compatible* with the type `u32`. r[abi.compatibility.pointer] Two pointer types, `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. +> [!NOTE] +> [`Sized`] types have a *metadata type* of `()`. + > [!NOTE] > With transitivity, this applies regardless of the mutability of either pointer type @@ -38,14 +41,13 @@ r[abi.compatibility.reference-box] The types `&T`, `&mut T`, [`Box`][core::boxed::Box], and [`NonNull`][core::ptr::NonNull], are *abi compatible* with `*const T` > [!NOTE] -> With transitivity,t hey are also *abi compatible** with each other, and with `*mut T`, as well as references/`Box` to different types that have the same *metadata type*. - +> With transitivity, they are also *abi compatible* with each other, and with `*mut T`, as well as references/`Box` to different types that have the same *metadata type*. r[abi.compatibility.core] The types [`MaybeUninit`][core::mem::MaybeUninit], [`UnsafeCell`][core::cell::UnsafeCell], and [`NonZero`][core::num::NonZero], are *abi compatible* with `T`. r[abi.compatibility.transparent] -A `struct` declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists +A `struct` declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists. r[abi.compatibilty.zst] Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. @@ -68,31 +70,36 @@ Two function signatures are compatible if: * Each parameter of both signatures, in order, are *abi compatible*, and * Either both signatures have C-varargs, or neither signature does. +> [!NOTE] +> A signature is compatible with itself. + r[abi.compatibility.simd-abi] A type has *simd abi requirements* if: * It is a type declared with the standard-library repr-attrbute `simd`, * It is a aggregate type, which has a type with *simd abi requirements* as a field. +> [!NOTE] +> The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. + r[abi.compatibility.simd-target-feature] A type with *simd abi requirements* may have one or more [*salient target features*][target_feature] . In the case of an aggregate type, the set of [*salient target features*][target_feature] is the union of the set of [*salient target features*][target_feature] of each field with *simd abi requirements*. > [!TARGET-SPECIFIC] > On x86 and x86-64, the [*salient target features*][target_feature] of the `simd` types are: -> * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`]: `sse` -> * [`__m256`], [`__m256i`], [`__m256f`], and [`__m256d`]: `avx` -> * [`__m512`], [`__m512i`], [`__m512f`], and [`__m512d`]: `avx512f` and `avx512vl` +> * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`] (128-bit vector types): `sse` +> * [`__m256`], [`__m256i`], [`__m256f`], and [`__m256d`] (256-bit vector types): `avx` +> * [`__m512`], [`__m512i`], [`__m512f`], and [`__m512d`] (512-bit vector types): `avx512f` and `avx512vl` r[abi.compatibility.call] -A call to a function `f` via a function item or function pointer with a given signature `S` is valid only if the signature of `f` is *compatible* with the signature `S`, and: -* The ABI tag of the function is `extern "Rust"`, or -* If the type of any parameter, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature]of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. +A call to a function `f` via a function item or function pointer with a given signature `S` is valid if and only if the signature of the definition `f` is *compatible* with the signature `S`, and: +* The ABI tag of the signature is `extern "Rust"`, or +* If any parameter type, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature] of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. The behaviour a call that is not valid is undefined. > [!NOTE] > the ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. - [`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html [`__m128i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128i.html [`__m128f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128f.html @@ -192,8 +199,6 @@ The *`no_mangle` attribute* may be specified as a built-in attribute, using the r[abi.symbol-name.export_name] The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. - - ## The `link_section` attribute r[abi.link_section] @@ -234,10 +239,6 @@ pub static VAR1: u32 = 1; > * `.tbss`: Readable and Writable - Uninitialized and Thread-local. > > This is not an exhaustive list, and generally extended versions of these section names such as `.text.foo`, are also defined with the same properties as the base section. -> -> - - [_MetaWord_]: attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax From b5c05286c771624c12d30a52a20e9c1b32963c08 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 11:16:48 -0400 Subject: [PATCH 04/25] Link to section that lists abi chapters --- src/abi.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index 0a3dedd9d..b2c9b1b7e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -59,13 +59,13 @@ r[abi.compatibility.fn-ptr] An `fn`-ptr type `T` is compatible with an `fn`-ptr type `U` if `T` and `U` have *abi compatible* tags. r[abi.compatibility.extern-tag] -Two abi tags are *abi compatible* if: +Two [abi tags][abi] are *abi compatible* if: * They are the same string, or * One tag is `"X"`, and the other is `"X-unwind"` r[abi.compatibility.signature] Two function signatures are compatible if: -* The abi tags of both signatures are *abi compatible*, +* The [abi tags][abi] of both signatures are *abi compatible*, * They have the same number of parameters, excluding C-varargs, * Each parameter of both signatures, in order, are *abi compatible*, and * Either both signatures have C-varargs, or neither signature does. @@ -246,6 +246,7 @@ pub static VAR1: u32 = 1; [attribute]: attributes.md [extern functions]: items/functions.md#extern-function-qualifier [`extern` block]: items/external-blocks.md +[abi]: items/external-blocks.md#abi [function]: items/functions.md [item]: items.md [static]: items/static-items.md From 15e156344338f69b28b4dd242fed46cde635e1be Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 11:42:42 -0400 Subject: [PATCH 05/25] Add links to clauses in abi chapter --- src/abi.md | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/abi.md b/src/abi.md index b2c9b1b7e..1f9ef8af7 100644 --- a/src/abi.md +++ b/src/abi.md @@ -19,53 +19,53 @@ Two types `T` and `U` are *abi compatible* if: > These properties ensure that *abi compatibility* is an equivalence relation. r[abi.compatibility.integer] -Two integer types are *abi compatible* if they have the same size and the same signednes +Two [integer types] are *abi compatible* if they have the same size and the same signednes > [!NOTE] > In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. r[abi.compatibility.char] -The type `char` is *abi compatible* with the type `u32`. +The type [`char`] is *abi compatible* with the type [`u32`][integer types]. r[abi.compatibility.pointer] -Two pointer types, `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. +Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. > [!NOTE] -> [`Sized`] types have a *metadata type* of `()`. +> [`core::marker::Sized`] types have a *metadata type* of `()`. > [!NOTE] > With transitivity, this applies regardless of the mutability of either pointer type r[abi.compatibility.reference-box] -The types `&T`, `&mut T`, [`Box`][core::boxed::Box], and [`NonNull`][core::ptr::NonNull], are *abi compatible* with `*const T` +The types [`&T`], [`&mut T`], [`alloc::boxed::Box`], and [`core::ptr::NonNull`], are *abi compatible* with `*const T` > [!NOTE] > With transitivity, they are also *abi compatible* with each other, and with `*mut T`, as well as references/`Box` to different types that have the same *metadata type*. r[abi.compatibility.core] -The types [`MaybeUninit`][core::mem::MaybeUninit], [`UnsafeCell`][core::cell::UnsafeCell], and [`NonZero`][core::num::NonZero], are *abi compatible* with `T`. +The types [`core::mem::MaybeUninit`], [`core::cell::UnsafeCell`], and [`core::num::NonZero`], are *abi compatible* with `T`. r[abi.compatibility.transparent] -A `struct` declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists. +A [`struct`] declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists. r[abi.compatibilty.zst] Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. r[abi.compatibility.option] -If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`Option`], [`Result`], and [`Result`]. +If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`core::option::Option`], [`core::result::Result`], and [`core::result::Result`]. r[abi.compatibility.fn-ptr] -An `fn`-ptr type `T` is compatible with an `fn`-ptr type `U` if `T` and `U` have *abi compatible* tags. +An [`fn`-ptr type] `T` is compatible with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags. r[abi.compatibility.extern-tag] -Two [abi tags][abi] are *abi compatible* if: +Two [abi tags][abi tag] are *abi compatible* if: * They are the same string, or * One tag is `"X"`, and the other is `"X-unwind"` r[abi.compatibility.signature] Two function signatures are compatible if: -* The [abi tags][abi] of both signatures are *abi compatible*, +* The [abi tags][abi tag] of both signatures are *abi compatible*, * They have the same number of parameters, excluding C-varargs, * Each parameter of both signatures, in order, are *abi compatible*, and * Either both signatures have C-varargs, or neither signature does. @@ -76,7 +76,7 @@ Two function signatures are compatible if: r[abi.compatibility.simd-abi] A type has *simd abi requirements* if: * It is a type declared with the standard-library repr-attrbute `simd`, -* It is a aggregate type, which has a type with *simd abi requirements* as a field. +* It is a aggregate type[^1], which has a type with *simd abi requirements* as a field. > [!NOTE] > The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. @@ -100,6 +100,8 @@ The behaviour a call that is not valid is undefined. > [!NOTE] > the ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. +[^1]: The aggregate types, for the purposes of this clause, are [`struct`] types, [`enum`] types, [`union`] types, and [array] types. + [`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html [`__m128i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128i.html [`__m128f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128f.html @@ -246,8 +248,18 @@ pub static VAR1: u32 = 1; [attribute]: attributes.md [extern functions]: items/functions.md#extern-function-qualifier [`extern` block]: items/external-blocks.md -[abi]: items/external-blocks.md#abi +[abi tag]: items/external-blocks.md#abi [function]: items/functions.md +[`fn`-ptr type]: types/function-pointer.md +[integer types]: types/numeric.md#integer-types +[`char`]: types/textual.md +[pointer types]: types/pointer.md#raw-pointers-const-and-mut +[`&T`]: types/pointer.md#shared-references- +[`&mut T`]: types/pointer.md#mutable-references-mut +[`struct`]: types/struct.md +[`enum`]: types/enum.md +[`union`]: types/union.md +[array]: types/array.md [item]: items.md [static]: items/static-items.md [target_feature]: attributes/codegen.md#the-target_feature-attribute \ No newline at end of file From d10ef05d79be3a8a7125573434cca8e2bad30a92 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 12:05:09 -0400 Subject: [PATCH 06/25] Add tests to abi chapter --- src/abi.md | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index 1f9ef8af7..00afc4c48 100644 --- a/src/abi.md +++ b/src/abi.md @@ -25,9 +25,40 @@ Two [integer types] are *abi compatible* if they have the same size and the same > In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. +```rust +#[cfg(target_pointer_width="32")] +fn foo(x: u32) -> u32{ + x +} +#[cfg(target_pointer_width="64")] +fn foo(x: u64) -> u64{ + x +} + +fn main(){ + let f: fn(usize)->usize = unsafe{core::mem::transmute(foo as fn(_)->_)}; + let x = 0usize; + let y = f(x); + assert_eq!(x,y); +} +``` + r[abi.compatibility.char] The type [`char`] is *abi compatible* with the type [`u32`][integer types]. +```rust +fn foo(x: char) -> u32{ + x as u32 +} + +fn main(){ + let f: fn(u32)->char = unsafe{core::mem::transmute(foo as fn(_)->_)}; + let x = b'A' as u32; // ascii character indecies are the same as Unicode character indecies + let y = f(x); + assert_eq!(y, 'A'); +} +``` + r[abi.compatibility.pointer] Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. @@ -37,12 +68,40 @@ Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metad > [!NOTE] > With transitivity, this applies regardless of the mutability of either pointer type +```rust +unsafe fn foo(x: *mut i32){ + unsafe{x.write(5);} +} + +fn main(){ + let f: unsafe fn(*mut ()) = unsafe{core::mem::transmute(foo as unsafe fn(_))}; // Type Erase the function + let mut val = 0; + let ptr = core::ptr::addr_of_mut!(val).cast::<()>(); // Get Opaque Userdata from somewhere + unsafe{f(ptr);} + assert_eq!(val, 5); +} +``` + r[abi.compatibility.reference-box] The types [`&T`], [`&mut T`], [`alloc::boxed::Box`], and [`core::ptr::NonNull`], are *abi compatible* with `*const T` > [!NOTE] > With transitivity, they are also *abi compatible* with each other, and with `*mut T`, as well as references/`Box` to different types that have the same *metadata type*. +```rust +fn foo(x: &mut i32){ + *x = 5; +} + +fn main(){ + let f: unsafe fn(*mut ()) = unsafe{core::mem::transmute(foo as fn(_))}; // Type Erase the function + let mut val = 0; + let ptr = core::ptr::addr_of_mut!(val).cast::<()>(); // Get Opaque Userdata from somewhere + unsafe{f(ptr);} + assert_eq!(val, 5); +} +``` + r[abi.compatibility.core] The types [`core::mem::MaybeUninit`], [`core::cell::UnsafeCell`], and [`core::num::NonZero`], are *abi compatible* with `T`. @@ -55,6 +114,7 @@ Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1 r[abi.compatibility.option] If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`core::option::Option`], [`core::result::Result`], and [`core::result::Result`]. + r[abi.compatibility.fn-ptr] An [`fn`-ptr type] `T` is compatible with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags. @@ -97,6 +157,9 @@ A call to a function `f` via a function item or function pointer with a given si The behaviour a call that is not valid is undefined. +> [!NOTE] +> When parameter/return types do not exactly match, they are converted as though by calling [`core::mem::transmute`]. The representation and validity requirements of the type in the definition/return site still apply, for example, passing `0` to a function pointer `fn(u32)` that points to a function declared as `fn foo(x: NonZeroU32)` is undefined behaviour. + > [!NOTE] > the ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. @@ -129,6 +192,11 @@ The *`used` attribute* may be specified as a built-in attribute, using the [_Met r[abi.used.restriction] The `used` attribute shall only be applied to a `static` item. It shall not be applied to a `static` item declared within an [`extern` block]. +```rust +#[used] +static FOO: u32 = 0; +``` + r[abi.used.application] A `static` item with the `used` attribute is an *exported item*. @@ -189,18 +257,81 @@ MetaItemExportName := "export_name" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL] r[abi.symbol-name.names] The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. +```rust +#[no_mangle] +extern "C" fn foo(x: i32) -> i32 { + x + 1 +} + +#[export_name = "bar"] +extern "C" fn baz(x: i32) -> i32 { + x + 2 +} +``` + +```rust,compile_fail +extern "C" { + #[export_name = "foo"] + fn __foo(x: i32) -> i32; +} +``` + > [!NOTE] > They may be applied to an associated `fn` of an `impl` block. + r[abi.symbol-name.exported] An item with either the *`no_mangle` attrbute* or the *`export_name` attribute* is an *exported item*. r[abi.symbol-name.no_mangle] The *`no_mangle` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the declaration name of the item. +```rust +extern "C" { + fn bar() -> i32; +} +mod inner{ + #[no_mangle] + extern "C" fn bar() -> i32 { + 0 + } +} + +fn main() { + let y = unsafe {bar()}; + assert_eq!(y,0); +} +``` + r[abi.symbol-name.export_name] The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. +```rust +extern "C" { + fn bar() -> i32; +} +mod inner{ + #[export_name = "bar"] + extern "C" fn __some_other_item_name() -> i32 { + 0 + } +} + +fn main(){ + let y = unsafe {bar()}; + assert_eq!(y,0); +} +``` + +r[abi.symbol-name.safety] +These attributes are unsafe as an unmangled symbol may collide with another symbol +with the same name (or with a well-known symbol), leading to undefined behavior. + +```rust +#[unsafe(no_mangle)] +extern "C" fn foo() {} +``` + ## The `link_section` attribute r[abi.link_section] @@ -212,8 +343,9 @@ MetaItemLinkSection := "link_section" "=" ([STRING_LITERAL] | [RAW_STRING_LITERA r[abi.link_section.syntax] The *`link_section` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. -r[abi.link_section.restriction] -The *`link_section` attribute* shall be aplied to a `static` or `fn` item. +r[abi.link_section.application] +The *`link_section` attribute* shall be applied to a `static` or `fn` item. + r[abi.link_section.def] An item with the *`link_section` attribute* is placed in the specified section when linking. The section specified shall not violate the constraints on section names on the target, and shall not be invalid for the item type, no diagnostic is required. @@ -224,6 +356,9 @@ An item with the *`link_section` attribute* is placed in the specified section w > > The result of using an invalid section name may be that the section is placed into the section but cannot be used as applicable, or that the section is given additional attributes that may be incompatible when linking. +r[abi.link_section.safety] +This attribute is unsafe as it allows users to place data and code into sections of memory not expecting them, such as mutable data into read-only areas. + ```rust,no_run #[unsafe(no_mangle)] @@ -242,6 +377,7 @@ pub static VAR1: u32 = 1; > > This is not an exhaustive list, and generally extended versions of these section names such as `.text.foo`, are also defined with the same properties as the base section. + [_MetaWord_]: attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md From e10129a644691e3dd835d6d847ae0374bc0c1db0 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 16:48:51 -0400 Subject: [PATCH 07/25] Fix style issues from CI --- src/abi.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/abi.md b/src/abi.md index 00afc4c48..d3e2a487e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -22,7 +22,7 @@ r[abi.compatibility.integer] Two [integer types] are *abi compatible* if they have the same size and the same signednes > [!NOTE] -> In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. +> In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. ```rust @@ -44,7 +44,7 @@ fn main(){ ``` r[abi.compatibility.char] -The type [`char`] is *abi compatible* with the type [`u32`][integer types]. +The type [`char`] is *abi compatible* with the type [`u32`][integer types]. ```rust fn foo(x: char) -> u32{ @@ -60,17 +60,17 @@ fn main(){ ``` r[abi.compatibility.pointer] -Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. +Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metadata type*s of `T` and `U` are the same type. > [!NOTE] -> [`core::marker::Sized`] types have a *metadata type* of `()`. +> [`core::marker::Sized`] types have a *metadata type* of `()`. > [!NOTE] > With transitivity, this applies regardless of the mutability of either pointer type ```rust unsafe fn foo(x: *mut i32){ - unsafe{x.write(5);} + unsafe{x.write(5);} } fn main(){ @@ -90,7 +90,7 @@ The types [`&T`], [`&mut T`], [`alloc::boxed::Box`], and [`core::ptr::NonNull ```rust fn foo(x: &mut i32){ - *x = 5; + *x = 5; } fn main(){ @@ -198,12 +198,12 @@ static FOO: u32 = 0; ``` r[abi.used.application] -A `static` item with the `used` attribute is an *exported item*. +A `static` item with the `used` attribute is an *exported item*. > [!NOTE] > *exported items* will generally appear in the output when linking a library crate, and will generally be available when linking a binary crate as a global symbol. > The `used` attribute does not give the `static` item a *linkage name*, and thus does not disable name mangling. It may be used to place data into a given section that is referenced by the linker via the input section, without regard to the name of the symbol. -> Due to toolchain limitations, it is not guaranteed that a `#[used]` static will appear in the final output when linking a binary, or when linking an rlib/staticlib crate into a `dylib` or `cdylib`. +> Due to toolchain limitations, it is not guaranteed that a `#[used]` static will appear in the final output when linking a binary, or when linking an rlib/staticlib crate into a `dylib` or `cdylib`. ``` rust // foo.rs @@ -245,7 +245,7 @@ $ nm -C foo.o 0000000000000000 T foo::quux ``` -## Symbol naming +## Symbol naming r[abi.symbol-name] @@ -255,7 +255,7 @@ MetaItemExportName := "export_name" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL] ``` r[abi.symbol-name.names] -The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. +The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. ```rust #[no_mangle] @@ -304,7 +304,7 @@ fn main() { ``` r[abi.symbol-name.export_name] -The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. +The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. ```rust extern "C" { @@ -341,7 +341,7 @@ MetaItemLinkSection := "link_section" "=" ([STRING_LITERAL] | [RAW_STRING_LITERA ``` r[abi.link_section.syntax] -The *`link_section` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. +The *`link_section` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. r[abi.link_section.application] The *`link_section` attribute* shall be applied to a `static` or `fn` item. @@ -374,7 +374,7 @@ pub static VAR1: u32 = 1; > * `.bss`: Readable and Writable - Uninitialized data, > * `.tdata`: Readable and Writable - Thread-local, > * `.tbss`: Readable and Writable - Uninitialized and Thread-local. -> +> > This is not an exhaustive list, and generally extended versions of these section names such as `.text.foo`, are also defined with the same properties as the base section. From 8b7d4df4b7f4f4ed2bb6f70c1423686480181e2a Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 16:50:41 -0400 Subject: [PATCH 08/25] Fix "File Must End with a newline" error --- src/abi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi.md b/src/abi.md index d3e2a487e..814914929 100644 --- a/src/abi.md +++ b/src/abi.md @@ -398,4 +398,4 @@ pub static VAR1: u32 = 1; [array]: types/array.md [item]: items.md [static]: items/static-items.md -[target_feature]: attributes/codegen.md#the-target_feature-attribute \ No newline at end of file +[target_feature]: attributes/codegen.md#the-target_feature-attribute From 6d695cd05dcf74c5ae10bee607550fa0e6db1767 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 24 Jul 2024 16:57:44 -0400 Subject: [PATCH 09/25] Fix broken links to abi chapter --- src/items/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/functions.md b/src/items/functions.md index d3f2c4548..969d5df20 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -347,7 +347,7 @@ fn documented() { > function items. The attributes that have meaning on a function are [`cfg`], [`cfg_attr`], [`deprecated`], -[`doc`], [`export_name`], [`link_section`], [`no_mangle`], [the lint check +[`doc`], [`export_name`][abi.symbol-name.export_name], [`link_section`][abi.link_section], [`no_mangle`][abi.symbol-name.no_mangle], [the lint check attributes], [`must_use`], [the procedural macro attributes], [the testing attributes], and [the optimization hint attributes]. Functions also accept attributes macros. From 92c0c940b535f645b91b68d623cbcd718a2bb64b Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 25 Jul 2024 10:45:23 -0400 Subject: [PATCH 10/25] Apply suggestions from code review Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- src/abi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index 814914929..d7e89f0ef 100644 --- a/src/abi.md +++ b/src/abi.md @@ -13,13 +13,13 @@ r[abi.compatibility.equivalence] Two types `T` and `U` are *abi compatible* if: * They are the same type, * `U` is *abi compatible* with `T`, or -* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatuble* with `U`, +* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatible* with `U`, > [!NOTE] > These properties ensure that *abi compatibility* is an equivalence relation. r[abi.compatibility.integer] -Two [integer types] are *abi compatible* if they have the same size and the same signednes +Two [integer types] are *abi compatible* if they have the same size and the same signedness > [!NOTE] > In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. From 5c441eae734e15d78a7aef09c7b480a014c56593 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 26 Jul 2024 19:22:33 +0000 Subject: [PATCH 11/25] Make suggested changes from PR comments --- src/abi.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/abi.md b/src/abi.md index d7e89f0ef..8239f3ca4 100644 --- a/src/abi.md +++ b/src/abi.md @@ -16,7 +16,7 @@ Two types `T` and `U` are *abi compatible* if: * There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatible* with `U`, > [!NOTE] -> These properties ensure that *abi compatibility* is an equivalence relation. +> These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that *abi compatibility* is an equivalence relation. r[abi.compatibility.integer] Two [integer types] are *abi compatible* if they have the same size and the same signedness @@ -69,13 +69,13 @@ Two [pointer types], `*mut T` and `*const U`, are *abi compatible* if the *metad > With transitivity, this applies regardless of the mutability of either pointer type ```rust -unsafe fn foo(x: *mut i32){ +unsafe fn foo(x: *mut u32){ unsafe{x.write(5);} } fn main(){ let f: unsafe fn(*mut ()) = unsafe{core::mem::transmute(foo as unsafe fn(_))}; // Type Erase the function - let mut val = 0; + let mut val: u32 = 0; let ptr = core::ptr::addr_of_mut!(val).cast::<()>(); // Get Opaque Userdata from somewhere unsafe{f(ptr);} assert_eq!(val, 5); @@ -116,13 +116,16 @@ If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable r[abi.compatibility.fn-ptr] -An [`fn`-ptr type] `T` is compatible with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags. +An [`fn`-ptr type] `T` is *abi compatible* with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags. r[abi.compatibility.extern-tag] Two [abi tags][abi tag] are *abi compatible* if: * They are the same string, or * One tag is `"X"`, and the other is `"X-unwind"` +> [!NOTE] +> e.g. `extern "C"` and `extern "C-unwind"` are compatible with each other. + r[abi.compatibility.signature] Two function signatures are compatible if: * The [abi tags][abi tag] of both signatures are *abi compatible*, From 3f5ca538ba56e27cb3f22245c475ae15bba121d9 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 26 Jul 2024 16:01:24 -0400 Subject: [PATCH 12/25] Apply suggestions from code review Co-authored-by: Eric Huss --- src/abi.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/abi.md b/src/abi.md index 8239f3ca4..0a049a1b4 100644 --- a/src/abi.md +++ b/src/abi.md @@ -2,11 +2,11 @@ r[abi] -## ABI Compatibility +## ABI compatibility r[abi.compatibility] -r[abi.compatibilty.type] +r[abi.compatibility.type] Two types, `T` and `U`, can be *abi compatible*. r[abi.compatibility.equivalence] @@ -19,27 +19,27 @@ Two types `T` and `U` are *abi compatible* if: > These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that *abi compatibility* is an equivalence relation. r[abi.compatibility.integer] -Two [integer types] are *abi compatible* if they have the same size and the same signedness +Two [integer types] are *abi compatible* if they have the same size and the same signedness. > [!NOTE] > In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. ```rust -#[cfg(target_pointer_width="32")] -fn foo(x: u32) -> u32{ +#[cfg(target_pointer_width = "32")] +fn foo(x: u32) -> u32 { x } -#[cfg(target_pointer_width="64")] -fn foo(x: u64) -> u64{ +#[cfg(target_pointer_width = "64")] +fn foo(x: u64) -> u64 { x } -fn main(){ - let f: fn(usize)->usize = unsafe{core::mem::transmute(foo as fn(_)->_)}; +fn main() { + let f: fn(usize) -> usize = unsafe { core::mem::transmute(foo as fn(_) -> _) }; let x = 0usize; let y = f(x); - assert_eq!(x,y); + assert_eq!(x, y); } ``` @@ -53,7 +53,7 @@ fn foo(x: char) -> u32{ fn main(){ let f: fn(u32)->char = unsafe{core::mem::transmute(foo as fn(_)->_)}; - let x = b'A' as u32; // ascii character indecies are the same as Unicode character indecies + let x = b'A' as u32; // ascii character indices are the same as Unicode character indices let y = f(x); assert_eq!(y, 'A'); } @@ -108,7 +108,7 @@ The types [`core::mem::MaybeUninit`], [`core::cell::UnsafeCell`], and [`co r[abi.compatibility.transparent] A [`struct`] declared with the `transparent` representation is *abi compatible* with its field that does not have size 0 and alignment 1, if such a field exists. -r[abi.compatibilty.zst] +r[abi.compatibility.zst] Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. r[abi.compatibility.option] @@ -138,7 +138,7 @@ Two function signatures are compatible if: r[abi.compatibility.simd-abi] A type has *simd abi requirements* if: -* It is a type declared with the standard-library repr-attrbute `simd`, +* It is a type declared with the standard-library repr-attribute `simd`, or * It is a aggregate type[^1], which has a type with *simd abi requirements* as a field. > [!NOTE] @@ -158,13 +158,13 @@ A call to a function `f` via a function item or function pointer with a given si * The ABI tag of the signature is `extern "Rust"`, or * If any parameter type, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature] of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. -The behaviour a call that is not valid is undefined. +The behavior of a call that is not valid is undefined. > [!NOTE] -> When parameter/return types do not exactly match, they are converted as though by calling [`core::mem::transmute`]. The representation and validity requirements of the type in the definition/return site still apply, for example, passing `0` to a function pointer `fn(u32)` that points to a function declared as `fn foo(x: NonZeroU32)` is undefined behaviour. +> When parameter or return types do not exactly match, they are converted as though by calling [`core::mem::transmute`]. The representation and validity requirements of the type in the definition or return site still apply. For example, passing `0` to a function pointer `fn(u32)` that points to a function declared as `fn foo(x: NonZeroU32)` is undefined behavior. > [!NOTE] -> the ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. +> The ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. [^1]: The aggregate types, for the purposes of this clause, are [`struct`] types, [`enum`] types, [`union`] types, and [array] types. @@ -185,9 +185,9 @@ The behaviour a call that is not valid is undefined. r[abi.used] -```abnf -MetaItemUsed := "used" -``` +> **Attribute Syntax**\ +> _MetaItemUsed_ :\ +>    `used` r[abi.used.syntax] The *`used` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. @@ -275,7 +275,7 @@ extern "C" fn baz(x: i32) -> i32 { ```rust,compile_fail extern "C" { #[export_name = "foo"] - fn __foo(x: i32) -> i32; + fn __foo(x: i32) -> i32; // error: not a free function, impl method, or static } ``` @@ -284,7 +284,7 @@ extern "C" { r[abi.symbol-name.exported] -An item with either the *`no_mangle` attrbute* or the *`export_name` attribute* is an *exported item*. +An item with either the *`no_mangle` attribute* or the *`export_name` attribute* is an *exported item*. r[abi.symbol-name.no_mangle] The *`no_mangle` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the declaration name of the item. From b99883aedfdc26e42086e2d1618f997ae2337f7f Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 26 Jul 2024 16:15:44 -0400 Subject: [PATCH 13/25] Elaborate more on *abi compatible* and *simd abi requirements*. Remove new claims about `link_section`. --- src/abi.md | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/abi.md b/src/abi.md index 0a049a1b4..d90f71570 100644 --- a/src/abi.md +++ b/src/abi.md @@ -2,6 +2,13 @@ r[abi] +This section documents features that affect the ABI of the compiled output of +a crate. + +See *[extern functions]* for information on specifying the ABI for exporting +functions. See *[`extern` block]s* for information on specifying the ABI for +linking external libraries. + ## ABI compatibility r[abi.compatibility] @@ -9,6 +16,9 @@ r[abi.compatibility] r[abi.compatibility.type] Two types, `T` and `U`, can be *abi compatible*. +> [!NOTE] +> *abi compatible* types can be used in place of each other in signatures when calling via [function pointer] at runtime (via pointer, or [`extern` block]). + r[abi.compatibility.equivalence] Two types `T` and `U` are *abi compatible* if: * They are the same type, @@ -116,7 +126,7 @@ If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable r[abi.compatibility.fn-ptr] -An [`fn`-ptr type] `T` is *abi compatible* with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags. +An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. r[abi.compatibility.extern-tag] Two [abi tags][abi tag] are *abi compatible* if: @@ -139,7 +149,13 @@ Two function signatures are compatible if: r[abi.compatibility.simd-abi] A type has *simd abi requirements* if: * It is a type declared with the standard-library repr-attribute `simd`, or -* It is a aggregate type[^1], which has a type with *simd abi requirements* as a field. +* It is a aggregate type[^aggregate], which has a type with *simd abi requirements* as a field. + +> [!NOTE] +> Types with *simd abi requirements* may be passed using special registers that aren't always available to code. + +> [!NOTE] +> Notably References and pointers to types with *simd abi requirements* do not have *simd abi requirements*. > [!NOTE] > The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. @@ -166,7 +182,7 @@ The behavior of a call that is not valid is undefined. > [!NOTE] > The ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. -[^1]: The aggregate types, for the purposes of this clause, are [`struct`] types, [`enum`] types, [`union`] types, and [array] types. +[^aggregate]: The aggregate types, for the purposes of this clause, are [`struct`] types, [`enum`] types, [`union`] types, and [array] types. [`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html [`__m128i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128i.html @@ -349,16 +365,6 @@ The *`link_section` attribute* may be specified as a built-in attribute, using t r[abi.link_section.application] The *`link_section` attribute* shall be applied to a `static` or `fn` item. - -r[abi.link_section.def] -An item with the *`link_section` attribute* is placed in the specified section when linking. The section specified shall not violate the constraints on section names on the target, and shall not be invalid for the item type, no diagnostic is required. - -> [!NOTE] -> A section name may be invalid if it violates the requirements for the item type, for example, an `fn` item must be placed in an executable section, and a mutable static item (`static mut` or one containing an `UnsafeCell`) must be placed in a writable section. -> The required format and any restrictions on section names are target-specific. -> -> The result of using an invalid section name may be that the section is placed into the section but cannot be used as applicable, or that the section is given additional attributes that may be incompatible when linking. - r[abi.link_section.safety] This attribute is unsafe as it allows users to place data and code into sections of memory not expecting them, such as mutable data into read-only areas. @@ -369,18 +375,6 @@ This attribute is unsafe as it allows users to place data and code into sections pub static VAR1: u32 = 1; ``` -> [!TARGET-SPECIFIC] -> On ELF Platforms, the standard section names, and their attributes are: -> * `.text`: Readable and Executable, -> * `.rodata`: Readable, -> * `.data`: Readable and Writable, -> * `.bss`: Readable and Writable - Uninitialized data, -> * `.tdata`: Readable and Writable - Thread-local, -> * `.tbss`: Readable and Writable - Uninitialized and Thread-local. -> -> This is not an exhaustive list, and generally extended versions of these section names such as `.text.foo`, are also defined with the same properties as the base section. - - [_MetaWord_]: attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md @@ -389,7 +383,7 @@ pub static VAR1: u32 = 1; [`extern` block]: items/external-blocks.md [abi tag]: items/external-blocks.md#abi [function]: items/functions.md -[`fn`-ptr type]: types/function-pointer.md +[function pointer]: types/function-pointer.md [integer types]: types/numeric.md#integer-types [`char`]: types/textual.md [pointer types]: types/pointer.md#raw-pointers-const-and-mut From 0d0635bb1cab8094d6c1d3e0021952d2b5cbb6de Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 26 Jul 2024 16:21:29 -0400 Subject: [PATCH 14/25] Add introductory clauses and reformat to use existing grammar style --- src/abi.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/abi.md b/src/abi.md index d90f71570..b337dd2ca 100644 --- a/src/abi.md +++ b/src/abi.md @@ -201,6 +201,8 @@ The behavior of a call that is not valid is undefined. r[abi.used] +The `#[used]` attribute allows indicating that a `static` item should be considered to be used by the program from outside of Rust and not discarded by the compiler. + > **Attribute Syntax**\ > _MetaItemUsed_ :\ >    `used` @@ -268,13 +270,17 @@ $ nm -C foo.o r[abi.symbol-name] -```abnf -MetaItemNoMangle := "no_mangle" -MetaItemExportName := "export_name" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL]) -``` + +The `no_mangle` and `export_name` attributes allow you to control which symbols are exported from rust code under provided symbol names. + +> **Attribute Syntax**\ +> _MetaItemNoMangle_ :\ +>    `no_mangle` +> _MetaItemExportName_ :\ +>    `export_name` `=` (_STRING_LITERAL | _RAW_STRING_LITERAL_) r[abi.symbol-name.names] -The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. +The *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. ```rust #[no_mangle] @@ -355,9 +361,11 @@ extern "C" fn foo() {} r[abi.link_section] -```abnf -MetaItemLinkSection := "link_section" "=" ([STRING_LITERAL] | [RAW_STRING_LITERAL]) -``` +The `link_section` attribute allows a program to control the section that certain items are placed into. + +> **Attribute Syntax**\ +> _MetaItemLinkSection_ :\ +>    `link_section` `=` (_STRING_LITERAL_ | _RAW_STRING_LITERAL_) r[abi.link_section.syntax] The *`link_section` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. From 073ca4251c951ed74d4f5d1fecf175debdf5f15d Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Sat, 21 Sep 2024 22:43:02 -0400 Subject: [PATCH 15/25] Add additional explanations to the abi compatibility section --- src/abi.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/abi.md b/src/abi.md index b337dd2ca..1e567681e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -13,11 +13,18 @@ linking external libraries. r[abi.compatibility] -r[abi.compatibility.type] -Two types, `T` and `U`, can be *abi compatible*. +r[abi.compatibility.intro] +Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee, but certain other types may be *abi compatible*. This can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. When the parameters or return types differ between the call site and def site, assuming they are *abi compatible*, the parameters or return types are transmuted to the type at the def site or call site respectively. > [!NOTE] -> *abi compatible* types can be used in place of each other in signatures when calling via [function pointer] at runtime (via pointer, or [`extern` block]). +> This can include calls to functions defined outside of rust, or built using a different Rust compiler version. +> Additional guarantees will apply in this case for "FFI Safe" types, which match up with the platform C ABI in well-defined ways. +> These are not fully documented here currently. + +> [!WARNING] +> Two types that are ABI Compatible may not allow the same set of values (e.g. [`*const T`] and [`core::ptr::NonNull`]). +> If an invalid value is passed as a parameter or returned from a function, the result is immediate undefined behaviour, even if the parameter or return value is never used. +> For example, passing a null pointer to a function that accepts a `NonNull` parameter via `fn(*const i32)` function pointer caused undefined behaviour. r[abi.compatibility.equivalence] Two types `T` and `U` are *abi compatible* if: @@ -27,12 +34,16 @@ Two types `T` and `U` are *abi compatible* if: > [!NOTE] > These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that *abi compatibility* is an equivalence relation. +> ABI compatibility is a pairwise relation between two types. With Transivity and Symmetry, however, it can be well-defined to refer to several types being ABI compatible r[abi.compatibility.integer] -Two [integer types] are *abi compatible* if they have the same size and the same signedness. +Two [integer types] are *abi compatible* if they have the same width and the same signedness. + +> [!NOTE] +> The width of an integer type is the number of bits, e.g. `u8` has a width of 8, and `i128` has a width of 128. > [!NOTE] -> In particular, `usize` is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. +> In particular, [`usize`] is *abi compatible* with `uN`, and `isize` is *abi compatible* with `iN` where `N` is the target_pointer_width. > Two integer types with different signedness, such as `u8` and `i8` are not *abi compatible*. ```rust @@ -124,7 +135,6 @@ Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1 r[abi.compatibility.option] If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`core::option::Option`], [`core::result::Result`], and [`core::result::Result`]. - r[abi.compatibility.fn-ptr] An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. @@ -147,7 +157,7 @@ Two function signatures are compatible if: > A signature is compatible with itself. r[abi.compatibility.simd-abi] -A type has *simd abi requirements* if: +Certain types have *simd abi requirements*, which can impose additional constraints on calls with a parameter or return value of that type. A type has *simd abi requirements* if: * It is a type declared with the standard-library repr-attribute `simd`, or * It is a aggregate type[^aggregate], which has a type with *simd abi requirements* as a field. @@ -155,14 +165,16 @@ A type has *simd abi requirements* if: > Types with *simd abi requirements* may be passed using special registers that aren't always available to code. > [!NOTE] -> Notably References and pointers to types with *simd abi requirements* do not have *simd abi requirements*. +> Notably References and pointers to types with *simd abi requirements* do not have *simd abi requirements*. +> Only direct parameters and return values are affected by *simd abi requirements*. > [!NOTE] -> The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. +> The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. The name used here is for *exposition only*. r[abi.compatibility.simd-target-feature] A type with *simd abi requirements* may have one or more [*salient target features*][target_feature] . In the case of an aggregate type, the set of [*salient target features*][target_feature] is the union of the set of [*salient target features*][target_feature] of each field with *simd abi requirements*. +r[abi.compatibility.simd-target-feature-x86] > [!TARGET-SPECIFIC] > On x86 and x86-64, the [*salient target features*][target_feature] of the `simd` types are: > * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`] (128-bit vector types): `sse` @@ -176,8 +188,6 @@ A call to a function `f` via a function item or function pointer with a given si The behavior of a call that is not valid is undefined. -> [!NOTE] -> When parameter or return types do not exactly match, they are converted as though by calling [`core::mem::transmute`]. The representation and validity requirements of the type in the definition or return site still apply. For example, passing `0` to a function pointer `fn(u32)` that points to a function declared as `fn foo(x: NonZeroU32)` is undefined behavior. > [!NOTE] > The ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. @@ -270,8 +280,7 @@ $ nm -C foo.o r[abi.symbol-name] - -The `no_mangle` and `export_name` attributes allow you to control which symbols are exported from rust code under provided symbol names. +The `no_mangle` and `export_name` attributes allow you to control which symbols are exported from rust code under provided symbol names. > **Attribute Syntax**\ > _MetaItemNoMangle_ :\ @@ -304,7 +313,6 @@ extern "C" { > [!NOTE] > They may be applied to an associated `fn` of an `impl` block. - r[abi.symbol-name.exported] An item with either the *`no_mangle` attribute* or the *`export_name` attribute* is an *exported item*. @@ -361,7 +369,7 @@ extern "C" fn foo() {} r[abi.link_section] -The `link_section` attribute allows a program to control the section that certain items are placed into. +The `link_section` attribute allows a program to control the section that certain items are placed into. > **Attribute Syntax**\ > _MetaItemLinkSection_ :\ @@ -395,11 +403,13 @@ pub static VAR1: u32 = 1; [integer types]: types/numeric.md#integer-types [`char`]: types/textual.md [pointer types]: types/pointer.md#raw-pointers-const-and-mut +[`*const T`]: types/pointer.md#raw-pointers-const-and-mut [`&T`]: types/pointer.md#shared-references- [`&mut T`]: types/pointer.md#mutable-references-mut [`struct`]: types/struct.md [`enum`]: types/enum.md [`union`]: types/union.md +[`usize`]: types/numeric.md#machine-dependent-integer-types [array]: types/array.md [item]: items.md [static]: items/static-items.md From 7dd54255cff7c059f4492b1d98c82e088651e4ce Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Sat, 21 Sep 2024 22:48:32 -0400 Subject: [PATCH 16/25] Fix style issues --- src/abi.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index 1e567681e..5e4d62b20 100644 --- a/src/abi.md +++ b/src/abi.md @@ -22,7 +22,7 @@ Function calls pass parameters and return values between the caller and the call > These are not fully documented here currently. > [!WARNING] -> Two types that are ABI Compatible may not allow the same set of values (e.g. [`*const T`] and [`core::ptr::NonNull`]). +> Two types that are ABI Compatible may not allow the same set of values (e.g. [`*const T`] and [`core::ptr::NonNull`]). > If an invalid value is passed as a parameter or returned from a function, the result is immediate undefined behaviour, even if the parameter or return value is never used. > For example, passing a null pointer to a function that accepts a `NonNull` parameter via `fn(*const i32)` function pointer caused undefined behaviour. @@ -188,7 +188,6 @@ A call to a function `f` via a function item or function pointer with a given si The behavior of a call that is not valid is undefined. - > [!NOTE] > The ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. From 97cd91f9f181c16343d28fd322b03c86a3d3247e Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Sat, 21 Sep 2024 23:54:20 -0400 Subject: [PATCH 17/25] Fix broken links --- src/abi.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/abi.md b/src/abi.md index 5e4d62b20..e4e7bbb05 100644 --- a/src/abi.md +++ b/src/abi.md @@ -275,6 +275,9 @@ $ nm -C foo.o 0000000000000000 T foo::quux ``` + + + ## Symbol naming r[abi.symbol-name] From e4c62acd4ca3cf638458e71bda806bab70c9f720 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 21 Oct 2024 13:04:23 -0400 Subject: [PATCH 18/25] Indicate that all types subject to mandatory discriminant elision are abi compatible with their *elision candidate field*s --- src/abi.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index e4e7bbb05..31145d230 100644 --- a/src/abi.md +++ b/src/abi.md @@ -132,8 +132,13 @@ A [`struct`] declared with the `transparent` representation is *abi compatible* r[abi.compatibility.zst] Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. -r[abi.compatibility.option] -If `T` is a type listed in [layout.enum.option](https://doc.rust-lang.org/stable/core/option/index.html#representation), then given `S` is a type with size 0 and alignment 1, `T` is *abi compatible* with the types [`core::option::Option`], [`core::result::Result`], and [`core::result::Result`]. +r[abi.compatibility.discriminant] +If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the type of the *elision candidate field*, then `T` is layout compatible with `U`. + +> [!NOTE] +> `Option`, `Result`, or `Result` are such types, when `U` are *elision candidate type*s, and `Z` is a 1-ZST type. +> +> Due to transitivity, two such types are *abi compatible* with each other if their *elision candidate field*s are *abi comaptible* r[abi.compatibility.fn-ptr] An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. @@ -206,6 +211,8 @@ The behavior of a call that is not valid is undefined. [`__m512f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512f.html [`__m512d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512d.html +[layout.repr.rust.option]: https://github.com/RalfJung/unsafe-code-guidelines/blob/option-like/reference/src/layout/enums.md#discriminant-elision-on-option-like-enums + ## The `used` attribute r[abi.used] From cbc834990fd7072558411077249a25766c067288 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 21 Oct 2024 13:07:02 -0400 Subject: [PATCH 19/25] Fix link reference to be the correct identifier --- src/abi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi.md b/src/abi.md index 31145d230..ac89663f3 100644 --- a/src/abi.md +++ b/src/abi.md @@ -211,7 +211,7 @@ The behavior of a call that is not valid is undefined. [`__m512f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512f.html [`__m512d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512d.html -[layout.repr.rust.option]: https://github.com/RalfJung/unsafe-code-guidelines/blob/option-like/reference/src/layout/enums.md#discriminant-elision-on-option-like-enums +[layout.repr.rust.option.elision]: https://github.com/RalfJung/unsafe-code-guidelines/blob/option-like/reference/src/layout/enums.md#discriminant-elision-on-option-like-enums ## The `used` attribute From 36f80c3fabfe6c304e5f6ddff369cbbef7f1dbfc Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 21 Oct 2024 13:08:43 -0400 Subject: [PATCH 20/25] Fix "Lines must not end with spaces" error --- src/abi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abi.md b/src/abi.md index ac89663f3..85b08c65e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -133,11 +133,11 @@ r[abi.compatibility.zst] Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1. r[abi.compatibility.discriminant] -If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the type of the *elision candidate field*, then `T` is layout compatible with `U`. +If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the type of the *elision candidate field*, then `T` is layout compatible with `U`. > [!NOTE] > `Option`, `Result`, or `Result` are such types, when `U` are *elision candidate type*s, and `Z` is a 1-ZST type. -> +> > Due to transitivity, two such types are *abi compatible* with each other if their *elision candidate field*s are *abi comaptible* r[abi.compatibility.fn-ptr] From 79a248d608c9f499e2a3452112c71ae957e0dcbf Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 11 Nov 2024 11:50:55 -0500 Subject: [PATCH 21/25] Remove simd abi requirements from definition and ensure that the return type is noted as being part of signature compatibility --- src/abi.md | 49 ++----------------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/src/abi.md b/src/abi.md index 85b08c65e..f599f5d9a 100644 --- a/src/abi.md +++ b/src/abi.md @@ -155,61 +155,16 @@ r[abi.compatibility.signature] Two function signatures are compatible if: * The [abi tags][abi tag] of both signatures are *abi compatible*, * They have the same number of parameters, excluding C-varargs, +* The return types of both signatures are *abi comaptible*, * Each parameter of both signatures, in order, are *abi compatible*, and * Either both signatures have C-varargs, or neither signature does. > [!NOTE] > A signature is compatible with itself. -r[abi.compatibility.simd-abi] -Certain types have *simd abi requirements*, which can impose additional constraints on calls with a parameter or return value of that type. A type has *simd abi requirements* if: -* It is a type declared with the standard-library repr-attribute `simd`, or -* It is a aggregate type[^aggregate], which has a type with *simd abi requirements* as a field. - -> [!NOTE] -> Types with *simd abi requirements* may be passed using special registers that aren't always available to code. - -> [!NOTE] -> Notably References and pointers to types with *simd abi requirements* do not have *simd abi requirements*. -> Only direct parameters and return values are affected by *simd abi requirements*. - -> [!NOTE] -> The `repr(simd)` attribute cannot be used by Rust code, only by the standard library. The name used here is for *exposition only*. - -r[abi.compatibility.simd-target-feature] -A type with *simd abi requirements* may have one or more [*salient target features*][target_feature] . In the case of an aggregate type, the set of [*salient target features*][target_feature] is the union of the set of [*salient target features*][target_feature] of each field with *simd abi requirements*. - -r[abi.compatibility.simd-target-feature-x86] -> [!TARGET-SPECIFIC] -> On x86 and x86-64, the [*salient target features*][target_feature] of the `simd` types are: -> * [`__m128`], [`__m128i`], [`__m128f`], and [`__m128d`] (128-bit vector types): `sse` -> * [`__m256`], [`__m256i`], [`__m256f`], and [`__m256d`] (256-bit vector types): `avx` -> * [`__m512`], [`__m512i`], [`__m512f`], and [`__m512d`] (512-bit vector types): `avx512f` and `avx512vl` r[abi.compatibility.call] -A call to a function `f` via a function item or function pointer with a given signature `S` is valid if and only if the signature of the definition `f` is *compatible* with the signature `S`, and: -* The ABI tag of the signature is `extern "Rust"`, or -* If any parameter type, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature] of that type is either set at both the definition site of the function, and at the call site, or is set at neither site. - -The behavior of a call that is not valid is undefined. - -> [!NOTE] -> The ABI tag `extern "Rust"` is the default when the `extern` keyword is not used (either to declare the function within an [`extern` block], or as a [function qualifier][extern functions]). Thus it is safe to call most functions that use simd types. - -[^aggregate]: The aggregate types, for the purposes of this clause, are [`struct`] types, [`enum`] types, [`union`] types, and [array] types. - -[`__m128`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128.html -[`__m128i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128i.html -[`__m128f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128f.html -[`__m128d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m128d.html -[`__m256`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256.html -[`__m256i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256i.html -[`__m256f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256f.html -[`__m256d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m256d.html -[`__m512`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512.html -[`__m512i`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512i.html -[`__m512f`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512f.html -[`__m512d`]: https://doc.rust-lang.org/stable/core/arch/x86_64/struct.__m512d.html +A call to a function `f` via a function item or function pointer with a given signature `S` is valid if and only if the signature of the definition `f` is *compatible* with the signature `S`. The behavior of a call that is not valid is undefined. [layout.repr.rust.option.elision]: https://github.com/RalfJung/unsafe-code-guidelines/blob/option-like/reference/src/layout/enums.md#discriminant-elision-on-option-like-enums From 1582d3f888d9d638c81fe09d5645cc44614f3705 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 11 Dec 2024 18:58:40 -0500 Subject: [PATCH 22/25] Apply suggestions from code review Co-authored-by: Ralf Jung --- src/abi.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/abi.md b/src/abi.md index b89a6e996..c077466c0 100644 --- a/src/abi.md +++ b/src/abi.md @@ -14,10 +14,10 @@ linking external libraries. r[abi.compatibility] r[abi.compatibility.intro] -Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee, but certain other types may be *abi compatible*. This can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. When the parameters or return types differ between the call site and def site, assuming they are *abi compatible*, the parameters or return types are transmuted to the type at the def site or call site respectively. +Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee. However, differences between caller and callee types can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. This is permitted if the caller and callee types are *abi compatible* (otherwise, it is undefined behavior). If the types are abi compatible, the parameters are transmuted to the callee type as part of the call and the return value is transmuted to the caller type upon return. > [!NOTE] -> This can include calls to functions defined outside of rust, or built using a different Rust compiler version. +> This can include calls to functions defined outside of Rust, or built using a different Rust compiler version. > Additional guarantees will apply in this case for "FFI Safe" types, which match up with the platform C ABI in well-defined ways. > These are not fully documented here currently. @@ -141,7 +141,7 @@ If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the > Due to transitivity, two such types are *abi compatible* with each other if their *elision candidate field*s are *abi comaptible* r[abi.compatibility.fn-ptr] -An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. +A [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. r[abi.compatibility.extern-tag] Two [abi tags][abi tag] are *abi compatible* if: From 2afe85e7905a2813c5fe3146a9384e1b51f55f77 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 11 Dec 2024 19:13:55 -0500 Subject: [PATCH 23/25] Fix abi chapter tests to comply with edition 2024 --- src/abi.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/abi.md b/src/abi.md index c077466c0..48e1fb90a 100644 --- a/src/abi.md +++ b/src/abi.md @@ -256,21 +256,21 @@ r[abi.symbol-name.names] The *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. ```rust -#[no_mangle] +#[unsafe(no_mangle(] extern "C" fn foo(x: i32) -> i32 { x + 1 } -#[export_name = "bar"] +#[unsafe(export_name = "bar")] extern "C" fn baz(x: i32) -> i32 { x + 2 } ``` ```rust,compile_fail -extern "C" { - #[export_name = "foo"] - fn __foo(x: i32) -> i32; // error: not a free function, impl method, or static +unsafe extern "C" { + #[unsafe(export_name = "foo")] + unsafe fn __foo(x: i32) -> i32; // error: not a free function, impl method, or static } ``` @@ -284,11 +284,11 @@ r[abi.symbol-name.no_mangle] The *`no_mangle` attribute* may be specified as a built-in attribute, using the [_MetaWord_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the declaration name of the item. ```rust -extern "C" { - fn bar() -> i32; +unsafe extern "C" { + unsafe fn bar() -> i32; } mod inner{ - #[no_mangle] + #[unsafe(no_mangle)] extern "C" fn bar() -> i32 { 0 } @@ -304,11 +304,11 @@ r[abi.symbol-name.export_name] The *`export_name` attribute* may be specified as a built-in attribute, using the [_MetaNameValueStr_] syntax. The *export name* of an item with the *`no_mangle` attribute* is the content of `STRING_LITERAL`. ```rust -extern "C" { - fn bar() -> i32; +unsafe extern "C" { + unsafe fn bar() -> i32; } mod inner{ - #[export_name = "bar"] + #[unsafe(export_name = "bar")] extern "C" fn __some_other_item_name() -> i32 { 0 } From 5be04238b8b0f6cde7570dd84c552de1dccd9d6d Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 11 Dec 2024 19:27:51 -0500 Subject: [PATCH 24/25] Fix parenthesis on `unsafe(no_mangle)` --- src/abi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abi.md b/src/abi.md index 48e1fb90a..e7aee484e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -256,7 +256,7 @@ r[abi.symbol-name.names] The *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block]. ```rust -#[unsafe(no_mangle(] +#[unsafe(no_mangle)] extern "C" fn foo(x: i32) -> i32 { x + 1 } From ce0915c13a933474eb3248b348b41a079b1f5e21 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Wed, 11 Dec 2024 19:34:47 -0500 Subject: [PATCH 25/25] Move clause about abi-compatibility being an equivalence relation until after other clauses --- src/abi.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/abi.md b/src/abi.md index e7aee484e..a2f244c9e 100644 --- a/src/abi.md +++ b/src/abi.md @@ -26,16 +26,6 @@ Function calls pass parameters and return values between the caller and the call > If an invalid value is passed as a parameter or returned from a function, the result is immediate undefined behaviour, even if the parameter or return value is never used. > For example, passing a null pointer to a function that accepts a `NonNull` parameter via `fn(*const i32)` function pointer caused undefined behaviour. -r[abi.compatibility.equivalence] -Two types `T` and `U` are *abi compatible* if: -* They are the same type, -* `U` is *abi compatible* with `T`, or -* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatible* with `U`, - -> [!NOTE] -> These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that *abi compatibility* is an equivalence relation. -> ABI compatibility is a pairwise relation between two types. With Transivity and Symmetry, however, it can be well-defined to refer to several types being ABI compatible - r[abi.compatibility.integer] Two [integer types] are *abi compatible* if they have the same width and the same signedness. @@ -136,13 +126,23 @@ r[abi.compatibility.discriminant] If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the type of the *elision candidate field*, then `T` is layout compatible with `U`. > [!NOTE] -> `Option`, `Result`, or `Result` are such types, when `U` are *elision candidate type*s, and `Z` is a 1-ZST type. +> `Option`, `Result`, or `Result` are examples of such types, when `U` are *elision candidate type*s, and `Z` is a 1-ZST type. > > Due to transitivity, two such types are *abi compatible* with each other if their *elision candidate field*s are *abi comaptible* r[abi.compatibility.fn-ptr] A [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags. +r[abi.compatibility.equivalence] +Two types `T` and `U` are *abi compatible* if: +* They are the same type, +* `U` is *abi compatible* with `T`, or +* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatible* with `U`, + +> [!NOTE] +> These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that *abi compatibility* is an equivalence relation. +> ABI compatibility is a pairwise relation between two types. With Transivity and Symmetry, however, it can be well-defined to refer to several types being ABI compatible + r[abi.compatibility.extern-tag] Two [abi tags][abi tag] are *abi compatible* if: * They are the same string, or