From 0c8fb9f2ff1c38e56cf5ea3b07dc586520cf9530 Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:11:01 -0400 Subject: [PATCH 01/11] Add notes about creating a custom target --- src/SUMMARY.md | 1 + src/compiler-support.md | 157 ++++++++++++++++++++-------------------- src/custom-target.md | 142 ++++++++++++++++++++++++++++++++++++ src/smallest-no-std.md | 15 ++++ 4 files changed, 237 insertions(+), 78 deletions(-) create mode 100644 src/custom-target.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7a25c7e..2d2fcd3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -11,3 +11,4 @@ - [DMA](./dma.md) --- [A note on compiler support](./compiler-support.md) +[Creating a custom target](./custom-target.md) diff --git a/src/compiler-support.md b/src/compiler-support.md index 30543b3..0266208 100644 --- a/src/compiler-support.md +++ b/src/compiler-support.md @@ -80,56 +80,85 @@ and the default linker. [specification]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md -The Rust compiler knows about several targets. These are said to be *built into* the compiler and +The Rust compiler knows about several targets. These are *built into* the compiler and can be listed by running the following command: ``` console $ rustc --print target-list | column -aarch64-fuchsia mips64el-unknown-linux-gnuabi64 -aarch64-linux-android mipsel-unknown-linux-gnu -aarch64-unknown-cloudabi mipsel-unknown-linux-musl -aarch64-unknown-freebsd mipsel-unknown-linux-uclibc -aarch64-unknown-linux-gnu msp430-none-elf -aarch64-unknown-linux-musl powerpc-unknown-linux-gnu -aarch64-unknown-openbsd powerpc-unknown-linux-gnuspe -arm-linux-androideabi powerpc-unknown-netbsd -arm-unknown-linux-gnueabi powerpc64-unknown-linux-gnu -arm-unknown-linux-gnueabihf powerpc64le-unknown-linux-gnu -arm-unknown-linux-musleabi powerpc64le-unknown-linux-musl -arm-unknown-linux-musleabihf s390x-unknown-linux-gnu -armebv7r-none-eabihf sparc-unknown-linux-gnu -armv4t-unknown-linux-gnueabi sparc64-unknown-linux-gnu -armv5te-unknown-linux-gnueabi sparc64-unknown-netbsd -armv5te-unknown-linux-musleabi sparcv9-sun-solaris -armv6-unknown-netbsd-eabihf thumbv6m-none-eabi -armv7-linux-androideabi thumbv7em-none-eabi -armv7-unknown-cloudabi-eabihf thumbv7em-none-eabihf -armv7-unknown-linux-gnueabihf thumbv7m-none-eabi -armv7-unknown-linux-musleabihf wasm32-experimental-emscripten -armv7-unknown-netbsd-eabihf wasm32-unknown-emscripten -asmjs-unknown-emscripten wasm32-unknown-unknown -i586-pc-windows-msvc x86_64-apple-darwin -i586-unknown-linux-gnu x86_64-fuchsia -i586-unknown-linux-musl x86_64-linux-android -i686-apple-darwin x86_64-pc-windows-gnu -i686-linux-android x86_64-pc-windows-msvc -i686-pc-windows-gnu x86_64-rumprun-netbsd -i686-pc-windows-msvc x86_64-sun-solaris -i686-unknown-cloudabi x86_64-unknown-bitrig -i686-unknown-dragonfly x86_64-unknown-cloudabi -i686-unknown-freebsd x86_64-unknown-dragonfly -i686-unknown-haiku x86_64-unknown-freebsd -i686-unknown-linux-gnu x86_64-unknown-haiku -i686-unknown-linux-musl x86_64-unknown-l4re-uclibc -i686-unknown-netbsd x86_64-unknown-linux-gnu -i686-unknown-openbsd x86_64-unknown-linux-gnux32 -mips-unknown-linux-gnu x86_64-unknown-linux-musl -mips-unknown-linux-musl x86_64-unknown-netbsd -mips-unknown-linux-uclibc x86_64-unknown-openbsd -mips64-unknown-linux-gnuabi64 x86_64-unknown-redox +aarch64-fuchsia mipsisa32r6el-unknown-linux-gnu +aarch64-linux-android mipsisa64r6-unknown-linux-gnuabi64 +aarch64-pc-windows-msvc mipsisa64r6el-unknown-linux-gnuabi64 +aarch64-unknown-cloudabi msp430-none-elf +aarch64-unknown-freebsd nvptx64-nvidia-cuda +aarch64-unknown-hermit powerpc-unknown-linux-gnu +aarch64-unknown-linux-gnu powerpc-unknown-linux-gnuspe +aarch64-unknown-linux-musl powerpc-unknown-linux-musl +aarch64-unknown-netbsd powerpc-unknown-netbsd +aarch64-unknown-none powerpc-wrs-vxworks +aarch64-unknown-none-softfloat powerpc-wrs-vxworks-spe +aarch64-unknown-openbsd powerpc64-unknown-freebsd +aarch64-unknown-redox powerpc64-unknown-linux-gnu +aarch64-uwp-windows-msvc powerpc64-unknown-linux-musl +aarch64-wrs-vxworks powerpc64-wrs-vxworks +arm-linux-androideabi powerpc64le-unknown-linux-gnu +arm-unknown-linux-gnueabi powerpc64le-unknown-linux-musl +arm-unknown-linux-gnueabihf riscv32i-unknown-none-elf +arm-unknown-linux-musleabi riscv32imac-unknown-none-elf +arm-unknown-linux-musleabihf riscv32imc-unknown-none-elf +armebv7r-none-eabi riscv64gc-unknown-linux-gnu +armebv7r-none-eabihf riscv64gc-unknown-none-elf +armv4t-unknown-linux-gnueabi riscv64imac-unknown-none-elf +armv5te-unknown-linux-gnueabi s390x-unknown-linux-gnu +armv5te-unknown-linux-musleabi sparc-unknown-linux-gnu +armv6-unknown-freebsd sparc64-unknown-linux-gnu +armv6-unknown-netbsd-eabihf sparc64-unknown-netbsd +armv7-linux-androideabi sparc64-unknown-openbsd +armv7-unknown-cloudabi-eabihf sparcv9-sun-solaris +armv7-unknown-freebsd thumbv6m-none-eabi +armv7-unknown-linux-gnueabi thumbv7a-pc-windows-msvc +armv7-unknown-linux-gnueabihf thumbv7em-none-eabi +armv7-unknown-linux-musleabi thumbv7em-none-eabihf +armv7-unknown-linux-musleabihf thumbv7m-none-eabi +armv7-unknown-netbsd-eabihf thumbv7neon-linux-androideabi +armv7-wrs-vxworks-eabihf thumbv7neon-unknown-linux-gnueabihf +armv7a-none-eabi thumbv7neon-unknown-linux-musleabihf +armv7a-none-eabihf thumbv8m.base-none-eabi +armv7r-none-eabi thumbv8m.main-none-eabi +armv7r-none-eabihf thumbv8m.main-none-eabihf +asmjs-unknown-emscripten wasm32-unknown-emscripten +hexagon-unknown-linux-musl wasm32-unknown-unknown +i586-pc-windows-msvc wasm32-wasi +i586-unknown-linux-gnu x86_64-apple-darwin +i586-unknown-linux-musl x86_64-fortanix-unknown-sgx +i686-apple-darwin x86_64-fuchsia +i686-linux-android x86_64-linux-android +i686-pc-windows-gnu x86_64-linux-kernel +i686-pc-windows-msvc x86_64-pc-solaris +i686-unknown-cloudabi x86_64-pc-windows-gnu +i686-unknown-freebsd x86_64-pc-windows-msvc +i686-unknown-haiku x86_64-rumprun-netbsd +i686-unknown-linux-gnu x86_64-sun-solaris +i686-unknown-linux-musl x86_64-unknown-cloudabi +i686-unknown-netbsd x86_64-unknown-dragonfly +i686-unknown-openbsd x86_64-unknown-freebsd +i686-unknown-uefi x86_64-unknown-haiku +i686-uwp-windows-gnu x86_64-unknown-hermit +i686-uwp-windows-msvc x86_64-unknown-hermit-kernel +i686-wrs-vxworks x86_64-unknown-illumos +mips-unknown-linux-gnu x86_64-unknown-l4re-uclibc +mips-unknown-linux-musl x86_64-unknown-linux-gnu +mips-unknown-linux-uclibc x86_64-unknown-linux-gnux32 +mips64-unknown-linux-gnuabi64 x86_64-unknown-linux-musl +mips64-unknown-linux-muslabi64 x86_64-unknown-netbsd +mips64el-unknown-linux-gnuabi64 x86_64-unknown-openbsd +mips64el-unknown-linux-muslabi64 x86_64-unknown-redox +mipsel-unknown-linux-gnu x86_64-unknown-uefi +mipsel-unknown-linux-musl x86_64-uwp-windows-gnu +mipsel-unknown-linux-uclibc x86_64-uwp-windows-msvc +mipsisa32r6-unknown-linux-gnu x86_64-wrs-vxworks ``` -You can print the specification of any of these targets using the following command: +You can print the specification of one of these targets using the following command: ``` console $ rustc +nightly -Z unstable-options --print target-spec-json --target thumbv7m-none-eabi @@ -163,38 +192,10 @@ $ rustc +nightly -Z unstable-options --print target-spec-json --target thumbv7m- ``` If none of these built-in targets seems appropriate for your target system, you'll have to create a -custom target by writing your own target specification file in JSON format. The recommended way is to -dump the specification of a built-in target that's similar to your target system into a file and then -tweak it to match the properties of your target system. To do so, use the previously shown command, -`rustc --print target-spec-json`. As of Rust 1.28, there's no up to date documentation on what each of -the fields of a target specification mean, other than [the compiler source code]. +custom target by writing your own target specification file in JSON format which is described in the +[next section][custom-target]. -[the compiler source code]: https://github.com/rust-lang/rust/blob/1.27.2/src/librustc_target/spec/mod.rs#L376-L400 - -Once you have a target specification file you can refer to it by its path or by its name if its in -the current directory or in `$RUST_TARGET_PATH`. - -``` console -$ rustc +nightly -Z unstable-options --print target-spec-json \ - --target thumbv7m-none-eabi \ - > foo.json - -$ rustc --print cfg --target foo.json # or just --target foo -debug_assertions -target_arch="arm" -target_endian="little" -target_env="" -target_feature="mclass" -target_feature="v7" -target_has_atomic="16" -target_has_atomic="32" -target_has_atomic="8" -target_has_atomic="cas" -target_has_atomic="ptr" -target_os="none" -target_pointer_width="32" -target_vendor="" -``` +[custom-target]: ./custom-target.md ## `rust-std` component @@ -241,8 +242,8 @@ mips-unknown-linux-musl x86_64-unknown-redox ``` If there's no `rust-std` component for your target or you are using a custom target, then you'll have -to use a tool like [Xargo] to have Cargo compile the `core` crate on the fly. Note that Xargo -requires a nightly toolchain; the long term plan is to upstream Xargo's functionality into Cargo -and eventually have that functionality available on stable. +to use a nightly toolchain to build the standard library. See the next page about [building for custom targets][use-target-file]. + +[use-target-file]: ./custom-target.md#use-the-target-file [Xargo]: https://github.com/japaric/xargo diff --git a/src/custom-target.md b/src/custom-target.md new file mode 100644 index 0000000..4eb5fc6 --- /dev/null +++ b/src/custom-target.md @@ -0,0 +1,142 @@ +# Creating a custom target + +If a custom target triple is not available for your platform, you must create a custom target.json file that describes your target to rustc. + +Keep in mind that it is required to use a nightly compiler to build the core library, which must be done for a target unknown to rustc. + +## Decide on a target triple + +Many targets already have a known triple used to describe them, typically in the form ARCH-VENDOR-SYS-ABI. You should aim to use the same triple that [LLVM uses][llvm-target-triple]; however, it may differ if you need to specify additional information to Rust that LLVM does not know about. Although the triple is technically only for human use, it's important for it to be unique and descriptive especially if the target will be upstreamed in the future. + + +The ARCH part is typically just the architecture name, except in the case of 32-bit ARM. For example, you would probably use x86_64 for those processors, but specify the exact ARM architecture version. Typical values might be `armv7`, `armv5te`, or `thumbv7neon`. Take a look at the names of the [built-in targets][built-in-target] for inspiration. + +The VENDOR part is optional, and describes the manufacturer. Omitting this field is the same as using `unknown`. + +The SYS part describes the OS that is used. Typical values include `win32`, `linux`, and `darwin` for desktop platforms. `none` is used for bare-metal usage. + +The ABI part describes how the process starts up. `eabi` is used for bare metal, while `gnu` is used for glibc, `musl` for musl, etc. + +Now that you have a target triple, create a file with the name of the triple and a `.json` extension. For example, a file describing `armv7a-none-eabi` would have the filename `armv7a-none-eabi.json`. + +[llvm-target-triple]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple + +## Fill the target file + +The target file must be valid JSON. There are two places where its contents are described: [`Target`], where every field is mandatory, and [`TargetOptions`], where every field is optional. **All underscores are replaced with hyphens**. + +The recommended way is to +base your target file on the specification of a built-in target that's similar to your target system, then +tweak it to match the properties of your target system. To do so, use the command +`rustc +nightly -Z unstable-options --print target-spec-json --target $SOME_SIMILAR_TARGET`, using [a target that's +already built into the compiler][built-in-target]. + +You can pretty much copy that output into your file. Start with a few modifications: +* Remove `"is-builtin": true` +* Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple] +* Decide on a panicking strategy. A bare metal implementation will likely use `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, even if you [tell Cargo to][aborting-on-panic], you must define an [eh_personality] function. +* Configure atomics. Pick the first option that describes your target: + * I have a single-core processor, no threads, no interrupts, or any way for multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set `"singlethread": true`. This will configure LLVM to convert all atomic operations to use their single threaded counterparts. + * I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case. + * I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the highest number of bits that you can emulate up to 64, then implement all of the [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while incorrectly implemented functions will possibly cause UB. + * I have no native atomic operations: you'll have to do some unsafe work to manually ensure synchronization in your code. You must set `"max-atomic-width": 0`. +* Change the linker if integrating with an existing toolchain. For example, if you're using a toolchain that uses a custom build of gcc, set `"linker-flavor": "gcc"` and `linker` to the command name of your linker. If you require additional linker arguments, use `pre-link-args` and `post-link-args` as so: + ``` json + "pre-link-args": { + "gcc": [ + "-Wl,--as-needed", + "-Wl,-z,noexecstack", + "-m64" + ] + }, + "post-link-args": { + "gcc": [ + "-Wl,--allow-multiple-definition", + "-Wl,--start-group,-lc,-lm,-lgcc,-lstdc++,-lsupc++,--end-group" + ] + } + ``` + Ensure that the linker type is the key within `link-args`. +* Configure LLVM features. Run `llc -march=ARCH -mattr=help` where ARCH is the base architecture (not including the version in the case of ARM) to list the available features and their descriptions. **If your target requires strict memory alignment access (e.g. `armv5te`), make sure that you enable `strict-align`**. To enable a feature, place a plus before it. Likewise, to disable a feature, place a minus before it. Features should be comma separated like so: `"features": "+soft-float,+neon`. Note that this may not be necessary if LLVM knows enough about your target based on the provided triple and CPU. +* Configure the CPU that LLVM uses if you know it. This will enable CPU-specific optimizations and features. At the top of the output of the command in the last step, there is a list of known CPUs. If you know that you will be targeting a specific CPU, you may set it in the `cpu` field in the JSON target file. + +[`Target`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html +[`TargetOptions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html +[aborting-on-panic]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/aborting-on-panic.html +[built-in-target]: ./compiler-support.md#built-in-target +[eh_personality]: ./smallest-no-std.md#eh_personality +[libcalls-atomic]: http://llvm.org/docs/Atomics.html#libcalls-atomic +[libcalls-sync]: http://llvm.org/docs/Atomics.html#libcalls-sync +[gcc-sync]: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html + +## Use the target file + +Once you have a target specification file, you may refer to it by its path or by its name (i.e. excluding `.json`) if it is in the current directory or in `$RUST_TARGET_PATH`. + +Verify that it is readable by rustc: +``` sh +❱ rustc --print cfg --target foo.json # or just foo if in the current directory +debug_assertions +target_arch="arm" +target_endian="little" +target_env="" +target_feature="mclass" +target_feature="v7" +target_has_atomic="16" +target_has_atomic="32" +target_has_atomic="8" +target_has_atomic="cas" +target_has_atomic="ptr" +target_os="none" +target_pointer_width="32" +target_vendor="" +``` + +Now, you finally get to use it! Many resources have been recommending [`xargo`] or [`cargo-xbuild`]. However, its successor, cargo's `build-std` feature, has received a lot of work recently and has quickly reached feature parity with the other options. As such, this guide will only cover that option. + +Start with a bare minimum [`no_std` program][no_std-program]. Now, run `cargo build -Z build-std=core --target foo.json`, again using the above rules about referencing the path. Hopefully, you should now have a binary in the target directory. + +You may optionally configure cargo to always use your target. See the recommendations at the end of the page about [the smallest `no_std` program][no_std-program]. However, you'll currently have to use the flag `-Z build-std=core` as that option is unstable. + +[`xargo`]: https://github.com/japaric/xargo +[`cargo-xbuild`]: https://github.com/rust-osdev/cargo-xbuild +[no_std-program]: ./smallest-no-std.md + +### Build additional built-in crates + +When using cargo's `build-std` feature, you can choose which crates to compile in. By default, when only passing `-Z build-std`, `std`, `core`, and `alloc` are compiled. However, you may want to exclude `std` when compiling for bare-metal. To do so, specify the crated you'd like after `build-std`. For example, to include `core` and `alloc`, pass `-Z build-std=core,alloc`. + +## Troubleshooting + +### language item required, but not found: `eh_personality` + +Either add `"panic-strategy": "abort"` to your target file, or define an [eh_personality] function. + +### undefined reference to `__sync_val_compare_and_swap_#` + +Rust thinks that your target has atomic instructions, but LLVM doesn't. Go back to the step about [configuring atomics][fill-target-file]. You will need to reduce the number in `max-atomic-width`. See [#58500] for more details. + +[fill-target-file]: #fill-the-target-file +[#58500]: https://github.com/rust-lang/rust/issues/58500 + +### could not find `sync` in `alloc` + +Similar to the above case, Rust doesn't think that you have atomics. You must implement them yourself or [tell Rust that you have atomic instructions][fill-target-file]. + +### multiple definition of `__(something)` + +You're likely linking your Rust program with code built from another language, and the other language includes compiler built-ins that Rust also creates. To fix this, you'll need to tell your linker to allow multiple definitions. If using gcc, you may add: + +``` json +"post-link-args": { + "gcc": [ + "-Wl,--allow-multiple-definition" + ] +} +``` + +### error adding symbols: file format not recognized + +Switch to cargo's `build-std` feature and update your compiler. This [was a bug][#8239] introduced for a few compiler builds that tried to pass in internal Rust object to an external linker. + +[#8239]: https://github.com/rust-lang/cargo/issues/8239 diff --git a/src/smallest-no-std.md b/src/smallest-no-std.md index 15e9530..8833032 100644 --- a/src/smallest-no-std.md +++ b/src/smallest-no-std.md @@ -104,3 +104,18 @@ $ cat .cargo/config ``` toml {{#include ../ci/smallest-no-std/.cargo/config}} ``` + +## eh_personality + +If your [target][custom-target] does not contain `"panic-strategy": "abort"`, which most targets for full operating systems don't, then you must add an `eh_personality` function, which requires a nightly compiler. [Here is Rust's documentation about it][more-about-lang-items], and [here is some discussion about it][til-why-eh-personality]. A simple implementation that does not do anything special when unwinding is as follows: + +``` rust +#![feature(lang_items)] + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} +``` + +[custom-target]: ./custom-target.md +[more-about-lang-items]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#more-about-the-language-items +[til-why-eh-personality]: https://www.reddit.com/r/rust/comments/estvau/til_why_the_eh_personality_language_item_is/ From 78898f0fe7603f7f97a9fdff79abfc77993cc698 Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:21:19 -0400 Subject: [PATCH 02/11] Format files --- src/compiler-support.md | 101 ++++++++++++++++------------- src/custom-target.md | 139 +++++++++++++++++++++++++++++----------- src/smallest-no-std.md | 21 ++++-- 3 files changed, 171 insertions(+), 90 deletions(-) diff --git a/src/compiler-support.md b/src/compiler-support.md index 0266208..91162e1 100644 --- a/src/compiler-support.md +++ b/src/compiler-support.md @@ -1,13 +1,14 @@ # A note on compiler support This book makes use of a built-in *compiler* target, the `thumbv7m-none-eabi`, for which the Rust -team distributes a `rust-std` component, which is a pre-compiled collection of crates like [`core`] and [`std`]. +team distributes a `rust-std` component, which is a pre-compiled collection of crates like [`core`] +and [`std`]. [`core`]: https://doc.rust-lang.org/core/index.html [`std`]: https://doc.rust-lang.org/std/index.html -If you want to attempt replicating the contents of this book for a different target architecture, you -need to take into account the different levels of support that Rust provides for (compilation) +If you want to attempt replicating the contents of this book for a different target architecture, +you need to take into account the different levels of support that Rust provides for (compilation) targets. ## LLVM support @@ -64,7 +65,8 @@ changes. On the other hand, if LLVM doesn't support the architecture, but a fork of LLVM does, you will have to replace the original version of LLVM with the fork before building `rustc`. The Rust build system -allows this and in principle it should just require changing the `llvm` submodule to point to the fork. +allows this and in principle it should just require changing the `llvm` submodule to point to the +fork. If your target architecture is only supported by some vendor provided GCC, you have the option of using [`mrustc`], an unofficial Rust compiler, to translate your Rust program into C code and then @@ -75,13 +77,13 @@ compile that using GCC. ## Built-in target A compilation target is more than just its architecture. Each target has a [specification] -associated to it that describes, among other things, its architecture, its operating system -and the default linker. +associated to it that describes, among other things, its architecture, its operating system and the +default linker. [specification]: https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md -The Rust compiler knows about several targets. These are *built into* the compiler and -can be listed by running the following command: +The Rust compiler knows about several targets. These are *built into* the compiler and can be listed +by running the following command: ``` console $ rustc --print target-list | column @@ -200,50 +202,61 @@ custom target by writing your own target specification file in JSON format which ## `rust-std` component For some of the built-in target the Rust team distributes `rust-std` components via `rustup`. This -component is a collection of pre-compiled crates like `core` and `std`, and it's required for -cross compilation. +component is a collection of pre-compiled crates like `core` and `std`, and it's required for cross +compilation. You can find the list of targets that have a `rust-std` component available via `rustup` by running the following command: ``` console $ rustup target list | column -aarch64-apple-ios mips64-unknown-linux-gnuabi64 -aarch64-linux-android mips64el-unknown-linux-gnuabi64 -aarch64-unknown-fuchsia mipsel-unknown-linux-gnu -aarch64-unknown-linux-gnu mipsel-unknown-linux-musl -aarch64-unknown-linux-musl powerpc-unknown-linux-gnu -arm-linux-androideabi powerpc64-unknown-linux-gnu -arm-unknown-linux-gnueabi powerpc64le-unknown-linux-gnu -arm-unknown-linux-gnueabihf s390x-unknown-linux-gnu -arm-unknown-linux-musleabi sparc64-unknown-linux-gnu -arm-unknown-linux-musleabihf sparcv9-sun-solaris -armv5te-unknown-linux-gnueabi thumbv6m-none-eabi -armv5te-unknown-linux-musleabi thumbv7em-none-eabi -armv7-apple-ios thumbv7em-none-eabihf +aarch64-apple-ios mipsel-unknown-linux-musl +aarch64-fuchsia nvptx64-nvidia-cuda +aarch64-linux-android powerpc-unknown-linux-gnu +aarch64-pc-windows-msvc powerpc64-unknown-linux-gnu +aarch64-unknown-linux-gnu powerpc64le-unknown-linux-gnu +aarch64-unknown-linux-musl riscv32i-unknown-none-elf +aarch64-unknown-none riscv32imac-unknown-none-elf +aarch64-unknown-none-softfloat riscv32imc-unknown-none-elf +arm-linux-androideabi riscv64gc-unknown-linux-gnu +arm-unknown-linux-gnueabi riscv64gc-unknown-none-elf +arm-unknown-linux-gnueabihf riscv64imac-unknown-none-elf +arm-unknown-linux-musleabi s390x-unknown-linux-gnu +arm-unknown-linux-musleabihf sparc64-unknown-linux-gnu +armebv7r-none-eabi sparcv9-sun-solaris +armebv7r-none-eabihf thumbv6m-none-eabi +armv5te-unknown-linux-gnueabi thumbv7em-none-eabi +armv5te-unknown-linux-musleabi thumbv7em-none-eabihf armv7-linux-androideabi thumbv7m-none-eabi -armv7-unknown-linux-gnueabihf wasm32-unknown-emscripten -armv7-unknown-linux-musleabihf wasm32-unknown-unknown -armv7s-apple-ios x86_64-apple-darwin -asmjs-unknown-emscripten x86_64-apple-ios -i386-apple-ios x86_64-linux-android -i586-pc-windows-msvc x86_64-pc-windows-gnu -i586-unknown-linux-gnu x86_64-pc-windows-msvc -i586-unknown-linux-musl x86_64-rumprun-netbsd -i686-apple-darwin x86_64-sun-solaris -i686-linux-android x86_64-unknown-cloudabi -i686-pc-windows-gnu x86_64-unknown-freebsd -i686-pc-windows-msvc x86_64-unknown-fuchsia -i686-unknown-freebsd x86_64-unknown-linux-gnu (default) -i686-unknown-linux-gnu x86_64-unknown-linux-gnux32 -i686-unknown-linux-musl x86_64-unknown-linux-musl -mips-unknown-linux-gnu x86_64-unknown-netbsd -mips-unknown-linux-musl x86_64-unknown-redox +armv7-unknown-linux-gnueabi thumbv7neon-linux-androideabi +armv7-unknown-linux-gnueabihf thumbv7neon-unknown-linux-gnueabihf +armv7-unknown-linux-musleabi thumbv8m.base-none-eabi +armv7-unknown-linux-musleabihf thumbv8m.main-none-eabi +armv7a-none-eabi thumbv8m.main-none-eabihf +armv7r-none-eabi wasm32-unknown-emscripten +armv7r-none-eabihf wasm32-unknown-unknown +asmjs-unknown-emscripten wasm32-wasi +i586-pc-windows-msvc x86_64-apple-darwin +i586-unknown-linux-gnu x86_64-apple-ios +i586-unknown-linux-musl x86_64-fortanix-unknown-sgx +i686-linux-android x86_64-fuchsia +i686-pc-windows-gnu x86_64-linux-android +i686-pc-windows-msvc x86_64-pc-windows-gnu +i686-unknown-freebsd x86_64-pc-windows-msvc +i686-unknown-linux-gnu x86_64-rumprun-netbsd +i686-unknown-linux-musl x86_64-sun-solaris +mips-unknown-linux-gnu x86_64-unknown-cloudabi +mips-unknown-linux-musl x86_64-unknown-freebsd +mips64-unknown-linux-gnuabi64 x86_64-unknown-linux-gnu (default) +mips64-unknown-linux-muslabi64 x86_64-unknown-linux-gnux32 +mips64el-unknown-linux-gnuabi64 x86_64-unknown-linux-musl +mips64el-unknown-linux-muslabi64 x86_64-unknown-netbsd +mipsel-unknown-linux-gnu x86_64-unknown-redox ``` -If there's no `rust-std` component for your target or you are using a custom target, then you'll have -to use a nightly toolchain to build the standard library. See the next page about [building for custom targets][use-target-file]. +If there's no `rust-std` component for your target, or you are using a custom target, then you'll +have to use a nightly toolchain to build the standard library. See the next page about [building for +custom targets][use-target-file]. [use-target-file]: ./custom-target.md#use-the-target-file - -[Xargo]: https://github.com/japaric/xargo +[xargo]: https://github.com/japaric/xargo diff --git a/src/custom-target.md b/src/custom-target.md index 4eb5fc6..e2a31b4 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -1,46 +1,78 @@ # Creating a custom target -If a custom target triple is not available for your platform, you must create a custom target.json file that describes your target to rustc. +If a custom target triple is not available for your platform, you must create a custom target file +that describes your target to rustc. -Keep in mind that it is required to use a nightly compiler to build the core library, which must be done for a target unknown to rustc. +Keep in mind that it is required to use a nightly compiler to build the core library, which must be +done for a target unknown to rustc. ## Decide on a target triple -Many targets already have a known triple used to describe them, typically in the form ARCH-VENDOR-SYS-ABI. You should aim to use the same triple that [LLVM uses][llvm-target-triple]; however, it may differ if you need to specify additional information to Rust that LLVM does not know about. Although the triple is technically only for human use, it's important for it to be unique and descriptive especially if the target will be upstreamed in the future. +Many targets already have a known triple used to describe them, typically in the form +ARCH-VENDOR-SYS-ABI. You should aim to use the same triple that [LLVM uses][llvm-target-triple]; +however, it may differ if you need to specify additional information to Rust that LLVM does not know +about. Although the triple is technically only for human use, it's important for it to be unique and +descriptive especially if the target will be upstreamed in the future. +The ARCH part is typically just the architecture name, except in the case of 32-bit ARM. For +example, you would probably use x86_64 for those processors, but specify the exact ARM architecture +version. Typical values might be `armv7`, `armv5te`, or `thumbv7neon`. Take a look at the names of +the [built-in targets][built-in-target] for inspiration. -The ARCH part is typically just the architecture name, except in the case of 32-bit ARM. For example, you would probably use x86_64 for those processors, but specify the exact ARM architecture version. Typical values might be `armv7`, `armv5te`, or `thumbv7neon`. Take a look at the names of the [built-in targets][built-in-target] for inspiration. +The VENDOR part is optional, and describes the manufacturer. Omitting this field is the same as +using `unknown`. -The VENDOR part is optional, and describes the manufacturer. Omitting this field is the same as using `unknown`. +The SYS part describes the OS that is used. Typical values include `win32`, `linux`, and `darwin` +for desktop platforms. `none` is used for bare-metal usage. -The SYS part describes the OS that is used. Typical values include `win32`, `linux`, and `darwin` for desktop platforms. `none` is used for bare-metal usage. +The ABI part describes how the process starts up. `eabi` is used for bare metal, while `gnu` is used +for glibc, `musl` for musl, etc. -The ABI part describes how the process starts up. `eabi` is used for bare metal, while `gnu` is used for glibc, `musl` for musl, etc. - -Now that you have a target triple, create a file with the name of the triple and a `.json` extension. For example, a file describing `armv7a-none-eabi` would have the filename `armv7a-none-eabi.json`. +Now that you have a target triple, create a file with the name of the triple and a `.json` +extension. For example, a file describing `armv7a-none-eabi` would have the filename +`armv7a-none-eabi.json`. [llvm-target-triple]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple ## Fill the target file -The target file must be valid JSON. There are two places where its contents are described: [`Target`], where every field is mandatory, and [`TargetOptions`], where every field is optional. **All underscores are replaced with hyphens**. +The target file must be valid JSON. There are two places where its contents are described: +[`Target`], where every field is mandatory, and [`TargetOptions`], where every field is optional. +**All underscores are replaced with hyphens**. -The recommended way is to -base your target file on the specification of a built-in target that's similar to your target system, then -tweak it to match the properties of your target system. To do so, use the command -`rustc +nightly -Z unstable-options --print target-spec-json --target $SOME_SIMILAR_TARGET`, using [a target that's -already built into the compiler][built-in-target]. +The recommended way is to base your target file on the specification of a built-in target that's +similar to your target system, then tweak it to match the properties of your target system. To do +so, use the command +`rustc +nightly -Z unstable-options --print target-spec-json --target $SOME_SIMILAR_TARGET`, using +[a target that's already built into the compiler][built-in-target]. You can pretty much copy that output into your file. Start with a few modifications: -* Remove `"is-builtin": true` -* Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple] -* Decide on a panicking strategy. A bare metal implementation will likely use `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, even if you [tell Cargo to][aborting-on-panic], you must define an [eh_personality] function. -* Configure atomics. Pick the first option that describes your target: - * I have a single-core processor, no threads, no interrupts, or any way for multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set `"singlethread": true`. This will configure LLVM to convert all atomic operations to use their single threaded counterparts. - * I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case. - * I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the highest number of bits that you can emulate up to 64, then implement all of the [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while incorrectly implemented functions will possibly cause UB. - * I have no native atomic operations: you'll have to do some unsafe work to manually ensure synchronization in your code. You must set `"max-atomic-width": 0`. -* Change the linker if integrating with an existing toolchain. For example, if you're using a toolchain that uses a custom build of gcc, set `"linker-flavor": "gcc"` and `linker` to the command name of your linker. If you require additional linker arguments, use `pre-link-args` and `post-link-args` as so: + +- Remove `"is-builtin": true` +- Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple] +- Decide on a panicking strategy. A bare metal implementation will likely use + `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, even if you [tell Cargo + to][aborting-on-panic], you must define an [eh_personality] function. +- Configure atomics. Pick the first option that describes your target: + - I have a single-core processor, no threads, no interrupts, or any way for multiple things to be + happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set + `"singlethread": true`. This will configure LLVM to convert all atomic operations to use their + single threaded counterparts. + - I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your + target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You + may set `"max-atomic-width": 32` in that case. + - I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the + highest number of bits that you can emulate up to 64, then implement all of the + [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as + `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc + documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while + incorrectly implemented functions will possibly cause UB. + - I have no native atomic operations: you'll have to do some unsafe work to manually ensure + synchronization in your code. You must set `"max-atomic-width": 0`. +- Change the linker if integrating with an existing toolchain. For example, if you're using a + toolchain that uses a custom build of gcc, set `"linker-flavor": "gcc"` and `linker` to the + command name of your linker. If you require additional linker arguments, use `pre-link-args` and + `post-link-args` as so: ``` json "pre-link-args": { "gcc": [ @@ -57,12 +89,23 @@ You can pretty much copy that output into your file. Start with a few modificati } ``` Ensure that the linker type is the key within `link-args`. -* Configure LLVM features. Run `llc -march=ARCH -mattr=help` where ARCH is the base architecture (not including the version in the case of ARM) to list the available features and their descriptions. **If your target requires strict memory alignment access (e.g. `armv5te`), make sure that you enable `strict-align`**. To enable a feature, place a plus before it. Likewise, to disable a feature, place a minus before it. Features should be comma separated like so: `"features": "+soft-float,+neon`. Note that this may not be necessary if LLVM knows enough about your target based on the provided triple and CPU. -* Configure the CPU that LLVM uses if you know it. This will enable CPU-specific optimizations and features. At the top of the output of the command in the last step, there is a list of known CPUs. If you know that you will be targeting a specific CPU, you may set it in the `cpu` field in the JSON target file. - -[`Target`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html -[`TargetOptions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html -[aborting-on-panic]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/aborting-on-panic.html +- Configure LLVM features. Run `llc -march=ARCH -mattr=help` where ARCH is the base architecture + (not including the version in the case of ARM) to list the available features and their + descriptions. **If your target requires strict memory alignment access (e.g. `armv5te`), make sure + that you enable `strict-align`**. To enable a feature, place a plus before it. Likewise, to + disable a feature, place a minus before it. Features should be comma separated like so: + `"features": "+soft-float,+neon`. Note that this may not be necessary if LLVM knows enough about + your target based on the provided triple and CPU. +- Configure the CPU that LLVM uses if you know it. This will enable CPU-specific optimizations and + features. At the top of the output of the command in the last step, there is a list of known CPUs. + If you know that you will be targeting a specific CPU, you may set it in the `cpu` field in the + JSON target file. + +[`target`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.Target.html +[`targetoptions`]: + https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html +[aborting-on-panic]: + https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/aborting-on-panic.html [built-in-target]: ./compiler-support.md#built-in-target [eh_personality]: ./smallest-no-std.md#eh_personality [libcalls-atomic]: http://llvm.org/docs/Atomics.html#libcalls-atomic @@ -71,9 +114,11 @@ You can pretty much copy that output into your file. Start with a few modificati ## Use the target file -Once you have a target specification file, you may refer to it by its path or by its name (i.e. excluding `.json`) if it is in the current directory or in `$RUST_TARGET_PATH`. +Once you have a target specification file, you may refer to it by its path or by its name (i.e. +excluding `.json`) if it is in the current directory or in `$RUST_TARGET_PATH`. Verify that it is readable by rustc: + ``` sh ❱ rustc --print cfg --target foo.json # or just foo if in the current directory debug_assertions @@ -92,11 +137,18 @@ target_pointer_width="32" target_vendor="" ``` -Now, you finally get to use it! Many resources have been recommending [`xargo`] or [`cargo-xbuild`]. However, its successor, cargo's `build-std` feature, has received a lot of work recently and has quickly reached feature parity with the other options. As such, this guide will only cover that option. +Now, you finally get to use it! Many resources have been recommending [`xargo`] or [`cargo-xbuild`]. +However, its successor, cargo's `build-std` feature, has received a lot of work recently and has +quickly reached feature parity with the other options. As such, this guide will only cover that +option. -Start with a bare minimum [`no_std` program][no_std-program]. Now, run `cargo build -Z build-std=core --target foo.json`, again using the above rules about referencing the path. Hopefully, you should now have a binary in the target directory. +Start with a bare minimum [`no_std` program][no_std-program]. Now, run +`cargo build -Z build-std=core --target foo.json`, again using the above rules about referencing the +path. Hopefully, you should now have a binary in the target directory. -You may optionally configure cargo to always use your target. See the recommendations at the end of the page about [the smallest `no_std` program][no_std-program]. However, you'll currently have to use the flag `-Z build-std=core` as that option is unstable. +You may optionally configure cargo to always use your target. See the recommendations at the end of +the page about [the smallest `no_std` program][no_std-program]. However, you'll currently have to +use the flag `-Z build-std=core` as that option is unstable. [`xargo`]: https://github.com/japaric/xargo [`cargo-xbuild`]: https://github.com/rust-osdev/cargo-xbuild @@ -104,7 +156,10 @@ You may optionally configure cargo to always use your target. See the recommenda ### Build additional built-in crates -When using cargo's `build-std` feature, you can choose which crates to compile in. By default, when only passing `-Z build-std`, `std`, `core`, and `alloc` are compiled. However, you may want to exclude `std` when compiling for bare-metal. To do so, specify the crated you'd like after `build-std`. For example, to include `core` and `alloc`, pass `-Z build-std=core,alloc`. +When using cargo's `build-std` feature, you can choose which crates to compile in. By default, when +only passing `-Z build-std`, `std`, `core`, and `alloc` are compiled. However, you may want to +exclude `std` when compiling for bare-metal. To do so, specify the crated you'd like after +`build-std`. For example, to include `core` and `alloc`, pass `-Z build-std=core,alloc`. ## Troubleshooting @@ -114,18 +169,23 @@ Either add `"panic-strategy": "abort"` to your target file, or define an [eh_per ### undefined reference to `__sync_val_compare_and_swap_#` -Rust thinks that your target has atomic instructions, but LLVM doesn't. Go back to the step about [configuring atomics][fill-target-file]. You will need to reduce the number in `max-atomic-width`. See [#58500] for more details. +Rust thinks that your target has atomic instructions, but LLVM doesn't. Go back to the step about +[configuring atomics][fill-target-file]. You will need to reduce the number in `max-atomic-width`. +See [#58500] for more details. [fill-target-file]: #fill-the-target-file [#58500]: https://github.com/rust-lang/rust/issues/58500 ### could not find `sync` in `alloc` -Similar to the above case, Rust doesn't think that you have atomics. You must implement them yourself or [tell Rust that you have atomic instructions][fill-target-file]. +Similar to the above case, Rust doesn't think that you have atomics. You must implement them +yourself or [tell Rust that you have atomic instructions][fill-target-file]. ### multiple definition of `__(something)` -You're likely linking your Rust program with code built from another language, and the other language includes compiler built-ins that Rust also creates. To fix this, you'll need to tell your linker to allow multiple definitions. If using gcc, you may add: +You're likely linking your Rust program with code built from another language, and the other +language includes compiler built-ins that Rust also creates. To fix this, you'll need to tell your +linker to allow multiple definitions. If using gcc, you may add: ``` json "post-link-args": { @@ -137,6 +197,7 @@ You're likely linking your Rust program with code built from another language, a ### error adding symbols: file format not recognized -Switch to cargo's `build-std` feature and update your compiler. This [was a bug][#8239] introduced for a few compiler builds that tried to pass in internal Rust object to an external linker. +Switch to cargo's `build-std` feature and update your compiler. This [was a bug][#8239] introduced +for a few compiler builds that tried to pass in internal Rust object to an external linker. [#8239]: https://github.com/rust-lang/cargo/issues/8239 diff --git a/src/smallest-no-std.md b/src/smallest-no-std.md index 8833032..cf10906 100644 --- a/src/smallest-no-std.md +++ b/src/smallest-no-std.md @@ -4,8 +4,8 @@ In this section we'll write the smallest `#![no_std]` program that *compiles*. ## What does `#![no_std]` mean? -`#![no_std]` is a crate level attribute that indicates that the crate will link to the [`core`] crate -instead of the [`std`] crate, but what does this mean for applications? +`#![no_std]` is a crate level attribute that indicates that the crate will link to the [`core`] +crate instead of the [`std`] crate, but what does this mean for applications? [`core`]: https://doc.rust-lang.org/core/ [`std`]: https://doc.rust-lang.org/std/ @@ -31,6 +31,7 @@ required. Because of these properties, a `#![no_std]` application can be the first and / or the only code that runs on a system. It can be many things that a standard Rust application can never be, for example: + - The kernel of an OS. - Firmware. - A bootloader. @@ -63,8 +64,8 @@ its entry point. At the time of writing, Rust's `main` interface makes some assu environment the program executes in: For example, it assumes the existence of command line arguments, so in general, it's not appropriate for `#![no_std]` programs. -The `#[panic_handler]` attribute. The function marked with this attribute defines the behavior -of panics, both library level panics (`core::panic!`) and language level panics (out of bounds +The `#[panic_handler]` attribute. The function marked with this attribute defines the behavior of +panics, both library level panics (`core::panic!`) and language level panics (out of bounds indexing). This program doesn't produce anything useful. In fact, it will produce an empty binary. @@ -107,7 +108,11 @@ $ cat .cargo/config ## eh_personality -If your [target][custom-target] does not contain `"panic-strategy": "abort"`, which most targets for full operating systems don't, then you must add an `eh_personality` function, which requires a nightly compiler. [Here is Rust's documentation about it][more-about-lang-items], and [here is some discussion about it][til-why-eh-personality]. A simple implementation that does not do anything special when unwinding is as follows: +If your [target][custom-target] does not contain `"panic-strategy": "abort"`, which most targets for +full operating systems don't, then you must add an `eh_personality` function, which requires a +nightly compiler. [Here is Rust's documentation about it][more-about-lang-items], and [here is some +discussion about it][til-why-eh-personality]. A simple implementation that does not do anything +special when unwinding is as follows: ``` rust #![feature(lang_items)] @@ -117,5 +122,7 @@ extern "C" fn eh_personality() {} ``` [custom-target]: ./custom-target.md -[more-about-lang-items]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#more-about-the-language-items -[til-why-eh-personality]: https://www.reddit.com/r/rust/comments/estvau/til_why_the_eh_personality_language_item_is/ +[more-about-lang-items]: + https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#more-about-the-language-items +[til-why-eh-personality]: + https://www.reddit.com/r/rust/comments/estvau/til_why_the_eh_personality_language_item_is/ From e4393746988e2db7921101eebc92dc8d17369e37 Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:34:03 -0400 Subject: [PATCH 03/11] Fix build --- ci/main/app/app.objdump | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci/main/app/app.objdump b/ci/main/app/app.objdump index 8e27a0f..51d27fc 100644 --- a/ci/main/app/app.objdump +++ b/ci/main/app/app.objdump @@ -12,5 +12,7 @@ main: b #-4 Reset: - bl #-14 + push {r7, lr} + mov r7, sp + bl #-18 trap From 77f46c76c8b0b1ea4a8be0ea62d82a6978e0670e Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:42:45 -0400 Subject: [PATCH 04/11] Fix build --- ci/asm/app/release.objdump | 6 ++++-- ci/asm/app/release.vector_table | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ci/asm/app/release.objdump b/ci/asm/app/release.objdump index a627559..1d6dede 100644 --- a/ci/asm/app/release.objdump +++ b/ci/asm/app/release.objdump @@ -11,7 +11,9 @@ main: trap Reset: - bl #-0x6 + push {r7, lr} + mov r7, sp + bl #-0xa trap DefaultExceptionHandler: @@ -22,4 +24,4 @@ UsageFault: HardFaultTrampoline: mrs r0, msp - b #-0x14 + b #-0x18 diff --git a/ci/asm/app/release.vector_table b/ci/asm/app/release.vector_table index 09d7760..fe5a9fa 100644 --- a/ci/asm/app/release.vector_table +++ b/ci/asm/app/release.vector_table @@ -2,7 +2,7 @@ app: file format ELF32-arm-little Contents of section .vector_table: - 0000 00000120 45000000 4b000000 4d000000 ... E...K...M... - 0010 4b000000 4b000000 4b000000 00000000 K...K...K....... - 0020 00000000 00000000 00000000 4b000000 ............K... - 0030 00000000 00000000 4b000000 4b000000 ........K...K... + 0000 00000120 45000000 4f000000 51000000 ... E...O...Q... + 0010 4f000000 4f000000 4f000000 00000000 O...O...O....... + 0020 00000000 00000000 00000000 4f000000 ............O... + 0030 00000000 00000000 4f000000 4f000000 ........O...O... From c476ab08ddd252753e54ac634f0dee3a0a2a9c6b Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:44:33 -0400 Subject: [PATCH 05/11] Fix formatting --- ci/asm/app/release.objdump | 6 +++--- ci/main/app/app.objdump | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci/asm/app/release.objdump b/ci/asm/app/release.objdump index 1d6dede..68e7902 100644 --- a/ci/asm/app/release.objdump +++ b/ci/asm/app/release.objdump @@ -11,9 +11,9 @@ main: trap Reset: - push {r7, lr} - mov r7, sp - bl #-0xa + push {r7, lr} + mov r7, sp + bl #-0xa trap DefaultExceptionHandler: diff --git a/ci/main/app/app.objdump b/ci/main/app/app.objdump index 51d27fc..f9f8df2 100644 --- a/ci/main/app/app.objdump +++ b/ci/main/app/app.objdump @@ -13,6 +13,6 @@ main: Reset: push {r7, lr} - mov r7, sp - bl #-18 + mov r7, sp + bl #-18 trap From de8d617f1084682b8b4eb51b28b509ea23b0d299 Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:48:28 -0400 Subject: [PATCH 06/11] Fix formatting --- ci/asm/app/release.objdump | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/asm/app/release.objdump b/ci/asm/app/release.objdump index 68e7902..c98c9ee 100644 --- a/ci/asm/app/release.objdump +++ b/ci/asm/app/release.objdump @@ -11,7 +11,7 @@ main: trap Reset: - push {r7, lr} + push {r7, lr} mov r7, sp bl #-0xa trap From 41cbadfc5c8bacbd9072b27205867c3aea6ff3ac Mon Sep 17 00:00:00 2001 From: lights0123 Date: Thu, 18 Jun 2020 11:54:48 -0400 Subject: [PATCH 07/11] Update note about eh_personality --- src/custom-target.md | 5 +++-- src/smallest-no-std.md | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/custom-target.md b/src/custom-target.md index e2a31b4..50d87ec 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -51,8 +51,8 @@ You can pretty much copy that output into your file. Start with a few modificati - Remove `"is-builtin": true` - Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple] - Decide on a panicking strategy. A bare metal implementation will likely use - `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, even if you [tell Cargo - to][aborting-on-panic], you must define an [eh_personality] function. + `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, unless you [tell Cargo + to][eh_personality], you must define an [eh_personality] function. - Configure atomics. Pick the first option that describes your target: - I have a single-core processor, no threads, no interrupts, or any way for multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set @@ -166,6 +166,7 @@ exclude `std` when compiling for bare-metal. To do so, specify the crated you'd ### language item required, but not found: `eh_personality` Either add `"panic-strategy": "abort"` to your target file, or define an [eh_personality] function. +Alternatively, [tell Cargo to ignore it][eh_personality]. ### undefined reference to `__sync_val_compare_and_swap_#` diff --git a/src/smallest-no-std.md b/src/smallest-no-std.md index cf10906..7072c31 100644 --- a/src/smallest-no-std.md +++ b/src/smallest-no-std.md @@ -108,11 +108,24 @@ $ cat .cargo/config ## eh_personality -If your [target][custom-target] does not contain `"panic-strategy": "abort"`, which most targets for -full operating systems don't, then you must add an `eh_personality` function, which requires a -nightly compiler. [Here is Rust's documentation about it][more-about-lang-items], and [here is some -discussion about it][til-why-eh-personality]. A simple implementation that does not do anything -special when unwinding is as follows: +If your configuration does not unconditionally abort on panic, which most targets for full operating +systems don't (or if your [custom target][custom-target] does not contain +`"panic-strategy": "abort"`), then you must tell Cargo to do so or add an `eh_personality` function, +which requires a nightly compiler. [Here is Rust's documentation about it][more-about-lang-items], +and [here is some discussion about it][til-why-eh-personality]. + +In your Cargo.toml, add: + +``` toml +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +``` + +Alternatively, declare the `eh_personality` function. A simple implementation that does not do +anything special when unwinding is as follows: ``` rust #![feature(lang_items)] @@ -121,6 +134,9 @@ special when unwinding is as follows: extern "C" fn eh_personality() {} ``` +You will receive the error `language item required, but not found: 'eh_personality'` if not +included. + [custom-target]: ./custom-target.md [more-about-lang-items]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#more-about-the-language-items From d32abf0ce4ade78e9c6aa6b1f9b30a3910f8b6de Mon Sep 17 00:00:00 2001 From: lights0123 Date: Mon, 6 Jul 2020 12:42:31 -0400 Subject: [PATCH 08/11] Update notes about atomics --- src/custom-target.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/custom-target.md b/src/custom-target.md index 50d87ec..2eda389 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -54,15 +54,15 @@ You can pretty much copy that output into your file. Start with a few modificati `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, unless you [tell Cargo to][eh_personality], you must define an [eh_personality] function. - Configure atomics. Pick the first option that describes your target: - - I have a single-core processor, no threads, no interrupts, or any way for multiple things to be - happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set - `"singlethread": true`. This will configure LLVM to convert all atomic operations to use their - single threaded counterparts. + - I have a single-core processor, no threads, **no interrupts**, or any way for multiple things to + be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may + set `"singlethread": true`. This will configure LLVM to convert all atomic operations to use + their single threaded counterparts. - I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case. - I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the - highest number of bits that you can emulate up to 64, then implement all of the + highest number of bits that you can emulate up to 128, then implement all of the [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while From 5ace0573bf8e8c2bda6ff0c7ebf0b5992b763d33 Mon Sep 17 00:00:00 2001 From: lights0123 Date: Mon, 6 Jul 2020 12:44:52 -0400 Subject: [PATCH 09/11] Add link about atomics --- src/custom-target.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/custom-target.md b/src/custom-target.md index 2eda389..8e59ede 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -54,10 +54,10 @@ You can pretty much copy that output into your file. Start with a few modificati `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, unless you [tell Cargo to][eh_personality], you must define an [eh_personality] function. - Configure atomics. Pick the first option that describes your target: - - I have a single-core processor, no threads, **no interrupts**, or any way for multiple things to - be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may - set `"singlethread": true`. This will configure LLVM to convert all atomic operations to use - their single threaded counterparts. + - I have a single-core processor, no threads, [**no interrupts**][interrupts-note], or any way for + multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM + (for now), you may set `"singlethread": true`. This will configure LLVM to convert all atomic + operations to use their single threaded counterparts. - I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case. @@ -108,6 +108,7 @@ You can pretty much copy that output into your file. Start with a few modificati https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/aborting-on-panic.html [built-in-target]: ./compiler-support.md#built-in-target [eh_personality]: ./smallest-no-std.md#eh_personality +[interrupts-note]: https://github.com/rust-lang/rust/issues/58500#issuecomment-654341233 [libcalls-atomic]: http://llvm.org/docs/Atomics.html#libcalls-atomic [libcalls-sync]: http://llvm.org/docs/Atomics.html#libcalls-sync [gcc-sync]: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html From e4b1afd685cc4a1ac153a45584b34f1c992ee33e Mon Sep 17 00:00:00 2001 From: lights0123 Date: Mon, 6 Jul 2020 12:57:50 -0400 Subject: [PATCH 10/11] More atomics notes --- src/custom-target.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/custom-target.md b/src/custom-target.md index 8e59ede..bb23b3b 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -52,12 +52,13 @@ You can pretty much copy that output into your file. Start with a few modificati - Fill `llvm-target` with [the triple that LLVM expects][llvm-target-triple] - Decide on a panicking strategy. A bare metal implementation will likely use `"panic-strategy": "abort"`. If you decide not to `abort` on panicking, unless you [tell Cargo - to][eh_personality], you must define an [eh_personality] function. + to][eh_personality] per-project, you must define an [eh_personality] function. - Configure atomics. Pick the first option that describes your target: - I have a single-core processor, no threads, [**no interrupts**][interrupts-note], or any way for multiple things to be happening in parallel: if you are **sure** that is the case, such as WASM (for now), you may set `"singlethread": true`. This will configure LLVM to convert all atomic - operations to use their single threaded counterparts. + operations to use their single threaded counterparts. Incorrectly using this option may result + in UB if using threads or interrupts. - I have native atomic operations: set `max-atomic-width` to the biggest type in bits that your target can operate on atomically. For example, many ARM cores have 32-bit atomic operations. You may set `"max-atomic-width": 32` in that case. @@ -66,7 +67,9 @@ You can pretty much copy that output into your file. Start with a few modificati [atomic][libcalls-atomic] and [sync][libcalls-atomic] functions expected by LLVM as `#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while - incorrectly implemented functions will possibly cause UB. + incorrectly implemented functions will possibly cause UB. For example, if you have a + single-core, single-thread processor with interrupts, you can implement these functions to + disable interrupts, perform the regular operation, and then re-enable them. - I have no native atomic operations: you'll have to do some unsafe work to manually ensure synchronization in your code. You must set `"max-atomic-width": 0`. - Change the linker if integrating with an existing toolchain. For example, if you're using a From c0cbfb7f9f8eb1c1d9989e72ca6146816297989d Mon Sep 17 00:00:00 2001 From: Ben Schattinger Date: Mon, 6 Jul 2020 13:52:39 -0400 Subject: [PATCH 11/11] Apply suggestions from code review Co-authored-by: Daniel Egger --- src/custom-target.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/custom-target.md b/src/custom-target.md index bb23b3b..9312e0e 100644 --- a/src/custom-target.md +++ b/src/custom-target.md @@ -6,7 +6,7 @@ that describes your target to rustc. Keep in mind that it is required to use a nightly compiler to build the core library, which must be done for a target unknown to rustc. -## Decide on a target triple +## Deciding on a target triple Many targets already have a known triple used to describe them, typically in the form ARCH-VENDOR-SYS-ABI. You should aim to use the same triple that [LLVM uses][llvm-target-triple]; @@ -19,7 +19,7 @@ example, you would probably use x86_64 for those processors, but specify the exa version. Typical values might be `armv7`, `armv5te`, or `thumbv7neon`. Take a look at the names of the [built-in targets][built-in-target] for inspiration. -The VENDOR part is optional, and describes the manufacturer. Omitting this field is the same as +The VENDOR part is optional and describes the manufacturer. Omitting this field is the same as using `unknown`. The SYS part describes the OS that is used. Typical values include `win32`, `linux`, and `darwin`