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
assembly x86 kernel bios
New contributor
add a comment |
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
assembly x86 kernel bios
New contributor
3
Nobody cares about efficiency of printing a string during booting using bios services. What is definitely bad practice is usingcall
on something that is not a function. Also, you should not put data at0x7c00
since that's the entry point for a boot sector (irrespective of where you might place astart
label if at all) and as such the cpu will try to execute whatever is there as code. Meaning, move themsg
to after thejmp 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 thanmov ax,0
, and there's no need to usecall
at all. Just fall through into the loop.or al,al
is the same size but worse thantest 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 smallloop
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
add a comment |
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
assembly x86 kernel bios
New contributor
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
assembly x86 kernel bios
New contributor
New contributor
edited Nov 21 at 0:30
Jester
45.9k34381
45.9k34381
New contributor
asked Nov 21 at 0:24
Carter Rogers
11
11
New contributor
New contributor
3
Nobody cares about efficiency of printing a string during booting using bios services. What is definitely bad practice is usingcall
on something that is not a function. Also, you should not put data at0x7c00
since that's the entry point for a boot sector (irrespective of where you might place astart
label if at all) and as such the cpu will try to execute whatever is there as code. Meaning, move themsg
to after thejmp 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 thanmov ax,0
, and there's no need to usecall
at all. Just fall through into the loop.or al,al
is the same size but worse thantest 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 smallloop
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
add a comment |
3
Nobody cares about efficiency of printing a string during booting using bios services. What is definitely bad practice is usingcall
on something that is not a function. Also, you should not put data at0x7c00
since that's the entry point for a boot sector (irrespective of where you might place astart
label if at all) and as such the cpu will try to execute whatever is there as code. Meaning, move themsg
to after thejmp 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 thanmov ax,0
, and there's no need to usecall
at all. Just fall through into the loop.or al,al
is the same size but worse thantest 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 smallloop
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 21 at 1:06
answered Nov 21 at 0:59
Shift_Left
884417
884417
add a comment |
add a comment |
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.
Carter Rogers is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 at0x7c00
since that's the entry point for a boot sector (irrespective of where you might place astart
label if at all) and as such the cpu will try to execute whatever is there as code. Meaning, move themsg
to after thejmp 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 thanmov ax,0
, and there's no need to usecall
at all. Just fall through into the loop.or al,al
is the same size but worse thantest 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