在我的内核中,全局变量不起作用
我想用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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。