Having Trouble Outputting Both Strings On My Printf Made With Syscalls
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
When using stack frames, you should not modify the
EBP register outside the function prologue/epilogue.
Since all of your registers are being used, you need a local variable on the stack which always points to the address of the next unused vararg parameter. This variable should be initialized to
ebp+12, because that is the address of the second parameter of printf, which is the first vararg parameter. After using that parameter, you should increment that local variable by 4, to make it point to that next vararg parameter.
As long as this variable always points to the next unused vararg parameter, you should have no trouble finding the next parameter.
In order to allocate space for such a local variable, you need to allocate 4 bytes on the stack. You can do this with a
push instruction or a
sub esp, 4 instruction. This can be done immediately after the function prologue.
- → OctoberCMS Backend Loging Hash Error
- → "failed to open stream" error when executing "migrate:make"
- → OctoberCMS - How to make collapsible list default to active only on non-mobile
- → Create plugin that makes objects from model in back-end
- → October CMS Plugin Routes.php not registering
- → OctoberCMS Migrate Table
- → How to install console for plugin development in October CMS
- → OctoberCMS Rain User plugin not working or redirecting
- → October CMS Custom Mail Layout
- → October CMS - How to correctly route
- → October CMS create a multi select Form field
- → How to update data attribute on Ajax complete
- → October CMS - Conditionally Load a Different Page