解析 kernel.lds
链接脚本
kernel.lds
是一个 链接脚本(Linker Script),用于告诉链接器(GNU ld)如何组织内核的内存布局,定义 各个代码段、数据段的地址及排列方式。
1. 链接脚本的作用
- 控制内核加载地址
- 定义内核的段布局(
.text
、.data
、.bss
) - 对齐段地址
- 特殊段的存放(如
first_task
进程) - 提供符号(
PROVIDE()
)给 C 代码使用
2. 关键解析
(1) 设置 kernel_base
PROVIDE(kernel_base = 0x0);
PROVIDE(symbol = value);
用于定义一个全局符号,供 C 代码使用。kernel_base = 0x0
表示 内核的基地址,即内核被加载到物理内存的0x0
地址处(可能用于 Bootloader 处理)。
(2) 设置 .text
(代码段)
. = 0x00010000;
PROVIDE(s_text = .);
.text : {
*(EXCLUDE_FILE(*first_task* *lib_syscall*) .text)
}
PROVIDE(e_text = .);
.= 0x00010000
:设置链接地址,内核从0x10000
(64KB)开始加载。s_text
/e_text
:提供text
段的起始和结束地址。.text
段:- 存放 内核代码,排除
first_task
和lib_syscall
相关的.text
代码。
- 存放 内核代码,排除
(3) .rodata
(只读数据段)
.rodata : {
*(EXCLUDE_FILE(*first_task* *lib_syscall*) .rodata)
}
- 存放 只读数据(如字符串常量、全局
const
变量)。 - 依然排除了
first_task
和lib_syscall
相关的数据。
(4) .data
& .bss
(数据段 & 未初始化数据段)
. = ALIGN(4096);
PROVIDE(s_data = .);
.data : {
*(EXCLUDE_FILE(*first_task* *lib_syscall*) .data)
}
.bss : {
*(EXCLUDE_FILE(*first_task* *lib_syscall*) .bss)
}
e_data = .;
- 对齐到 4KB:
ALIGN(4096)
,保证.data
页对齐,方便页表管理。 .data
段:存放已初始化的全局变量。.bss
段:存放未初始化的全局变量,初始化为0
。
(5) first_task
(初始进程)
. = 0x80000000;
PROVIDE(s_first_task = LOADADDR(.first_task));
.first_task : AT(e_data) {
*first_task_entry*(.text .data .rodata .data)
*first_task*(.text .data .rodata .data)
*lib_syscall*(.text .data .bss)
}
PROVIDE(e_first_task = LOADADDR(.first_task) + SIZEOF(.first_task));
. = 0x80000000;
:first_task
进程在高地址0x80000000
运行。AT(e_data)
:表示first_task
在低端e_data
处存储,但运行时会搬运到0x80000000
。LOADADDR(.first_task)
:获取first_task
在文件中的加载地址。SIZEOF(.first_task)
:获取first_task
占用的大小。
📌 first_task
作用
- 操作系统启动时的第一个用户态进程,可能是
init
进程。 - 存放在低地址
e_data
,运行时会搬运到高地址0x80000000
。
(6) 计算空闲内存的起始地址
PROVIDE(mem_free_start = e_first_task);
mem_free_start
指示可用内存的起始地址,即first_task
之后的内存可用于动态分配。
3. 这份 kernel.lds
的整体布局
段 | 地址 | 内容 |
---|---|---|
kernel_base | 0x0 | 提供 kernel_base 符号 |
.text | 0x00010000 | 内核代码 |
.rodata | 代码段后 | 只读数据(字符串、常量) |
.data | 4KB 对齐 | 已初始化的全局变量 |
.bss | .data 之后 | 未初始化的全局变量 |
e_data | 结束地址 | 记录 .data 和 .bss 结束地址 |
.first_task | 加载在 e_data 但运行时搬运到 0x80000000 | 第一个用户态进程 |
mem_free_start | e_first_task | 可用内存的起始地址 |
4. 结论
- 这个
kernel.lds
用于内核的内存布局,管理 代码段、数据段、进程加载。 first_task
初始进程先存放在低端内存,运行时移动到高端0x80000000
。mem_free_start
标记内核使用的内存结束处,以便操作系统后续进行内存管理。
🚀 这份 kernel.lds
主要控制:
✅ 内核加载地址(0x10000
开始)。
✅ 内核各段(.text
、.data
、.bss
)的内存布局。
✅ 初始用户进程 first_task
的存放和运行地址。
✅ 空闲内存的计算,供后续内存管理使用。