diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e2abdc..c2a70457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.4.0] - 2018-04-09 + +### Added + +- LLD support. The linker script provided by this crate has been tweaked to support both LLD and GNU + LD. To use LLD as a linker change `.cargo/config` to look like this: + +``` diff + [target.thumbv7m-none-eabi] + rustflags = [ + "-C", "link-arg=-Tlink.x", +- "-C", "linker=arm-none-eabi-ld", +- "-Z", "linker-flavor=ld", ++ "-C", "linker=lld", ++ "-Z", "linker-flavor=ld.lld", + ] +``` + +### Removed + +- [breaking-change] Stack overflow protection has been removed. Unfortunately, supporting this + feature produces totally wrong `arm-none-eabi-size` reports when LLD is used to link the + program. If you need the stack overflow protection feature you can continue to use version + v0.3.13+. + +- [breaking-change] The "abort-on-panic" Cargo feature, which provided a `panic_fmt` implementation, + has been removed. If you were using this feature you can instead use a [panic implementation + crate][panic-impl]. + +[panic-impl]: https://crates.io/keywords/panic-impl + ## [v0.3.15] - 2018-04-08 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 1b619171..cd31b2db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,16 +7,8 @@ keywords = ["arm", "cortex-m", "runtime", "startup"] license = "MIT OR Apache-2.0" name = "cortex-m-rt" repository = "https://github.com/japaric/cortex-m-rt" -version = "0.3.15" +version = "0.4.0" [dependencies] cortex-m = "0.3.0" -r0 = "0.2.1" - -[features] -# provides a panic_fmt implementation that calls the abort instruction (`udf 0xfe`) -abort-on-panic = [] - -[build-dependencies] -rustc_version = "0.2.1" -chrono = "0.4.0" +r0 = "0.2.1" \ No newline at end of file diff --git a/build.rs b/build.rs index c1028c4e..1d0160c0 100644 --- a/build.rs +++ b/build.rs @@ -1,28 +1,9 @@ -extern crate chrono; -extern crate rustc_version; - use std::env; use std::fs::File; use std::io::Write; use std::path::PathBuf; -use chrono::NaiveDate; - fn main() { - let meta = rustc_version::version_meta().unwrap(); - let commit_date = meta.commit_date.unwrap().parse::().unwrap(); - if meta.channel == rustc_version::Channel::Dev - || commit_date > NaiveDate::from_ymd(2017, 12, 26) - { - println!("cargo:rustc-cfg=has_termination_lang") - } - - // newest nightlies don't need 'extern crate compiler_builtins' - if commit_date < NaiveDate::from_ymd(2018, 04, 07) - { - println!("cargo:rustc-cfg=needs_cb") - } - let target = env::var("TARGET").unwrap(); has_fpu(&target); diff --git a/link.x b/link.x index 4eaa8bea..7e398dee 100644 --- a/link.x +++ b/link.x @@ -48,27 +48,16 @@ SECTIONS . = ALIGN(4); } > FLASH - /* limits of the .stack region */ - _estack = _stack_start; - /* HACK the `true` case indicates that two RAM regions are being used and - /* that the stack was placed in the second region. In that case we don't know - /* the size of the second RAM region, or its start address, so we just assume - /* its zero sized */ - _sstack = _stack_start < ORIGIN(RAM)? _stack_start : ORIGIN(RAM); - - /* fictitious region that represents the memory available for the stack */ - .stack _sstack (INFO) : ALIGN(4) - { - . += (_estack - _sstack); - } - PROVIDE(_sbss = ORIGIN(RAM)); .bss _sbss : ALIGN(4) { *(.bss .bss.*); . = ALIGN(4); _ebss = .; - } > RAM + } > RAM AT > FLASH + /* NOTE(AT > FLASH) without this LLD v6 produces a binary that crashes OpenOCD whereas LLD v7 + emits a ".rodata and .bss sections overlap" error ... This hacky workaround doesn't increase + the binary size AFAICT */ .data : ALIGN(4) { @@ -79,16 +68,8 @@ SECTIONS _edata = .; } > RAM AT > FLASH - PROVIDE(_heap_size = 0); - + /* The heap starts right after the .bss + .data section ends */ _sheap = _edata; - _eheap = _sheap + _heap_size; - - /* fictitious region that represents the memory available for the heap */ - .heap _sheap (INFO) : ALIGN(4) - { - . += _heap_size; - } /* fake output .got section */ /* Dynamic relocations are unsupported. This section is only used to detect @@ -101,26 +82,9 @@ SECTIONS _egot = .; } > RAM AT > FLASH - /* The heap starts right after the .bss + .data section ends */ - _sheap = _edata; - - /* Due to an unfortunate combination of legacy concerns, - toolchain drawbacks, and insufficient attention to detail, - rustc has no choice but to mark .debug_gdb_scripts as allocatable. - We really do not want to upload it to our target, so we - remove the allocatable bit. Unfortunately, it appears - that the only way to do this in a linker script is - the extremely obscure "INFO" output section type specifier. */ - /* a rustc hack will force the program to read the first byte of this section, - so we'll set the (fake) start address of this section to something we're - sure can be read at runtime: the start of the .text section */ - .debug_gdb_scripts _stext (INFO) : { - KEEP(*(.debug_gdb_scripts)) - } - /DISCARD/ : { - *(.ARM.exidx.*) + *(.ARM.exidx.*); } } diff --git a/src/lang_items.rs b/src/lang_items.rs index f3750a09..571a8a50 100644 --- a/src/lang_items.rs +++ b/src/lang_items.rs @@ -1,10 +1,3 @@ -/// Default panic handler -#[cfg(feature = "abort-on-panic")] -#[lang = "panic_fmt"] -unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32, _: u32) -> ! { - ::core::intrinsics::abort() -} - // Lang item required to make the normal `main` work in applications // // This is how the `start` lang item works: @@ -24,7 +17,6 @@ unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u3 // The final piece is that the entry point of our program, the reset handler, // has to call `rustc_main`. That's covered by the `reset_handler` function in // root of this crate. -#[cfg(has_termination_lang)] #[lang = "start"] extern "C" fn start(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -35,21 +27,11 @@ where 0 } -#[cfg(not(has_termination_lang))] -#[lang = "start"] -extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { - main(); - - 0 -} - #[lang = "termination"] -#[cfg(has_termination_lang)] pub trait Termination { fn report(self) -> i32; } -#[cfg(has_termination_lang)] impl Termination for () { fn report(self) -> i32 { 0 diff --git a/src/lib.rs b/src/lib.rs index 06ee5514..7028cce5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,11 +8,6 @@ //! //! - Before main initialization of the FPU (for targets that have a FPU). //! -//! - A `panic_fmt` implementation that just calls abort that you can opt into -//! through the "abort-on-panic" Cargo feature. If you don't use this feature -//! you'll have to provide the `panic_fmt` lang item yourself. Documentation -//! [here](https://doc.rust-lang.org/unstable-book/language-features/lang-items.html) -//! //! - A minimal `start` lang item to support the standard `fn main()` //! interface. (The processor goes to sleep (`loop { asm!("wfi") }`) after //! returning from `main`) @@ -31,8 +26,6 @@ //! //! - A `_sheap` symbol at whose address you can locate a heap. //! -//! - Zero cost stack overflow protection when using the `cortex-m-rt-ld` linker. -//! //! # Example //! //! Creating a new bare metal project. (I recommend you use the @@ -43,19 +36,10 @@ //! $ cargo new --bin app && cd $_ //! //! $ # add this crate as a dependency -//! $ $EDITOR Cargo.toml && tail $_ -//! [dependencies.cortex-m-rt] -//! features = ["abort-on-panic"] -//! version = "0.3.0" +//! $ cargo add cortex-m-rt --vers 0.4.0 //! -//! $ # tell Xargo which standard crates to build -//! $ $EDITOR Xargo.toml && cat $_ -//! [dependencies.core] -//! stage = 0 -//! -//! [dependencies.compiler_builtins] -//! features = ["mem"] -//! stage = 1 +//! $ # select a panicking behavior (look for the panic-impl keyword on crates.io) +//! $ cargo add panic-abort //! //! $ # memory layout of the device //! $ $EDITOR memory.x && cat $_ @@ -74,6 +58,7 @@ //! #![no_std] //! //! extern crate cortex_m_rt; +//! extern crate panic_abort; // panicking behavior //! //! fn main() { //! // do something here @@ -91,9 +76,9 @@ //! ``` //! //! ``` text -//! $ cargo install xargo +//! $ rustup target add thumbv7m-none-eabi //! -//! $ xargo rustc --target thumbv7m-none-eabi -- \ +//! $ cargo rustc --target thumbv7m-none-eabi -- \ //! -C link-arg=-Tlink.x -C linker=arm-none-eabi-ld -Z linker-flavor=ld //! //! $ arm-none-eabi-objdump -Cd $(find target -name app) | head @@ -112,195 +97,10 @@ //! .vector_table 0x400 0x8000000 //! .text 0x24a 0x8000400 //! .rodata 0x0 0x800064c -//! .stack 0x2000 0x20000000 //! .bss 0x0 0x20000000 //! .data 0x0 0x20000000 //! ``` //! -//! ## Zero cost stack overflow protection -//! -//! Consider the following variation of the previous program: -//! -//! ``` ignore -//! extern crate cortex_m_rt; -//! -//! const N: usize = 256; -//! static mut XS: [u32; N] = [0; N]; -//! -//! fn main() { -//! #[inline(never)] -//! fn fib(n: u32) -> u32 { -//! unsafe { assert!(XS.iter().all(|x| *x == 0)) } -//! -//! if n < 2 { -//! 1 -//! } else { -//! fib(n - 1) + fib(n - 2) -//! } -//! } -//! -//! let x = fib(400); -//! unsafe { *XS.iter_mut().first().unwrap() = x } -//! } -//! ``` -//! -//! This program allocates a 1KB array in `.bss`, recursively computes the 400th fibonacci number -//! and stores the result in the head of the array. This program will hit a stack overflow at -//! runtime because there's not enough memory to recursively call the `fib` function so many times. -//! -//! If you inspect the program using GDB you'll see that the assertion failed after `fib` was nested -//! around 300 times. -//! -//! ``` console -//! > continue -//! Program received signal SIGTRAP, Trace/breakpoint trap. -//! -//! > backtrace -//! #0 0x08000516 in cortex_m_rt::default_handler () -//! #1 -//! #2 0x0800050a in rust_begin_unwind () -//! #3 0x08000586 in core::panicking::panic_fmt () -//! #4 0x0800055c in core::panicking::panic () -//! #5 0x080004f6 in app::main::fib () -//! #6 0x080004a0 in app::main::fib () -//! (..) -//! #301 0x080004a0 in app::main::fib () -//! #302 0x080004a0 in app::main::fib () -//! #303 0x08000472 in app::main () -//! #304 0x08000512 in cortex_m_rt::lang_items::start () -//! #305 0x08000460 in cortex_m_rt::reset_handler () -//! ``` -//! -//! What this means is that the stack grew so much that it crashed into the `.bss` section and -//! overwrote the memory in there. Continuing the GDB session you can confirm that the `XS` variable -//! has been modified: -//! -//! ``` console -//! > x/4 0x20000000 # start of .bss -//! 0x20000000 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! -//! > x/4 0x200003f0 # end of .bss -//! 0x200003f0 : 0x20000400 0x080004f5 0x00000000 0x00000001 -//! ``` -//! -//! The problem is that the stack is growing towards the `.bss` section and both sections overlap as -//! shown below: -//! -//! ``` console -//! $ arm-none-eabi-size -Ax $(find target -name app) -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x186 0x8000400 -//! .rodata 0x50 0x8000590 -//! .stack 0x2000 0x20000000 -//! .bss 0x400 0x20000000 -//! .data 0x0 0x20000400 -//! ``` -//! -//! Graphically the RAM sections look like this: -//! -//!

