Assembly 在简单内核的上下文中理解链接器脚本值
关于开发一个小内核,我遵循这本书: 我已经到了必须链接二进制文件的地步,我想确保在继续之前理解链接器脚本:Assembly 在简单内核的上下文中理解链接器脚本值,assembly,x86,ld,linker-scripts,multiboot,Assembly,X86,Ld,Linker Scripts,Multiboot,关于开发一个小内核,我遵循这本书: 我已经到了必须链接二进制文件的地步,我想确保在继续之前理解链接器脚本: ENTRY(loader) /* the name of the entry label */ SECTIONS { . = 0x00100000; /* the code should be loaded at 1 MB */ .text ALIGN (0x1000) : /* align at 4 KB */
ENTRY(loader) /* the name of the entry label */
SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */
.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}
.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}
.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}
.bss ALIGN (0x1000) : /* align at 4 KB */
{
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
}
}
首先,为什么特定的对齐部分(4KB)?
(我认为这不太可能与优化有关,或者我可能弄错了,这可能是出于性能原因,因为否则我认为引导过程没有限制-通过删除脚本中的ALIGN
函数调用确认)
然后考虑要链接的可执行文件:
global loader ; the entry symbol for ELF
MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
FLAGS equ 0x0 ; multiboot flags
CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum
; (magic number + checksum + flags should equal 0)
section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number to the machine code,
dd FLAGS ; the flags,
dd CHECKSUM ; and the checksum
loader: ; the loader label (defined as entry point in linker script)
mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax
.loop:
jmp .loop ; loop forever
我说的.rodata
和.bss
部分还不需要,对吗?(因为内核仍然可以正常启动)
从这个小小的链接器脚本中还有什么我无法从ld
手册中理解的东西吗(我读了一些手册来理解点、部分和入口点)
看起来我可以在脚本中重新安排部分的顺序,内核仍然可以工作,这是为什么?在某些情况下,我认为如果在同一个4kb部分中有可写的数据段和代码,那么最终可能会导致缓存失效(性能问题)。如果您开始使用C或其他高级语言进行链接,您会发现数据放在.rodata
中(通常是常量数据).bss
用于未初始化的数据或初始化为0的数据。通常,在执行依赖于它的代码执行之前,引导程序代码会希望显式地将零数据写入.bss
部分。在C中,这通常是在调用main
函数之前执行的C运行时代码中完成的。如果您刚开始编写汇编程序代码,那么这些可选部分中的许多部分都不适用,除非您自己创建它们(并且不要求有它们)。我不会只在汇编中执行,我尽可能多地使用C。如果您使用C,那么您几乎肯定要处理.bss。但是,如果您构建一个ELF二进制文件并使用多重引导,那么这实际上已经得到了解决。Grub将为您将.bss
初始化为全零。您的标志设置为多引导0x0,表示ELF。您应该做的是创建一个引导堆栈(当grub加载时,您不能依赖于有一个有效的堆栈供您使用)。您可以在此处了解如何执行此操作:。您还需要使用-ffreestanding-nostlib-lgcc
编译您的C代码(如果使用gcc),最后,如果您要使用C/C++请注意网站上关于使用交叉编译器生成内核的建议。您尤其需要一个i686 elf gcc
交叉编译器。操作系统开发站点应该链接到构建操作系统的说明。如果您使用主机环境中的gcc
,您可能会在生成的代码中发现一些小问题。这是因为编译器和C运行时将以主机环境为目标,而不是以基本环境为目标。相信我,你不想回来帮助我们找出由于使用错误的gcc而导致的错误