Assembly Printing A String Efficiently











up vote
0
down vote

favorite












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









share|improve this question









New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 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 at 0: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?
    – Peter Cordes
    Nov 21 at 1:12












  • See also Tips for golfing in x86/x64 machine code 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 at 1:14















up vote
0
down vote

favorite












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









share|improve this question









New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 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 at 0: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?
    – Peter Cordes
    Nov 21 at 1:12












  • See also Tips for golfing in x86/x64 machine code 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 at 1:14













up vote
0
down vote

favorite









up vote
0
down vote

favorite











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









share|improve this question









New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











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






assembly x86 kernel bios






share|improve this question









New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Nov 21 at 0:30









Jester

45.9k34381




45.9k34381






New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Nov 21 at 0:24









Carter Rogers

11




11




New contributor




Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Carter Rogers is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 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 at 0: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?
    – Peter Cordes
    Nov 21 at 1:12












  • See also Tips for golfing in x86/x64 machine code 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 at 1:14














  • 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 at 0: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?
    – Peter Cordes
    Nov 21 at 1:12












  • See also Tips for golfing in x86/x64 machine code 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 at 1:14








3




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 at 0:29






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 at 0: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?
– Peter Cordes
Nov 21 at 1:12






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?
– Peter Cordes
Nov 21 at 1:12














See also Tips for golfing in x86/x64 machine code 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 at 1:14




See also Tips for golfing in x86/x64 machine code 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 at 1:14












1 Answer
1






active

oldest

votes

















up vote
0
down vote













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.







share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });






    Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.










     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403610%2fassembly-printing-a-string-efficiently%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    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.







    share|improve this answer



























      up vote
      0
      down vote













      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.







      share|improve this answer

























        up vote
        0
        down vote










        up vote
        0
        down vote









        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.







        share|improve this answer














        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.








        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 21 at 1:06

























        answered Nov 21 at 0:59









        Shift_Left

        884417




        884417






















            Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.










             

            draft saved


            draft discarded


















            Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.













            Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.












            Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.















             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403610%2fassembly-printing-a-string-efficiently%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...