Posted on , updated on , in Programming, tagged with c, embedded
Explicitly Place All Sections When Linking With GNU LD
The Problem
If you place your sections manually, you sometimes forget one and the gnu linker places it automatically. Having data or code linked in the wrong place often works for a while or when not doing in depth tests, but can cause your system to have very odd behavior that is hard to pinpoint. If you are writing a linker script, it is best to place everything explicitly and get notified about every unplaced section.
The Solution
A way to produce such a warning, is to define a catch all section and using ASSERT()
to test, that it is empty:
1 memories {...}
2 sections {
3
4 .text : {
5 *(.text)
6 } > rom
7 .data : {
8 *(.data)
9 } > ram
10
11 .debug_macro : { *(.debug_macro) }
12 .debug_line : { *(.debug_line) }
13 .debug_str : { *(.debug_str) }
14 .debug_frame : { *(.debug_frame) }
15 .debug_info : { *(.debug_info) }
16 .debug_abbrev : { *(.debug_abbrev) }
17 .debug_aranges : { *(.debug_aranges) }
18 .debug_ranges : { *(.debug_ranges) }
19 .debug_loc : { *(.debug_loc) }
20 .comment : { *(.comment) }
21 .version_info : { *(.version_info) }
22
23 .unplaced : {
24 __unplaced_start = . ;
25 *(*)
26 __unplaced_end = . ;
27
28 ASSERT(__unplaced_start == __unplaced_end, "ASSERT(.unplaced empty) failed");
29 /*
30 * If the assert failed, check the .unplaced section in map file and
31 * manually place anything that was placed there.
32 */
33 }
34 }
This part of the linker script places .data
in ram, a bunch of debug stuff at its default location and anything else will end up in .unplaced
and trigger an error like this:
ld: error: ASSERT(.unplaced empty) failed
If you look at the map file:
.unplaced memory region -> /DISCARD/
0x00000000 0x1234
0x00000000 __unplaced_start = .
*(*)
.text.hello_world
0x00000000 0x32 ./lib/lib.a(test.o)
0x00000034 __unplaced_end = .
0x00000000 ASSERT ((__unplaced_start == __unplaced_end), ...)
This tells you, that there is a section .text.hello_world
which the compiler created when compiling test.o
which is part of lib/lib.a
and you did not place it explicitly.
The reason is, that we captured .text
but not .text.*
. The issue was
introduced when adding -ffunction-sections
to the compiler options in order to
reduce ROM usage (by also passing -gc-sections
to the linker). This changes
the section where code is placed, so it ended up in the wrong place.
Depending on your compilers settings, a bunch of different debug sections will have to be added to the script. I have not found a more compact way which still allows debugging. Please write to me if you know the way!