1

I am having an issue while programming in NASM. I am learning how to develop an OS purely in assembly and have started by creating a boot loader.

When I try to use the print function from the print.asm file, I encounter an error that prints two characters at a time.

File: bootloader.asm

[BITS 16]
[ORG 0x7c00]

mov al, 65
call print_char

%include "print.asm"

jmp $

times 512-($-$$) db 0

dw 0xaa55

File: print.asm

print_char:
mov ah, 0x0e
mov bh, 0x00
mov bl, 0x07
int 0x10
ret

qemu: enter image description here

Thank you all for the support!

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Nttkkhanh
  • 11
  • 1
  • 3
    `%include` the file so it does not land in the place that instruction pointer will just fall through. One letter is from the `call` the other one is just continuation of the execution of the instructions that `%include` puts where you use the directive. – Paweł Łukasik Sep 14 '21 at 17:54

1 Answers1

2

Unlike include in high level languages (where the compiler decides about where the external contents go), this %include will insert the contents of your print.asm file right where you have written the line. The true source code then becomes:

[BITS 16]
[ORG 0x7c00]

mov al, 65
call print_char

print_char:
mov ah, 0x0e
mov bh, 0x00
mov bl, 0x07
int 0x10
ret

jmp $

times 512-($-$$) db 0

dw 0xaa55

As you can see, once the call print_char returns, the code falls through in the print_char routine and thus executes the same instructions a second time (producing "AA").
Additionally, because the second time, the ret instruction has no sensible return address on the stack, the computer will crash, but in a dangerous way because there's no telling about where execution will go to!
If you want, the jmp $ is also a crash but at least it's a 'safe' one.

This is what your code should have been:

[BITS 16]
[ORG 0x7C00]

mov al, 65
call print_char

cli
hlt
jmp $-2

%include "print.asm"

times 510-($-$$) db 0
dw 0xAA55

times 512-($-$$) db 0 (512 instead of 510) was wrong because it forces the mandatory signature bytes out of the 512-bytes bootsector. I don't understand why your emulator even launches this code without a valid signature where it belongs!
jmp $ is not wrong, but the preferred way is using cli hlt jmp $-2.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • The HLL analogy of doing `include` in the wrong place would be in C putting `#include` *inside* a function instead of global scope. It *does* substitute right there in the source, but yeah the consequences would be different. (Missing declarations elsewhere, or nested-function errors, instead of function definitions being inlined into this one. That's one reason why it's weird to define global functions in an asm include file, although using a linker would be overkill for a boot sector.) – Peter Cordes Oct 28 '21 at 02:17
  • 2
    Also, we already have at least two canonical duplicates for %include in the path of execution in a bootloader or .com: [I'm making a bootloader but it fails with %include](https://stackoverflow.com/q/63704833) / [Assembly with %include at the top - Printing Outputs Unexpected Result: just an " S"](https://stackoverflow.com/q/61072003). Might want to move your answer to one of those if you want to explain in more detail than the existing answers. – Peter Cordes Oct 28 '21 at 02:19