diff options
author | 2018-08-07 14:43:28 -0500 | |
---|---|---|
committer | 2018-08-07 15:22:39 -0500 | |
commit | f2c5e2e4058b0a57a1d874878bde67f612b2d9dd (patch) | |
tree | ba2164706a20c1fac83a9118753cd81302724402 | |
parent | 6e5e5ea4597ec6634f5d730b3218f8b71156da40 (diff) | |
download | cortex-m-f2c5e2e4058b0a57a1d874878bde67f612b2d9dd.tar.gz cortex-m-f2c5e2e4058b0a57a1d874878bde67f612b2d9dd.tar.zst cortex-m-f2c5e2e4058b0a57a1d874878bde67f612b2d9dd.zip |
refactor the linker script
to make it more compatible with LLD. This commit contains no functional changes.
fixes #70
Overview of changes:
- Alignment checks are enabled now that rust-lld (LLD 7.0) supports the modulo
operator.
- Removed some private symbols (e.g. __foo) in favor of ADDR and SIZEOF.
- Turned .got into a NOLOAD section now that rust-lld supports it.
- Replaced `ABSOLUTE(.)` with `.` as an old LLD overlap bug seems to be gone and
ABSOLUTE seems to cause problems, like #70, on bigger programs.
- Made the linker assertion messages more uniform.
- Extended test suite to check that linking works with both rust-lld and GNU
LD.
-rw-r--r-- | cortex-m-rt/Cargo.toml | 1 | ||||
-rw-r--r-- | cortex-m-rt/build.rs | 8 | ||||
-rw-r--r-- | cortex-m-rt/ci/script.sh | 25 | ||||
-rw-r--r-- | cortex-m-rt/examples/alignment.rs | 45 | ||||
-rw-r--r-- | cortex-m-rt/link.x.in | 160 |
5 files changed, 149 insertions, 90 deletions
diff --git a/cortex-m-rt/Cargo.toml b/cortex-m-rt/Cargo.toml index 1b7427c..9cd9d19 100644 --- a/cortex-m-rt/Cargo.toml +++ b/cortex-m-rt/Cargo.toml @@ -17,6 +17,7 @@ r0 = "0.2.1" [dev-dependencies] panic-semihosting = "0.3.0" +panic-abort = "0.2.0" [features] device = [] diff --git a/cortex-m-rt/build.rs b/cortex-m-rt/build.rs index 8edba9f..fc53d79 100644 --- a/cortex-m-rt/build.rs +++ b/cortex-m-rt/build.rs @@ -42,12 +42,12 @@ INCLUDE device.x"# writeln!( f, r#" -ASSERT(__einterrupts - __eexceptions <= 0x{:x}, " -There can't be more than {} interrupt handlers. This may be a bug in -your device crate, or you may have registered more than 240 interrupt +ASSERT(SIZEOF(.vector_table) <= 0x{:x}, " +There can't be more than {1} interrupt handlers. This may be a bug in +your device crate, or you may have registered more than {1} interrupt handlers."); "#, - max_int_handlers * 4, + max_int_handlers * 4 + 0x40, max_int_handlers ).unwrap(); diff --git a/cortex-m-rt/ci/script.sh b/cortex-m-rt/ci/script.sh index 221386d..2515b8f 100644 --- a/cortex-m-rt/ci/script.sh +++ b/cortex-m-rt/ci/script.sh @@ -6,11 +6,13 @@ main() { cargo check --target $TARGET --features device local examples=( + alignment minimal main state ) if [ $TRAVIS_RUST_VERSION = nightly ]; then + # linking with GNU LD for ex in "${examples[@]}"; do cargo rustc --target $TARGET --example $ex -- \ -C link-arg=-nostartfiles \ @@ -28,6 +30,29 @@ main() { cargo rustc --target $TARGET --example device --features device --release -- \ -C link-arg=-nostartfiles \ -C link-arg=-Wl,-Tlink.x + + # linking with rustc's LLD + for ex in "${examples[@]}"; do + cargo rustc --target $TARGET --example $ex -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x + + cargo rustc --target $TARGET --example $ex --release -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x + done + + cargo rustc --target $TARGET --example device --features device -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x + + cargo rustc --target $TARGET --example device --features device --release -- \ + -C linker=rust-lld \ + -Z linker-flavor=ld.lld \ + -C link-arg=-Tlink.x fi } diff --git a/cortex-m-rt/examples/alignment.rs b/cortex-m-rt/examples/alignment.rs new file mode 100644 index 0000000..ef1beaa --- /dev/null +++ b/cortex-m-rt/examples/alignment.rs @@ -0,0 +1,45 @@ +//! This is not an example; this is a link-pass test + +#![deny(warnings)] +#![no_main] +#![no_std] + +#[macro_use(entry, exception)] +extern crate cortex_m_rt as rt; +extern crate panic_abort; + +use core::ptr; + +use rt::ExceptionFrame; + +entry!(main); + +static mut BSS1: u16 = 0; +static mut BSS2: u8 = 0; +static mut DATA1: u8 = 1; +static mut DATA2: u16 = 1; +static RODATA1: &[u8; 3] = b"012"; +static RODATA2: &[u8; 2] = b"34"; + +fn main() -> ! { + unsafe { + let _bss1 = ptr::read_volatile(&BSS1); + let _bss2 = ptr::read_volatile(&BSS2); + let _data1 = ptr::read_volatile(&DATA1); + let _data2 = ptr::read_volatile(&DATA2); + let _rodata1 = ptr::read_volatile(&RODATA1); + let _rodata2 = ptr::read_volatile(&RODATA2); + } + + loop {} +} + +exception!(HardFault, hard_fault); + +fn hard_fault(_ef: &ExceptionFrame) -> ! { + loop {} +} + +exception!(*, default_handler); + +fn default_handler(_irqn: i16) {} diff --git a/cortex-m-rt/link.x.in b/cortex-m-rt/link.x.in index 9b99427..5df965a 100644 --- a/cortex-m-rt/link.x.in +++ b/cortex-m-rt/link.x.in @@ -48,87 +48,86 @@ PROVIDE(SysTick = DefaultHandler); /* # Interrupt vectors */ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ -/* # User overridable symbols I */ -/* Lets the user place the stack in a different RAM region */ -PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); - /* # Sections */ SECTIONS { + PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); + /* ## Sections in FLASH */ /* ### Vector table */ - .vector_table ORIGIN(FLASH) : ALIGN(4) + .vector_table ORIGIN(FLASH) : { /* Initial Stack Pointer (SP) value */ - __STACK_START = .; /* Just to get a nicer name in the disassembly */ LONG(_stack_start); /* Reset vector */ - KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */ - __reset_vector = ABSOLUTE(.); + KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ + __reset_vector = .; /* Exceptions */ - KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */ - __eexceptions = ABSOLUTE(.); + KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ + __eexceptions = .; /* Device specific interrupts */ - KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */ - __einterrupts = ABSOLUTE(.); + KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ } > FLASH + PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); + /* ### .text */ .text _stext : { *(.text .text.*); - __etext = ABSOLUTE(.); } > FLASH /* ### .rodata */ .rodata : { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - /* __srodata = ABSOLUTE(.); */ - *(.rodata .rodata.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __erodata = ABSOLUTE(.); + /* 4-byte align the end (VMA) of this section */ + /* WHY? To my knowledge there's no way to indicate the alignment of *LMA* so we align *this* + section with the goal of using its end address as the LMA of .data */ + . = ALIGN(4); } > FLASH /* ## Sections in RAM */ /* ### .data */ - .data : AT(__erodata) /* LMA */ + .data : AT(ADDR(.rodata) + SIZEOF(.rodata)) /* LMA */ { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - __sdata = ABSOLUTE(.); - *(.data .data.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __edata = ABSOLUTE(.); } > RAM + /* VMA of .data */ + __sdata = ADDR(.data); + __edata = ADDR(.data) + SIZEOF(.data); + + /* LMA of .data */ + __sidata = LOADADDR(.data); + /* ### .bss */ .bss : { - . = ALIGN(4); /* 4-byte align the start (VMA) of this section */ - __sbss = ABSOLUTE(.); - *(.bss .bss.*); . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __ebss = ABSOLUTE(.); } > RAM - /* ## Fake output .got section */ + __sbss = ADDR(.bss); + __ebss = ADDR(.bss) + SIZEOF(.bss); + + /* Place the heap right after `.bss` */ + __sheap = ADDR(.bss) + SIZEOF(.bss); + + /* ## .got */ /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in the input files and raise an error if relocatable code is found */ - .got : + .got (NOLOAD) : { - __sgot = ABSOLUTE(.); KEEP(*(.got .got.*)); - __egot = ABSOLUTE(.); - } > FLASH + } /* ## Discarded sections */ /DISCARD/ : @@ -138,67 +137,56 @@ SECTIONS } } -/* # User overridable symbols II */ -/* (The user overridable symbols are split in two parts because LLD demands that the RHS of PROVIDE - to be defined before the PROVIDE invocation) */ -/* Lets the user override this to place .text a bit further than the vector table. Required by -microcontrollers that store their configuration right after the vector table. */ -PROVIDE(_stext = __einterrupts); +/* Do not exceed this mark in the error messages below | */ +/* # Alignment checks */ +ASSERT(ORIGIN(FLASH) % 4 == 0, " +ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); -/* # Hardcoded symbols */ -/* Place `.bss` at the start of the RAM region */ -__sidata = LOADADDR(.data); -/* Place the heap right after `.bss` and `.data` */ -__sheap = __ebss; +ASSERT(ORIGIN(RAM) % 4 == 0, " +ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); -/* # Sanity checks */ +ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " +BUG(cortex-m-rt): .data is not 4-byte aligned"); -/* Do not exceed this mark in the error messages below | */ -ASSERT(__reset_vector == ORIGIN(FLASH) + 0x8, " -cortex-m-rt: The reset vector is missing. This is a bug in cortex-m-rt. Please file a bug -report at: https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__eexceptions - ORIGIN(FLASH) == 0x40, " -cortex-m-rt: The exception vectors are missing. This is a bug in cortex-m-rt. Please file -a bug report at: https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__sheap >= __ebss, " -cortex-m-rt: The heap overlaps with the .bss section. This is a bug in cortex-m-rt. Please -file a bug report at: https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__sheap >= __edata, " -cortex-m-rt: The heap overlaps with the .data section. This is a bug in cortex-m-rt. -Please file a bug report at: https://github.com/japaric/cortex-m-rt/issues"); - -ASSERT(__einterrupts - __eexceptions > 0, " -cortex-m-rt: The interrupt vectors are missing. Possible solutions, from most likely to -less likely: -- Link to a device crate -- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency - may be enabling it) -- Supply the interrupt handlers yourself. Check the documentation for details."); +ASSERT(__sidata % 4 == 0, " +BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " +BUG(cortex-m-rt): .bss is not 4-byte aligned"); -ASSERT(__einterrupts <= _stext, " -cortex-m-rt: The '.text' section can't be placed inside the '.vector_table' section. Set -'_stext' to an address greater than '__einterrupts' (cf. `nm` output)"); +ASSERT(__sheap % 4 == 0, " +BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); -ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), " -cortex-m-rt The '.text' section must be placed inside the FLASH memory. Set '_stext' to an -address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)"); +/* # Position checks */ -/* This has been temporarily omitted because it's not supported by LLD */ -/* ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " */ -/* .bss is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ +/* ## .vector_table */ +ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " +BUG(cortex-m-rt): the reset vector is missing"); -/* ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " */ -/* .data is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */ +ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " +BUG(cortex-m-rt): the exception vectors are missing"); -/* ASSERT(__sidata % 4 == 0, " */ -/* __sidata is not 4-byte aligned. This is a cortex-m-rt bug."); */ +ASSERT(SIZEOF(.vector_table) > 0x40, " +ERROR(cortex-m-rt): The interrupt vectors are missing. +Possible solutions, from most likely to less likely: +- Link to a svd2rust generated device crate +- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency +may be enabling it) +- Supply the interrupt handlers yourself. Check the documentation for details."); -ASSERT(__sgot == __egot, " -.got section detected in the input object files. Dynamic relocations are not supported. -If you are linking to C code compiled using the `cc` crate then modify your build script -to compile the C code _without_ the -fPIC flag. See the documentation of the -`cc::Build.pic` method for details."); +/* ## .text */ +ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " +ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section +Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); + +ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " +ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. +Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); + +/* # Other checks */ +ASSERT(SIZEOF(.got) == 0, " +ERROR(cortex-m-rt): .got section detected in the input object files +Dynamic relocations are not supported. If you are linking to C code compiled using +the 'cc' crate then modify your build script to compile the C code _without_ +the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); /* Do not exceed this mark in the error messages above | */ |