Search code examples
cgccassemblypowerpc

GCC Avoid compiling branch to link register (blr) statements


I'm writing C code and compiling it for the PowerPC architecture. I want to tell the compiler to replace all return-like instructions with branches to the end of the function's code instead. This is due to some odd requirements where I can't use any return in this piece of code to ensure the execution of a few more lines of assembly afterwards.

For instance, I compiled C code into the following assembly code:

lis r9,4096
lis r8,255
lwz r10,0(r9)
ori r8,r8,65535
addi r9,r10,192
cmplw cr7,r9,r8
blelr- cr7 # Return if the cr7 register is "less than or equal"
lis r8,512
cmplw cr7,r9,r8
bgtlr- cr7 # Return if the cr7 register is "greater than or equal"
lwz r10,192(r10)
lis r8,303
ori r8,r8,65535
addi r9,r10,320
cmplw cr7,r9,r8
blelr- cr7 # Return if the cr7 register is "less than or equal"
lis r8,528
cmplw cr7,r9,r8
bgtlr- cr7 # Return if the cr7 register is "greater than or equal"
lwz r10,320(r10)
lis r8,287
ori r8,r8,65535
subi r9,r10,448
cmplw cr7,r9,r8
blelr- cr7
lis r8,544
cmplw cr7,r9,r8
bgtlr- cr7 # Return if the cr7 register is "greater than or equal"
lis r9,4919
ori r9,r9,4919
stw r9,-448(r10)
blr # Return

What I want is all the return-like statements to be replaced with an always branch to the end of the function's code like as follows:

lis r9,4096
lis r8,255
lwz r10,0(r9)
ori r8,r8,65535
addi r9,r10,192
cmplw cr7,r9,r8
ble _END # Branch to the _END label if "less than"
lis r8,512
cmplw cr7,r9,r8
bgt _END # Branch to the _END label if "greater than"
lwz r10,192(r10)
lis r8,303
ori r8,r8,65535
addi r9,r10,320
cmplw cr7,r9,r8
ble cr7 # Branch to the _END label if "less than"
lis r8,528
cmplw cr7,r9,r8
bgt _END # Branch to the _END label if "greater than"
lwz r10,320(r10)
lis r8,287
ori r8,r8,65535
subi r9,r10,448
cmplw cr7,r9,r8
blelr- cr7
lis r8,544
cmplw cr7,r9,r8
bgt _END # Branch to the _END label if "greater than"
lis r9,4919
ori r9,r9,4919
stw r9,-448(r10)
_END:
blr # I guess it should stay otherwise the function call will continue executing "random" garbage such as the next function in the .text section. Via post-processing this would be easy to strip though!

Any way to automate this compilation preference?


Solution

  • The comments from @Jester and @fuz provide an answer, I'll just write it down.

    You need to:

    1. Avoid returning in the middle of a function, in the C code. So replace return with goto.
    2. Prevent the compiler from figuring out that goto end; and return; are the same thing. Inline assembly is a good way to tell the compiler "don't mess with this".

    With some macros:

    #define RETURN goto _end
    #define END _end: asm volatile("")
    void foo(int x) { if (x==1) RETURN; if (x==2) RETURN; printf("Hello, world\n"); END; }

    asm volatile("") instructs the compiler to insert some assembly code. The compiler doesn't know what this assembly code does, so it can't do any optimization that would skip it (even in case where it's 0 instructions).