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

标签 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。这就是我调用用汇编编写并使用 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 代码通常不是位置无关的,如果移动它,则必须调整代码内部的一些数据偏移量。显然,您没有进行这些调整。在简单的情况下,没有什么需要调整的,你会得到错误的地址。

编辑:

其实这里还有更多的问题:

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

关于c - 实模式 OS 中的 16 位 .com C 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9854968/

相关文章:

c - 如何减少 SQLite 内存消耗?

c++ - 您需要先加载内核错误

x86 - 我们是否也将寄存器 RAX、RBX 等称为 R1、R2 等?

linux - 汇编后硬编码地址更改

将 u_int32_t 转换为 char **

c - 什么是异或和?

c - 多线程程序中的段错误

c - 如何使用 XADD 来增加内存中的值?

c - Dos 中断处理程序锁定程序

assembly - 为什么x86 movsd导致三重故障异常?