a linker script
When the linker combines your object files, it has to decide where everything goes: which input sections get merged into which output sections, what address each output section starts at, and the order they appear in the final file. For a normal program on a normal operating system, the linker uses a sensible built-in default and you never think about it. A linker script is the explicit recipe that overrides that default — a text file that tells the linker exactly how to lay out the program's sections and segments in memory.
A linker script is organized around two main ideas. The SECTIONS command lists the output sections to create and, for each, which input sections to gather into it and at what address — for example, 'put all input .text sections into an output .text section starting at address 0x8000000'. A special symbol, the location counter written as a dot ('.'), tracks the current address as the script lays things down, and you can assign to it to leave gaps or align to a boundary. The optional MEMORY command describes the physical regions available (their start addresses and sizes), which matters enormously on bare-metal and embedded systems where you must place code in flash and data in a specific RAM range. The script can also define symbols (like the start and end of a region) that your code can then reference.
It matters most outside ordinary application programming. On embedded microcontrollers there is no operating system to lay out memory for you, so a linker script is mandatory: it places the interrupt vector table at the reset address, puts code in flash, and reserves RAM for the stack and variables — without it the chip would not even boot. The honest note is that for everyday Linux or macOS programs you almost never write one, and writing one by hand for a hosted system is easy to get subtly wrong; the default script the toolchain provides is carefully tuned. See the related field on section and segment placement for how sections become the segments the loader maps.
/* tiny linker script fragment */ SECTIONS { . = 0x8000000; /* set location counter (start address) */ .text : { *(.text*) } /* gather all input .text into output .text */ .data : { *(.data*) } _end = .; /* define a symbol at the current address */ }
The SECTIONS block maps input sections to output sections at chosen addresses; the dot is the location counter, and _end becomes a symbol your code can use.
For hosted programs on Linux/macOS you rarely write a linker script — the toolchain's default is carefully tuned. It is essential on bare-metal/embedded targets, where it must place the vector table, code in flash, and data in RAM, or the device will not boot.