Search code examples
assemblyx86gnu-assembler

Print .ascii declaration using Lodsb or just mov


I'm writing this bootloader that just prints out some stuff on the screen. This is what I have so far in assembly:

    .globl _start

    .code16

_start:

    movw $0x0003, %ax
    int $0x10

    movb $0x0e, %ah
    movb $0x69, %al
    int $0x10

    movw $_header, %bx
    movb %bl, %al
    int $0x10

_header: .ascii "W\0"

    .org 0x1FE

    .byte 0x55
    .byte 0xAA

So right now it prints ASCII 69 ("i"), but I want it to print the .ascii declaration as well. Right now I only have it set to "W" so I could find it easily in Objdump. I can't seem to get access to that value (57). I can leal $_header, %edx and such, but then I can't seem to access the value at %edx.

I tried using lodsb, but I can't seem to figure it out. I set %di to 0x00, and set %si to the address of _header with leal %si, _header but then my lodsb followed by int 0x10 doesn't seem to print anything. Any ideas I'd appreciate.


Solution

  • Here:

    movw $_header, %bx
    movb %bl, %al
    

    First, movb %bl, %al isn't reading a byte from memory into al, it's reading a byte from bl. You want to change it to:

    movb (%bx), %al
    

    To get just one character out of _header you could load that character from the memory into al directly:

    movb _header, %al
    

    Secondly, and most importantly, it appears that you're making several assumptions:

    1. that your code starts running with cs=0x7c0, ip=0. It can be cs=0, ip=0x7c00 instead, but your code is expecting ip=0 (I infer from the code that the assembler starts assembling it with the implicit .org 0). You should make your code resilient to this second option. You can reload cs and ip to more suitable values with a jump instruction, something like this: jmp $0x7c0,$_next and the corresponding label on the next line: _next:.
    2. that your code starts running with ds=0x7c0. ds isn't guaranteed to be set to any value you may want or need. You have to initialize it yourself.

    Finally, what happens after the last int $0x10?

    With the corrections your code should look something like this:

        .globl _start
    
        .code16
    
    _start:
        /* .org 0 is implied here! But the code may start with ip != 0. */
    
        jmp $0x7c0,$_next
    _next:
        /* We have just ensured that cs=0x7c0,ip=$_next */
    
        /* Let's now load data segment registers with proper values */
        movw %cs, %ax
        movw %ax, %ds
        movw %ax, %es
    
        movw $0x0003, %ax
        int $0x10
    
        movb $0x0e, %ah
        movb $0x69, %al
        int $0x10
    
        movw $_header, %bx
        movb (%bx), %al /* read into al a byte from memory at address from bx */
        int $0x10
    
        /* Halt execution, don't just execute whatever garbage is in memory */
        /*after the end of the code. */
    _halt:
        hlt
        jmp _halt
    
    _header: .ascii "W\0"
    
        .org 0x1FE
    
        .byte 0x55
        .byte 0xAA