阅读材料
- Xv6代码:kernel.ld
链接器脚本:kernel.ld
链接后可执行文件的布局
首先指定输出的可执行文件架构为RISC-V,指定整个内核程序的入口点为_entry(定义在entry.S)
OUTPUT_ARCH( "riscv" )
ENTRY( _entry )
指定地址从0x80000000开始,低于该地址的物理地址空间用于MMIO
. = 0x80000000;
代码段
代码段是存放内核源码编译后生成的机器指令,这里又细分为2部分
- .text段:内核文件中所有.c和.S文件编译后生成的的二进制文件
- trampsec段:trampoline.S文件汇编后生成的二进制文件,且特别要求该段大小一定要在一页之内(4096bytes)
最后导出etext符号,用于标记内核代码段的结束,后续内核虚拟内存初始化(vm.c)时会用到这个符号
.text : {
*(.text .text.*)
. = ALIGN(0x1000);
_trampoline = .;
*(trampsec)
. = ALIGN(0x1000);
ASSERT(. - _trampoline == 0x1000, "error: trampoline larger than one page");
PROVIDE(etext = .);
}
数据段
数据段细分为3个部分:
- .rodata:存储只能读不能写的数据
- .data:存放已初始化的全局变量和已初始化的局部静态变量
- .bss:存放未初始化的全局变量和未初始化的局部静态变量
最后导出end符号,用于标记内核数据段的结束,后续内核物理内存初始化(kalloc.c)时会用到这个符号
.rodata : {
. = ALIGN(16);
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata .rodata.*)
}
.data : {
. = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */
. = ALIGN(16);
*(.data .data.*)
}
.bss : {
. = ALIGN(16);
*(.sbss .sbss.*) /* do not need to distinguish this from .bss */
. = ALIGN(16);
*(.bss .bss.*)
}
PROVIDE(end = .);