我的操作系统内核位于 D:某些嵌入的字符串不起作用

发布于 2024-10-08 20:55:50 字数 1098 浏览 0 评论 0原文

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

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

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

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

我将其范围缩小到两种可能性:

  1. 堆栈在某种程度上未正确设置:我排除了这种情况,因为没有运行时库一切正常,并且我通过反汇编文件确认在我的代码之前没有执行其他代码.

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

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

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

谢谢你!

I'm aware that is a rather difficult question to answer, mainly because there's so many things that could be wrong that it's hard to pin things down. But I'll give as much info as I can; hopefully that'll help.

I started writing my own kernel using the D language and the Digital Mars D compiler, and after a lot of trouble with figuring out how to generate flat binaries that can be relocated, I finally came up with the idea of generating an ordinary PE file for the address 0xC0000000, and replacing all of its headers with the byte 0x90 (the NOP opcode). This worked perfectly fine, and I was able to write things on the screen, set up paging, enter protected mode, etc. perfectly well, with--of course--the help of a 16-bit assembly-based boot loader.

Everything was well, that is, I decided to port the D run-time library for use in my kernel. I managed to extract a subset of the library and modify it to get it to compile into my app. Then I ran my program. (Note: I did not use the library at all; my code was the first code executing after the boot--the first thing that happened was printing "Kernel" to the screen, and no run-time code was called before that.)

A D array (and hence a string, since a string is just a char[]) is no more than a structure with a pointer and a size member, so on a 32-bit system it would be 8 bytes big. The funny thing was, when I ran my program, the structure's members showed up to be zero -- that is, both the pointer and the size were zero. (I verified this by printing the pointer's value to the screen, as well as the length member -- both were zero.) As soon as I removed the source code for the run-time (which was never executed anyway), they worked fine.

I narrowed this down to two possibilities:

  1. The stack was somehow not set up correctly: I ruled this out, because everything worked fine without the runtime library, and I confirmed that no other code was executed before my code by disassembling the file.

  2. Something is funny with the PE file sections: I checked, and figured out that there were two TLS (thread-local) variables in the version with the run-time. Sure enough, when I made them shared (rather than thread-local), my code worked! However, my code still exhibited the same problem when I called code I'd written in a different file--only kernel.d, which is the startup file, behaved correctly with strings; in the other files, the arrays were zero again.

Now, does anyone have any guess as to why this might be happening?

If any more information is needed, I'll be happy to post it.

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ι不睡觉的鱼゛ 2024-10-15 20:55:50

首先,免责声明:我对 D 一无所知。

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

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

  • 为你的内核生成一个 ELF 二进制文件...为此,请像平常一样构建所有目标文件。在链接步骤中,向 ld 提供链接描述文件,该脚本将定义二进制文件的起始地址、各部分(文本、数据、rodata 等)的顺序等内容...
  • 使用 GRUB 启动它(相当容易做到...您需要在二进制文件的开头附近放置一些魔术词。您可以在 .asm 中使用 dbdw 类型语句来完成此操作文件,前提是相应的 obj 最终链接到内核开头附近。 “ rel="nofollow">此链接)

这样您就可以专注于比破解 PE 标头或编写引导加载程序更有趣的事情。

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

First, a disclaimer: I don't know the first thing about D.

Second, another disclaimer: Based on the use of the term "PE file" I'm going to guess you're using Windows. I'm about to give a suggestion for a GNU toolchain...

But... Assuming the D compiler generates object files just like any other... Why not do the following (this is what I did when I worked on a hobby OS in C, back when I had time for such things):

  • Generate an ELF binary for your kernel... To do this, build all your object files as normal. At the link step, feed a linker script to ld that will define things like start address, the order of sections (text, data, rodata, etc.) of the binary...
  • Boot it with GRUB (Fairly easy to do... You need to put some magic words near the start of your binary. You can do this with db or dw type statements in an .asm file, provided the corresponding obj ends up linked near the beginning of the kernel. Check out this link)

This way you can focus on more interesting things than hacking up a PE header or writing a bootloader.

Of course... It sounds entirely possible that there's some problem in the code itself, rather than the way you link. It might be informative to run it in something that will let you step through the assembly output. The x86 PC emulator qemu has some debugging options which will output assembly and register state to a log. I used to use that.

阳光①夏 2024-10-15 20:55:50

一年后...

解决了! :D

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

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

One year later...

Solved! :D

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

It was a problem with my boot loader: I was reading too few sectors into memory. (Namely, 64 sectors instead of 128 125.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文