ld generates invalid addresses
Sun May 13 13:22:00 GMT 2012
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