![]() When a symbol needs to be placed to a different target than the one designated for the object file, the object file is expanded, which includes the following steps: 1. Creating a new placement for the symbol's input section with the specified target. 2. Excluding the object placement from the orignal target. 3. Creating a new intermediate placement for the object for the original target, where its input sections are expanded, excluding the input section for the symbol. Let's illustrate the object expansion process with the following example: [sections:rodata] entries: .rodata+ .sdata2+ .srodata+ [scheme:default] entries: text -> flash_text rodata -> flash_rodata [scheme:noflash] entries: text -> iram0_text rodata -> dram0_data [mapping:soc_pm] archive: libsoc.a entries: gpio_periph: GPIO_HOLD_MASK (noflash) gpio_periph section headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 000000 00 AX 0 0 2 [ 2] .data PROGBITS 00000000 000034 000000 00 WA 0 0 1 [ 3] .bss NOBITS 00000000 000034 000000 00 WA 0 0 1 [ 4] .rodata.GPIO_HOLD_MASK PROGBITS 00000000 000034 000058 00 A 0 0 4 [ 5] .rodata.GPIO_PIN_MUX_REG PROGBITS 00000000 00008c 000058 00 A 0 0 4 [ 6] .debug_info PROGBITS 00000000 0000e4 0000d8 00 0 0 1 [ 7] .rela.debug_info RELA 00000000 0009d4 000108 0c I 16 6 4 [ 8] .debug_abbrev PROGBITS 00000000 0001bc 000070 00 0 0 1 [ 9] .debug_aranges PROGBITS 00000000 00022c 000018 00 0 0 1 [10] .rela.debug_aranges RELA 00000000 000adc 00000c 0c I 16 9 4 [11] .debug_line PROGBITS 00000000 000244 0001ab 00 0 0 1 [12] .debug_str PROGBITS 00000000 0003ef 00022d 01 MS 0 0 1 [13] .comment PROGBITS 00000000 00061c 000030 01 MS 0 0 1 [14] .note.GNU-stack PROGBITS 00000000 00064c 000000 00 0 0 1 [15] .riscv.attributes RISCV_ATTRIBUTES 00000000 00064c 000044 00 0 0 1 [16] .symtab SYMTAB 00000000 000690 000260 10 17 36 4 [17] .strtab STRTAB 00000000 0008f0 0000e1 00 0 0 1 [18] .shstrtab STRTAB 00000000 000ae8 0000d1 00 0 0 1 1. Creating a new placement .dram0.data : { *libsoc.a:gpio_periph.*(.rodata.GPIO_HOLD_MASK .sdata2.GPIO_HOLD_MASK .srodata.GPIO_HOLD_MASK) } 2. Excluding the object placement .flash.rodata : { *(EXCLUDE_FILE(*libsoc.a:gpio_periph.*) .rodata.* ...) } 3. Creating a new intermediate placement .flash.rodata : { *libsoc.a:gpio_periph.*(.rodata.GPIO_PIN_MUX_REG) } Now, let's do the same, but also move GPIO_PIN_MUX_REG to noflash with an updated mapping. [mapping:soc_pm] archive: libsoc.a entries: gpio_periph: GPIO_HOLD_MASK (noflash) gpio_periph: GPIO_PIN_MUX_REG (noflash) 1. Creating a new placement .dram0.data : { *libsoc.a:gpio_periph.*(.rodata.GPIO_HOLD_MASK .sdata2.GPIO_HOLD_MASK .srodata.GPIO_HOLD_MASK) *libsoc.a:gpio_periph.*(.rodata.GPIO_PIN_MUX_REG .sdata2.GPIO_PIN_MUX_REG .srodata.GPIO_PIN_MUX_REG) } 2. Excluding the object placement .flash.rodata : { *(EXCLUDE_FILE(*libsoc.a:gpio_periph.*) .rodata.* ...) } 3. Creating a new intermediate placement .flash.rodata : { *libsoc.a:gpio_periph.* } The *libsoc.a:gpio_periph.* entity in step 3 no longer has input sections, as there are no remaining .rodata input sections in the object file. The linker behavior for this mapping is to include all object input sections that have not yet been placed as described in https://sourceware.org/binutils/docs/ld.html#Input-Section-Basics "If you use a file name without a list of sections, then all sections in the input file will be included in the output section. This is not commonly done, but it may by useful on occasion." The map file for such mapping now contains following input sections .flash.rodata 0x3c0a0120 0x19b34 *libsoc.a:gpio_periph.*() .debug_info 0x3c0b95bf 0xd8 esp-idf/soc/libsoc.a(gpio_periph.c.obj) .debug_abbrev 0x3c0b9697 0x70 esp-idf/soc/libsoc.a(gpio_periph.c.obj) .debug_aranges 0x3c0b9707 0x18 esp-idf/soc/libsoc.a(gpio_periph.c.obj) .debug_line 0x3c0b971f 0x1ab esp-idf/soc/libsoc.a(gpio_periph.c.obj) .debug_str 0x3c0b98ca 0x21a esp-idf/soc/libsoc.a(gpio_periph.c.obj) 0x22d (size before relaxing) .comment 0x3c0b9ae4 0x30 esp-idf/soc/libsoc.a(gpio_periph.c.obj) .note.GNU-stack 0x3c0b9ae4 0x0 esp-idf/soc/libsoc.a(gpio_periph.c.obj) .riscv.attributes 0x3c0b9ae4 0x44 esp-idf/soc/libsoc.a(gpio_periph.c.obj) This is incorrect, and such intermediate placement should not be generated. This type of placement can be recognized because it is not explicitly defined in the mapping and lacks input sections. We can identify this in the significant function and prevent issuing commands for such placement. Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com> |
||
---|---|---|
.. | ||
ldgen | ||
samples | ||
test | ||
README.md | ||
ldgen.py |
README.md
Linker Script Generator
Contains code that implements linker script generation, ldgen
. For more information about the feature,
see docs/en/api-guides/linker-script-generation.rst
.
Source Files
The following are the source files in the directory:
ldgen.py
- Python executable that gets called during build.entity.py
- contains classes related to entities (library, object, symbol or combination of the above) with mappable input sections.fragments.py
- contains classes for parsing the different types of fragments in linker fragment files.generation.py
- contains bulk of the logic used to process fragments into output commands.sdkconfig.py
- used for evaluating conditionals in fragment files.linker_script.py
- augments the input linker script template with output commands from generation process to produce the output linker script.output_commands.py
- contains classes that represent the output commands in the output linker script.ldgen_common.py
- contains miscellaneous utilities/definitions that can be used in the files mentioned above.
Tests
Unit tests are in the test
directory. These tests are run as part of CI in the job test_ldgen_on_host
.
There is also a test app for ldgen
in tools/test_apps/build_system/ldgen_test
.
Build System
Linker script generation is a part of the build process. The build scripts tools/cmake/ldgen.cmake
and make/ldgen.mk
contain the build-system-side implementation for CMake and Make, respectively.
Basic Flow
The build system invokes ldgen.py
, passing some information from the build.
The linker fragment files are parsed by fragments.py
, evaluating conditional expressions
with sdkconfig.py
.
From the parsed fragments, generation.py
generates output commands defined in output_commands.py
,
with some help from entity.py
.
linker_script.py
writes the output linker script, replacing markers with output commands generated.
More details about the implementation are in the respective source files.