CALL instruction hangs in QEMU (i386)

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.

Hi,
Instead of making people guess,
You should describe what language your code is running and how you’ve inserted into the boot sector… in other words everything needed should someone want to replicate what you’re doing. Even if not replicated, a proper description should enable viewers to follow what you’re trying to do clearly.

TSU

as --32, as indicated

That is the dd instruction in the build script.

I am trying to use CALL to call a function.

I would also like to mention that the instruction

MOV $ADDRESS, %ESI

behaves as if it were immediately followed by the instruction


ADD %AL, (%ESI)

which is extremely unexpected and confusing and the only workaround seems to be to clear %EAX beforehand. The same goes for setting %EBP.

Thanks for your help, I forgot this:

.CODE16