Skip to content

Commit f2c5e2e

Browse files
committed
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.
1 parent 6e5e5ea commit f2c5e2e

File tree

5 files changed

+149
-90
lines changed

5 files changed

+149
-90
lines changed

cortex-m-rt/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ r0 = "0.2.1"
1717

1818
[dev-dependencies]
1919
panic-semihosting = "0.3.0"
20+
panic-abort = "0.2.0"
2021

2122
[features]
2223
device = []

cortex-m-rt/build.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ INCLUDE device.x"#
4242
writeln!(
4343
f,
4444
r#"
45-
ASSERT(__einterrupts - __eexceptions <= 0x{:x}, "
46-
There can't be more than {} interrupt handlers. This may be a bug in
47-
your device crate, or you may have registered more than 240 interrupt
45+
ASSERT(SIZEOF(.vector_table) <= 0x{:x}, "
46+
There can't be more than {1} interrupt handlers. This may be a bug in
47+
your device crate, or you may have registered more than {1} interrupt
4848
handlers.");
4949
"#,
50-
max_int_handlers * 4,
50+
max_int_handlers * 4 + 0x40,
5151
max_int_handlers
5252
).unwrap();
5353

cortex-m-rt/ci/script.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ main() {
66
cargo check --target $TARGET --features device
77

88
local examples=(
9+
alignment
910
minimal
1011
main
1112
state
1213
)
1314
if [ $TRAVIS_RUST_VERSION = nightly ]; then
15+
# linking with GNU LD
1416
for ex in "${examples[@]}"; do
1517
cargo rustc --target $TARGET --example $ex -- \
1618
-C link-arg=-nostartfiles \
@@ -28,6 +30,29 @@ main() {
2830
cargo rustc --target $TARGET --example device --features device --release -- \
2931
-C link-arg=-nostartfiles \
3032
-C link-arg=-Wl,-Tlink.x
33+
34+
# linking with rustc's LLD
35+
for ex in "${examples[@]}"; do
36+
cargo rustc --target $TARGET --example $ex -- \
37+
-C linker=rust-lld \
38+
-Z linker-flavor=ld.lld \
39+
-C link-arg=-Tlink.x
40+
41+
cargo rustc --target $TARGET --example $ex --release -- \
42+
-C linker=rust-lld \
43+
-Z linker-flavor=ld.lld \
44+
-C link-arg=-Tlink.x
45+
done
46+
47+
cargo rustc --target $TARGET --example device --features device -- \
48+
-C linker=rust-lld \
49+
-Z linker-flavor=ld.lld \
50+
-C link-arg=-Tlink.x
51+
52+
cargo rustc --target $TARGET --example device --features device --release -- \
53+
-C linker=rust-lld \
54+
-Z linker-flavor=ld.lld \
55+
-C link-arg=-Tlink.x
3156
fi
3257
}
3358

cortex-m-rt/examples/alignment.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//! This is not an example; this is a link-pass test
2+
3+
#![deny(warnings)]
4+
#![no_main]
5+
#![no_std]
6+
7+
#[macro_use(entry, exception)]
8+
extern crate cortex_m_rt as rt;
9+
extern crate panic_abort;
10+
11+
use core::ptr;
12+
13+
use rt::ExceptionFrame;
14+
15+
entry!(main);
16+
17+
static mut BSS1: u16 = 0;
18+
static mut BSS2: u8 = 0;
19+
static mut DATA1: u8 = 1;
20+
static mut DATA2: u16 = 1;
21+
static RODATA1: &[u8; 3] = b"012";
22+
static RODATA2: &[u8; 2] = b"34";
23+
24+
fn main() -> ! {
25+
unsafe {
26+
let _bss1 = ptr::read_volatile(&BSS1);
27+
let _bss2 = ptr::read_volatile(&BSS2);
28+
let _data1 = ptr::read_volatile(&DATA1);
29+
let _data2 = ptr::read_volatile(&DATA2);
30+
let _rodata1 = ptr::read_volatile(&RODATA1);
31+
let _rodata2 = ptr::read_volatile(&RODATA2);
32+
}
33+
34+
loop {}
35+
}
36+
37+
exception!(HardFault, hard_fault);
38+
39+
fn hard_fault(_ef: &ExceptionFrame) -> ! {
40+
loop {}
41+
}
42+
43+
exception!(*, default_handler);
44+
45+
fn default_handler(_irqn: i16) {}

cortex-m-rt/link.x.in

Lines changed: 74 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -48,87 +48,86 @@ PROVIDE(SysTick = DefaultHandler);
4848
/* # Interrupt vectors */
4949
EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
5050

51-
/* # User overridable symbols I */
52-
/* Lets the user place the stack in a different RAM region */
53-
PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
54-
5551
/* # Sections */
5652
SECTIONS
5753
{
54+
PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
55+
5856
/* ## Sections in FLASH */
5957
/* ### Vector table */
60-
.vector_table ORIGIN(FLASH) : ALIGN(4)
58+
.vector_table ORIGIN(FLASH) :
6159
{
6260
/* Initial Stack Pointer (SP) value */
63-
__STACK_START = .; /* Just to get a nicer name in the disassembly */
6461
LONG(_stack_start);
6562

6663
/* Reset vector */
67-
KEEP(*(.vector_table.reset_vector)); /* this is `__RESET_VECTOR` symbol */
68-
__reset_vector = ABSOLUTE(.);
64+
KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
65+
__reset_vector = .;
6966

7067
/* Exceptions */
71-
KEEP(*(.vector_table.exceptions)); /* this is `__EXCEPTIONS` symbol */
72-
__eexceptions = ABSOLUTE(.);
68+
KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
69+
__eexceptions = .;
7370

7471
/* Device specific interrupts */
75-
KEEP(*(.vector_table.interrupts)); /* this is `__INTERRUPTS` symbol */
76-
__einterrupts = ABSOLUTE(.);
72+
KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
7773
} > FLASH
7874

75+
PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
76+
7977
/* ### .text */
8078
.text _stext :
8179
{
8280
*(.text .text.*);
83-
__etext = ABSOLUTE(.);
8481
} > FLASH
8582

8683
/* ### .rodata */
8784
.rodata :
8885
{
89-
. = ALIGN(4); /* 4-byte align the start (VMA) of this section */
90-
/* __srodata = ABSOLUTE(.); */
91-
9286
*(.rodata .rodata.*);
9387

94-
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
95-
__erodata = ABSOLUTE(.);
88+
/* 4-byte align the end (VMA) of this section */
89+
/* WHY? To my knowledge there's no way to indicate the alignment of *LMA* so we align *this*
90+
section with the goal of using its end address as the LMA of .data */
91+
. = ALIGN(4);
9692
} > FLASH
9793

9894
/* ## Sections in RAM */
9995
/* ### .data */
100-
.data : AT(__erodata) /* LMA */
96+
.data : AT(ADDR(.rodata) + SIZEOF(.rodata)) /* LMA */
10197
{
102-
. = ALIGN(4); /* 4-byte align the start (VMA) of this section */
103-
__sdata = ABSOLUTE(.);
104-
10598
*(.data .data.*);
10699

107100
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
108-
__edata = ABSOLUTE(.);
109101
} > RAM
110102

103+
/* VMA of .data */
104+
__sdata = ADDR(.data);
105+
__edata = ADDR(.data) + SIZEOF(.data);
106+
107+
/* LMA of .data */
108+
__sidata = LOADADDR(.data);
109+
111110
/* ### .bss */
112111
.bss :
113112
{
114-
. = ALIGN(4); /* 4-byte align the start (VMA) of this section */
115-
__sbss = ABSOLUTE(.);
116-
117113
*(.bss .bss.*);
118114

119115
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
120-
__ebss = ABSOLUTE(.);
121116
} > RAM
122117

123-
/* ## Fake output .got section */
118+
__sbss = ADDR(.bss);
119+
__ebss = ADDR(.bss) + SIZEOF(.bss);
120+
121+
/* Place the heap right after `.bss` */
122+
__sheap = ADDR(.bss) + SIZEOF(.bss);
123+
124+
/* ## .got */
124125
/* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
125126
the input files and raise an error if relocatable code is found */
126-
.got :
127+
.got (NOLOAD) :
127128
{
128-
__sgot = ABSOLUTE(.);
129129
KEEP(*(.got .got.*));
130-
__egot = ABSOLUTE(.);
131-
} > FLASH
130+
}
132131

133132
/* ## Discarded sections */
134133
/DISCARD/ :
@@ -138,67 +137,56 @@ SECTIONS
138137
}
139138
}
140139

141-
/* # User overridable symbols II */
142-
/* (The user overridable symbols are split in two parts because LLD demands that the RHS of PROVIDE
143-
to be defined before the PROVIDE invocation) */
144-
/* Lets the user override this to place .text a bit further than the vector table. Required by
145-
microcontrollers that store their configuration right after the vector table. */
146-
PROVIDE(_stext = __einterrupts);
140+
/* Do not exceed this mark in the error messages below | */
141+
/* # Alignment checks */
142+
ASSERT(ORIGIN(FLASH) % 4 == 0, "
143+
ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned");
147144

148-
/* # Hardcoded symbols */
149-
/* Place `.bss` at the start of the RAM region */
150-
__sidata = LOADADDR(.data);
151-
/* Place the heap right after `.bss` and `.data` */
152-
__sheap = __ebss;
145+
ASSERT(ORIGIN(RAM) % 4 == 0, "
146+
ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
153147

154-
/* # Sanity checks */
148+
ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
149+
BUG(cortex-m-rt): .data is not 4-byte aligned");
155150

156-
/* Do not exceed this mark in the error messages below | */
157-
ASSERT(__reset_vector == ORIGIN(FLASH) + 0x8, "
158-
cortex-m-rt: The reset vector is missing. This is a bug in cortex-m-rt. Please file a bug
159-
report at: https://github.com/japaric/cortex-m-rt/issues");
160-
161-
ASSERT(__eexceptions - ORIGIN(FLASH) == 0x40, "
162-
cortex-m-rt: The exception vectors are missing. This is a bug in cortex-m-rt. Please file
163-
a bug report at: https://github.com/japaric/cortex-m-rt/issues");
164-
165-
ASSERT(__sheap >= __ebss, "
166-
cortex-m-rt: The heap overlaps with the .bss section. This is a bug in cortex-m-rt. Please
167-
file a bug report at: https://github.com/japaric/cortex-m-rt/issues");
168-
169-
ASSERT(__sheap >= __edata, "
170-
cortex-m-rt: The heap overlaps with the .data section. This is a bug in cortex-m-rt.
171-
Please file a bug report at: https://github.com/japaric/cortex-m-rt/issues");
172-
173-
ASSERT(__einterrupts - __eexceptions > 0, "
174-
cortex-m-rt: The interrupt vectors are missing. Possible solutions, from most likely to
175-
less likely:
176-
- Link to a device crate
177-
- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
178-
may be enabling it)
179-
- Supply the interrupt handlers yourself. Check the documentation for details.");
151+
ASSERT(__sidata % 4 == 0, "
152+
BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
153+
154+
ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
155+
BUG(cortex-m-rt): .bss is not 4-byte aligned");
180156

181-
ASSERT(__einterrupts <= _stext, "
182-
cortex-m-rt: The '.text' section can't be placed inside the '.vector_table' section. Set
183-
'_stext' to an address greater than '__einterrupts' (cf. `nm` output)");
157+
ASSERT(__sheap % 4 == 0, "
158+
BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
184159

185-
ASSERT(_stext < ORIGIN(FLASH) + LENGTH(FLASH), "
186-
cortex-m-rt The '.text' section must be placed inside the FLASH memory. Set '_stext' to an
187-
address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)");
160+
/* # Position checks */
188161

189-
/* This has been temporarily omitted because it's not supported by LLD */
190-
/* ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " */
191-
/* .bss is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */
162+
/* ## .vector_table */
163+
ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
164+
BUG(cortex-m-rt): the reset vector is missing");
192165

193-
/* ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " */
194-
/* .data is not 4-byte aligned at its boundaries. This is a cortex-m-rt bug."); */
166+
ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
167+
BUG(cortex-m-rt): the exception vectors are missing");
195168

196-
/* ASSERT(__sidata % 4 == 0, " */
197-
/* __sidata is not 4-byte aligned. This is a cortex-m-rt bug."); */
169+
ASSERT(SIZEOF(.vector_table) > 0x40, "
170+
ERROR(cortex-m-rt): The interrupt vectors are missing.
171+
Possible solutions, from most likely to less likely:
172+
- Link to a svd2rust generated device crate
173+
- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
174+
may be enabling it)
175+
- Supply the interrupt handlers yourself. Check the documentation for details.");
198176

199-
ASSERT(__sgot == __egot, "
200-
.got section detected in the input object files. Dynamic relocations are not supported.
201-
If you are linking to C code compiled using the `cc` crate then modify your build script
202-
to compile the C code _without_ the -fPIC flag. See the documentation of the
203-
`cc::Build.pic` method for details.");
177+
/* ## .text */
178+
ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
179+
ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
180+
Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
181+
182+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), "
183+
ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory.
184+
Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'");
185+
186+
/* # Other checks */
187+
ASSERT(SIZEOF(.got) == 0, "
188+
ERROR(cortex-m-rt): .got section detected in the input object files
189+
Dynamic relocations are not supported. If you are linking to C code compiled using
190+
the 'cc' crate then modify your build script to compile the C code _without_
191+
the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
204192
/* Do not exceed this mark in the error messages above | */

0 commit comments

Comments
 (0)