Search code examples
assemblyx86x86-16bootloaderreal-mode

STOSB instruction not storing byte when run from a bootloader


After making a small bootloader to teach myself assembly language, I noticed that the stosb instruction does not seem to be work. I compressed the issue to a minimal example:

BITS 16

start:
mov ax, 07C0h       
add ax, 288     
mov ss, ax
mov sp, 4096

mov ax, 07C0h       
mov ds, ax ;setting up stack

mov al, 'j'
mov di, buffer
stosb

mov si, buffer
jmp loops

loops:
mov ah, 0Eh
lodsb
cmp al, 0
je done
int 10h
jmp loops

done:
hlt

buffer times 64 db 0

times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
dw 0xAA55

When this bootloader is run it should store the letter j into a buffer, and then print that buffer to the display. The output should be:

j

When run it doesn't seem to print anything. What is the problem, and how can I fix it?


Solution

  • The solution was given by Michael Petch, Weather Vane, Jim Mischel, and GJ in the comments. To elaborate:

    The STOSB instruction implicitly stores data to [ES:DI], whereas the LODSB instruction implicitly loads data from [DS:SI]. You use STOSB to write to buffer and LODSB to read from buffer. However, you set the DS segment register but not ES. Therefore, you are not storing the 'j' character to the same location that you are reading from.

    The solution is just to set ES along with DS:

    mov ax, 07C0h       
    mov ds, ax
    mov es, ax
    

    Note: You may also want to explicitly clear the direction flag before using string instructions (e.g. LODSB, STOSB) in your code. You can do this with the CLD instruction. The BIOS would most likely leave the direction flag cleared before handing off to the bootsector (which is why it worked for you without the CLD), but to be absolutely sure, you should clear the flag yourself.