I am trying to figure out how to flip flop a string 'without using the stack'.
I.E.
bobby -> ybbob
I am using Irvine32 and conceptually I am stumped as to how to take a string that is read in from the macro readstring
mov edx,offset mes1
call WriteString
mov edx,offset inName
call ReadString
In the above, a message displays 'whatever' and then a string entered and assigned to the variable inName.
I am not the best with string tools in asm and not sure the best route to take.
Hi BCDD && StatusQuo,
This thread (http://www.masm32.com/board/index.php?topic=14041.0) has solutions to your homework problem.
Joyful reading & good night,
jj
SwapIt PROTO :DWORD,:DWORD
.CODE
SwapIt PROC lpString:DWORD,dwLength:DWORD
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
ret
SwapIt ENDP
to use it.....
.DATA
TstStr db 'abcde',0
.CODE
;be sure to pass the length of the string, less the null terminator
INVOKE SwapIt,offset TstStr,sizeof TstStr-1
I think I am doing it right, but it just hangs???
Title flipTest
INCLUDE Irvine32.inc
;################################################
.data
mes1 BYTE "Enter a 5 digit string: ",0
inName DWORD 3 dup(0)
math1 BYTE 2
;################################################
.code
;################################################
getNameProc PROC
push ebp
mov ebp, esp
push edx
mov edx,offset mes1
call WriteString
mov edx,offset inName
mov ecx, sizeof inName
call ReadString
pop edx
pop ebp
ret
getNameProc ENDP
SwapIt PROC lpString:DWORD,dwLength:DWORD
push ebp
mov ebp,esp
push ecx
push edx
mov edi,[ebp+8]
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
pop ebp
ret
SwapIt ENDP
main PROC
call getNameProc
push OFFSET inName
call SwapIt
call writedec
exit
main ENDP
INVOKE SwapIt,offset inName,sizeof inName-1
;INVOKE ExitProcess,0
;INVOKE stringLengthProc,offset msg1
END main
PS, the above is coming from this working program I am trying to adjust to the flip flop method in this post.
INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
;################################################
.data
mes1 BYTE "Enter Your Name: ",0
inName DWORD 128 dup(0)
;stringSize BYTE 128 dup(0)
math1 BYTE 2
;################################################
.code
;################################################
getNameProc PROC
push ebp
mov ebp, esp
push edx
mov edx,offset mes1
call WriteString
mov edx,offset inName
mov ecx, sizeof inName
call ReadString
pop edx
pop ebp
ret
getNameProc ENDP
stringLengthProc PROC
push ebp
mov ebp,esp
push ecx
push edx
mov edi,[ebp+8]
mov ecx, 0
L1:
mov bl,[edi + ecx]
cmp bl, 0
JE L1Exit
inc ecx
JMP L1
L1Exit:
mov eax,ecx
pop edx
pop ecx
pop ebp
ret 4
stringLengthProc ENDP
main PROC
call getNameProc
push OFFSET inName
call stringLengthProc
call writedec
exit
main ENDP
INVOKE ExitProcess,0
;INVOKE stringLengthProc,offset msg1
END main
you are close :U
when you specify parameters on the PROC line, or if you specify local variables, the assembler generates a prologue and epilogue
you can turn this feature off with OPTION directives - we'll skip that for now
what that means is, the assembler takes care of EBP for you
SwapIt PROC lpString:DWORD,dwLength:DWORD
push ebp ;remove this line
mov ebp,esp ;remove this line
push ecx
push edx
mov edi,[ebp+8] ;remove this line, too
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
pop ebp ;remove this line
ret
SwapIt ENDP
She still just hangs??
Title flipTest
INCLUDE Irvine32.inc
;################################################
.data
mes1 BYTE "Enter a 5 digit string: ",0
inName DWORD 3 dup(0)
math1 BYTE 2
;################################################
.code
;################################################
getNameProc PROC
push ebp
mov ebp, esp
push edx
mov edx,offset mes1
call WriteString
mov edx,offset inName
mov ecx, sizeof inName
call ReadString
pop edx
pop ebp
ret
getNameProc ENDP
SwapIt PROC lpString:DWORD,dwLength:DWORD
; push ebp
; mov ebp,esp
push ecx
push edx
; mov edi,[ebp+8]
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
; pop ebp
ret
SwapIt ENDP
main PROC
call getNameProc
push OFFSET inName
call SwapIt
call writedec
exit
main ENDP
INVOKE SwapIt,offset inName,sizeof inName-1
;INVOKE ExitProcess,0
;INVOKE stringLengthProc,offset msg1
END main
try this....
Title flipTest
INCLUDE Irvine32.inc
;################################################
SwapIt PROTO :DWORD,:DWORD
stringLengthProc PROTO :DWORD
;################################################
.data
mes1 BYTE "Enter a 5 digit string: ",0
inName DWORD 3 dup(0)
math1 BYTE 2
;################################################
.code
;************************************************
getNameProc PROC
push edx
mov edx,offset mes1
call WriteString
mov edx,offset inName
mov ecx, sizeof inName
call ReadString
pop edx
ret
getNameProc ENDP
;************************************************
stringLengthProc PROC lpString:DWORD
;returns the string length in EAX
push ecx
push edi
mov al,0
or ecx,-1
mov edi,lpString
repnz scasb
or eax,-2
sub eax,ecx
pop edi
pop ecx
ret
stringLengthProc ENDP
;************************************************
SwapIt PROC lpString:DWORD,dwLength:DWORD
push ecx
push edx
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
ret
SwapIt ENDP
;************************************************
main PROC
call getNameProc
INVOKE stringLengthProc,offset inName
INVOKE SwapIt,offset inName,eax
mov edx,offset inName
call WriteString
call Crlf
exit
main ENDP
;################################################
END main
Awesome!
Can you explain to how the information is passed through edi without calling on it again?
I am curious how that worked.
well - if you look closely, we do not use EDI
we use EDX, instead
a matter of preference, as in win32, EDI should be preserved, whereas EDX need not be
Kip Irvine did not necessarily use that convention in his library, though :P
we are using a calling convention named "StdCall" - this is declared in Irvine32.inc
so - the following information applies to that convention
when you use INVOKE...
INVOKE SwapIt,offset inName,eax
the assembler generates code that pushes the parameters (right-to-left) onto the stack, then makes the call
push eax
push offset inName
call SwapIt
the assembler also takes care of parameter passing, the stack frame base pointer (EBP), and cleaning up the stack after the call
that includes a LEAVE instruction just before the RET
so, before you ask what LEAVE does, it is equivalent to this
mov esp,ebp ;restore ESP with original contents
pop ebp ;restore EBP with original contents
now for the rest of the PROC
we write this code...
SwapIt PROC lpString:DWORD,dwLength:DWORD
push ecx
push edx
mov ecx,dwLength
mov edx,lpString
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
ret
SwapIt ENDP
the assembler actually generates something like this...
SwapIt PROC lpString:DWORD,dwLength:DWORD
push ebp
mov ebp,esp
push ecx
push edx
mov ecx,[ebp+12]
mov edx,[ebp+8]
dec ecx
add ecx,edx
jmp short SwpIt1
SwpIt0: mov al,[edx]
mov ah,[ecx]
mov [ecx],al
mov [edx],ah
dec ecx
inc edx
SwpIt1: cmp ecx,edx
ja SwpIt0
pop edx
pop ecx
leave
ret 8
SwapIt ENDP
so, the assembler pushes EBP and fills it with ESP, setting up the stack frame
it then replaces the named parameters with EBP-relative indexed addresses, like [EBP+8]
and, everyplace we put a RET instruction, it inserts a LEAVE and balances the stack by adjusting the RET to RET 8
if we had 3 dword parameters, it would change it to RET 12, and so on
In addition to Dave's perfect examples, here two short algos for string flipping. The upper algo, xx1, weighs in at a whopping 33 bytes, while the lower one does the job with 30 bytes without ever using the stack :bg
You might lookup the otherwise rarely used instructions repne scasb and stosb.
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
.data
Src db "TheStringToFlipFlopHas34Characters", 0
Dest db "Not yet filled with anything, 34cs", "?"
Overflow db "This should be left intact", 0
Init
CodeSize xx1
CodeSize xx2
xx1_s:
mov edi, offset Src
or ecx, -1
xor eax, eax
repne scasb
mov edx, offset Dest ; edi is at end of source
xchg edx, edi ; now edi is start of dest, edx is end of source
dec edx
dec edx
neg ecx
dec ecx
push edi
.Repeat
mov al, [edx] ; get a byte from end of source
stosb ; poke to start of dest, increase dest
dec edx ; lower source
dec ecx ; decrease counter
.Until Zero?
pop edi
xx1_endp:
Print edi, CrLf$
Src2 equ Dest ; we flipped a string above, now we flip it back to
Dest2 equ Src ; the original state, so we need to swap src and dest
xx2_s: ; -------------------------------------------------------------
mov edi, offset Src2 ; get a pointer to the source (in this case, the old destination)
or ecx, -1 ; no limit for repne
mov al, 0 ; to get the len, we search for a nullbyte
repne scasb ; edi is now at end of source+1
mov edx, offset Dest2
mov ecx, edx ; we will test against the start of the destination
xchg edx, edi ; now edi is start of dest, edx is end of source
dec edx
.Repeat
dec edx ; lower source pointer
mov al, [edx] ; get a byte from end of source
stosb ; poke to start of dest, increase dest
.Until edx<=ecx
xx2_endp: ; -------------------------------------------------------------
Inkey edx, CrLf$ ; show the dest
; Inkey offset Overflow ; optional: check if the buffer behind dest is intact
Exit
end start