rust-embedded/cortex-m

HardFaultTrampoline, relocation R_ARM_THM_JUMP11 out of range

Closed this issue · 5 comments

On a Cortex-M0 running Hubris OS with link time optimizations temporarily disabled for debugging, I find linking often fails with the following:

 = note: rust-lld: error: /target/thumbv6m-none-eabi/release/deps/libcortex_m_rt-30b54eec0d9b4b99.rlib(cortex-m-rt.o):(function HardFaultTrampoline: .HardFaultTrampoline+0xc): relocation R_ARM_THM_JUMP11 out of range: -5547 is not in [-2048, 2047]; references 'HardFault'

I suppose this is why the Trampolines were made optional.

Is any guidance available for this issue. I believe there are two paths: either disabling the trampolines (I'm not sure what effect that has) or manually coaxing the linker into placing sections closer together?

looking at the source:

.section .HardFaultTrampoline, \"ax\"

I guess I could fork the library and maybe try to edit the assembly to work around the usage of the B instruction (BX would work better although it modifies the return address). Although that is a bit of a pain.

What linker script are you using? In the one provided with cortex-m-rt, HardFaultTrampoline should always come immediately before HardFault for this specific reason, so I'm not sure what's going wrong here - maybe a different linker script or maybe some new bug in cortex-m-rt that's causing the functions to not go into the correct sections?

/* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
so must be placed close to it. */
*(.HardFaultTrampoline);
*(.HardFault.*);

I'm using https://github.com/oxidecomputer/hubris/blob/master/build/kernel-link.x

It appears to do what is shown in your example

  /* ### .text */
  .text _stext :
  {
    __stext = .;
    /* place these 2 close to each other or the `b` instruction will fail to link */
    *(.PreResetTrampoline);
    *(.Reset);

    *(.text .text.*);

    /* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
       so must be placed close to it. */
    *(.HardFaultTrampoline);
    *(.HardFault.*);
    . = ALIGN(4);
    __etext = .;
  } > FLASH

However, disabling link time optimizations does reproduce the issue 80% of the time, at least on my project.

When I dump the symbols for a build with optimizations enabled, I notice that HardFaultTrampoline is placed after HardFault.

$ nm -C kernel | grep -i hard
080060cd T HardFault
0800673b T HardFaultTrampoline

I wonder if it is possible that the certain linker expressions might be capturing either more or less than expected?

I think the script is trying to place HardFaultTrampoline before HardFault, yet when I compile it gets placed after. Which makes it sensitive to size and vulnerable to failing when optimizations are disabled.

edit: I fiddled with the linker script with no success, hard to debug "which lines are pulling in what"

Which version of cortex-m-rt is this? With 0.7.5, there should not be a symbol called HardFaultTrampoline. The symbol that's getting placed in section .HardFaultTrampoline is called HardFault:

                    core::arch::global_asm!(
                        ".cfi_sections .debug_frame
                        .section .HardFaultTrampoline, \"ax\"
                        .global HardFault
                        .type HardFault,%function
                        .thumb_func
                        .cfi_startproc
                        HardFault:",

I guess it may be 0.6.12, as that's the version referenced by https://github.com/oxidecomputer/hubris/blob/master/Cargo.toml?

And then, which version of hybris are you using?
This relatively recent change seems to be relevant:
oxidecomputer/hubris@134b7d7#diff-f5c9d3c68205bc09ad754c71a08e8892e47c9e25af57e32de4a143864b999607

It places the HardFault symbol defined in sys/kern/src/arch/arm_m.rs at the right location. Without that, it'll be thrown somewhere into the .text section.

Closing because I just realized I am using an out of date version!

I need to investigate this after I go through the process of getting the project up to date.