Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

gcc, arm, inline assembly, BX produce unexpected results trying to jump over a goto section

I am using Cortex M0+;

I am trying to preserve a piece of code inside the regular code flow, don’t ask me why 🙂
Basically later on, I’d like to jump to MYCODE.

This is the code

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    bool x = false; // defined somewhere globally 

    if (x) goto MYCODE; // prevents removal of MYCODE

    //goto MYJUMP; // this is working as expected
    __asm volatile("BX %0" : : "r" (&&MYJUMP) : ); // this crashes !!!

MYCODE:

    __asm volatile ("nop");
    __asm volatile ("nop");
    __asm volatile ("nop");

MYJUMP:
    __asm volatile ("nop"); // first NOP will crash !!!
    __asm volatile ("nop");
    __asm volatile ("nop");

Now in the first place, GCC removes anything from MYCODE, no matter -Ox I use.
One way to convince to keep the code, was to declare ‘x’ as global and make a fake if() before.

Another way was to use jump in assembly with this

__asm volatile("BX %0" : : "r" (&&MYJUMP) : );

The generated code is

 96           __asm volatile("BX %0" : : "r" (&&MYJUMP) : );
0800285e:   ldr     r3, [pc, #96]  
08002860:   bx      r3                    // value is 0800286c

Using inline jump, always crashes into DefaultHandler!
This is very curious, the NOPs appears to be fine

08002864:   nop     ; (mov r8, r8)
100         __asm volatile ("nop");
08002866:   nop     ; (mov r8, r8)
101         __asm volatile ("nop");
08002868:   nop     ; (mov r8, r8)
102         __asm volatile ("nop");
0800286a:   nop     ; (mov r8, r8)
105         __asm volatile ("nop");
0800286c:   nop     ; (mov r8, r8)       // <-- the code reaches here just fine as expected
106         __asm volatile ("nop");      // but when executed this NOP will jump to DefaultHandler
0800286e:   nop     ; (mov r8, r8)
107         __asm volatile ("nop");
08002870:   nop     ; (mov r8, r8)  

Any idea what’s happening?
I am debugging for few hours and I just don’t get it.

I’d like to use assembly jump, in this case, GCC will not optimize anymore.

Thanks a lot in advance!

>Solution :

Jumping out of an inline asm needs special handling. There is extra syntax for it: asm goto.

Briefly, your jump should look like this:

__asm goto("B %l0" : : : : MYJUMP);

Try on godbolt

This compiles to a simple b label. I didn’t test it but the generated asm looks "obviously correct".

As a bonus you do not need to load the label address into a scratch register. It also prevents optimizing out MYCODE (without the need for a dummy variable) because the compiler assumes that the jump may or may not be taken. (The docs mention that if you want to inform the compiler that the asm will always jump, you can follow it with __builtin_unreachable().)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading