使用ld链接文件以输出二进制文件在操作系统开发中出现错误

3

我正在学习操作系统教程。我创建了2个文件。

  1. boot.asm
  2. kernel.c

kernel.c 的内容如下:

int main()
{
  char *src = (char *)0xB8000000L;
  *src = 'M';
  src += 2;
  *src = 'D';
  return 0;
}

内核用于将字符写入文本模式视频显示区域。该内核是使用Windows版本的GCC编译的,具体编译选项如下:

gcc -ffreestanding -c -m16 kernel.c -o kernel.o

我使用LD将内核对象链接到二进制文件:

ld -Ttext 0x10000 --oformat binary -o kernel.bin kernel.o

我收到的错误信息如下:

ld : 无法链接非 PE 可执行文件类型的文件

请问有谁能解决这个错误呢?
以下是一些相关信息:
  • 操作系统:Windows
  • 编译器:GCC
  • 链接器:ld

除了链接器问题,你是在尝试将旧的TurboC/MSVC 16位代码转换为_GCC_吗?我觉得(char *)0xB8000000L很可疑。如果它是一个真正的16位C编译器,如果它是(char far *)0xB8000000L,那么可能还好。_GCC_不是一个真正的16位C编译器,也没有旧式far指针的概念。所以即使你让这段代码编译通过,它也可能不会做你想做的事情。我假设从_GCC_的-m16选项中,你正在尝试创建一个实模式的16位内核(而不是保护模式)。 - Michael Petch
是的,没错。我正在尝试在屏幕上打印文本,而不使用标准库。我的代码有什么问题吗?那我该怎么做呢? - Panther Coder
你应该把这个作为一个新的问题来提问。我现在知道你正在使用实模式,并且使用_GCC.. _GCC_的代码并不完全是16位的(该代码使堆栈操作变为32位宽,并在必要时添加地址大小前缀到指令中)。该代码只能在80386+(而不是80286、8086)或者实模式下的386+模拟器上运行。这对你可能是可以接受的,但是这是必须要说的一点。你可能需要使用汇编语言编写屏幕更新代码或者将其嵌入到程序中。 - Michael Petch
我很好奇我的回答是否至少解决了您的链接器问题,并为您生成了一个名为 kernel.bin 的文件? - Michael Petch
是的,它生成了一个二进制文件。 - Panther Coder
显示剩余2条评论
2个回答

4

您的LD的Windows版本可能仅支持Windows PE类型。一个解决方法是将输出转换为PE,然后使用objcopy将PE文件转换为二进制文件。

为了使此方法可行,您需要将main重命名为_mainGCC使用-ffreestanding会发出一个没有Windows ABI约定的对象(不包括非静态函数前面加下划线)。我们将首先使用您的LD来输出一个Windows PE文件,它会抱怨未定义的__main入口点。为了解决这个问题,您需要将main重命名为_main,以便链接器不会抱怨。

使用以下指令生成内核二进制文件:

gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin

LD 命令将输出到名为 kernel.pe 的文件。使用命令 objcopykernel.pe 转换为二进制数据,使用参数 -O binary 并输出到 kernel.bin 文件中。


1
这意味着 ld 本身在编译时未配置为支持除 PE(Windows本地可执行文件格式)和 Portable Executable 之外的输出格式。

寻找一个支持它或自己构建一个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接