News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Passing local variables by reference to system stack

Started by jman, May 18, 2015, 12:48:29 PM

Previous topic - Next topic

jman

If I have a procedure like the one below can I pass the local variable myVar on top of the system stack by reference to be used in the exchange procedure?  I know I am not supposed to use OFFSET though I left it because it's the closest thing I can think of. 

sortList PROC
   push      ebp               ; set up stack frame
   mov      ebp, esp
   sub      esp, 8                               ; for locals
   
   myVar   EQU DWORD PTR [ebp-4]   
   mov      eax, [esi+ebx]                  ; base indexed reference of array position
   mov      myVar, eax
   push      OFFSET myVar
        call           exchange
...

dedndave

ok - my mistake i see how it's defined

however.....
show us the code for exchange
i suspect there is no need to put that code in a proc   :biggrin:

dedndave

   myVar   EQU DWORD PTR [ebp-4]   
   mov      eax, [esi+ebx]                  ; base indexed reference of array position
   mov      myVar, eax
   push      OFFSET myVar


myVar is actually a TEXTEQU
myVar TEXTEQU <DWORD PTR [ebp-4]>

so, when you push, the assembler interprets the line as
    push    OFFSET DWORD PTR [ebp-4]
that won't work, because OFFSET wants a constant address
you could use LEA
    lea     edx,myVar    ;should assemble as "lea edx,[ebp-4]"
    push    edx

but, you've already got the variable in EAX

jj2007

In normal Masm code, you are doing that all the time:

ShowTheRect proc hWin
LOCAL rc:RECT
  invoke GetClientRect, hWin, addr rc   ; <<<<< pass a pointer to a local variable ("by reference" in VB speak)
  print str$(rc.right), 9, "right", 13, 10
  print str$(rc.bottom), 9, "bottom", 13, 10
  ret
ShowTheRect endp
...
invoke ShowTheRect, rv(GetForegroundWindow)

jman

Thanks dedndave and jj.  Yes dedndave the proc is not necessary.  I could just use the keyword xchg without even using the call to my exchange proc.  By the way I was using lea though I messed up the syntax.  I figured how to pass what I needed to on the stack by reference with using a combination of what you wrote.

jman

Actually I think I am using a double pointer variable passed to the exchange proc.  My problem is the values just don't swap.  How would you go about dereferencing the double pointers inside the exchange proc ebp+20 and ebp+24 either syntactically or conceptually?  I must not understand dereferencing because I thought I should use the following in the first code block.  The second code block is most of my code.  My problem I am pretty sure only involves the stack parameters j and i from eax I pushed onto the stack.    

mov eax, [[ebp+20]]
xchg eax, [[ebp+24]]       
mov [[ebp+20]], eax


proc sortList

    push       ebp                    ; set up stack frame
    mov        ebp, esp
    mov        esi, [ebp+12]            ; get address of array
    mov        ecx, [ebp+8]            ; get value of listSize

    sub        esp, 8

    j    EQU DWORD PTR [ebp-4]   
    i    EQU DWORD    PTR [ebp-8]

...

; code loads addresses of array indexes j and i into eax to swap values

    mov        eax, [esi+ebx]
    mov        j, eax
    lea        eax, j
    push        eax
    mov        eax, [esi+edx]
    mov        i, eax
    lea        eax, i
    push        eax
    call        exchange

.....

    mov        esp, ebp            ; remove locals from stack
    pop        ebp
    ret 8
sortList ENDP

; exchange
; Swaps array elements i and j, j is i+1
; Receives: @i and @j
; Returns: 8 more bytes from stack
exchange PROC
    push        ebp                    ; set up stack frame
    mov        ebp, esp

; swap i and j
   
    mov        eax, [ebp+20]
    xchg        eax, [ebp+24]
    mov        [ebp+24], eax

    pop ebp
    ret 8
exchange ENDP

dedndave

#6
something like this
mov ecx,[ebp+24]
mov edx,[edx+20]
mov eax,[ecx]
xchg eax,[edx]
mov [ecx],eax


edit - oops - forgot that last line   :icon_cool:

jman

