ARM Cortex-M Broken Binaries with -O2 and -O3 (-fschedule-insns)

Mike via D.gnu d.gnu at puremagic.com
Fri Jul 21 18:11:02 PDT 2017


On Friday, 21 July 2017 at 23:44:53 UTC, Mike wrote:

> I'm getting broken binaries with -O2 and -O3.  I've nailed the 
> culprit down to -fschedule-insns (i.e. if I add 
> -fno-schedule-insns to -O2 or -O3, the binary works fine).
>
> I disassembled '-O2' and '-O2 -fno-schedule-insns' and compared 
> them, but they were quite different all the way through.  No 
> only because of address locations, but also different registers 
> and even different opcodes.  (e.g. 'str r2, [sp, #12]' vs 'strd 
> r1, r2, [sp, #8]')

Interestingly, I added a stategically placed `asm { "nop"; }` and 
my binary was able to execute further.  Comparing the disassembly 
of the function I modified still showed quite a significant 
difference.

Working Binary
-------------
ldr	r2, [pc, #188]	; (8000c50 <hardwareInit+0x104>)
ldr	r1, [pc, #188]	; (8000c54 <hardwareInit+0x108>)
ldr	r3, [r2, #0]
and.w	r3, r3, #780	; 0x30c
orr.w	r3, r3, #37888	; 0x9400
movs	r0, #0
str	r3, [r2, #0]
strb	r0, [r1, #0]
;-------------------------------------------------------
nop                     ; My stategically placed nop
;-------------------------------------------------------
ldr	r3, [pc, #172]	; (8000c58 <hardwareInit+0x10c>)
ldr	r0, [pc, #176]	; (8000c5c <hardwareInit+0x110>)
ldr	r4, [pc, #176]	; (8000c60 <hardwareInit+0x114>)
ldr	r2, [pc, #180]	; (8000c64 <hardwareInit+0x118>)
movs	r1, #1
strb	r1, [r3, #0]
ldr	r3, [r0, #0]
orr.w	r3, r3, #49152	; 0xc000
str	r3, [r0, #0]
strb	r1, [r4, #0]

Not Working Binary
------------------
ldr	r0, [pc, #184]	; (8000c4c <hardwareInit+0x100>)
ldr	r1, [pc, #184]	; (8000c50 <hardwareInit+0x104>)
ldr	r2, [pc, #188]	; (8000c54 <hardwareInit+0x108>)
ldr	r3, [r1, #0]
ldr	r4, [pc, #188]	; (8000c58 <hardwareInit+0x10c>)
movs	r5, #0
strb	r5, [r0, #0]
movs	r0, #1
strb	r0, [r2, #0]
ldr	r2, [r4, #0]
ldr	r5, [pc, #180]	; (8000c5c <hardwareInit+0x110>)
orr.w	r2, r2, #49152	; 0xc000
and.w	r3, r3, #780	; 0x30c
str	r2, [r4, #0]
orr.w	r3, r3, #37888	; 0x9400
ldr	r2, [pc, #168]	; (8000c60 <hardwareInit+0x114>)
strb	r0, [r5, #0]
str	r3, [r1, #0]

By "Not Working" I mean this code gets stuck in the while loop

PWR.CR.ODEN.value = true;
while(!PWR.CSR.ODRDY.value) { }

This is simply setting the "Overdrive Enable" register on the 
power control peripheral of my hardware.  The documentation 
states:

To set or reset the ODEN bit, the HSI or HSE must be selected as 
system clock.

I'm setting the HSI prior to setting ODEN, but it appears that 
maybe the compiler is reordering the instructions.  I still need 
to investigate that further, but hopefully that provides a little 
more insight.

Mike



More information about the D.gnu mailing list