cancel
Showing results for 
Search instead for 
Did you mean: 

Strange padding in the .data section of the .elf file

Szymon M
Associate II

I'm currently writing a program on STM32F411 that uses a simple bootloader and two sub-applications. The sub-applications are located in the flash memory and the bootloader loads one of them (both code and data) into the RAM memory and then starts executing it (from RAM). The copying is done simply by iterating over the addresses in flash and copying data from these addresses to RAM.

Recently I've encountered some strange bug. I was trying to read some data from a globally defined array. I was getting back wrong values, e.g. when I tried to read array[0] I was getting back the value of array[1].

I did some debugging and disassembly of the .elf and .hex files and I think I've found the cause of this bug. It turned out that there is an empty space between the .ARM section of the .elf file of this project. 

Surprisingly, this empty space is not present in the .hex file (which I use for flashing the STM32 board). 

This is what I am talking about:

  • .elf file:
2000ee70:   469e        mov   lr, r3
2000ee72:   4770        bx   lr
 
Disassembly of section .ARM:
 
2000ee74 <__exidx_start>:
2000ee74:   7fff267c   svcvc   0x00ff267c
2000ee78:   00000001   andeq   r0, r0, r1
 
 
Disassembly of section .data:
 
2000ee80 <evnames.5255>:
2000ee80:   00000000   andeq   r0, r0, r0
2000ee84:   08030104   stmdaeq   r3, {r2, r8}

  • .hex file
802de70:   4770469e   
 802de74:   7fff267c   svcvc   0x00ff267c
 802de78:   00000001   andeq   r0, r0, r1
 802de7c:   00000000   andeq   r0, r0, r0
 802de80:   08030104   stmdaeq   r3, {r2, r8}

Obviously, the addresses are different because the addresses in the .elf file are VMA and the addresses in the .hex file are LMA. 

What I've noticed here is that in the .elf file, after the .ARM section, the next memory address should be 2000ee7C but from unknown reasons, the .data section begins at 2000ee80. So there is one mysterious, empty machine word between them (maybe some padding). But this empty word is not present in the .hex file. The 00000001 is immediately followed by 00000000

So basically, I think the disassembly of the .hex file should output the following result:

802de70:   4770469e   
 802de74:   7fff267c   svcvc   0x00ff267c
 802de78:   00000001   andeq   r0, r0, r1
 802de7c:      <something here>
 802de80:   00000000   andeq   r0, r0, r0
 802de84:   08030104   stmdaeq   r3, {r2, r8}

Because of this empty memory space, which disappears in the .hex file, when my bootloader loads the data to RAM, the array[0] which LMA is 2000eec8 ends up being at the address 2000eec4.

What I've also noticed recently is that sometimes the data is aligned correctly in the .elf file (the first address of the .data section is the address that immediately follows the end of the .ARM section). It depends on the address where the .ARM section happens to end. I can manipulate that by adding some extra function invocations in the code (resulting in the larger .text area), for example:

2000ee84:   469e        mov   lr, r3
2000ee86:   4770        bx   lr
 
Disassembly of section .ARM:
 
2000ee88 <__exidx_start>:
2000ee88:   7fff2668   svcvc   0x00ff2668
2000ee8c:   00000001   andeq   r0, r0, r1
 
 
Disassembly of section .data:
 
2000ee90 <evnames.5255>:
2000ee90:   00000000   andeq   r0, r0, r0
2000ee94:   2001111c   andcs   r1, r1, ip, lsl r1

This way, I've estabilished that: 

  •  when the .ARM section ends at address 0x*******0 the .data section incorrectly starts at 0x*******8 (should be 0x*******4
  •  when the .ARM section ends at address 0x*******8 the .data section incorrectly starts at 0x*******0 (should be 0x*******C
  •  when the .ARM section ends at address 0x*******4 the .data section CORRECTLY starts at 0x*******8
  •  when the .ARM section ends at address 0x*******C the .data section CORRECTLY starts at 0x*******0

This is probably the troubling snippet of the linker script that I use:

/* ARM specific sections, they also go to FLASH and are copied to RAM */
 .ARM.extab : { 
     *(.ARM.extab* .gnu.linkonce.armextab.*) 
 } > RAMAPP AT> FLASH_APP
 .ARM : {
     __exidx_start = .;
     *(.ARM.exidx*)
     __exidx_end = .;
 } > RAMAPP AT> FLASH_APP
 
 /* Initialized data sections - variables etc. */
 .data :
 {
     . = ALIGN(4);
     *(.data)          /* .data sections */
     *(.data*)         /* .data* sections */
     . = ALIGN(4);   
 
 } >RAMAPP AT> FLASH_APP /* Data section is placed in FLASH_APP but its Virtual Memory Address is in RAM_APP */

I use the following command to link the .o files into one .elf file:

arm-none-eabi-gcc -Wl,--gc-sections -mthumb -mthumb-interwork -mcpu=cortex-m4 --specs=nosys.specs -L[path_to_library_files] -T[path_to_ld_file] [long_list_of_object_files] -o [output_elf_file]

I use the following command to convert the .elf file into the .hex file:

arm-none-eabi-objcopy -O ihex [elf_file] [output_hex_file]

I've tried to experiment with the parameters I give to the arm-none-eabi-objcopy and arm-none-eabi-gcc to get rid of this unexplained padding, for example --file-alignment or --gap-fill but to no success so far.

I've also tried the following

  •  using the older/newer versions of arm-none-eabi-gcc and arm-none-eabi-objcopy in my toolchain, 
  •  ALIGN(4) of the .ARM section, 
  •  not copying the .ARM section to RAM. 
  •  using diffeerent alignments for the .data section

Unfortunately, none of these solutions fixed this problem. 

Does anyone have an idea about where does this empty space come from and how to get rid of it (or make it present in the .hex file as well)?

8 REPLIES 8

.HEX files are sparse, gaps simply aren't encoded in the output

There should be variables around the .data section content so the code in startup.s can correctly determine where it is and copy it into RAM.

Will have to pull an equivalent linker script here, but I think the ordering of extab is later.

Either way, in GNU/GCC you are responsible for what you put in the script, and unpacking when the processor starts. Keil's linker packs these things into defined structures and provides library code to unpack itself into RAM properly.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III

This looks like a general issue, better ask this on Stack Overflow to get more attention.

-- pa

Szymon M
Associate II

@Pavel A.​  I've asked it on the stack overflow already, got less attention 😉

@Community member​  The problem is that my bootloaderer is linked separately (project requirement), it has absolutely no insight into the sub-application's symbols, so defining them in the sub-applications linker script wouldn't help in that case. This bootloader's job is to copy everything from the hardcoded, specified regions in flash to RAM.

Anyway, your answer gave me this idea to try this approach:

  • bootloader only copies the code of the subapplication to RAM,
  • the application itself is responsible for initializing its data section (it should be able to do that since it knows its .data segment start and end addresses)

The loader should copy the FLASH image end-to-end to RAM and then let the application unpack itself from there.

If the loader has to manage this it needs the .ELF object to export the symbols of interest, or you build you OWN tables to describe the sectioning that the startup.s code normally manages.

Your problem in the script is you've dumped stuff in the middle, whereas the unpacking code expects the data/bss sections to be at a specific local and be a specific length, as described by the symbols you have defined around those sections.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

Yeah, thank you. Making the sub-application responsible for its data initialization seems smarter than making bootloader responsible for all of this.

Anyway, I still don't know where does this gap in my main post comes from.

When I add some big alignment of the .data section, for example

.=ALIGN(0x100)

The gap gets pretty big and is present in the .hex file as well. So it seems that " gaps simply aren't encoded in the output" is not the case here.

Gaps and ordering are an option you have with .HEX, whereas the .BIN doesn't have those luxuries. A relocatable object format would likely be a better approach for things loaded into RAM. The .ELF format could be used, but you'd probably want to sanitize it so it's not carrying about megabytes of debug and symbol info. Historically I've used more customized formats describing sections individually, along with fixups and entries points as required. Typically one has to write linkers or object file utilities to do that effectively.

The linker is probably the best tool to collect the data and build structures, I've exploited Keil's scatter tables and scatter loaders for my own purposes, including External Loaders for the ST programming utilities. You could probably do some table building with the GNU tools, allowing the linker to fixup symbols in tables. The GNU startup.s vs .ld method is a bit half-assed, but that's a consequence of it not being built as an embedded tool chain, but rather something building executable files for LINUX.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Szymon M
Associate II

Okay, It turned out I had to add ALIGN_WITH_INPUT to the .data section in the linker script. Like this:

  .data : ALIGN_WITH_INPUT
  {
    . = ALIGN(4);
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */
    . = ALIGN(4);    
  } >RAMAPP AT> FLASH_APP

This parameter causes the LMAs of the section to be aligned in the same way the VMAs are.

Now the alignment in the .hex file is identical to the one in the .elf file.

Shout out to reddit user FreddieChopin who helped me to resolve this issue.

Interesting. How do you produce the hex file? Can you also produce a .bin file and see if the same issue exists?

IMHO this looks more like a problem with the tool which produces hex from elf.

-- pa