我一直在研究实模式操作系统,使用 NASM 编写程序集并编译为平面 .bin 可执行文件。
我想用 C 写一些操作系统,所以写了一个实验程序 (ctest.c),我想访问一个字符串并打印第一个字符:
void test();
int main() { test(); return 0; }
char msg [] = "Hello World!";
void test() {
_asm
{
mov si, word ptr [msg]
mov al, [si]
mov ah, 0eh
int 10h
}
for(;;);
}
我使用 wcl ctest.c -lr -l=COM
使用 Open Watcom v1.9 编译了它。这将创建 ctest.com。我在 NASM 汇编中编写的内核将此程序加载到 0x2010:0x0000,将 DS 和 ES 设置为 0x2000:0x0000,然后跳转到 0x2010:0x0000。这就是我调用用汇编编写并使用 nasm -f bin test.asm -o test.com
编译的 .COM 程序的方式。
当我测试操作系统(使用 Bochs)时,它成功加载了 ctest.com,但打印出一个不属于 msg[] 的无意义字符。
有人对此有什么建议吗?我认为字符串只是在错误的地方被初始化。我想将其保留为 16 位操作系统。
谢谢!
最佳答案
您使用的地址有误。
您要么在 0x2000:0x0100 处加载并跳转到 0x2000:0x0100(不要忘记在此之前设置 DS=ES=SS=0x2000 和 SP=0)或者您在 0x2000 处加载: 0x0000(相当于 0x1FF0:0x0100 因为 0x2000*0x10+0x0000 = 0x1FF0*0x10+0x0100 = 0x20000 = 实模式下的物理内存地址)并跳转到 0x1FF0:0x0100(不要忘记设置 DS=ES=SS=0x1FF0 和 SP =0 之前)。
所有这一切的原因是编译后的 x86 代码通常不是位置无关的,如果移动它,则必须调整代码内部的一些数据偏移量。显然,您没有进行这些调整。在简单的情况下,没有什么需要调整的,你会得到错误的地址。
编辑:
其实这里还有更多的问题:
mov si, word ptr [msg]
必须更改为lea si, byte ptr [msg]
因为你不想加载si
与字符串中的内容,你想用字符串的地址加载它。- 通过 OW 链接到您的程序的启动代码依赖于 DOS 并调用 DOS 函数,这些函数在您启动程序时是没有的。查看如何解决此问题 here .
关于c - 实模式 OS 中的 16 位 .com C 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9854968/