For reasons I can not put my finger on, using a variable inside my bootloader causes it to be marked as an undefined symbol.
.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
I've searched and looked if there is something wrong with the way I declare my variable, but apparently, it should work like this. For context, I oriented myself on this.
Any help is much appreciated. Thanks.
Edit:
MASM and linker used to compile the sources. 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
Errors:
1>src\boot\boot.asm(14): error A2006: undefined symbol : bootInfo
1>src\boot\boot.asm(14): error A2114: INVOKE argument type mismatch : argument : 1
CodePudding user response:
The errors are because you're using the invoke
directive with a forward reference. bootInfo
is declared after you use invoke
. The issue has been discussed on the MASM32 forum. One way to resolve this is not use invoke
and do a call
. This would require you having to push the address of bootInfo on the stack yourself like this:
; INVOKE Print, OFFSET bootInfo
mov ax, OFFSET bootInfo
push ax ; Push register since original 8086
; didn't have a push IMMediate instruction
call Print
Another coding option is to move the data to near the beginning of your bootloader and the first instruction of the bootloader jumps over the data to the code. This would put bootInfo
before the invoke
and you'd no longer have a forward reference. Something like this:
;------------------------------
; CODE
;------------------------------
.code
org 07c00h
Print PROTO lpStr:WORD
_start:
jmp skipdata
;------------------------------
; DATA
;------------------------------
bootInfo db "Booting CompatOS...", 0
skipdata:
INVOKE Print, OFFSET bootInfo
cli
hlt
Another way to solve this is to use JWASM (an open source MASM compatible assembler). I noticed JWASM has no problem with forward references when using invoke
.
Note: I realize you are somewhat constrained because this is a bootloader and you can't just put bootInfo
in a .data
section before the .code
section because you want to make sure the 0xaa55 signature is placed exactly where it is needed with the data and code before it.
I recommend taking a look at my bootloader tips for common problems when developing a bootloader, including suggestions when testing on real hardware.
You may wish to use the .8086
directive rather than .386
if you intended to run on real hardware that may predate the 386. Legacy bootloaders are generally developed with the lowest common denominator in mind - the 8086 processor. If you don't intend to run on ancient hardware then this may not be an issue.