使用 open watcom 为 286 cpu 编译引导加载程序

标签 c bootloader watcom 80286

我正在尝试为我的旧 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 指令为我提供了执行和打印的代码,但它还在测试消息之前打印出一些随机垃圾

有人可以帮助我吗?

最佳答案

感谢评论者,我现在得到了我想要的。

修复:

  1. 放弃将asm与c代码分开的想法,只使用c进行内联汇编
  2. 从此处升级以打开 watcom 2.0 beta https://github.com/open-watcom/open-watcom-v2/releases (当前版本包含版本和安装程序)
  3. 添加 offset=0x7c00 选项

测试.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);
}

buildtest.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 的东西可能仍然会按预期工作

关于使用 open watcom 为 286 cpu 编译引导加载程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76807564/

相关文章:

rust - 如何使用 Assembly (NASM) 引导加载程序编译 Rust 内核

c - 调试崩溃的用 OpenWatcom 编译的 32 位 DOS 可执行文件

java - 如何使用JNI从C调用JAVA方法

assembly - 带 MASM 的 2 阶段引导加载程序

c++ - 如何在macOS中测量线程的执行时间?

linux - GRUB 的第 1 阶段引导加载程序如何加载第 2 阶段引导加载程序?

c - 设置编译器 在 Windows XP 中打开 watcom

c - 如何通过 Watcom 编译器从 C 生成 16 位可执行 BINARY RAW 格式?

c++ - 我如何在此功能中释放内存?

c -\b 和\r 在 C 中的用法