Skip to content

Commit 8d60315

Browse files
committed
Comment and explain the linker script and the way the relocation works
1 parent 6ccad3d commit 8d60315

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

stm32-lvgl/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ Optionally, you can also run build and run the code in a desktop OS SDL "simulat
4444
```console
4545
$ make simulator
4646
```
47+
48+
## Additional information
49+
50+
- The ELF linking, linker script and packaging scheme is destribed in detail [inside the linker script](Sources/Support/linkerscript.ld).

stm32-lvgl/Sources/Support/Startup.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ void enable_fpu(void) {
1818

1919
// Reset entrypoint. Enables FPU, relocates the data sections from FLASH to DRAM
2020
// and jumps to main (implemented in Application/Main.swift).
21+
//
22+
// See linkerscript.ld for a detailed explanation.
2123
__attribute__((naked)) __attribute__((noreturn)) void ResetISR(void) {
2224
asm volatile("bl enable_fpu");
2325
asm volatile("ldr r0, =__data_start // dst");

stm32-lvgl/Sources/Support/linkerscript.ld

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,62 @@
1+
/*===----------------------------------------------------------------------===*/
2+
/* */
3+
/* This source file is part of the Swift open source project */
4+
/* */
5+
/* Copyright (c) 2025 Apple Inc. and the Swift project authors. */
6+
/* Licensed under Apache License v2.0 with Runtime Library Exception */
7+
/* */
8+
/* See https://swift.org/LICENSE.txt for license information */
9+
/* */
10+
/*===----------------------------------------------------------------------===*/
11+
12+
/*
13+
* This application uses ELF for linking, and uses the elf2hex.py post-processing tool for package the result into a
14+
* form suitable for flashing. The entire memory layout scheme (which this linker script participates in) is:
15+
*
16+
* - At normal application runtime, the expected memory layout is:
17+
*
18+
* - 0x08000000-0x08100000 (flash) ... code + read-only globals
19+
* - 0x20000000-0x20008000 (SRAM) ... stack
20+
* - 0x20008000-0x20030000 (SRAM) ... read-write globals, and bss (zero initialized globals)
21+
* - 0x20030000-0x20050000 (SRAM) ... heap
22+
*
23+
* - However, this layout cannot be flashed as is (because it uses the SRAM too), so a few more steps are needed.
24+
*
25+
* - In a linked ELF file, the memory locations of the sections match the expected runtime layout. The ELF file does not
26+
* contain the stack and the heap, so we don't have to worry about those (there is also no expectation that the memory
27+
* for those is zeroed out at program start).
28+
*
29+
* - The ELF file is given to the elf2hex.py tool, which will produce a .hex output, and we use the
30+
* --relocate-data-segment flag to relocate the read-write globals region (0x20008000-0x20030000) into the flash
31+
* region, concretely the region is appended at a 4-byte-aligned location after the other contents of the flash.
32+
*
33+
* - This is concretely achieved using the __flash_data_start+__flash_data_len and __data_start+__data_end symbols
34+
* defined in this linker script. The elf2hex.py script finds the addresses of these symbols and performs the
35+
* relocation of those bytes.
36+
* - Note that after the relocation, the segments in ELF headers (PT_LOAD commands) don't match the actual physical
37+
* layout. However, this relocation is reversed at early startup time, so that at "normal" runtime, the layout is
38+
* as expected. See below.
39+
*
40+
* - The ARM core loads the initial stack pointer, and initial program counter from the vector table which is placed at
41+
* a well-known location, concretely the very beginning of flash, 0x08000000. The linker script places the .vectors
42+
* section as the very first section into the flash to satisfy this. See Startup.c for the concrete content of the
43+
* vector table, and how the initial SP and PC are set up.
44+
*
45+
* - The initial startup code (ResetISR in Startup.c) only does one setup step (enabling the FPU) before performing the
46+
* reverse relocation of the data segment. The runtime back-relocation is simply a memcpy from __flash_data_start back
47+
* into __data_start (in the SRAM region).
48+
*
49+
* - During this and before this (e.g. when doing the FPU enablement), read-write globals cannot be used. Reading
50+
* a read-write global won't read the correct initial value of that global.
51+
* - That's why the ResetISR code is written as attribute((naked)) asm implementation. The implementation is also
52+
* very simple and it's easy to see that it indeed does not touch any globals.
53+
* - We expect that the implementation of memcpy is also not accessing any globals. This is a reasonable expectation
54+
* on any embedded-friendly memcpy implementation.
55+
*
56+
* - After that, the normal runtime memory layout is matched, and the application continues to initialize itself and
57+
* run.
58+
*/
59+
160
MEMORY
261
{
362
flash (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* end: 0x08100000 */

0 commit comments

Comments
 (0)