Files
Elyz/kernel/docs/boot/linker.md
2026-07-07 16:40:41 +03:00

152 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Линкер-скрипты: архитектурные детали
## Назначение
Линкер-скрипты управляют расположением секций ELF-образа ядра.
Для каждой архитектуры — свой скрипт, но все они следуют одной схеме.
## Общая структура
```
OUTPUT_FORMAT(...) ← формат ELF (зависит от архитектуры)
ENTRY(kmain) ← точка входа
PHDRS ← сегменты (program headers)
{
text PT_LOAD;
rodata PT_LOAD;
data PT_LOAD;
}
SECTIONS ← расположение секций
{
. = 0xffffffff80000000; ← база higher half
.text : { *(.text .text.*) } :text
. = ALIGN(MAXPAGESIZE);
.rodata : { *(.rodata .rodata.*) } :rodata
. = ALIGN(MAXPAGESIZE);
.data : {
*(.data .data.*)
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
} :data
.bss : { *(.bss .bss.*) *(COMMON) } :data
/DISCARD/ : { *(.eh_frame*) *(.note .note.*) }
}
```
## Детали
### OUTPUT_FORMAT
| Архитектура | Формат |
|-------------|--------|
| x86_64 | `elf64-x86-64` |
| aarch64 | `elf64-littleaarch64` |
| riscv64 | `elf64-littleriscv` |
| loongarch64 | `elf64-loongarch` |
### Базовый адрес: 0xFFFFFFFF80000000
Ядро размещается в **higher half** — верхней 2 GiB виртуального
адресного пространства. Это стандартная практика для x86-64:
```
0x0000_0000_0000_00000 ─── user space (не используется ядром)
0xFFFF_8000_0000_00000 ─── kernel space (higher half)
0xFFFF_FFFF_FFFF_FFFF ─── конец
```
Любой адрес в области 0xFFFF800000000000 — 0xFFFFFFFFFFFFFFFF корректен;
0xFFFFFFFF80000000 выбран как начало typical higher half региона.
### PHDRS: PT_LOAD сегменты
Bootloader загружает только PT_LOAD сегменты. Их три:
1. **text**: код + inline-константы.
2. **rodata**: неизменяемые данные (строки, таблицы).
3. **data**: изменяемые данные + BSS.
### Section alignment
```ld
. = ALIGN(CONSTANT(MAXPAGESIZE));
```
MAXPAGESIZE = 0x1000 (4 KiB). Каждая секция начинается с новой страницы,
что даёт bootloader'у правильные MMU permissionы:
- text = read + execute (no write)
- rodata = read (no write, no execute)
- data = read + write (no execute)
### Limine Requests в .data
```ld
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
```
- `KEEP` — запрещает линкеру выбрасывать эти секции (dead code elimination).
- `.requests_start_marker` и `.requests_end_marker` — маркеры границ.
- Bootloader сканирует память между ними, чтобы найти requests.
### BSS
```ld
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
```
- BSS — неинициализированные глобальные переменные.
- Занимает место в виртуальной памяти, но не в ELF-файле.
- Bootloader обнуляет BSS перед передачей управления.
### DISCARD
```ld
/DISCARD/ : {
*(.eh_frame*)
*(.note .note.*)
}
```
- `.eh_frame*` — исключительные фреймы C++/Rust unwinding.
- `.note.*` — ELF notes.
- Не нужны bare-metal ядру, могут вызвать проблемы.
## Архитектурные различия
### RISC-V
```ld
.data : {
*(.data .data.*)
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
*(.sdata .sdata.*) ← RISC-V: small data
} :data
.bss : {
*(.sbss .sbss.*) ← RISC-V: small BSS
*(.bss .bss.*)
*(COMMON)
} :data
```
RISC-V имеет `.sdata`/`.sbss` секции для small data (GP-relative addressing).
### AArch64 и LoongArch64
Идентичны x86_64, за исключением OUTPUT_FORMAT.