Affected crate: cortex-m v0.7.8.
Problem
After updating cortex-m to 0.7.8, my project failed to build with a pretty cryptic error:
error: out of range pc-relative fixup value
|
note: instantiated into assembly here
--> <inline asm>:1:10
|
1 | ldr r0, =0xE000ED14
| ^
After a few moments of deduction, I realized the error originated from either here or here.
I have a quite large boot function, where an obvious part of it is enabling the I-cache and D-cache. In version 0.77 instead of inline assembly an extern function is created, forcing the compiler to create an actual function:
extern "C" {
// see asm-v7m.s
fn __enable_dcache();
}
However in v0.7.8 the __enable_dcache and __enable_icache functions are instead replaced with inlined asm.
The problem is that the following inline assembly expression:
will use the LDR (literal) instruction, which reads a given value from a PC-relative address with a limited range. The actual VALUE is stored in the function body, and unfortunately, the compiler seems to always choose the end of the function body to store such values:
8006540: 4916 ldr r1, [pc, #88]
/* ... the rest of the function body ... */
800659c: e000ed14 .word 0xe000ed14
If a function body is large enough, you will encounter an error like this one.
Solution
I suggest to replace all usages of such LDR expressions in the cortex-m crate with a pair of MOVW and MOVT instructions, which produce truly inline and independent code, like this:
movw {0}, #:lower16:VALUE
movt {0}, #:upper16:VALUE
For example, an expression with VALUE = 0xE000ED14, produce:
8000268: f64e 5114 movw r1, #60692 @ 0xed14
800026c: f2ce 0100 movt r1, #57344 @ 0xe000
Please note, that MOVW must come BEFORE MOVT. Otherwise MOVW will erase the upper part of the register.
A MOVW/MOVT pair also improves instruction-cache locality, especially that the VALUE can be separated from the LDR instruction by a large amount.
Affected crate:
cortex-mv0.7.8.Problem
After updating
cortex-mto 0.7.8, my project failed to build with a pretty cryptic error:After a few moments of deduction, I realized the error originated from either here or here.
I have a quite large boot function, where an obvious part of it is enabling the I-cache and D-cache. In version 0.77 instead of inline assembly an extern function is created, forcing the compiler to create an actual function:
However in
v0.7.8the__enable_dcacheand__enable_icachefunctions are instead replaced with inlined asm.The problem is that the following inline assembly expression:
will use the
LDR (literal)instruction, which reads a given value from a PC-relative address with a limited range. The actualVALUEis stored in the function body, and unfortunately, the compiler seems to always choose the end of the function body to store such values:If a function body is large enough, you will encounter an error like this one.
Solution
I suggest to replace all usages of such
LDRexpressions in thecortex-mcrate with a pair ofMOVWandMOVTinstructions, which produce truly inline and independent code, like this:For example, an expression with
VALUE=0xE000ED14, produce:Please note, that
MOVWmust come BEFOREMOVT. OtherwiseMOVWwill erase the upper part of the register.A
MOVW/MOVTpair also improves instruction-cache locality, especially that theVALUEcan be separated from theLDRinstruction by a large amount.