user1133383
user1133383

Reputation: 103

Hello World bootloader hanging after first character

I am using this code for a Hello world bootloader. Instead of printing out "Hello world\n" it just prints out a 'H' and hangs. I have used loadsb print out the message successfully but I can't understand why this approach won't work as it seems equivalent.

[ORG 0x7c00]
[BITS 16]

    xor ax, ax  ;make it zero
    mov ds, ax

    mov ecx, msg
bios_print:
    mov al, [ecx]
    add ecx,1
    cmp al, 0  ;zero=end of str
    je hang    ;get out
    cmp al,100
    jge hang
    mov ah, 0x0E
    int 0x10
    jmp bios_print


hang:
    jmp hang

msg   db 'Hello World', 13, 10, 0






   times 510-($-$$) db 0
   db 0x55
   db 0xAA

Edit: I changed the [BITS 64] to [BITS 16]

Upvotes: 2

Views: 456

Answers (1)

Daniel Kamil Kozar
Daniel Kamil Kozar

Reputation: 19286

Your program is working exactly in a way you've coded it. The lower-case e in ASCII is represented as 65h, which equals 101 in decimal. Therefore, executing cmp al, 100 / jge hang if e (101) is in al results in a jump to the label hang. Everything's alright. :)

A solution to your problem would be simply deleting that line, since I don't really see any purpose for it - seeing how you've got your string terminated by a \0, the loop will end when it reaches the end.

Four extra tips, though :

  • Remember that the flags are set after (almost) every arithmetical and logical operation. Therefore, there's really no need to do a cmp after an add, especially if the only condition of the jump can be represented by one of the flags. In this case, add ecx, 1 / cmp al, 0 / je hang can be replaced by a very simple add ecx, 1 / jz hang. This saves you two bytes, so valuable in those bootsector conditions.
  • You really do want to preserve the registers that you're using in your application when calling a BIOS routine. BIOSes come from different vendors and some of them might not play nice and destroy what you have in your registers. The instruction pusha does just that. It's generally a rule of thumb to preserve all the runtime information when calling any piece of code you haven't written yourself (though this may sound extreme in more "civilized" environments - but BIOS and general real mode code isn't one).
  • When the computer boots up, it's in real mode. The default operand and address size in this mode is 16 bits (addresses are artificially extended by segmentation to 20 bits). You can, of course, use the 32-bit parts of the registers, but a operand size prefix must be generated before the instruction for that to happen. This is another byte, and you've got only 510 of them now. :) Therefore, mov ecx, msg is simply redundant - the offset part of the address will never be longer than 16 bits. Same goes for add ecx, 1. Just replace ecx with cx in both those cases.
  • Use the hlt instruction. It makes your CPU's blood pressure much lower, and there's really no use in stressing it all over the place. Simply add hlt after the hang label and before the jump.

Upvotes: 4

Related Questions