引导程序中的Masm字符串变量导致:未定义的符号错误



由于我无法理解的原因,在引导程序中使用变量会导致它被标记为未定义的符号。

.386
option segment:use16
.model tiny, stdcall
;------------------------------
; CODE
;------------------------------
.code
org 07c00h
Print PROTO lpStr:WORD
_start:
INVOKE Print, OFFSET bootInfo
cli
hlt
error:
cli
hlt
Print PROC USES ax si lpStr:WORD
mov si, lpStr
mov ah, 0Eh
@@loop:
lodsb
cmp al, 0
je @@done
int 10h
jmp @@loop
@@done:
ret
Print ENDP
;------------------------------
; DATA
;------------------------------
bootInfo db "Booting CompatOS...", 0
;------------------------------
; PADDING
;------------------------------
byte 510-($-_start) dup (0)
dw 0AA55h
END _start

我已经搜索并查看了我声明变量的方式是否有问题,但显然,它应该是这样工作的。就上下文而言,我将自己定位于此。

非常感谢您的帮助。谢谢

编辑:

MASM和用于编译源的链接器。Makefile:

.PHONY: clear
clear:
rm -f -r -d ./tmp/
rm -f -r -d ./bin/
.PHONY: build_debug
build_debug:
mkdir -p tmp
mkdir -p bin
masm_615/bin/ml /nologo /AT /c /Febin\CompatOS.img /Fotmp\boot.obj src\boot\boot.asm
masm_615/bin/link /nologo /TINY /NOD tmp\boot.obj, bin\CompatOS.img, NUL, NUL, NUL

错误:

1>srcbootboot.asm(14): error A2006: undefined symbol : bootInfo
1>srcbootboot.asm(14): error A2114: INVOKE argument type mismatch : argument : 1

错误是因为您使用了带有前向引用的invoke指令。bootInfo是在使用invoke之后声明的。这个问题已经在MASM32论坛上进行了讨论。解决此问题的一种方法是不使用invoke并执行call。这将需要您自己在堆栈上推送bootInfo的地址,如下所示:

;   INVOKE Print, OFFSET bootInfo
mov ax, OFFSET bootInfo
push ax                       ; Push register since original 8086
; didn't have a push IMMediate instruction
call Print

另一个编码选项是将数据移动到引导程序的开头附近,引导程序的第一条指令将数据跳转到代码。这将把bootInfo放在invoke之前,您将不再有正向引用。类似这样的东西:

;------------------------------
; CODE
;------------------------------
.code
org 07c00h
Print PROTO lpStr:WORD
_start:
jmp skipdata
;------------------------------
; DATA
;------------------------------
bootInfo db "Booting CompatOS...", 0
skipdata:
INVOKE Print, OFFSET bootInfo
cli
hlt

解决此问题的另一种方法是使用JWASM(一种与MASM兼容的开源汇编程序(。我注意到JWASM在使用invoke时对前向引用没有问题。


注释

  • 我意识到您受到了一些限制,因为这是一个引导加载程序,您不能只将bootInfo放在.data节中,然后将其放置在.code节之前,这将是一个在引导加载程序之外工作的解决方案。您需要一个解决方案,将代码正确地放在数据(或被代码包围的数据(之前,然后在512字节扇区的末尾加上启动签名0xaa55。

  • 我建议在开发引导程序时查看我的引导程序提示,以了解常见问题,包括在实际硬件上测试时的建议。

  • 如果您打算在386之前的实际硬件上运行,则可能希望使用.8086指令,而不是.386指令。传统的引导加载程序通常在开发时考虑到了最低的公分母——8086处理器。如果你不打算在古老的硬件上运行,那么这可能不是问题。