16位实模式C内核全局变量失效问题求助
16位实模式C内核全局变量失效问题求助
我正在尝试用C语言编写一个16位实模式的操作系统,目前使用的是Open Watcom C编译器和链接器。
现在遇到了一个棘手的问题:当我在kmain函数里用局部变量定义VGA显存指针时,代码能正常在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 (;;); }
下面说明我的OS结构:
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, 计算出的DGROUP地址后,实际的DGROUP地址似乎又发生了变化。
我还尝试过把CODE类的段也加入DGROUP,这样全局变量确实能正常工作了,但直觉告诉我这绝对不是正确的解决方案。另外我也翻了Open Watcom链接器的官方手册,但没找到能解决这个问题的有效信息。
最后附上我的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
备注:内容来源于stack exchange,提问作者Ld120
相关产品推荐
相关产品推荐