The first two lines are okay. The second line had to be mov edx,[ebp+24] though doesn't matter.  The third and fourth lines are just supposed to dereference the the address pointed to by ecx and edx, respectively right?  When I run with debugging the compiler throws an unhanded exception, access violation reading location.  Is this supposed to be dereferenced a different way?  Did I actually create a double pointer?  I don't know if I steered you in the wrong direction.

dedndave

if you pass pointers to the variables, the code i posted in reply #6 should work
you are getting awfully buried in passing pointers
this code will be slow
best if you can perform the XCHG locally   :t
and the pointer confusion won't be so bad

i.e., remove the "call exchange" and replace it with an XCHG instruction

jman

After your correct syntax with dereferencing a double pointer the only problem I had was that the stack parameters were incorrect. It was one of those things I changed on the fly and didn't remember.  Thanks for your help.

jman

Ok this is driving me nuts.  I thought that I solved this problem.  The problem is on line 307 and in the exchange procedure. I get this error
Unhandled exception at 0x00401269 in Project.exe: 0xC0000005: Access violation reading location 0x000002f3.
I guess the memory is trashed somewhere but I don't know what it means.  I know I am asking a lot though I have included all the code.  What am I doing wrong? I am using Irvine's library.  I have included a link to the code because it displays line numbers as well as the one I pasted.  The issue happens in my exchange proc at this piece of code.

mov eax,[ecx]

Link to code
http://www.codeshare.io/enQ7T



TITLE Sorting Random Integers   

; Program Description: Program displays an introduction, instructions, gets number from user to generate that many random numbers
; in an array, prints the unsorted and sorted array, prints the median when array sorted
; Author: Jason F
; Date Created: 5/14/2015
; Last Modification Date: 5/19/2015

INCLUDE Irvine32.inc

; Constants
MIN = 10 ; min user input allowed
MAX = 200 ; max, both for n numbers entered
LO = 100 ; lower bound of random numbers allowed
HI = 999 ; upper bound

.data

programName BYTE "Sorting Random Integers",0
author BYTE "Programmed by Jason Flaig",0
instrLn1 BYTE "This program generates n user specified random numbers in range 100 - 999.",0
instrLn2 BYTE "It displays an unsorted list, sorts the list and calculates the median.",0
instrLn3 BYTE "Then it displays the list in descending order.", 0
enterNumber BYTE "Enter n numbers to be generated; 10 - 200 only: ", 0
invalidInput BYTE "Invalid input",0
unsortedHdr BYTE "Unsorted random numbers:",0
sortedHdr BYTE "Sorted list:",0
medianHdr BYTE "Median: ",0
listSize DWORD ? ; number of random numbers user specifies, goes into array
list DWORD MAX DUP(?) ; array to hold random numbers
spaces BYTE "   ",0


.code
main PROC

call intro ; displays program name, author and directions

push OFFSET listSize
call getData ; get number for listSize from user, verified between 10 through 200 inclusive

call Randomize
push OFFSET list
push listSize
call fillArray ; fill array with n numbers of user specified random numbers

push OFFSET unsortedHdr
push OFFSET list
push listSize
call displayList ; prints numbers in array: unsorted list

push OFFSET list
push listSize
call sortList ; sorts array in descending order

push OFFSET medianHdr
push OFFSET list
push listSize
call displayMedian ; calculates and displays median of sorted list
call CrLf ; if listSize even, add 2 middle vals / 2: else odd, just middle val

push OFFSET sortedHdr
push OFFSET list
push listSize
call displayList ; prints numbers in array: sorted list

exit ; exit to operating system
main ENDP

; intro
; Displays program name, author and instructions for program
; Receives: nothing
; Returns: nothing
intro PROC

; Display program and author
mov edx, OFFSET programName
call WriteString
call CrLf

mov edx, OFFSET author
call WriteString
call CrLf

; Display instructions
mov edx, OFFSET instrLn1
call WriteString
call CrLf

mov edx, OFFSET instrLn2
call WriteString
call CrLf

mov edx, OFFSET instrLn3
call WriteString
call CrLf
call CrLf

ret
intro ENDP

