So my assignment was to write a program in assembly code that could make a statement, recieve a user inputted string. Print that string then reverse it using the cpu stack and print it again. this is what I have thus far.
INCLUDE Irvine32.inc
.data
buffer byte 20 DUP(0)
byteCount DWORD ?
Question byte "Please enter your name." ,0
Greeting byte "Hello " ,0
Statement byte " Here is your name backwards"
.code
main proc
mov edx , OFFSET Question
call WriteString
call CRLF
Call CRLF
mov edx, OFFSET buffer
mov Ecx, SIZEOF buffer
call ReadString
push edx
mov EDX ,OFFSET greeting
Call WriteString
pop edx
call WriteString
Call CRLF
Call CRLF
As you can see this successfully accepts a user entered input and displays it but Im really struggling trying to reverse it.
I tried these here that I copied from the book from a chapter about reversing strings.
; Push the name on the stack.
mov ecx,nameSize
mov esi,0
L1: movzx eax,aName[esi] ; get character
push eax ; push on stack
inc esi
loop L1
; Pop the name from the stack in reverse
; and store it in the aName array.
mov ecx,nameSize
mov esi,0
L2: pop eax ; get character
mov aName[esi],al ; store in string
inc esi
loop L2
Invoke ExitProcess,0
main endp
end main
but I get as output nothing.
it says "hello, (yourname here)"
it says "this is your name backwards "
ive tried just about every different incarnation of this I can think of and no avail. im at the end of my "string" here
This is against my better judgement since the snippet of code for reversing hasn't even been integrated into the code the original poster created. The variable names differ. A quick and dirty integration of the code is to create a variable nameSize that holds the number of characters read from a call to ReadString. ReadString (part of the Irvine32 library) returns the number of characters read in register EAX.
In the .data
section add the variable:
nameSize DWORD ?
After the ReadString move contents of EAX register to nameSize. This code:
mov edx, OFFSET buffer
mov Ecx, SIZEOF buffer
call ReadString
Should be:
mov edx, OFFSET buffer
mov Ecx, SIZEOF buffer
call ReadString
mov nameSize, eax ; EAX contains number of characters read into buffer
In the code snippet for reversing code remove the lines off the bottom for the end of procedure etc. These aren't needed since we will do this in our original code.
Invoke ExitProcess,0
main endp
end main
Everywhere in the string reversal code where we see the variable aName change it to buffer since that is where we placed the user's name. Place that code into our program and use WriteString to print the reversed buffer at the end. The code could look something like:
INCLUDE Irvine32.inc
.data
buffer byte 20 DUP(0)
byteCount DWORD ?
nameSize DWORD ?
Question byte "Please enter your name." ,0
Greeting byte "Hello " ,0
Statement byte " Here is your name backwards"
.code
main proc
mov edx , OFFSET Question
call WriteString
call CRLF
Call CRLF
mov edx, OFFSET buffer
mov Ecx, SIZEOF buffer
call ReadString
mov nameSize, eax
push edx
mov EDX ,OFFSET greeting
Call WriteString
pop edx
call WriteString
Call CRLF
Call CRLF
mov ecx,nameSize
mov esi,0
L1: movzx eax,buffer[esi] ; get character
push eax ; push on stack
inc esi
loop L1
; Pop the name from the stack in reverse
; and store it in the aName array.
mov ecx,nameSize
mov esi,0
L2: pop eax ; get character
mov buffer[esi],al ; store in string
inc esi
loop L2
mov EDX ,OFFSET buffer
call WriteString ; Write the reversed string that is now in buffer
exit
main ENDP
END
If you get linking errors, you may not be linking in all the prerequisite libraries. Try adding these lines to the top of your program:
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB user32.lib
INCLUDELIB kernel32.lib
I should point out that this is a very inefficient way to reverse a string if you don't mind destroying the original. It can be done without a secondary buffer on the stack by reversing the string in place.
At a high level:
- Allocate a 'reverse' and 'text' buffer
- Read the string into 'text'
- Make a pointer at the end of text, copying each character to the beginning, decrementing and incrementing both respectively.
- Print new 'reverse' buffer.
Doing this without allocating a new buffer is possible as well, but should be avoided in general because of the cost of invoking a system call (which you would need to do after each character)
section .data
prompt db "Please enter your name: ", 10
length equ $ - prompt
text times 255 db 0
buffer times 255 db 0
Enter your text
section .text
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, prompt
mov rdx, length
syscall
mov rax, 0
mov rdi, 0
mov rsi, text
syscall
mov rcx, rax ; rcx will be the character counter.
mov rsi, text ; a pointer to the current character. Start from the beginning.
add rsi, rcx
dec rsi ; Remember the 0-index
mov rdi, buffer
;; This subroutine is also SUB-optimal if your teacher demands
;; performance, look into the advantages of `lea` and a simple
;; rep;scas loop as well.
process_loop:
mov bl, [rsi] ; Now copy from back to front
mov [rdi], bl
inc rdi
dec rsi
dec rax
jnz process_loop
mov rax, 1 ; And print the string
mov rdi, 1
mov rsi, buffer
mov rdx, rcx
syscall
exit:
mov rax, 60
mov rdi, 0
syscall