Working on an college - Assembly Language C course -assignment where I need to create a basic printf function using only system calls. Whenever there is a '%' I need to check the next character to determine how to implement either a character or a string.
If there is a 'c', replace it with a character, if there is a 's', replace it with a string. If there is another '%', output that. The professor stated that he knows this is a tough assignment, so it's okay if the solution is partially implemented, but i'm so close to a full solution, so I wanted to push ahead.
I've done extensive work on this code, and made comments on mostly every line, so I want to emphasize this is for purposes of me learning. I can print out one string 'woot woot' using mov eax, [abp + 12] or the second 'woot woot' using mov eax, [ebp + 16], but I cannot find a solution to print both. This is my dilemma.
Thank you for your time, and happy coding!
Here is a link to the assignment for clarification: https://imgur.com/h9tP89j
This is my sample output:
Hello world
str3 is 'woot woots', isn't that cool?
A is a char, but so is %,, s again!
Here is my code:
4 segment .data
5
6 str1 db "Hello world", 10, 0
7 str2 db "str3 is '%s', isn't that cool?", 10, 0
8 str3 db "woot woot", 0
9 str4 db "%c is a char, but so is %%, %s again!", 10, 0
10
11 segment .bss
12
13
14 segment .text
15 global asm_main
16
17 asm_main:
18 push ebp
19 mov ebp, esp
20 ; ********** CODE STARTS HERE **********
21
22 ;; EVERYTHING UP UNTIL THE PRINTF FUNCTION DOES NOT CHANGE AT ALL
23
24 ; eax (syscall-number) What do we want done? 3 is Read, 4 is Write
25 ; ebx (other-info) Usually when do you want the thing done? Or printed?
26 ; 0 is if you want to type something yourself, 1 is if you want to print something
27 ; ecx (other-info) Usually this is where you would put the string to be printed (example: str1)
28 ; edx (other-info) How long is the data that needs to be printed? You can ignore the null character
29 ; int 0x80 = Turn on the kernel and do the thing
30
31 push str1 ; push string 1 - 4 bytes
32 call printf ; call function
33 add esp, 4 ; str1 is a dword with 4 bytes
34
35 push str3 ; push string 3 - 4 bytes
36 push str2 ; push string 2 - 4 bytes
37 call printf ; call function
38 add esp, 8 ; str3 and str2 is 8 bytes total
39
40 push str3 ; push string 3 - 4 bytes
41 push 'A' ; Push A character - it's still a dword so 4 bytes
42 push str4 ; push string 4 - 4 bytes
43 call printf ; call function
44 add esp, 8 ; two arguments, 8 bytes total
45
46 ; *********** CODE ENDS HERE ***********
47 mov eax, 0
48 mov esp, ebp
49 pop ebp
50 ret
51
52 printf:
53 push ebp ; Prologue - every function starts with this
54 mov ebp, esp ; Prologue - and this
55
56 mov edx, -1 ; this is a counter to walk through each string slowly
57 mov edi, -1
58 loop:
59 inc edx ; increment counter for each loop
60 mov esi, edx ; constantly update this reserve to preserve counter, for use with offsetedx
61 mov eax, DWORD [ebp + 8] ; set eax to the dword pointer at ebp + 8
62 cmp BYTE [eax + edx], 0 ; compare the byte in the string with a null terminator
63 je loopEnd ; if there is a null terminator, jump to the end of the loop
64
65 percentCheck: ; each time we come up to a %, we want to check the next character to see how to proceed
66 cmp BYTE [eax + edx], 37 ; compare the current byte with a 37, which is is a '%' on the ascii table
67 jne continue ; if there is no percentage, we can continue walking through the string
68 inc edx ; move to the next byte
69
70 charCheck:
71 cmp BYTE [eax + edx], 99 ; compare the byte with a 99, which is 'c' on the ascii table
72 jne stringCheck ; if there is no 'c', move to the next check
73 mov eax, 4 ; syscall write operation
74 mov ebx, 1 ; syscall for printing to screen
75 lea ecx, [ebp + 12] ; pointer is possibly on the character. If not...?
76
77 offsetCheck: ; my idea is to check for the byte where ecx is pointing to see if there's an 'A'
78 je offsetEnd ; if it is, then output that bad boy!
79 add ebp, 4 ; if not, then add to the stack to adjust for the offset
80 lea ecx, [ebp] ; now point ecx to the new pointer on the stack
81 jmp offsetCheck ; run it again to make sure you are poiting to the 'A' character
82 offsetEnd:
83
84 int 0x80 ; make the kernel do the thing
85 jmp loop ; re-run the loop
86
87 stringCheck: ; this loop is a little tricky, as we need to be able to point to the correct string to output instead of the 's', but w$
88 cmp BYTE [eax + edx], 115 ; compare the byte with a 115, which is an 's' on the ascii table
89 jne continue ; if there is no 's', just let the string keep going
90 mov edx, -1 ; to calculate string length, just use the walktrhough loop again
91 offsetedx:
92 inc edx ; edx is our counter here
93 ; mov edi, edx
94 mov eax, DWORD [ebp + 8] ; set eax to the dword pointer at ebp + 8 again
95 cmp BYTE [eax + edx], 0 ; checking for a null terminator
96 je offsetedxEnd ; if there is a null terminator, assume we have reached the end of the string we wanted to drop in, and proc$
97
98 mov eax, 4 ; syscall write operation
99 mov ebx, 1 ; syscall for printing to screen
100 mov ecx, DWORD [ebp + 12] ; having trouble figuring out how to dymically set this to the right place. What to compare ecx to? $
101 cmp edi, -1
102 je continueoffset
103 inc edi ; trying to increment edi so on the next check, I can set ecx to run the second 'woot woot' output
104 mov ecx, DWORD [ebp + 4] ; this will output the sencond woot woot, but I can't get it to make the adjustment
105
106 continueoffset:
107 mov edx, 9
108 ; mov edi, ecx
109 int 0x80
110 ;; inc edi
111 ; mov edx, edi
112 ; jmp offsetedx
113 offsetedxEnd:
114
115 ; int 0x80 ; let the kernel do its thing
116 mov edx, esi ; make sure to put edx back to what it was supposed to be so the top loop isn't screwed up
117 jmp loop ; re-run the loop
118
119 continue:
120 mov eax, 4 ; SYS_write - Print the thing out
121 mov ebx, 1 ; STDOUT (terminal) - Write to screen
122 mov ecx, DWORD [ebp + 8] ; sets pointer to format string
123
124 add ecx, edx ; added counter to pointer, which ecx is pointing to
125 mov edx, 1 ;; Want edx to only output 1 character, but after the output, we need it restored to original count
126
127 int 0x80 ; kernel please grant me your strength
128 mov edx, esi ; Extra important since we need edx to be walking through the string, so it needs to be restored to where it was
129 jmp loop ; run that loop back again
130
131 loopEnd:
132
133 mov esp, ebp ; Epilogue - every function ends with this
134 pop ebp ; Epilogue - and this
135 ret ; Epilogue - also this