0

So I'm currently working on a simple chunk of assembly which I hope to turn into an efficient bootloader to load a C-kernel.

My main question right now is. Are there any pointers for how I'm currently storing and printing a string out of the SI register?

It renders the string perfectly. I just want to make sure I'm developing good practice.

Here's my code.

ORG 0x7c00
msg db 'Hello World!', 0

start:
    mov ax, 0x00
    mov ds, ax
    mov ah, 0x0e ;prepare AH register to be written to.
    mov si, msg ;move string into SI register and prepare for read/write
    call print

print:
    lodsb ;load byte string pointed to in SI and DS register
    or al, al ;check if al equals 0
    jz end ; if zero, end execution
    int 0x10 ;print string
    jmp print ;^ above line and this only execute if AL > 0.

end:
    hlt
    jmp end

times 510-($-$$) db 0
dw 0xaa55
Jester
  • 56,577
  • 4
  • 81
  • 125
  • 3
    Nobody cares about efficiency of printing a string during booting using bios services. What is definitely bad practice is using `call` on something that is not a function. Also, you should not put data at `0x7c00` since that's the entry point for a boot sector (irrespective of where you might place a `start` label if at all) and as such the cpu will try to execute whatever is there as code. Meaning, move the `msg` to after the `jmp end` so it's not in the execution path. – Jester Nov 21 '18 at 00:29
  • In a bootloader, the only measure of "efficiency" that matters is code-size. Being constrained to 510 bytes, you need to get the job done in as few bytes of code as possible. That said, your code is terrible for both code-size and efficiency. `xor ax,ax` is shorter than `mov ax,0`, and there's no need to use `call` at all. Just fall through into the loop. `or al,al` is the same size but worse than `test al,al`, and you know the first byte is *not* the terminator so you can restructure it: [Why are loops always compiled into "do...while" style?](/q/47783926) – Peter Cordes Nov 21 '18 at 01:12
  • See also [Tips for golfing in x86/x64 machine code](https://codegolf.stackexchange.com/q/132981) for more. You might consider using the slow but small `loop` instruction at the bottom of your loop. Of course for efficiency, if the BIOS has any function that prints multiple characters with one call, that would be *much* faster. `int` is a slow instruction, so it's much faster to make only one for the whole string. – Peter Cordes Nov 21 '18 at 01:14

1 Answers1

0

Your code should look something like this.

    org     0x7c00

    xor     ax, ax
    mov     ds, ax
    jmp     Begin

print:
    mov     ah, 0x0e            ; BIOS TTY function
.L0:
    lodsb
    or      al, al
    jnz     .J0
    ret
.J0:
    int     0x10
    jmp     .L0

Prompt:
     db     'Hello World', 0

Begin:
    mov     si, Prompt
    call    print
.spin:
    hlt
    jmp     .spin

    times 510 - $+$$ db 0

    dw      0xAA55

Because you don't bounce over your prompting text, this is what the computer would think it needs to execute right after BIOS as passed control to the boot sector.

00  48                dec ax
01  656C              gs insb
03  6C                insb
04  6F                outsw
05  20576F            and [bx+0x6f],dl
08  726C              jc 0x76
0A  6490              fs nop

Other than that, the only change I've made is to initialize AH in the loop otherwise, every time you call the function you'd have to repeat setting AH.

I have several version of bootloader and in each, I've paid particular attention to optimization especially as it applies to space as there is only so much that will fit in one sector.

There could be a few variants to this, but it is important control flow follows a predicable path.

Shift_Left
  • 1,208
  • 8
  • 17