Skip to content

Fix potential and hard to debug "Out of range pc-relative fixup value" errors #682

Description

@royaltm

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:

        ldr {0}, =VALUE

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions