ld generates invalid addresses

Niklas Gürtler profclonk@gmx.de
Sun May 13 13:22:00 GMT 2012

Dear readers,

I ran into problems linking a C/C++ program for the STM32F4 (which is a 
Cortex-M4F, ARMv7) mikrocontroller using the gcc-arm toolchain 
https://launchpad.net/gcc-arm-embedded/ on Windows. Since only the 
program memory (flash) of the controller can be programmed, the linker 
should generate a single section ending up in the flash, consisting of 
the program data, the program code and the necessary startup code to 
load the data into the RAM.
I used the example code from ST for the linker script and startup 
assembly code. This worked well first, until suddenly, after doing a 
tiny modification to the code, strange behaviour occured, which is a 
result of global variables being initialized incorrectly. The reason is:
As instructed by the linker script, ld concatenates the ISR Vector, the 
program code (including the startup code), the three arrays 
preinit_array, init_array, fini_array and the initialization data. ld 
generates three labels:
-   _sidata  is a pointer to the beginning of the initialization data in 
the program memory ( = flash)
-   _sdata   is a pointer to the RAM, where the initialization data 
should be placed before main() is called
-   _edata   points to the end of that data, thereby determining its size.

Upon startup, the controller executes the startup code, which 
effectively does a memcpy (_sdata, _sidata, _edata - _sdata); (written 
in assembly language, but this way it's shorter), which should 
initialize all global variables with the initialization data from the 
program memory. The problem is now, that the _sidata label is set 
incorrectly - in my case, the initialization data in the flash begins at 
addess 0x080021b0 (placed there by ld), so ld should set _sidata to 
exactly that address, but it sets it to 0x080021ac. This address points 
into the fini_array, so the startup code copies that data into the RAM, 
corrupting all global variables. I have no idea why ld does that, can 
anyone help me with that?

My code can be found at http://2g2s.de/testcase.zip and compiled by 
"ruby build.rb" (which requires the ruby interpreter). The build.bat can 
also be used to do that. Compiling should also be possible on Linux. In 
the 'Debug' directory, i included the compiled code in ELF, ihex and 
binary format and the disassembly, where you can see that _sidata got 
the wrong address.
The C/C++ Code is unfinished and of not much use, as I can't continue 
programming with ld  failing that way...

Any help would be very much appreciated, thank you in advance!

More information about the Binutils mailing list