GNU linker and ELF program header

14.11.2012 12:15

Here's a little annoyance I've been trying to fix.

Most of the time we are using a custom bootloader on VESNA. On the VESNA's STM32F1 microcontroller the flash ROM starts at the address 0x8000000 and the bootloader takes the first 0x12800 bytes of it. At CPU reset the bootloader does some housekeeping tasks, possibly reprogramming some sections of the flash ROM, and then transfers control to the application code that lives above 0x8012800.

When linking application code using GNU linker, we are using the following script:

MEMORY
{
	rom (rx) : ORIGIN = 0x08012800, LENGTH = 512K - 0x12800
	ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}

INCLUDE libopencm3_stm32f1.ld

This produces a working binary (using objdump -Obinary) when it's loaded at 0x8012800 by our bootloader.

However, sometimes it's convenient to skip the application reprogramming through the bootloader (which is slow for unrelated reasons) and program the application code directly through JTAG using openocd. Strangely enough this corrupts the bootloader, even though the linker MEMORY definition above only specifies the application area of the ROM.

Looking closely at the ELF file produced by the linker, I noticed the program headers:

Program Header:
0x70000001 off    0x0000e4cc vaddr 0x0801e4cc paddr 0x0801e4cc align 2**2
         filesz 0x000000e8 memsz 0x000000e8 flags r--
    LOAD off    0x00000000 vaddr 0x08010000 paddr 0x08010000 align 2**15
         filesz 0x0000e5b4 memsz 0x0000e5b4 flags r-x
    LOAD off    0x00010000 vaddr 0x20000000 paddr 0x0801e5b8 align 2**15
         filesz 0x000009b4 memsz 0x00000bc0 flags rw-
private flags = 5000002: [Version5 EABI] [has entry point]

For some reason GNU linker insists on aligning program segments on a 32 kB boundary. Therefore it aligns the segment containing the application code at 0x8010000, which is 0x2800 bytes inside the bootloader territory. Since the code still has to start at 0x8012800, it pads the start of the segment and this padding overwrites a part of the bootloader when it's loaded into flash ROM by openocd.

Why does it do that? I have no idea. There also doesn't seem to be any option to adjust the alignment (flash ROM in this microcontroller has 512 byte pages, so it would make more sense to align the segments to those).

The simplest solution I've found is to simply dump the plain binary with objdump and use that instead of the ELF file with openocd. But that's ugly, because then you have to repeat the segment offset in the openocd script.

Posted by Tomaž | Categories: Code

Add a new comment


(No HTML tags allowed. Separate paragraphs with a blank line.)