broken big-endian compilation on GCC8

Asked by jdobry on 2019-07-15

ARM GCC 8 (Version 8-2019-q3-update or 8-2018-q4-major) generate invalid binary for big endian. GCC7 and bellow was correct. IT looks like some problem on linker (ld tool from binutils)

Short description:
Lets have empty file empty.ld and file test.c with this content:
   int main(){}
Compile it by command
   arm-none-eabi-g++ -o test.elf -mcpu=cortex-r5 -mthumb -T empty.ld -Wl,--gc-sections test.c
Make dump by command
   arm-none-eabi-objdump -S -s -z -j .init -w test.elf

GCC8 create invalid output like this:
  test.elf: file format elf32-littlearm

  Contents of section .init:
   0000 f8b500bf .... <<<<< !!!!!!! here is problem !!!!!!!

  Disassembly of section .init:

  00000000 <_init>:
     0: b5f8 push {r3, r4, r5, r6, r7, lr}
     2: bf00 nop

Correct GCC7 generated contents of section .init:
   0000 b5f8bf00 ....

Binary content have broken endianity for every instruction.

In long, it looks like problem on ld (binutils). When I try compile it to object file, this step is correct.
  arm-none-eabi-g++ -o test.o -c -mcpu=cortex-r5 -mthumb -T empty.ld -Wl,--gc-sections test.c -mbig-endian
  arm-none-eabi-objdump -S -s -z -j .text -w test.o
It create correct binary dump:
  test.o: file format elf32-bigarm

  Contents of section .text:
   0000 b480af00 23004618 46bdbc80 4770 ....#.F.F...Gp

  Disassembly of section .text:

  00000000 <main>:
     0: b480 push {r7}
     2: af00 add r7, sp, #0
     4: 2300 movs r3, #0
     6: 4618 mov r0, r3
     8: 46bd mov sp, r7
     a: bc80 pop {r7}
     c: 4770 bx lr


PS: I know that big-endian is not supported version. Default package not contain needed multilib library variants. For all previous version was sufficient to use simple patch
Something in GCC8 broke it completely.

Question information

English Edit question
GNU Arm Embedded Toolchain Edit question
No assignee Edit question
Solved by:
Last query:
Last reply:
jdobry (jdobry) said : #1

Another example:
  arm-none-eabi-g++ -o test.elf -mcpu=cortex-r5 -mthumb --specs=nosys.specs -Wl,--gc-sections test.c -mbig-endian
  arm-none-eabi-objdump -S -s -z -j .text -w test.elf

Snippet from dump, see to address 8108 (for ex.):

 80fc 00018824 000082bd 000082c9 80b400af ...$............
 810c 00231846 bd4680bc 70470000 70b548f2 .#.F.F..pG..p.H.

00008108 <main>:
    8108: b480 push {r7}
    810a: af00 add r7, sp, #0
    810c: 2300 movs r3, #0
    810e: 4618 mov r0, r3
    8110: 46bd mov sp, r7
    8112: bc80 pop {r7}
    8114: 4770 bx lr
    8116: 0000 movs r0, r0

jdobry (jdobry) said : #2

It look like linker (binutils) problem. I thy this:
On GCC8 compile it into module:
   arm-none-eabi-g++ -o test.o -c -mcpu=cortex-r5 -mthumb --specs=nosys.specs -Wl,--gc-sections test.c -mbig-endian
On GCC7 link obj -> elf
   arm-none-eabi-g++ -o test.elf -mcpu=cortex-r5 -mthumb --specs=nosys.specs -Wl,--gc-sections test.o -mbig-endian
And back to the GCC8 to dump result
   arm-none-eabi-objdump -S -s -z -j .text -w test.elf

It create correct result (snippet)
  80fc 000188a4 000082f9 00008305 b480af00 ................
  810c 23004618 46bdbc80 47700000 b570f248 #.F.F...Gp...p.H

Tejas Belagod (belagod-tejas) said : #3

Hi Jiri,

We don't maintain that patch, so we can't test our toolchain with it. It is very difficult to support bespoke patched toolchains - it may have been working in the past, but we can't guarantee correctness with patches that aren't upstream. As we have requested before, it would be great if the patch submitter tries to submit it to the gcc patches list for taking it upstream. Once it gets into mainline trunk, we can think of supporting/testing it.

Meanwhile you could use --print-mult-lib and/or --print-multi-directory to figure out if the right multilibs are being linked in. I'm not sure the linker could be the issue because the older driver means you're using the older multilib structure. The linker is just using the directory structure from an older multilib that the compiler driver is telling it to.


42Bastian (bastian-schick) said : #4

Hi Tejas,

I wonder, why can't you (after so many year) not test big endian targets? What is the problem with it?

jdobry (jdobry) said : #5

Problem is endian behavior changed in GCC8:
"The default link behavior for Armv6 and Armv7-R targets has been changed to produce BE8 format when generating big-endian images. A new flag -mbe32 can be used to force the linker to produce legacy BE32 format images. There is no change of behavior for Armv6-M and other Armv7 or later targets: these already defaulted to BE8 format. This change brings GCC into alignment with other compilers for the ARM architecture."

This command produce correct code:
arm-none-eabi-g++ -o test.elf -mcpu=cortex-r5 -mthumb -T empty.ld -Wl,--gc-sections test.c -mbe32 -mbig-endian