The build system for U-Boot SPL determines the linker script used during the final linking stage. Based on the logic in scripts/Makefile.spl, if a board-specific script (e.g., board/sunxi/u-boot-spl.lds) is not present, the build system defaults to the architecture-specific script located at arch/arm/cpu/armv8/u-boot-spl.lds. The if_changed_dep function processes this source file to generate the final spl/u-boot-spl.lds, expanding macros and preparing the layout for the binary.
Memory Region Definitions
The script defines two primary memory regions used by the SPL phase:
#define CONFIG_SPL_TEXT_BASE 0x10060
#define CONFIG_SPL_MAX_SIZE 0x7fa0
#define CONFIG_SPL_BSS_START_ADDR 0x4ff80000
#define CONFIG_SPL_BSS_MAX_SIZE 0x00080000
- SRAM: Used for execution.
CONFIG_SPL_TEXT_BASE(0x10060) marks the start of the code region. - SDRAM: Used for the BSS segment.
CONFIG_SPL_BSS_START_ADDR(0x4ff80000) marks where uninitialized data will reside at runtime.
The output format is specified as elf64-littleaarch64, with the entry point set to _start.
Code Section (.text) Layout
The executable code is mapped to the SRAM region. The layout ensures specific ordering:
- Alignment: The address counter
.is aligned to 8 bytes immediately. - Image Boudnaries: Zero-length arrays,
__image_copy_startand__image_copy_end, are placed at the beginning and end of the copyable content. These symbols, defined inarch/arm/lib/section.c, do not consume space but mark the range for memory copy operations. - Startup Code: The code from
arch/arm/cpu/armv8/start.ois forced to the beginning of the text section to ensure execution starts there. - General Code: All other object files contribute their text sections following the startup code.
/* arch/arm/lib/section.c */
char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
SRAM Data Sections
Following the text section, the SRAM region contains:
- .rodata: Read-only data. The linker sorts these by alignment (descending) and then by name to minimize padding.
- .data: Initialized global and static variables.
- .u_boot_list: A section for linker-list structures (often used for command registration). The
KEEPdirective ensures these sections are retained even if unused. They are sorted by name.
The linker list mechanism relies on macros defined in include/linker_lists.h. For example, declaring a command involves placing a structure into a specific section:
/* Macro expansion creates symbols like _u_boot_list_2_cmd_2_help */
#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))
BSS and SDRAM Placement
The BSS (Block Started by Symbol) segment holds uninitialized global variables. In the linker script, this section is assigned to the SDRAM region. Unlike the text and data sections, BSS does not occupy space in the binary file; it is zeroed out in memory during runtime initialization.
Because the BSS is located in external memory (SDRAM), the SPL must initialize the SDRAM controller before attempting to use any uninitialized global variables or before performing relocation to that memory region.
Discarding Sections
The /DISCARD/ directive at the end of the script instructs the linker to exclude specific sections (such as comment sections or debugging info) from the final output binary to reduce size.