Code: Select all
__entry_point:
mov edi, 0xb8000
mov esi, string
mov ah, 0x0f
.displaying:
lodsb
stosw
or al, al
jnz .displaying
jmp short $
Code: Select all
__entry_point:
mov edi, 0xb8000
mov esi, string
mov ah, 0x0f
.displaying:
lodsb
stosw
or al, al
jnz .displaying
jmp short $
No, it's part of assembly code, and I want to make it a function, in assembly.Octocontrabass wrote:Are you calling this function from C?
If so, what calling conventions does the compiler expect?
Code: Select all
print_string:
push ax
mov ah, 0x0f
.displaying:
lodsb
stosw
or al, al
pop ax
jnz .displaying
ret
Code: Select all
print_string:
push eax
push edi
push esi
mov edi, 0xb8000
mov esi, string
mov ah, 0x0f
.displaying:
lodsb
stosw
or al, al
jnz .displaying
pop esi
pop edi
pop eax
ret
Code: Select all
string db 'foo', 10, 13, 0
string2 db 'bar', 10, 13, 0
Can you explain how?Techel wrote:you have to move to the current character location to a new line manually.
Code: Select all
;; esi: pointer to nullterminated string
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PrintSomeText:
pusha
mov edi, 0xB8000 ;;video memory
mov eax, dword[CurrentPosition]
shl eax, 1
add edi, eax ;;2 bytes per character
.loopi:
lodsb ;;get character
cmp al, 0 ;;test if null
je .done
stosb ;;write to video memory
mov al, 0x07 ;;grey on black
stosb
jmp .loopi
.done:
sub edi, 0xB8000
shr edi, 1
add edi, 80-1 ;;go one line below
mov eax, edi
xor edx, edx
mov ebx, 80
div ebx ;;x-offset = cursor pos%80
sub edi, edx ;;sub x-offset
cmp edi, 80*50;;check if out of screen
jnae .inscreen ;;else move screen up
push edi
mov esi, 0xB8000+80*2 ;;begin at second line
mov edi, 0xB8000 ;;to first line
mov ecx, 80*49 ;;entire screen minus one line
rep movsw
mov edi, 0xB8000+49*80*2 ;;clear last line
mov cx, 80
mov ax, 0x0720 ;;character (space) + color
rep stosw
pop edi
sub edi, 80
.inscreen:
mov dword[CurrentPosition], edi ;;save current cursor position
mov al, 0x0F ;;update hardware cursor
mov dx, 0x3D4
mov al, 0x0F
out dx, al
mov eax, edi
inc dx
out dx, al
mov al, 0x0E
dec dx
out dx, al
mov eax, edi
xchg al, ah
inc dx
out dx, al
popa
ret
Note that assembly doesn't really have "functions" (as people are used to them in high level languages). It's better to think of them as something different ("routines"), that can return multiple values, and can have multiple entry points. There is also no calling convention, and you decide where each routine's entry point expects to find input parameters and leaves output parameters. People that don't understand these differences end up writing bad code (code restricted by limitations that exist for compiler generated code but don't exist in assembly).Haghiri75 wrote:Greetings. This is part of my code :
Code: Select all
__entry_point: mov edi, 0xb8000 mov esi, string mov ah, 0x0f .displaying: lodsb stosw or al, al jnz .displaying jmp short $
Haghiri75 wrote:and I wanna make the print part a function, but It doesn't work. My way was pushing and popping ax, and also adding a "ret" to the printing part.
Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text
;______________________________________________________________________________
;
;Input
; esi Address of ASCIIZ string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString_blackAndWhite_top_left:
mov edi, 0xb8000
mov ah, 0x0f
.displaying:
lodsb
stosw
or al, al
jnz .displaying
ret
Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text
;______________________________________________________________________________
;
;Input
; esi Address of ASCIIZ string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString_blackAndWhite_top_left:
mov edi, 0xb8000
mov ah, 0x0f
lodsb
.displaying:
stosw
lodsb
test al, al
jnz .displaying
ret
Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text
;______________________________________________________________________________
;
;Input
; esi Address of ASCIIZ string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString_blackAndWhite_top_left:
mov edi, 0xb8000
;Print an ASCIIZ string with "black and white" text
;______________________________________________________________________________
;
;Input
; esi Address of ASCIIZ string
; edi Address in display memory to put string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString_blackAndWhite:
mov ah, 0x0f
;Print an ASCIIZ string
;______________________________________________________________________________
;
;Input
; ah Attribute for string
; esi Address of ASCIIZ string
; edi Address in display memory to put string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString:
lodsb
.displaying:
stosw
lodsb
test al, al
jnz .displaying
ret
Code: Select all
;Print an ASCIIZ string at coords (x, y)
;______________________________________________________________________________
;
;Input
; ah Attribute for string
; ebx Y position
; esi Address of ASCIIZ string
; edi X position
;
;Output
; None
;
;Trashed
; eax, ebx, esi, edi
;______________________________________________________________________________
printString_atCoords:
shl ebx,5 ;ebx = y * 32 = y * 16 * 2
lea edi,[0xB8000+edi*2] ;edi = 0xB8000 + x * 2
lea ebx,[ebx*5] ;ebx = y * 16 * 2 * 5 = y * 80 * 2
add edi,ebx ;edi = 0xB8000 + x*2 + y * 80 * 2 = 0xB8000 + (y * 80 + x) * 2
jmp printString
Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text
;______________________________________________________________________________
;
;Input
; esi Address of ASCIIZ string
;
;Output
; None
;
;Trashed
; eax, esi, edi
;______________________________________________________________________________
printString_blackAndWhite_top_left:
mov edi, 0xb8000
call printString_blackAndWhite
ret
Code: Select all
printString_blackAndWhite_top_left:
mov edi, 0xb8000
; call printString_blackAndWhite
; ret
jmp printString_blackAndWhite
How many POPs are being executed here?Haghiri75 wrote:Is this the right way?!Code: Select all
print_string: push ax mov ah, 0x0f .displaying: lodsb stosw or al, al pop ax jnz .displaying ret
Thank you very much! But I have another question, does "printString_atCoords" routine, changes cursor place? I tried it but it didn't work.Brendan wrote:Hi,
Note that assembly doesn't really have "functions" (as people are used to them in high level languages). It's better to think of them as something different ("routines"), that can return multiple values, and can have multiple entry points. There is also no calling convention, and you decide where each routine's entry point expects to find input parameters and leaves output parameters. People that don't understand these differences end up writing bad code (code restricted by limitations that exist for compiler generated code but don't exist in assembly).Haghiri75 wrote:Greetings. This is part of my code :
Code: Select all
__entry_point: mov edi, 0xb8000 mov esi, string mov ah, 0x0f .displaying: lodsb stosw or al, al jnz .displaying jmp short $
Haghiri75 wrote:and I wanna make the print part a function, but It doesn't work. My way was pushing and popping ax, and also adding a "ret" to the printing part.
To turn your code into a routine, you need to document its inputs, outputs and which registers it trashes; and mostly just put a "ret" at the end. For example, your original code might become:
Note that this has a bug - it prints the last "0x00" character. It's also more efficient to use "test al,al" (as it doesn't modify AL). To fix that:Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text ;______________________________________________________________________________ ; ;Input ; esi Address of ASCIIZ string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString_blackAndWhite_top_left: mov edi, 0xb8000 mov ah, 0x0f .displaying: lodsb stosw or al, al jnz .displaying ret
Also note that it'd be trivial to add multiple entry points to make this more flexible:Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text ;______________________________________________________________________________ ; ;Input ; esi Address of ASCIIZ string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString_blackAndWhite_top_left: mov edi, 0xb8000 mov ah, 0x0f lodsb .displaying: stosw lodsb test al, al jnz .displaying ret
Of course these entry points naturally lead into each other. In some cases you can't do that and you need a "jmp" instruction. For example:Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text ;______________________________________________________________________________ ; ;Input ; esi Address of ASCIIZ string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString_blackAndWhite_top_left: mov edi, 0xb8000 ;Print an ASCIIZ string with "black and white" text ;______________________________________________________________________________ ; ;Input ; esi Address of ASCIIZ string ; edi Address in display memory to put string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString_blackAndWhite: mov ah, 0x0f ;Print an ASCIIZ string ;______________________________________________________________________________ ; ;Input ; ah Attribute for string ; esi Address of ASCIIZ string ; edi Address in display memory to put string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString: lodsb .displaying: stosw lodsb test al, al jnz .displaying ret
Note that there's 2 ways to think about this. You could think of it as multiple entry points for the same routine. Alternatively you could think of it as multiple separate routines that use tail call optimisation combined with the removal of pointless "jmp" instructions.Code: Select all
;Print an ASCIIZ string at coords (x, y) ;______________________________________________________________________________ ; ;Input ; ah Attribute for string ; ebx Y position ; esi Address of ASCIIZ string ; edi X position ; ;Output ; None ; ;Trashed ; eax, ebx, esi, edi ;______________________________________________________________________________ printString_atCoords: shl ebx,5 ;ebx = y * 32 = y * 16 * 2 lea edi,[0xB8000+edi*2] ;edi = 0xB8000 + x * 2 lea ebx,[ebx*5] ;ebx = y * 16 * 2 * 5 = y * 80 * 2 add edi,ebx ;edi = 0xB8000 + x*2 + y * 80 * 2 = 0xB8000 + (y * 80 + x) * 2 jmp printString
For the latter, imagine you have something like this:
Because we're not using the stack for arguments; the "tail call optimisation" mostly just means replacing "call then ret" with "jmp", like this:Code: Select all
;Print an ASCIIZ string at the top left of the screen, with "black and white" text ;______________________________________________________________________________ ; ;Input ; esi Address of ASCIIZ string ; ;Output ; None ; ;Trashed ; eax, esi, edi ;______________________________________________________________________________ printString_blackAndWhite_top_left: mov edi, 0xb8000 call printString_blackAndWhite ret
If the target of a jump is the next instruction, then the "jmp" does nothing and can be removed too. That gives us the same code as before.Code: Select all
printString_blackAndWhite_top_left: mov edi, 0xb8000 ; call printString_blackAndWhite ; ret jmp printString_blackAndWhite
Of course it's easier to think of it as a routine with multiple entry points (and not need to optimise) than it is to think of it as multiple routines (and then do 2 extra optimisations).
Cheers,
Brendan