实模式OS中的16位.com C程序

时间:2012-03-24 19:48:36

标签: c assembly x86 bootloader watcom

我一直在研究一个真正的模式操作系统,用汇编编写并使用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。这就是我一直在调用汇编编写的.COM程序,并用nasm -f bin test.asm -o test.com编译 当我测试操作系统(使用Bochs)时,它成功加载ctest.com,但打印出一个无意义的字符,该字符不属于msg []。
有人对此有任何建议吗?我认为字符串只是在错误的地方初始化。我想将其保留为16位操作系统 谢谢!

2 个答案:

答案 0 :(得分:4)

您使用的是错误的地址。

你要么加载到0x2000:0x0100并跳转到0x2000:0x0100(不要忘记在此之前设置DS = ES = SS = 0x2000和SP = 0) OR 你加载到0x2000: 0x0000(相当于0x1FF0:0x0100因为0x2000 * 0x10 + 0x0000 = 0x1FF0 * 0x10 + 0x0100 = 0x20000 =实模式下的物理存储器地址)并跳转到0x1FF0:0x0100(不要忘记设置DS = ES = SS = 0x1FF0和SP之前= 0)。

所有这一切的原因是编译的x86代码通常不是与位置无关的,如果你移动它,你必须调整代码内部的一些数据偏移。显然,你没有做出这些调整。在简单的情况下,没有什么可以调整的,你就得错了地址。

修改

实际上,这里存在更多问题:

  1. mov si, word ptr [msg]必须更改为lea si, byte ptr [msg],因为您不想加载si字符串中的内容,而是希望使用字符串的地址加载它。
  2. 由OW链接到您的程序的启动代码依赖于DOS并调用DOS函数,这是您在启动程序时没有的。了解如何解决此问题here

答案 1 :(得分:1)

在MS-DOS下,COM程序在偏移量0x100处加载。我猜想Open Watcom会做出这样的假设。我建议加载COM程序在0x2010:0x0100,看看它做了什么。