在我的内核中,全局变量不起作用

编程语言 2026-07-11

我想用C 写一个16位实模式操作系统。后来我发现应该使用Open Watcom C编译器和链接器。

我在内核代码的主函数中使用局部变量,并且我设法在QEMU上把信息打印到屏幕:

#define VGA_MEM  0xB8000000UL
#define WHITE_ON_BLACK 0x07

void write_string(unsigned char far* vga, const char* msg)
{
    int i = 0;

    while (msg[i]) {
        vga[i * 2] = msg[i];
        vga[i * 2 + 1] = WHITE_ON_BLACK;
        i++;
    }
}

void kmain()
{
    unsigned char far* vga = (unsigned char far *)VGA_MEM;
    const char* msg = "Hello from Watcom C kernel!";
    write_string(vga, msg);
    for (;;);
}

这段代码能工作。但如果比如把VGA指针设为全局变量,那么就不会打印信息了。

我的操作系统结构是:
boot.asm将扇区2 的CHS加载到0x1000:0x0000,并跳转过去。这个扇区包含kernel.bin,这是由entry.obj和 kernel.o链接而成的文件。Entry.asm先出现:

BITS 16

GLOBAL _start
EXTERN kmain_

SEGMENT CONST CLASS=DATA
SEGMENT CONST2 CLASS=DATA
SEGMENT _DATA CLASS=DATA
SEGMENT _BSS CLASS=BSS
GROUP DGROUP CONST CONST2 _DATA _BSS

SEGMENT TEXT CLASS=CODE

_start:
    CLI
    PUSH    cs
    POP     ax
    MOV     ds, ax
    MOV     es, ax
    XOR     ax, ax
    MOV     ss, ax
    MOV     sp, 0x9FFF
    STI

    JMP     kmain_

据我理解,DS寄存器应该指向DGROUP的起始地址:
kernel.bin映射。

Segment                Class          Group          Address         Size

=======                =====          =====          =======         ====

TEXT                    CODE           AUTO           00010000        00000012
\_TEXT                  CODE           AUTO           00010012        00000042
CONST                   DATA           DGROUP         00010054        0000002d
CONST2                  DATA           DGROUP         00010082        00000002
\_DATA                  DATA           DGROUP         00010084        00000012
\_BSS                   BSS            DGROUP         00010096        00000002

TEXT是 entry.asm
_TEXT是 kernel.c

全局VGA指针位于 _DATA段

但问题是我不明白应该如何把DS指向DGROUP。
我可以在运行时计算DGROUP,但如果我写下MOV ds, calculated address DGROUP的指令,那么实际的DGROUP地址显然会增加

linker.lnk文件:

NAME kernel.bin
FORMAT RAW BIN

OPTION  QUIET,
        NODEFAULTLIBS,
        START=_start,
        VERBOSE,
        OFFSET=0x10000,
        STACK=0x200,
        MAP

FILE entry.obj
FILE kernel.o

ORDER
    CLNAME CODE
    CLNAME DATA
    CLNAME BSS

我尝试把CODE段也分组到DGROUP,然后全局变量就能工作,但我觉得那样很蠢,还有别的解决办法。

我也尝试去阅读Open Watcom的链接器手册,但并没有真正找到什么

链接到这个项目的github: https://github.com/hotfixx/os16

解决方案

我认为你需要告诉watcom C你要一个FAR指针(SEGMENT和 OFFSET):

#include <dos.h>
#include <i86.h>

unsigned int segment = 0xB800; // e.g., Text-mode Video Memory
unsigned int offset = 0x0000;

char __far *my_screen = (char __far *)MK_FP(segment, offset);
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章