我正在尝试为我的旧 286 构建一个小型引导加载程序/程序。我开始使用 fasm 进行此操作,但很快就厌倦了编写汇编。所以我想我想用 c 语言来编写它,但是针对 286 的 c 工具链的选择似乎很少。我选择开放 watcom 1.9。到目前为止,我设法编译了一些东西,但是输出被破坏了,我不知道为什么。
init.asm,为兼容watcoms汇编器而编写,初始化寄存器,跳转到c函数kernelMain并提供简单的打印函数:
.code INIT
extern kernelMain_ : proc
org 7c00h
;export functions
PUBLIC initMain
PUBLIC _print
initMain:
;init stack to use the 30kb before this boot sector
;init other segment registers
mov bp,7C00h ; stack base pointer
xor ax,ax ; ax = 0
mov ds,ax ; data segment = 0
mov es,ax ; extra segment
mov ss,ax ; stack segment = 0
mov sp,bp ; stack pointer = 7C00h
jmp kernelMain_
;void __cdecl print(char* message, unsigned char length);
_print:
pop si ; message
pop cx ; length
printLoop: ; print string which is at adress si with length cx
mov ah,0Eh ; TTY output function number
mov bh,0 ; page 0
mov bl,01h ; foreground color
lodsb ; loads byte from [si] into al and advances pointer in si by 1
int 10h ; BIOS video interrupt, write byte to screen
loop printLoop ; loop till message is printed
ret
end
test.c,包含kernelMain函数:
extern void __cdecl print(char* message, unsigned short length);
void kernelMain(void)
{
print("this is a test", 14);
}
这就是我用来构建它的
wasm -2 -ms init.asm
wcc -2 -d0 -wx -ms -s -zl test.c
wlink file init.obj file test.obj format raw bin name test.bin option NODEFAULTLIBS,verbose,start=initMain ORDER clname CODE segment INIT
生成的二进制文件约为 32KB,而不是预期的几个字节,因为链接器解释 org 指令,实际上在代码之前用 0 字节填充所有内容。在代码完全破坏代码之前删除 0 填充。它不打印任何东西。删除 org 指令会给我执行和打印的代码,但它也会在测试消息之前打印出一些随机垃圾
有人可以帮助我吗?
感谢评论者,我现在得到了我想要的。
修复:
测试.c:
void kernelMain(void);
void initasm(void);
#pragma aux initasm = \
"mov bp,7C00h", \
"xor ax,ax", \
"mov ds,ax", \
"mov es,ax", \
"mov ss,ax", \
"mov sp,bp", \
"jmp kernelMain" \
modify [ AX ];
void __pascal print(char* message, unsigned short length);
#pragma aux print = \
"pop cx", \
"pop si", \
"printLoop:", \
"mov ah,0Eh", \
"mov bh,0", \
"mov bl,01h",\
"lodsb", \
"int 10h", \
"loop printLoop" \
modify [ SI CX AH BH BL];
void init(){
initasm(); //jumps to kernelMain after initializing registers. seperate init was necessary as adding any actual function calls (like print) would add push instructions before the inline assembly which would be called before initializing the stack and registers
}
void kernelMain(void)
{
print("this is a test", 14);
}
构建测试.bat:
wcc -2 -d0 -wx -ms -s -zl test.c
wlink file test.obj format raw bin name test.bin option NODEFAULTLIBS,verbose,start=init_,OFFSET=0x7C00
这给了我一个链接在地址 0x7c00 的原始二进制文件。
要制作可写入软盘(或被虚拟机用作软盘)的可引导扇区,您必须将文件的其余部分填充到 510 字节长度,并添加 0x55 0xAA 作为最后 2 个字节,(总共 512 字节),将其标记为可引导扇区。
备注:如果作者(我)实际上可以编写正确的汇编,那么单独的 asm 和 c 的东西可能仍然会按预期工作