We have now written our Hello World program as well as a program implementing a function like int print(size_t, char*), but now let us look into a huge function collection for printing strings or numbers in various ways.
The following code implements:
void printf(char * format, ...) (extern from the C library)int stringlen(char *) returns the length of the stringint printstring(char *) writes the string, ends with a new lineint printnum(int) writes the number, ends with a new lineint print(char *) writes the string, single lineint println(char *) writes the string, ends with a new lineint print_sized(size_t, char *) writes the string's first size_t chars, single lineint println_sized(size_t, char *) writes the string's first size_t chars, ends with a new lineNOTE: I encourage you to print as shown in Hello World Again instead. Those below implementations are solely to show you other possibilities.
extern printf
global stringlen
global printstring
global printnum
global print
global println
global print_sized
global println_sized
segment .data
char db 0x0
formatnum: ; dword
dd frmtnumber
formatstr: ; dword
dd frmtstring
segment .rodata
frmtnumber: db 25H, 64H, 0AH, 00H ; "%d\n"
frmtstring: db 25H, 73H, 0AH, 00H ; "%s\n"
newline: db 0xA, 0x0 ; "\n"
segment .text
stringlen:; Function size_t (char * string), returns length of string in edx:eax
mov edx, dword [esp + 4] ; edx = char *
stringlen_asm: ; REQ: EDX = char *
xor eax, eax ; eax = 0
strlen_loop:
cmp byte [edx + eax], 0 ; CMP char[0], 0
jz strlen_cond0_return ; char[0] = 0? -> return
add eax, 1 ; eax = eax + 1
JMP strlen_loop
strlen_cond0_return: ; char[i] = 0? -> return
xor edx, edx
ret
; stringlen end
printstring:; Function int printstring(char*)
push dword [esp + 4] ; char*
push dword [formatstr]
call printf ; printf("%s\n", char*)
add esp, 8
xor eax, eax
ret
; printstring End of function
printnum:; Function int printnum(int)
push dword [esp + 4]
push dword [formatnum]
call printf ; printf("%d\n", int);
add esp, 8
xor eax, eax
ret
; prtinnum End of function
print: ; func: size_t print(char *), prints the string
mov ecx, [esp + 4]
pusha
enter 0,0
push ecx
call stringlen ; eax = stringlen(edx)
mov edx, eax
clc
call print_sized_asm ; eax = print_sized(eax, edx)
print_exit:
leave
popa
xor eax, eax ; eax = 0
ret
println: ; func: size_t println(char *), prints the string and starts newline
mov ecx, [esp + 4] ; ecx = char *
pusha
enter 0,0
push ecx
call stringlen ; eax = stringlen(ecx)
push eax
call println_sized ; eax = println_sized(eax, edx)
;return
leave
popa
xor eax, eax ; eax = 0
mov eax, 0
ret
print_sized: ; int print(size_t size, char * string)
STC ; set carry flag
enter 0, 0
pusha
mov edx, [ebp + 8] ; get the first element on stack which is the 32-bit int size
mov ecx, [ebp + 12] ; get the char* and move on to print_asm
print_sized_asm: ; REQ: ECX <- char* string, EDX <- sizeof string
mov eax, 4 ; sys_write
mov ebx, 1
int 0x80 ; syscall kernel with sys_write
JNC exit ; jump to exit if no carry flag set, used to avoid popping unnecessarily
popa ; pop everything back
leave
xor edx, edx
xor eax, eax
exit:
ret
println_sized: ; func: int println_sized(size_t, char *)
enter 0,0
push ebx
clc
mov ecx, [esp + 16] ; string
mov edx, [esp + 12] ; size
println_s_print: ; REQ: ECX = string, EDX = size
mov eax, 4
mov ebx, 1
int 0x80
JC println_s_return
println_s_newline:
mov ecx, newline ; char = '\n'
mov edx, 1
stc
JMP println_s_print
println_s_return:
xor eax, eax ; return 0
mov eax, 0
pop ebx
leave
ret