I start liking the GNU linker (ld) more and more. Yes, that linker command file syntax needs some time to learn, but it is very powerful. I stumbled over an interesting way how to define linker symbols:
/* Linker file for GNU C Compiler */ /* Entry Point */ ENTRY(Reset_Handler) HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;
The interesting part is how the HEAP_SIZE and STACK_SIZE symbols are defined.
It checks if e.g. __heap_size__ is DEFINED, and if so, it uses that symbol, otherwise it is using 0x400. Very similar to the C/C++ ‘?’ operator. So I can overwrite the default of 0x400 with my value or symbol. The questions is: from where does the symbol come from?
I checked http://www.math.utah.edu/docs/info/ld_3.html which explains DEFINED as
DEFINED(symbol)
Return 1 if symbol is in the linker global symbol table and is defined, otherwise return 0. You can use this function to provide default values for symbols. For example, the following command-file fragment shows how to set a global symbol
begin
to the first location in the.text
section–but if a symbol calledbegin
already existed, its value is preserved:SECTIONS{ ... .text : { begin = DEFINED(begin) ? begin : . ; ... } ... }
So this is really a cool way to overwrite a symbol in the linker file, without touching the linker file itself. After some digging, I have found a way how this can be done: with options in passed to the linker: It requires the -Xlinker option and the –defsym option:
-Xlinker --defsym=
So to set the __heap_size__ to 0x600, I use
-Xlinker --defsym=__heap_size__=0x600
If using the GNU ARM Eclipse plugins (e.g. Kinetis Design Studio or my DIY Eclipse IDE), the options is added to the ‘other linker flags’ of the Cross ARM C++ Linker settings:
An easy way to verify if things are working as intended is to check the linker map file, and search for that symbol. For my case above I get:
LOAD c:/freescale/kds_1.1.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.8.0/m4/fp/v4-sp-d16/crti.o LOAD c:/freescale/kds_1.1.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.8.0/m4/fp/v4-sp-d16/crtbegin.o LOAD c:/freescale/kds_1.1.0/toolchain/bin/../lib/gcc/arm-none-eabi/4.8.0/../../../../arm-none-eabi/lib/m4/fp/v4-sp-d16/crt0.o 0x00000600 __heap_size__ = 0x600
So that worked as expected 🙂
Summary
If symbols are defined in the GNU linker file with
newSymbol = DEFINED(symbol) ? symbol : default ;
Then I can overwrite it using a linker command:
-Xlinker --defsym=symbol=value
Happy Defining 🙂
Please forgive my ignorance (I’m not really an engineer, I just play one in my mind), but under what conditions would one want to do this? How does it change the resulting process or program?
Thank you.
LikeLike
You can use the same linker file for multiple applications. Then it is up to the application (make file, or even with source files) to configure the behaviour of the linker file. For example one application needs more or less stack space, so this can be configured.
LikeLike
Thank you.
LikeLike
And we’re constantly adjusting that looking for stack overflows on these micros. Useful tip!
LikeLike
Hi Erich,
I like the approach of reusing th linker file.
In my mind, it would be nice to overwrite memory origin and length informations e.g. for generating bootloader and application specific setions.
My question to you:
Is there a way to define the memory origin and length information inside a header file and pass it to the linker?
Best regards,
Markus
LikeLike
The linker file only can define symbols, so I can define a symbol at the beginning and one at the end, and doing in C the calculation of the size will be (end-begin).
You cannot use directly C code to the linker. But you can have things in the linker syntax in separate files and then include it with the INCLUDE directive in the linker file:
this works the same as the #include in a C file.
LikeLike