7

我知道这是一个很难回答的问题,主要是因为有很多事情可能是错误的,很难确定。但我会提供尽可能多的信息;希望这会有所帮助。

我开始使用 D 语言和 Digital Mars D 编译器编写自己的内核,在弄清楚如何生成可以重定位的平面二进制文件后遇到了很多麻烦,我终于想出了生成一个普通 PE 文件的想法地址,并用字节(NOP 操作码)0xC0000000替换其所有标头。0x90这工作得非常好,我可以在屏幕上写东西,设置分页,进入保护模式等等。当然,借助 16 位基于汇编的引导加载程序的帮助。

一切都很好,也就是说,我决定移植 D 运行时库以在我的内核中使用。我设法提取了该库的一个子集并对其进行了修改以将其编译到我的应用程序中。然后我运行我的程序。(注意:我根本没有 使用该库;我的代码是启动后执行的第一个代码——发生的第一件事是打印"Kernel"到屏幕上,在此之前没有调用任何运行时代码。)

AD 数组(因此是字符串,因为字符串只是 a char[])只不过是一个具有指针和大小成员的结构,因此在 32 位系统上它将是 8 个字节大。有趣的是,当我运行我的程序时,结构的成员显示为零——也就是说,指针和大小都为零。(我通过在屏幕上打印指针的值以及长度成员来验证这一点——两者都为零。)一旦我删除了运行时的源代码(无论如何都没有执行),它们工作得很好.

我将其缩小为两种可能性:

  1. 堆栈不知何故设置不正确:我排除了这一点,因为没有运行时库一切正常,我通过反汇编文件确认在我的代码之前没有执行其他代码。

  2. PE 文件部分有些有趣:我检查并发现运行时版本中有两个 TLS(线程本地)变量。果然,当我让它们共享(而不是线程本地)时,我的代码工作了!但是,当我调用我在不同文件中编写的代码时,我的代码仍然表现出同样kernel.d的问题——只有作为启动文件的代码在使用字符串时表现正确;在其他文件中,数组再次为零。

现在,有没有人猜测为什么会发生这种情况?

如果需要更多信息,我很乐意发布。

谢谢!

4

2 回答 2

6

首先,免责声明:我不知道关于 D 的第一件事。

其次,另一个免责声明:基于术语“PE 文件”的使用,我猜您使用的是 Windows。我即将提出一个关于 GNU 工具链的建议......

但是...假设 D 编译器像其他任何编译器一样生成目标文件...为什么不执行以下操作(这是我在 C 中从事爱好 OS 时所做的事情,当时我有时间做这些事情):

  • 为您的内核生成一个 ELF 二进制文件...为此,请照常构建所有目标文件。在链接步骤中,提供一个链接器脚本,ld该脚本将定义二进制文件的起始地址、部分的顺序(文本、数据、rodata 等)...
  • 用 GRUB 引导它(很容易做到……你需要在二进制文件的开头附近放一些魔法词。你可以使用dbdw在 .asm 文件中键入语句来执行此操作,前提是相应的 obj 最终链接到开头附近内核。查看此链接

通过这种方式,您可以专注于比破解 PE 标头或编写引导加载程序更有趣的事情。

当然......听起来完全有可能是代码本身存在问题,而不是链接方式。在可以让您逐步完成程序集输出的情况下运行它可能会提供信息。x86 PC 模拟器qemu有一些调试选项,可以将汇编和寄存器状态输出到日志。我以前用那个。

于 2010-12-22T05:25:36.627 回答
1

一年之后...

解决了!:D

(> '.')> (^'.'^) <( '.' )> (v'.'v) <('.' <)

这是我的引导加载程序的问题:我将太少的扇区读入内存。(即 64 个扇区而不是128 125 个扇区。)

于 2011-06-21T03:40:41.387 回答