Issue
I am currently writting a embedded program for a microcontroller with a splitted flash region. Something like
MEMORY {
flash1 : ORIGIN = 0x1000, LENGTH = 0x1000
/* 1K gap */
flash2 : ORIGIN = 0x3000, LENGTH = 0x1000
}
My application has grown to a point where the ".text" section is larger than the area of flash1. Is it possible to automatically split the text section accross the two areas?
Something like:
SECTIONS {
.text0 : { *(.text) } > flash1
.text1 : { *(.text) } > flash2
}
If I am doing something like the one above. I get a error message telling me that
ld: a.out section `.text' will not fit in region `flash1'
ld: region `flash1' overflowed by 240 bytes
I know I could do something like:
SECTIONS {
.text0 : { mylargefile (.text) } > flash1
.text1 : { *(.text) } > flash2
}
but I don't have a single large file. So the question is is it possible to tell the linker to fill the first output section until the it is full and afterwards continue with the next section?
Further information:
I do not provide a full example as my actually application is much more complex as I am although using LMA and VMA section and special section for some special files. But this answer should provide me enough help to continue or ask further questions.
I am looking forward for answers. I hope my question is clear enough without a full sample
EDIT1: The solution of the question Splitting embedded program in multiple parts in memory is not correct in my case as the solution uses wildcards to spilt the files manually. I ask if there is a automatically solution. Otherwise I would be forced to manually adjust the linker file every time I do larger changes on the code base.
EDIT2: Changed example to make sure there is a gap as remarked by Tom V
Solution
Well, some compilers allow in their linkers (and the scripts) to overflow to another section, if the first one is full.
But also these have sometimes problems, that it depends on the order of when the section is full and when it switches, it does not come back to fill the first one up, e.g. you have in the beginning or the middle a very big part. When the linker skips now to the next section due to overflow, the first was maybe just filled to the half. It does not use smaller parts AFTER that big part, to go back to the first sections to fill in.
So, it seems, the GNU LD, the Gold-linker and also the LLVM/CLANG linker (which state at their site, that the linker script is the same as GNU LD, and the exceptions page does not state anything), do not support to overflow into another section.
So, to make it easier, maybe some hints:
Filtering by filename patterns can get tedious over time. And, it does not allow you to filter by symbol, only by filename pattern and input section names.
If you have a approach like AUTOSAR MemMap, you could split the code by placing them into new sections with a different naming than default
.text, .rodata, .data, .bss
. (Unfortunately, GCC + CLANG went that extra way of using attribute(( )) instead of the #pragma or _Pragma() way of the C-standard). (AUTOSAR MemMap example at the end)- you could split into fast and slow code, e.g. introducing new sections like
.codefast, .codeslow
(e.g. ISR code as fast, task level code as "slow") - you could split into QM vs ASIL partitions introducing sections like
.code_qm, .code_asila, .code_asilb
- you could split code and config / const data , where the configuration is put into a separately flashable section, e.g. sections
.text, .rodata
could be split into.text, .const .postbuildconfig, .calib
.. with a partial different coding style, you could here keep the code the same, but project config (e.g. CAN config, filter chains etc) could use a configurable config, where you just flash a new config, without updating the code itself.text
--> flash memory sector 1.postbuildconfig
--> flash memory sector 2.calib
--> flash memory sector 3
- you could split into fast and slow code, e.g. introducing new sections like
Before starting actually to really compile and link, maybe an inbetween build phase could use tools like
objdump / nm / size / readelf
to first scan over the.o
files to give out the object / section sizes and summarize them by a script according to certain criterias e.g. input memory layout and by above special sections or by ordering by size and.o
file name patterns, which you could use to update the linker script to adapt the memory definitions. SO, the script could try to fit until the gap as much as fits, then switches to the other memory. It could even try to generate the linker script parts which is later passed to the linker. You could write such a linker preprocess script in perl or python.
Together with the memory mapping to different sections, you could filter now like this:
MEMORY {
// Maybe you have two 128k areas separate by a gap
// Put the code in the first big part, and the more
// "configurable part" in the second area might even
// allow you to flash/update the separately
CODE1 : origin = 0x10000, len = 128k
// maybe here is a gap
CODE2 : origin = 0x10000, len = 64k
CONST : origin = 0x20000, len = 4k
CALIB : origin = 0x40000, len = 4k
POSTBUILD : origin = 0x50000, len = 48k
}
SECTIONS {
.code1 : {
*(.text) // default .text
*(.code_fast) // fast/slow code split
*(.code_qm) // qm/asil code split
} > CODE1
.code2 : {
*(.code_slow) // fast/slow code split
*(.code_asila) // qm/asil code split
*(.code_asilb) // qm/asil code split
} > CODE2
.const : {
*(.const)
*(.rodata)
} > CALIB
.calib : {
*(.calib)
*_calib.o(.calib) // in case you separate them also out into xxx_Calib.c files compiled to xxx_Calib.o files
} > CALIB
.postbuild : {
*(.postbuild)
*_PBCfg.o(.postbuild) // in case you separate them also out into xxx_PBCfg.c files compiled to xxx_PBCfg.o files
} > POSTBUILD
}
This approach allows you also to prepare the layout in a header, and generate that configs and calibs by certain external tools.
Additionally, it also allows a bit better to estimate your memory resource consumptions and therefore also, how and where to place/link them to the memory sections.
Here is an AUTOSAR MemMap usage example in code
#define XXX_START_SEC_CODE_FAST
#include "MemMap.h"
void XXX_Channel0_Notification(void) {
// Channel0 Finished Notification e.g. called from ISR
}
#define XXX_STOP_SEC_CODE_FAST
#include "MemMap.h"
The MemMap.h can configure this like:
#if defined(XXX_START_SEC_CODE_FAST)
#undef XXX_START_SEC_CODE_FAST
// open section .codefast
#pragma section code ".codefast"
#elif defined(XXX_START_SEC_CODE_SLOW)
#undef XXX_START_SEC_CODE_SLOW
// open section .codeslow
#pragma section code ".codeslow"
#endif
#if defined(XXX_STOP_SEC_CODE_FAST)
#undef XXX_STOP_SEC_CODE_FAST
// back to default section
#pragma section code
#elif defined(XXX_STOP_SEC_CODE_SLOW)
#undef XXX_STOP_SEC_CODE_SLOW
// back to default section
#pragma section code
#endif
The MemMap.h file could be generated, by scanning all the start/stop section defines, and generating the pragmas by a config tool (could be even Excel).
The advantage is, that you do not spill all the pragmas possible (e.g. different compilers <-> different dialects), or if to map or not to map. So you can actually reuse the code in different projects if possible.
Answered By - kesselhaus Answer Checked By - Willingham (WPSolving Volunteer)