-//! Stack overflow -//!

-//! -//! To prevent memory corruption due to stack overflows in this scenario it suffices to switch the -//! sections so that the `.bss` section is near the end of the RAM region and the `.stack` comes -//! *before* `.bss`, at a lower address. -//! -//! To swap the sections you can use the [`cortex-m-rt-ld`] linker to link the program. -//! -//! ``` console -//! $ cargo install cortex-m-rt-ld -//! -//! $ xargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld -//! ``` -//! -//! Now you get non overlapping linker sections: -//! -//! ``` console -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x186 0x8000400 -//! .rodata 0x50 0x8000590 -//! .stack 0x1c00 0x20000000 -//! .bss 0x400 0x20001c00 -//! .data 0x0 0x20002000 -//! ``` -//! -//! Note that the `.stack` section is smaller now. Graphically, the memory layout now looks like -//! this: -//! -//!

-//! Swapped sections -//!

-//! -//! On stack overflows `.stack` will hit the lower boundary of the RAM region raising a hard fault -//! exception, instead of silently corrupting the `.bss` section. -//! -//! You can confirm this by inspecting the program in GDB. -//! -//! ``` console -//! > continue -//! Program received signal SIGTRAP, Trace/breakpoint trap. -//! -//! > p $sp -//! $1 = (void *) 0x1ffffff0 -//! ``` -//! -//! The failure mode this time was the `.stack` crashing into the RAM boundary. The variable `XS` is -//! unaffected this time: -//! -//! ``` console -//! > x/4x app::XS -//! 0x20001c00 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! -//! > x/4x app::XS+252 -//! 0x20001ff0 : 0x00000000 0x00000000 0x00000000 0x00000000 -//! ``` -//! -//! ## `.heap` -//! -//! If your program makes use of a `.heap` section a similar problem can occur: -//! -//!

