xv6, line by line
kernel/kernel.ld

kernel/kernel.ld

linker script · 45 lines · annotated 100% · kernel · upstream

About this file

The compiler turns each source file into a separate object file (.o) with its code and data at made-up addresses starting from 0. The linker (ld) glues them into one program, kernel/kernel, and this linker script tells it exactly where in memory each part goes.

For an ordinary program those details are left to defaults. A kernel cannot leave them:

  • its first instruction must be at 0x80000000, where QEMU jumps;
  • the trampoline code must fill exactly one page of its own, because the kernel maps that page into every process;
  • C code needs to know where the code ends (etext) and where free memory starts (end), and only the linker knows those addresses.

The resulting layout of the kernel in physical memory:

0x80000000  .text     code (entry.S first), then the trampoline page
            etext     ← end of code, page-aligned
            .rodata   constants, string literals
            .data     initialized globals
            .bss      zero-initialized globals (e.g. stack0)
            end       ← first free byte; kalloc hands out pages from here up

Read next: kernel/entry.S.

1OUTPUT_ARCH( "riscv" )
2ENTRY( _entry )
4SECTIONS
5{
6 /*
7 * ensure that entry.S / _entry is at 0x80000000,
8 * where qemu's -kernel jumps.
9 */
10 . = 0x80000000;
12 .text : {
14 *(.text .text.*)
15 . = ALIGN(0x1000);
18 . = ALIGN(0x1000);
19 ASSERT(. - _trampoline == 0x1000, "error: trampoline larger than one page");
20 PROVIDE(etext = .);
21 }
24 . = ALIGN(16);
25 *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
26 . = ALIGN(16);
27 *(.rodata .rodata.*)
28 }
30 .data : {
31 . = ALIGN(16);
32 *(.sdata .sdata.*) /* do not need to distinguish this from .data */
33 . = ALIGN(16);
34 *(.data .data.*)
35 }
37 .bss : {
38 . = ALIGN(16);
39 *(.sbss .sbss.*) /* do not need to distinguish this from .bss */
40 . = ALIGN(16);
41 *(.bss .bss.*)
42 }
44 PROVIDE(end = .);