我正在开发玩具操作系统和引导程序。我正在尝试用C编写内核,然后将其转换为二进制文件以直接从引导加载程序跳转(即,我没有加载ELF或类似的东西)。
我已经使用正确的源设置了链接器文件(我正在加载内核以寻址0xC0000000)并确认objdump
它正确使用它。但是,它并没有像我想的那样将我的入口点放在开头(0xC0000000)。我猜这不是ENTRY
指令的用途。
我的问题很简单,我想在地址0xC0000000处放置一个特定的函数kernel_main
。有没有办法用gcc进行编译和链接?
以下是我的链接器文件的相关部分:
ENTRY(kernel_main)
SECTIONS
{
/* Origin */
. = 0xC0000000;
.text BLOCK(4K) : ALIGN(4K)
{
*(.text)
}
/* etc. */
}
答案 0 :(得分:4)
ENTRY
链接器命令告诉链接器加载程序时加载程序应跳转到哪个符号。如果您正在制作自己的操作系统,那么由于没有装载机,它实际上没有使用。
相反,如您所知,程序只是从第一个代码地址开始。
要首先放置一段特殊的代码,您可以将其放在一个特殊的代码段中,并将其放在列表的第一位:
.text BLOCK(4K) : ALIGN(4K)
{
*(.text.boot) *(.text)
}
列表中的段按照给定的顺序放置。
答案 1 :(得分:3)
ENTRY
指令仅对支持入口点的输出格式有用。由于您使用的是二进制输出,因此无法使用。你可以做的是在一个单独的源文件中写一个小存根(即entry.c
或entry.asm
或其他)。然后,在ld
脚本中,在*(.text)
行之前,您可以放置entry.o(.text)
。这指示ld
加载来自特定目标文件的符号(而*
表示所有目标文件)。所以新的ld
脚本看起来像这样:
ENTRY(kernel_main)
SECTIONS
{
/* Origin */
. = 0xC0000000;
.text BLOCK(4K) : ALIGN(4K)
{
entry.o(.text)
*(.text)
}
/* etc. */
}
只要entry.o
只包含一个函数(只调用你的内核主函数),这应该可行。