.data
for immutable data;module_a.c
: static int local_function(); int external_counter; static int counter; static int preset_counter = 5; const int constant = 10; int public_function() { volatile int i = 3 + constant; ++external_counter; return local_function() * i; } static int local_function() { ++counter; ++preset_counter; return counter + preset_counter; }
% rake 'show:sections[a]' arm-none-eabi-gcc -mthumb -O2 -mcpu=cortex-m0 -c module_a.c -o build/module_a.o arm-none-eabi-objdump build/module_a.o -h build/module_a.o: file format elf32-littlearm Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000034 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 00000004 00000000 00000000 00000068 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000004 00000000 00000000 0000006c 2**2 ALLOC 3 .rodata 00000004 00000000 00000000 0000006c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .comment 00000071 00000000 00000000 00000070 2**0 CONTENTS, READONLY 5 .ARM.attributes 00000031 00000000 00000000 000000e1 2**0 CONTENTS, READONLY
% rake 'show:symbols:text[a]' arm-none-eabi-objdump build/module_a.o -j .text -t build/module_a.o: file format elf32-littlearm SYMBOL TABLE: 00000000 ld .text 00000000 .text 00000000 g F .text 00000034 public_function
.text
is a debugging symbol that indicates the beginning of a section, public_function
is a symbol that indicates our function. There is local_function
symbol for local_function
, since the function is declared as static
, i.e., it is not exported outside the object file. % rake 'show:symbols:data[a]' arm-none-eabi-objdump build/module_a.o -j .data -j .bss -t build/module_a.o: file format elf32-littlearm SYMBOL TABLE: 00000000 ld .data 00000000 .data 00000000 ld .bss 00000000 .bss 00000000 l O .data 00000004 preset_counter 00000000 l O .bss 00000004 counter
.data
and .bss
sections there are two of our counters - preset_counter
and counter
. They are in different sections, since preset_counter
has an initial value, which is stored in .data
: % rake 'show:contents[a,.data]' arm-none-eabi-objdump build/module_a.o -j .data -s build/module_a.o: file format elf32-littlearm Contents of section .data: 0000 05000000
counter
no value, so it is initialized to zero and falls into the .bss
section. The .bss
section itself is not physically present in the file, since its contents are always fixed - these are zeros. If you declared char buffer[1024]
in the code, then the compiler would have to write a kilobyte of empty space into the object file, which makes no sense.external_counter
go? % rake 'show:symbols:all[a]' arm-none-eabi-objdump build/module_a.o -t build/module_a.o: file format elf32-littlearm SYMBOL TABLE: 00000000 l df *ABS* 00000000 module_a.c 00000000 ld .text 00000000 .text 00000000 ld .data 00000000 .data 00000000 ld .bss 00000000 .bss 00000000 ld .rodata 00000000 .rodata 00000000 l O .data 00000004 preset_counter 00000000 l O .bss 00000004 counter 00000000 ld .comment 00000000 .comment 00000000 ld .ARM.attributes 00000000 .ARM.attributes 00000000 g F .text 00000034 public_function 00000004 O *COM* 00000004 external_counter 00000000 g O .rodata 00000004 constant
external_counter
went to the *COM*
section. In this case, this means that it may be outside of this object file. Already at the layout stage, ld will figure out whether a character is declared in another file, or whether it should create it itself - in this case, in the .bss
section. Also note that const int constant
got into .rodata
. The compiler ensures that the code does not need to change the value at this address, so that the linker can easily place it in flash memory..comment
: % rake 'show:contents[a,.comment]' arm-none-eabi-objdump build/module_a.o -j .comment -s build/module_a.o: file format elf32-littlearm Contents of section .comment: 0000 00474343 3a202847 4e552054 6f6f6c73 .GCC: (GNU Tools 0010 20666f72 2041524d 20456d62 65646465 for ARM Embedde 0020 64205072 6f636573 736f7273 2920342e d Processors) 4. 0030 372e3320 32303133 30333132 20287265 7.3 20130312 (re 0040 6c656173 6529205b 41524d2f 656d6265 lease) [ARM/embe 0050 64646564 2d345f37 2d627261 6e636820 dded-4_7-branch 0060 72657669 73696f6e 20313936 3631355d revision 196615] 0070 00
.ARM.attributes
, though for this you should not use objdump , but readelf : % rake 'show:attrs[a]' arm-none-eabi-readelf build/module_a.o -A Attribute Section: aeabi File Attributes Tag_CPU_name: "Cortex-M0" Tag_CPU_arch: v6S-M Tag_CPU_arch_profile: Microcontroller Tag_THUMB_ISA_use: Thumb-1 Tag_ABI_PCS_wchar_t: 4 Tag_ABI_FP_denormal: Needed Tag_ABI_FP_exceptions: Needed Tag_ABI_FP_number_model: IEEE 754 Tag_ABI_align_needed: 8-byte Tag_ABI_align_preserved: 8-byte, except leaf SP Tag_ABI_enum_size: small Tag_ABI_optimization_goals: Aggressive Speed
layout.ld:
MEMORY { rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x8000 ram(WAIL) : ORIGIN = 0x10000000, LENGTH = 0x2000 } ENTRY(public_function) SECTIONS { .text : { *(.text) } > rom _data_start = .; .data : { *(.data) } > ram AT> rom _bss_start = .; .bss : { *(.bss) } > ram _bss_end = .; }
rom
and ram
. The letters in parentheses define the attributes: access to read, write, execute, allocate memory. Sections that are not explicitly indicated in the script will be scattered across regions with matching attributes automatically. If there is no space for a section, the linker will refuse to work, arguing its behavior in some way: error: no memory region specified for loadable section `.data'
.ORIGIN
and LENGTH
, specify the beginning and length of the region, respectively, org
, o
, len
and l
can be found, they are equivalent. Value is an expression, i.e., it is possible to perform arithmetic operations or use the suffixes K
, M
, etc. The recording LENGTH = 0x8000
, for example, can alternatively be done like this: l = 32K
._(_)
, the symbol *
behaves in a standard way, so the entry *(.text)
means: the .text
sections from all files..text
) into flash memory, data ( .data
) into flash memory, but on the basis that they will be available in RAM, and .bss
into RAM..bss
, in general, initialization is not required ( UPD : I’m prompted in the gill that is required, we must ensure that there are zeros, and not garbage, which appeared for some reason), since the microcontroller’s operational memory and so probably reset. But with .data
will have to tinker separately, the problem is due to the dual nature. On the one hand, specific data is stored there (the preset_counter
starting value), so it should be in flash memory. On the other hand, this is a writeable section, so it should be in RAM. This problem is solved by different LMA and VMA, as well as an additional C code, which, when launched, will copy content from LMA to VMA. For constant data, which usually resides in the .rodata
section, such a procedure, for example, is not needed, we can safely read from straight from the flash memory..
(point). % rake 'show:map[a]' arm-none-eabi-ld -T layout.ld -M -o build/out.elf build/module_a.o Allocating common symbols Common symbol size file external_counter 0x4 build/module_a.o Memory Configuration Name Origin Length Attributes rom 0x0000000000000000 0x0000000000008000 xr ram 0x0000000010000000 0x0000000000002000 awl *default* 0x0000000000000000 0xffffffffffffffff
external_counter
into a separate category. Next, we see that our memory configuration has been loaded and added to the default configuration (which allocates the entire address space). Linker script and memory map .text 0x0000000000000000 0x34 *(.text) .text 0x0000000000000000 0x34 build/module_a.o 0x0000000000000000 public_function 0x0000000000000034 _data_start = .
.text
. .rodata 0x0000000000000034 0x4 .rodata 0x0000000000000034 0x4 build/module_a.o 0x0000000000000034 constant .glue_7 0x0000000000000038 0x0 .glue_7 0x0000000000000000 0x0 linker stubs .glue_7t 0x0000000000000038 0x0 .glue_7t 0x0000000000000000 0x0 linker stubs .vfp11_veneer 0x0000000000000038 0x0 .vfp11_veneer 0x0000000000000000 0x0 linker stubs .v4_bx 0x0000000000000038 0x0 .v4_bx 0x0000000000000000 0x0 linker stubs .iplt 0x0000000000000038 0x0 .iplt 0x0000000000000000 0x0 build/module_a.o .rel.dyn 0x0000000000000038 0x0 .rel.iplt 0x0000000000000000 0x0 build/module_a.o
.rodata
, .glue_7
, .glue_7t
, .vfp11_veneer
, .v4_bx
, .iplt
, .rel.dyn
. With .rodata
everything is clear, our constant constant
is stored in four bytes. As for the rest of the sections, their existence is obliged to full support of efficiency, for example, the jumps from ARM to Thumb. All of these sections are empty and do not fall into the final image. .data 0x0000000010000000 0x4 load address 0x0000000000000038 *(.data) .data 0x0000000010000000 0x4 build/module_a.o 0x0000000010000004 _data_end = .
.data
section, as you see, it is located at 0x10000000
, although it is physically stored at 0x38
(that is, immediately after .rodata
). Here we see the value of our variable, read from the cursor, _data_end
. .igot.plt 0x0000000010000004 0x0 load address 0x000000000000003c .igot.plt 0x0000000000000000 0x0 build/module_a.o .bss 0x0000000010000004 0x8 load address 0x000000000000003c *(.bss) .bss 0x0000000010000004 0x4 build/module_a.o COMMON 0x0000000010000008 0x4 build/module_a.o 0x0000000010000008 external_counter 0x000000001000000c _bss_end = .
.bss
. LOAD build/module_a.o OUTPUT(build/out.elf elf32-littlearm) .comment 0x0000000000000000 0x70 .comment 0x0000000000000000 0x70 build/module_a.o 0x71 (size before relaxing) .ARM.attributes 0x0000000000000000 0x31 .ARM.attributes 0x0000000000000000 0x31 build/module_a.o
0x0000000000000034 _data_start = . ... .data 0x0000000010000000 0x4 load address 0x0000000000000038
.data
actually indicates the wrong place! But the truth is, the cursor after .text
indicates its end. To set a variable correctly, it must be moved inside the description of the output section: .data : { _data_start = .; *(.data) _data_end = .; } > ram AT> rom
% rake 'show:map[a]' SCRIPT=layout2.ld arm-none-eabi-ld -T layout2.ld -M -o build/module_a.elf build/module_a.o ... .data 0x0000000010000000 0x4 load address 0x0000000000000038 0x0000000010000000 _data_start = . *(.data) .data 0x0000000010000000 0x4 build/module_a.o 0x0000000010000004 _data_end = . ...
.data
? As you remember, the data is physically stored in a flash, and working with them will be from RAM. For this reason, we will have to write a boot code that will copy the .data
into RAM, and these variables will help us find out the specific addresses where the section should be moved.external_counter
and some C ++ code: module_b.cpp
int external_counter; extern "C" int public_function(); void function_b() { external_counter += public_function(); } void function_c() { } void function_d() { }
% rake 'show:symbols:text[b]' arm-none-eabi-gcc -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -mthumb -O2 -mcpu=cortex-m0 -c module_b.cpp -o build/module_b.o arm-none-eabi-objdump build/module_b.o -j .text -t build/module_b.o: file format elf32-littlearm SYMBOL TABLE: 00000000 ld .text 00000000 .text 00000000 g F .text 00000014 _Z10function_bv 00000014 g F .text 00000002 _Z10function_cv 00000018 g F .text 00000002 _Z10function_dv
-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables
flags to avoid additional sections related to exception handling. The names of the functions were coded accordingly.public_function
function from module a
. We compose both modules at once: % rake 'show:map[a|b]' SCRIPT=layout2.ld arm-none-eabi-ld -T layout2.ld -M -o build/out.elf build/module_a.o build/module_b.o ... .text 0x0000000000000000 0x34 build/module_a.o 0x0000000000000000 public_function .text 0x0000000000000034 0x1c build/module_b.o 0x0000000000000034 function_b() 0x0000000000000048 function_c() 0x000000000000004c function_d() ...
.text
, as well as others, are arranged one after another.--gc-sections
flag: % rake 'show:map[a|b]' SCRIPT=layout2.ld GC=1 arm-none-eabi-ld --gc-sections -T layout2.ld -M -o build/out.elf build/module_a.o build/module_b.o Discarded input sections .rodata 0x0000000000000000 0x4 build/module_a.o COMMON 0x0000000000000000 0x0 build/module_a.o .text 0x0000000000000000 0x1c build/module_b.o .data 0x0000000000000000 0x0 build/module_b.o ... .text 0x0000000000000000 0x34 *(.text) .text 0x0000000000000000 0x34 build/module_a.o 0x0000000000000000 public_function ...
.text
section of build/module_b.o
was removed completely, as it contained useless functions! At the same time, the linker threw out unused constants from the first module.module_c.cpp
void function_b(); extern "C" int public_function() { function_b(); }
a
with module c
and see if the linker can delete the section. % rake 'show:map[b|c]' SCRIPT=layout2.ld GC=1 arm-none-eabi-gcc -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -mthumb -O2 -mcpu=cortex-m0 -c module_c.cpp -o build/module_c.o arm-none-eabi-ld --gc-sections -T layout2.ld -M -o build/out.elf build/module_b.o build/module_c.o Discarded input sections .data 0x0000000000000000 0x0 build/module_b.o .data 0x0000000000000000 0x0 build/module_c.o .bss 0x0000000000000000 0x0 build/module_c.o ... .text 0x0000000000000000 0x24 *(.text) .text 0x0000000000000000 0x1c build/module_b.o 0x0000000000000000 function_b() 0x0000000000000014 function_c() 0x0000000000000018 function_d() .text 0x000000000000001c 0x8 build/module_c.o 0x000000000000001c public_function
function_c()
and function_d()
, which ended up in the same section as the function_b()
that we need. Compiler flags will come to the rescue, which break functions and data into different sections: -ffunction-sections
and -fdata-sections
: % rake clean && rake 'show:symbols:all[b]' SPLIT_SECTIONS=1 arm-none-eabi-gcc -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -mthumb -O2 -mcpu=cortex-m0 -c module_b.cpp -o build/module_b.o arm-none-eabi-objdump build/module_b.o -t build/module_b.o: file format elf32-littlearm SYMBOL TABLE: 00000000 l df *ABS* 00000000 module_b.cpp 00000000 ld .text 00000000 .text 00000000 ld .data 00000000 .data 00000000 ld .bss 00000000 .bss 00000000 ld .text._Z10function_bv 00000000 .text._Z10function_bv 00000000 ld .text._Z10function_cv 00000000 .text._Z10function_cv 00000000 ld .text._Z10function_dv 00000000 .text._Z10function_dv 00000000 ld .bss.external_counter 00000000 .bss.external_counter 00000000 ld .comment 00000000 .comment 00000000 ld .ARM.attributes 00000000 .ARM.attributes 00000000 g F .text._Z10function_bv 00000014 _Z10function_bv 00000000 *UND* 00000000 public_function 00000000 g F .text._Z10function_cv 00000002 _Z10function_cv 00000000 g F .text._Z10function_dv 00000002 _Z10function_dv 00000000 g O .bss.external_counter 00000004 external_counter
% rake clean && rake 'show:map[b|c]' SCRIPT=layout2.ld GC=1 SPLIT_SECTIONS=1 arm-none-eabi-gcc -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -mthumb -O2 -mcpu=cortex-m0 -c module_b.cpp -o build/module_b.o arm-none-eabi-gcc -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -mthumb -O2 -mcpu=cortex-m0 -c module_c.cpp -o build/module_c.o arm-none-eabi-ld --gc-sections -T layout2.ld -M -o build/out.elf build/module_b.o build/module_c.o Discarded input sections .text 0x0000000000000000 0x0 build/module_b.o .data 0x0000000000000000 0x0 build/module_b.o .bss 0x0000000000000000 0x0 build/module_b.o .text._Z10function_cv 0x0000000000000000 0x4 build/module_b.o .text._Z10function_dv 0x0000000000000000 0x4 build/module_b.o .text 0x0000000000000000 0x0 build/module_c.o .data 0x0000000000000000 0x0 build/module_c.o .bss 0x0000000000000000 0x0 build/module_c.o ...
Source: https://habr.com/ru/post/191058/
All Articles