I am trying to add a print function to a ASM kernel that I am writing, though I have tried many with no success. Most, like the one from osdev, simply print out: ?, or two happy faces. I am using the mikeos bootloader and qemu. This is my current kernel, which print out gibberish infinitely:
%include "print.asm"
os_main:
hello db "Hi!", 0
mov si, hello
call print
jmp $
Contents of print.asm (from a tutorial):
print:
pusha
; keep this in mind:
; while (string[i] != 0) { print string[i]; i++ }
; the comparison for string end (null byte)
start:
mov al, [bx] ; 'bx' is the base address for the string
cmp al, 0
je done
; the part where we print with the BIOS help
mov ah, 0x0e
int 0x10 ; 'al' already contains the char
; increment pointer and do next loop
add bx, 1
jmp start
done:
popa
ret
print_nl:
pusha
mov ah, 0x0e
mov al, 0x0a ; newline char
int 0x10
mov al, 0x0d ; carriage return
int 0x10
popa
ret
What is wrong with this code? I am a new to assembly language, any help would be appreciated.
Assembler: nasm
os_main: hello db "Hi!", 0 mov si, hello call print jmp $
You have placed the string at the label hello in the path of the program's execution! The CPU will execute those 4 bytes ("H", "i", "!", 0) as if they represented instructions. Obviously they aren't. Hence the output of gibberish.
This will work:
os_main:
mov si, hello
call print
jmp $
hello db "Hi!", 0
Like fuz wrote in a comment, the print code is wrong in that it uses the wrong address register (BX
) to match your call (SI
).
Better use next code:
; IN (si) OUT ()
print:
pusha
mov bx, 0007h ; BH is DisplayPage, BL is GraphicsColor
start:
mov al, [si] ; <<<<<<<<<
cmp al, 0
je done
mov ah, 0x0E ; BIOS.Teletype
int 0x10
inc si ; <<<<<<<<<
jmp start
done:
popa
ret
; IN () OUT ()
print_nl:
pusha
mov bh, 0 ; BH is DisplayPage (No need for GraphicsColor in BL)
mov ax, 0x0E0D ; BIOS.Teletype CR
int 0x10
mov ax, 0x0E0A ; BIOS.Teletype LF
int 0x10
popa
ret