Linker: ELF file program segment too big

Asked by Tony on 2019-01-11

Note: I have already posted this on stackoverflow (https://stackoverflow.com/q/54151670/428857), but I have since realised that it is almost certainly a linker bug, so I reckoned this was a more appropriate place for it.

I am implementing a stand-alone OS for ARM Cortex M0, and I have a weird problem with the linker. Here is my source file OS.c, stripped down to illustrate the problem:

<start OS.c>
  int EntryPoint (void) { return 99 ; }
<end OS.c>

And here is my linker script file OS.ld, simply assigning all code to the region starting at 0x10080:

<start OS.ld>
  MEMORY
    {
    NVM (rx) : ORIGIN = 0x10080, LENGTH = 0x1000
    }

  SECTIONS
    {
    .text 0x10080 :
      {
      OS.o (.text)
      } > NVM
    }
<end OS.ld>

I compile and link it:

arm-none-eabi-gcc.exe -march=armv6-m -mthumb -c OS.c
arm-none-eabi-gcc.exe -oOS.elf -Xlinker --script=OS.ld OS.o -nostartfiles -nodefaultlibs

And now when I list the program segments with readelf OS.elf -l, I get:

<start readelf output>
  Elf file type is EXEC (Executable file)
  Entry point 0x10080
  There are 1 program headers, starting at offset 52

  Program Headers:
    Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
    LOAD 0x000000 0x00010000 0x00010000 0x0008c 0x0008c R E 0x10000
<end readelf output>

According to this, the one and only program segment starts at offset 0x000000 in the ELF output file, which is crazy: that region contains ELF header info irrelevant to the OS. And the physical start address is 0x00010000, which doesn't exist in my hardware.

But the weird thing is that if I change both instances of 0x10080 to 0x10040 in the linker script file, it works! I get:

<start readelf output>
  Elf file type is EXEC (Executable file)
  Entry point 0x10040
  There are 1 program headers, starting at offset 52

  Program Headers:
    Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
    LOAD 0x010040 0x00010040 0x00010040 0x0000c 0x0000c R E 0x10000
<end readelf output>

Now the program segment is in the right place in the file, and has length 0x0000c instead of 0x0008c. Unfortunately address 0x00010040 doesn't exist in my hardware either, so this is not a solution.

Is this a bug in the GCC ARM compiler? Running it with --version gives:

arm-none-eabi-gcc.exe (GNU Tools for Arm Embedded Processors 7-2018-q2-update) 7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907]

Is this even the right place to report the problem, or is it something for the mainstream GCC team?

Also, I have noticed that it seems to happen when the first program segment fits into the first page in the ELF file (i.e. its starting offset within its page is >= the number of bytes in the ELF header). In this case the segment erroneously gets extended downwards to the beginning of the file. This would explain why the problem disappears if the in-page offset of the start address is reduced from 0x80 to 0x40.

Question information

Language:
English Edit question
Status:
Open
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
2019-01-11
Last reply:

Can you help with this problem?

Provide an answer of your own, or ask Tony for more information if necessary.

To post a message you must log in.