-//! Memory layout when `.heap` exists -//!

-//! -//! The `.stack` can crash into the `.heap`, or vice versa, and you'll also get memory corruption. -//! -//! `cortex-m-rt-ld` can also be used in this case but the size of the `.heap` section must be -//! specified via the `_heap_size` symbol in `memory.x`, or in any other linker script. -//! -//! ``` console -//! $ $EDITOR memory.x && tail -n1 $_ -//! _heap_size = 0x400; -//! ``` -//! -//! ``` console -//! $ xargo rustc --target thumbv7m-none-eabi -- \ -//! -C link-arg=-Tlink.x -C linker=cortex-m-rt-ld -Z linker-flavor=ld -//! -//! $ arm-none-eabi-size -Ax $(find target -name app) | head -//! section size addr -//! .vector_table 0x400 0x8000000 -//! .text 0x1a8 0x8000400 -//! .rodata 0x50 0x80005b0 -//! .stack 0x1800 0x20000000 -//! .bss 0x400 0x20001800 -//! .data 0x0 0x20001c00 -//! .heap 0x400 0x20001c00 -//! ``` -//! -//! Graphically the memory layout looks like this: -//! -//!

-//! Swapped sections when `.heap` exists -//!

-//! -//! Now both stack overflows and dynamic memory over-allocations (OOM) will generate hard fault -//! exceptions, instead of running into each other. -//! //! # Symbol interfaces //! //! This crate makes heavy use of symbols, linker sections and linker scripts to @@ -351,7 +151,7 @@ //! #[linkage = "weak"] //! #[naked] //! #[no_mangle] -//! extern "C" fn WWDG() { +//! extern "C" fn PVD() { //! unsafe { //! asm!("b DEFAULT_HANDLER" :::: "volatile"); //! core::intrinsics::unreachable(); @@ -423,10 +223,6 @@ //! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM); //! ``` //! -//! ### `_heap_size` -//! -//! The size of the `.heap` section. Only meaningful when using `cortex-m-rt-ld`. -//! //! ### `_stext` //! //! This symbol indicates where the `.text` section will be located. If not @@ -472,20 +268,14 @@ //! } //! ``` //! -//! *NOTE* if you are using `cortex-m-rt-ld` and/or have defined the `_heap_size` symbol then you should -//! use the address of the `_eheap` to compute the size of the `.heap` section, instead of -//! duplicating the value that you wrote in `memory.x`. -//! //! [1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html //! [qs]: https://docs.rs/cortex-m-quickstart/0.2.0/cortex_m_quickstart/ -//! [`cortex-m-rt-ld`]: https://crates.io/crates/cortex-m-rt-ld //! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html -#![cfg_attr(any(target_arch = "arm", feature = "abort-on-panic"), feature(core_intrinsics))] #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] -#![cfg_attr(needs_cb, feature(compiler_builtins_lib))] +#![feature(core_intrinsics)] #![feature(global_asm)] #![feature(lang_items)] #![feature(linkage)] @@ -493,8 +283,6 @@ #![feature(used)] #![no_std] -#[cfg(needs_cb)] -extern crate compiler_builtins; #[cfg(target_arch = "arm")] extern crate cortex_m; #[cfg(target_arch = "arm")]