5.5.17 · D1Embedded Systems & Real-Time Software

Foundations — Linker scripts — memory regions, sections (.text, .data, .bss)

2,221 words10 min readBack to topic

Before you can read the parent note you need a small vocabulary. Below, every symbol and term is defined in plain words, drawn as a picture, and justified by why the topic can't proceed without it. Read top to bottom — each item leans on the one above.


1. Memory as a row of numbered boxes

Everything starts here. Memory is not a mysterious cloud — it is a long line of tiny boxes, each holding one byte (8 bits), and each box has a number called its address.

Figure — Linker scripts — memory regions, sections (.text, .data, .bss)
  • The 0x prefix means "the following digits are hex."
  • Hex digits run 0 1 2 3 4 5 6 7 8 9 A B C D E F (A = ten, F = fifteen).
  • Each address points at one byte; the next box up is address + 1.

Why the topic needs this: the whole linker script is a list of addresses — ORIGIN = 0x08000000 is literally "the first box of Flash is numbered eight-oh-million-in-hex." Without addresses there is no map.


2. Two kinds of memory: Flash and RAM

The line of boxes is actually split into two physically different chips, and they behave like an attic versus a desk.

Figure — Linker scripts — memory regions, sections (.text, .data, .bss)

Key words you must own:

  • Volatile here means "loses contents without power" (a memory property). Note: this is different from the C keyword volatile in Volatile keyword & memory-mapped IO — same word, different meaning. Don't confuse them.
  • Non-volatile = keeps contents forever.

3. ORIGIN and LENGTH — where a memory starts and how big it is

A region is fully described by two numbers.

Why the topic needs it: the MEMORY { FLASH : ORIGIN=..., LENGTH=... } block in every linker script is literally these two numbers per region. If your data would exceed , the linker throws a "region overflowed" error — that check is only possible because you told it .


4. The location counter . — a moving cursor

When the linker fills a region, it lays sections down one after another like books on a shelf. It tracks where it currently is with a single special symbol: the dot.

Figure — Linker scripts — memory regions, sections (.text, .data, .bss)

Why the topic needs it: lines like _sdata = .; ... *(.data*) ... _edata = .; capture the cursor before and after placing data, so the difference is exactly the size of .data.


5. Symbols — names the linker glues to addresses

Naming pattern used everywhere in the parent (learn it now):

  • _s... = start of a region (e.g. _sdata = start of .data).
  • _e... = end of a region (e.g. _edata = end of .data).
  • _si... = start of the init values (e.g. _sidata = where .data's initial values sit in Flash).

Why the topic needs it: startup code cannot say "copy Flash to RAM" without numbers. The linker script exports _sidata, _sdata, _edata as those numbers, and the copy loop walks from _sdata to _edata. Symbols are the bridge from the map to the running code — see Startup code & Reset_Handler.


6. LMA vs VMA — the two-address idea

This is the single hardest concept the parent uses, so we build it slowly.

Figure — Linker scripts — memory regions, sections (.text, .data, .bss)

Some data needs to be in two places at two different times:

  • At rest (power off): the starting value 5 for int x = 5; must survive, so it is stored in Flash.
  • While running: x must be changeable, so it must live in RAM.

Why the topic needs it: the AT> FLASH directive exists entirely to set LMA separately from VMA. If you can't hold "one section, two addresses" in your head, AT> looks like nonsense.


7. Sections — labelled bundles of stuff

The four you must recognise (full detail lives in the parent):

  • .text ::: machine code → Flash.
  • .rodata ::: read-only constants → Flash.
  • .data ::: initialized variables → RAM run, Flash load (the two-address case).
  • .bss ::: zero-initialized variables → RAM only, no Flash bytes, just zeroed at boot.

Two more you'll meet: .stack and .heap live in RAM at runtime — see Stack vs Heap in embedded systems.


8. The vector table — the first thing the CPU reads

Why the topic needs it: the linker script must force the vector table to be first in .text and must never delete it (that's what KEEP(...) guarantees). If it moves or vanishes, the chip jumps into garbage on power-up.


How these foundations feed the topic

Address (hex box number)

Flash and RAM regions

ORIGIN and LENGTH

Location counter dot

Symbols name addresses

LMA vs VMA two addresses

Sections text data bss

Vector table placement

Linker script topic 5.5.17

Read it top-down: addresses give you regions; regions plus the moving cursor give you computed placement; computed placement plus symbols lets startup code find things; the two-address idea explains .data; sections and the vector table finish the map.


Equipment checklist

Test yourself — cover the right side and answer each before revealing.

What does the 0x prefix on a number mean, and why is hex used for addresses?
It marks a hexadecimal (base-16) number; each hex digit = 4 bits, so addresses map cleanly onto the chip's binary.
Which memory forgets everything at power-off, and which keeps it?
RAM is volatile (forgets); Flash is non-volatile (keeps).
Given ORIGIN = 0x08000000, LENGTH = 256K, what is the last usable address?
0x0803FFFF (since bytes, last box ).
What does the . (dot) symbol mean in a linker script?
The location counter — the linker's current address cursor, which advances as sections are placed.
What is a symbol like _sdata?
A name the linker binds to a real address, so startup code can refer to that box number.
What is the difference between VMA and LMA?
VMA = run address (where data lives while running, RAM for .data); LMA = load address (where its initial bytes are stored at rest, Flash).
Why does .text have VMA = LMA but .data does not?
Code executes directly from Flash so needs one address; .data must be stored non-volatile (Flash) yet writable (RAM), so it needs two.
Why does .bss store no bytes in the Flash binary?
It is zero-initialized — only its size is recorded, and startup code writes the zeros into RAM at boot.
Why must the vector table be first in Flash and wrapped in KEEP?
The CPU reads the very first Flash boxes on reset to find its stack pointer and boot code; KEEP stops garbage collection from deleting it.