The following program runs OK from the boot sector:
as --32 \
<<'EOF'
.EQUIV VIDEO_INTERRUPT, 020
.EQUIV KEYBOARD_INTERRUPT, 026
.EQUIV REBOOT_INTERRUPT, 031
.EQUIV VIDEO_TELETYPE_OUTPUT, 07000
.EQUIV VIDEO_WRITE_STRING, 011401
.EQUIV CONTROL_CHAR_CARRIAGE_RETURN, 015
.EQUIV CONTROL_CHAR_LINE_FEED, 012
.EQUIV HELLO_LENGTH, HELLO_END - HELLO
.EQUIV CR_LF_LENGTH, CR_LF_END - CR_LF
.GLOBAL _start
_start:
MOV $VIDEO_TELETYPE_OUTPUT, %EAX
MOV $HELLO_LENGTH, %ECX
MOV $HELLO, %ESI
MOV $RET18, %EDI
JMP PRINTSTR
RET18:
MOV $VIDEO_TELETYPE_OUTPUT, %EAX
MOV $CR_LF_LENGTH, %ECX
MOV $CR_LF, %ESI
MOV $RET31, %EDI
JMP PRINTSTR
RET31:
XOR %EAX, %EAX
INT $KEYBOARD_INTERRUPT
INT $REBOOT_INTERRUPT
PRINTSTR:
CLD
XOR %EBX, %EBX
L30:
LODSB
INT $VIDEO_INTERRUPT
LOOP L30
JMP *%EDI
.DATA
HELLO:
.ASCII "HELLO!"
HELLO_END:
CR_LF:
.BYTE CONTROL_CHAR_CARRIAGE_RETURN, CONTROL_CHAR_LINE_FEED
CR_LF_END:
COUNT10: .ASCII "LOOK, I CAN COUNT TO 10!"
COUNT10_END:
DATA_END:
.FILL 01000, 02, 0XAA55
EOF
cat a.out >a.o
ld -melf_i386 -Tdata=0X7D00 \
-Ttext=0X7C00 a.o \
--oformat binary
dd if=a.out of=/tmp/fd0 \
count=2880 \
conv=notrunc
However, when I try to use normal CALL/RET instead of JMP, the code either hangs in qemu-system-i386
or reboots by itself. Can you help me please?
Note: I have checked that manually pushing the return address works too, so should not be the case that the stack pointer is wrong.