; getData
; Repetedly asks for listSize to be n between MIN, 10, and MAX, 200; range satisfied uses range and exits procedure
; Receives: @listSize from esp+8
; Returns: 4 more bytes off stack
getData PROC

; set up stack frame and point to correct area in memory for listSize
push ebp ; set up stack frame
mov ebp, esp
mov ebx, [ebp+8] ; get address of listSize

; prints enterNumber instructions and gets number
rangeLoop:
mov edx, OFFSET enterNumber ; asks user to enter a number
call WriteString
call ReadInt

cmp eax, MAX ; if greater than MAX
jg error ; error reloop

cmp eax, MIN ; if less than MIN
jl error ; error reloop

jmp endLoop ; else successful value entered

error:
mov edx, OFFSET invalidInput ; error message and reloop
call WriteString
call CrLf

loop rangeLoop

; success: place value entered into address of listSize
endLoop:
call CrLf
mov [ebx], eax
pop ebp

ret 4
getData ENDP


; fillArray
; runs through arraySize as loop counter filling in values in random range from lo, 100 to hi, 999
; Receives: @list from esp+8, listSize value from esp+12
; Returns: 8 more bytes off stack
fillArray PROC

; set up stack frame and point to correct area in memory for listSize
push ebp ; set up stack frame
mov ebp, esp
mov esi, [ebp+12] ; get address of array
mov ecx, [ebp+8] ; get value of listSize

; iterates through array list incrementing esi by 4, dword, filling in random values
randomLoop:
mov eax, hi ; 100 CITATION: Lecture 20: slide 7
sub eax, lo ; 999
inc eax
call RandomRange
add eax, lo
mov [esi], eax
add esi, 4 ; CITATION: Lecture 20: slide 7
loop randomLoop

pop ebp
ret 8
fillArray ENDP


; displayList
; runs through arraySize as loop counter printing the values in each index, prints a linefeed for every 10 array elements
; Receives: @list from esp+8, listSize value from esp+12
; Returns: 8 more bytes off stack
displayList PROC

; set up stack frame and point to correct area in memory for listSize
push ebp ; set up stack frame
mov ebp, esp
mov edx, [ebp+16] ; push offset of title; sorted or unsorted
mov esi, [ebp+12] ; get address of array
mov ecx, [ebp+8] ; get value of listSize, used as the loop counter
mov ebx, 0 ; counter for line feed, 10 elements for each line feed
call WriteString ; prints title
call CrLf
printLoop:
mov eax, [esi]
add esi, 4 ; mov to next element in array

call WriteDec
inc ebx ; increment linefeed counter

mov edx, OFFSET spaces ; 3 spaces between each number
call WriteString

cmp ebx, 10 ;
jnz noLineBreak ; if !10th element goto noLineBreak

call CrLf ; else 10th elem; reset counter and print linefeed
mov ebx, 0
noLineBreak: ; else ! 10th element

loop printLoop

mov edx, 0
mov eax, [ebp+8]
mov ebx, 10
div ebx

mov eax, edx ; if # of elems is divisible by 10
cmp eax, 0
je noExtraLineFeed ; one LF

call CrLf
call CrLf
jmp endFormatting

noExtraLineFeed: ; else 2 LFs
call CrLf
endFormatting:

pop ebp
ret 12
displayList ENDP

; sortList
; performs selection sort algorithm on array in descending order
; Receives: @list from esp+8, listSize value from esp+12
; Returns: 8 more bytes off stack
sortList PROC
push ebp ; set up stack frame
mov ebp, esp
mov esi, [ebp+12] ; get address of array
mov ecx, [ebp+8] ; get value of listSize
sub esp, 16

outer EQU DWORD PTR [ebp-4] ; outer loop counter
inner EQU DWORD PTR [ebp-8] ; inner loop counter

j EQU DWORD PTR [ebp-12] ; outer loop counter
i EQU DWORD PTR [ebp-16] ; inner loop counter

; perform nested selection sort
mov outer, 0
mov inner, 0
dec ecx
mov edx, 0
outerLoop:
push ecx ; push listSize

mov ecx, [ebp+8] ; listSize
dec ecx
sub ecx, outer
mov ebx, edx
innerLoop:

;if array+1 > array, swap values
add ebx, 4
mov eax, [esi+ebx] ; if array x+1 <= array x
cmp eax, [esi+edx]

jle noSwap ; noSwap else swap values

push ecx
push ebx
mov j, eax
lea eax, j
push eax
mov eax, [esi+edx]
mov i, eax
lea eax, i
push eax

call exchange
pop ebx
pop ecx

; else no swap
noSwap:
;inc inner
loop innerLoop

inc outer
add edx, 4
;mov inner, 0 ; resets inner counter
pop ecx
loop outerLoop

mov esp, ebp ; remove locals from stack
pop ebp
ret 8
sortList ENDP

; exchange
; Swaps array elements i and j, j is i+1
; Receives: @i and @j
; Returns: 8 more bytes from stack
exchange PROC
push ebp ; set up stack frame
mov ebp, esp

; swap i and j
mov ecx,[ebp+28]
mov ebx,[ebp+24]

mov eax,[ecx]
xchg eax, [ebx]
mov [ecx],eax

pop ebp
ret 8
exchange ENDP

; displayMedian
; runs through array and calculates median as 1) middle value if # array elems odd or 2) average of middle values if even
; Receives: @list from esp+8, listSize value from esp+12
; Returns: 8 more bytes off stack
displayMedian PROC
push ebp ; set up stack frame
mov ebp, esp
mov edx, [ebp+16] ; get address of medianHdr
mov esi, [ebp+12] ; get address of array
mov eax, [ebp+8] ; get value of listSize

; print median header
call WriteString

; 2 ways calculate median; 1) middle value if # array elems odd 2) average of middle values if even
test eax, 1 ; if even
jz evenLbl

; odd so get just middle value
shr eax, 1 ; gets nth element as middle
shl eax, 2 ; translate * 4, dword, to get actual index of median

add esi, eax
mov eax, [esi] ; saves median value

jmp printMedian

; even so average the middle 2 values
evenLbl:
shr eax, 1 ; divide by 2
shl eax, 2 ; translate * 4, dword, to get actual index upper median

add esi, eax
mov eax, [esi] ; upper middle val
add eax, [esi-4] ; add lower mid val to upper mid val
shr eax, 1 ; get the avg

printMedian:
call WriteDec ; print median
call CrLf

pop ebp
ret 12
displayMedian ENDP

END main

sinsi

Are you sure the offsets here are right?

; swap i and j
mov ecx,[ebp+28]
mov ebx,[ebp+24]

I would have thought 12 and 8 maybe...
Tá fuinneoga a haon déag níos fearr :biggrin:

jman

The correct values are found at [ebp+28] and [ebp+32] which is strange because last night [ebp+28] and [ebp+24] worked.  If I comment out this code block I don't get the error though I am not swapping the values anymore.

mov eax,[ecx]
xchg eax, [ebx]
mov [ecx],eax

rrr314159

Evidently when u got to "mov eax, [ecx]", ecx has the value 755 (decimal) in it which is no good, addresses are much higher. That number sounds like it comes from your RNG? Probably ecx is supposed to have the address of 755, not the number itself.

If that's right then if u comment back in those statements and run it you'll keep getting the error

Quote from: William H. Gates IIIUnhandled exception at 0x00401269 in Project.exe: 0xC0000005: Access violation reading location 0x000002f3

- except instead of 2f3 it'll be between 00a and 3e7 randomly. That would give u something to work on
I am NaN ;)

jman

rrr.  I remember seeing the value coming back each time as I was testing, thanks for pointing that out.  I didn't realize what some of the statements did.  I didn't solve the problem the way I wanted though I just used bubble sort and passed by reference by pushing esi.  I knew that I would need to do this kind of thing in the future so I was apprehensive to let up though I realized I can use gcc and disassemble to MASM instructions so this will help with the pointer logic.  To my understanding, which I could be incorrect, is that I might not be using a double pointer at all.  Creating a double pointer with MASM syntax is something I don't understand yet.  Thanks for checking that out.