db "Hello, Pedro :)"
...
> Evertyhing seems to be ok except with
> line 15. Some garbage is printed. If I replace 15 with stars are printed as
> expected. So what is wrong with line 15.
As nasm64developer says, the problem isn't with line 15, but with line 2... or maybe even with "line 0"...
You don't give any "org", so Nasm will default to "org 0". This isn't a problem, although a lot of bootsectors are written to assemble at "org 7C00h". The difference is the value we need to put in ds. We know the bios will load us at 0x7C000 physical, and jump to that address - either ip = 7Cooh, cs = 0, or rarely (perhaps mythically) ip = 0, cs = 7C0h. We know that dl will hold the number of the drive we booted from. And that's *all* we can count on! Specifically, we don't know what's going to be in ds (or any other segreg). Bochs, of course, starts off with known, predictable values, but if you want your bootsector to work on any machine, not just Bochs, assume nothing!
Let's state the origin specifically, just for clarity:
org 0
> 1 entry:
> 2
You're trying to execute data here. A bootsector is expected to start with "jmp short overdata"/"nop", or "jmp near overdata". Some biosen check for this! (most don't, IME)
jmp short overdata
nop
> 3 msg db 'Hello, World!'
> 4 len: equ $-msg
> 5
(If you want your bootsector to be compatible with FAT12, you want some specific data here - the Bios Parameter Block - but it isn't strictly necessary.)
overdata:
mov ax, 7C0h
mov ds, ax
; really ought to set up a sane stack here, too!
; since we're not using the stack - except for the int(!!!),
; we can let it slide - the bios "probably" left us with
; a small, but usable stack
> 6 mov ecx, msg ; ecx contains startadress of string
The 32-bit registers *will* work here, but will emit an instruction size override byte (66h) or an address size override byte (67h) every time you do it. Not something I would use in a bootsector! Using 16-bit registers will generate smaller code. You'll have to select your registers differently - "mov al, [cx]" is *not* valid with 16-bit registers, but "mov al, [bx]" would be (but NG for int 10h/0Eh!), or "mov al, [di]" or "mov al, [si]". The "lodsb" instruction will do "mov al, [si]"/"inc si" in one short (but not especially fast) instruction. (really should clear the direction flag - "cld" - before using "stosb" (or other "string" instructions, but it would be a rude bios indeed that left it "down").
> 7 mov edx, msg
> 8 add edx, $len ; edx contains endadress of string
> 9 mov ah, 0x0e ; function 0eh: writting in TTY-mode
> 10 xor bh, bh ; which screen (0)
My machine doesn't care what's in bl, *or* bh - writes to the "current" page, regardless. Some video biosen write to the page in bh, so it's good to clear it. More rarely, you'll encounter a video bios that uses bl for the color/attribute, so for maximum compatibility, you might do "mov bx, 7"...
> 11 begin_str:
> 12 cmp ecx, edx ; end of string
> 13 je end_str ; if ecx and edx contain the same adress jump
> 14 ; the next line makes problems
> 15 mov al, [ecx] ; get one byte of the string
> 16 ; the next line would work fine
> 17 ; mov al, '*' ; get one byte of the string
> 18 int 0x10 ; BIOS interrupt
> 19 inc ecx ; next byte of string
> 20 jmp begin_str
> 21 end_str:
> 22
> 23 loop_for_ever: jmp loop_for_ever
> 24
> 25 ; now fill the bootsector and write the last two bytes
> 26 size equ $ - entry
> 27 %if size+2 > 512
> 28 %error "code is too large for boot sector"
> 29 %endif
You should get an error from "times" anyway, if this condition exists. Doesn't hurt to do it - doesn't emit any code...
> 30 times (512 - size - 2) db 0
> 31 db 0x55, 0xAA ;2 byte boot signature
Though there are other things I'd change, just jumping over your data, and loading ds with an appropriate value, should get your message on screen.
Happy Bootin',
Frank