Ok, I think I'm just missing something obvious here.  Here's a function and a call to it:


FuncTest  proc  dwNumberIn:DWORD

  mov  eax, dwNumberIn

  ret
FuncTest  endp

invoke  FuncTest, 5491


When I do this, the debugger doesn't show the value 5491 being moved into eax.  It shows "ntdll.7C910208" being passed as if it's the value of dwNumberIn.  I've written hundreds of procs and never seen this behavior.  What stupid thing am I overlooking?
Posted on 2009-03-25 09:50:21 by rdaneel
Ok, this makes no sense.  If I put the call to the procedure above the procedure itself, it runs once correctly and again with the wierd values.  It's like the function is getting called twice:


invoke  FuncTest, 5491

FuncTest  proc  dwNumberIn:DWORD

  mov  eax, dwNumberIn

  ret
FuncTest  endp


Why would this code run FuncTest twice?  This is a console app so maybe I'm not understanding right.  This is my first console app.
Posted on 2009-03-25 11:30:48 by rdaneel
Well, if this is how your code looks exactly then it's normal that it would get executed twice. First when you call it and then a swcond time when it returns as there is no ret after your invoke FuncTest, 5491 . Also, I assume the second time it would use some random on the stack value as there wasn't anything pushed.

Easy fix:

invoke  FuncTest, 5491
ret

FuncTest  proc  dwNumberIn:DWORD

  mov  eax, dwNumberIn

  ret
FuncTest  endp
Posted on 2009-03-25 12:08:35 by JimmyClif
Thanks for the response JC.  How come I've never had to use "ret" after an invoke before?  This is new to me.  For instance, the familiar:


start:
  invoke  GetModuleHandle, NULL
  mov    hInstance, eax

  invoke  GetCommandLine
  mov    pCommandLine, eax

  ...etc...


These don't seem to require ret's after each invoke.  Is it something that is specific to console apps?  I don't think I had to do that in my DOS apps either.  Thanks again.
Posted on 2009-03-25 13:16:36 by rdaneel
Now you've got me all wishy washy :shock:

Why not just post your source code so that I can have a look ;)
Posted on 2009-03-25 13:39:16 by JimmyClif
I think I see what's going on now.  If I put my procedure after my ExitProcess call it works.  So, I guess, basically you can't define procedures in-line with the normal code.  I guess it's not an issue in event-based code for GUI apps given the way they are layed out.  This, being linear, exposed it.  I've been doing too much scripting I guess. :)  Here's the way the code was before I moved it:


;+----------------------------------------------------------------------------+
;|  Assembler Directives:
.386
.model  flat,stdcall
option  casemap:none
;|
;+----------------------------------------------------------------------------+

;+----------------------------------------------------------------------------+
;|  Function Prototypes:
NumberToString  proto  :DWORD

;|
;+----------------------------------------------------------------------------+

;+----------------------------------------------------------------------------+
;|  Includes:
;|      Headers:
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\userenv.inc
include \masm32\include\kernel32.inc
include confunc.inc

;|
;|      Libraries:
includelib \masm32\lib\user32.lib
includelib \masm32\lib\userenv.lib
includelib \masm32\lib\kernel32.lib

;|
;|      Project:

;|
;+----------------------------------------------------------------------------+

.const
;+----------------------------------------------------------------------------+
;|  Constants:
WSOCK_VERSION           EQU     02h

;|
;|  Structs:

;|
;|
;+----------------------------------------------------------------------------+

.data   ;|Data section begins
;+----------------------------------------------------------------------------+
;|  Globals:
;|      Initialized:
AppTitle     db "TestBed",0
strCRLF     db 0dh,0ah,0
strPressAnyKey  db      "Press any key to continue...",0 

;|
;+----------------------------------------------+

.data?
;+----------------------------------------------+
;|      Uninitialized:
hInstance dd ?
hInput dd ?
hOutput dd ?
dwWritten dd ?
strInput    db 255  dup(?)
bufInput    dw 128  dup(?)

;|
;+----------------------------------------------------------------------------+

.code   ;|Code section begins
;+----------------------------------------------------------------------------+
;|  Startup:
start:


;## Create a console for io
invoke GetModuleHandle, NULL
mov hInstance, eax

;## Set the console window's title
invoke SetConsoleTitle, ADDR AppTitle

;## Get a handle for input
invoke GetStdHandle,STD_INPUT_HANDLE
.IF (eax == INVALID_HANDLE_VALUE)
invoke MessageBox, NULL, ADDR AppTitle, ADDR AppTitle, MB_OK
invoke ExitProcess, 1
.ENDIF
mov hInput,eax

;## Get a handle for output
invoke GetStdHandle,STD_OUTPUT_HANDLE
.IF (eax == INVALID_HANDLE_VALUE)
invoke MessageBox, NULL, ADDR AppTitle, ADDR AppTitle, MB_OK
invoke ExitProcess, 1
.ENDIF
mov hOutput,eax 

;## Write some text to the screen
invoke Print, hOutput, ADDR AppTitle
invoke  Print, hOutput, NULL


;## ----------------------------------
;## -----Start main body of code------

invoke  NumberToString, 9328

NumberToString   proc    dwNumberIn:DWORD
    LOCAL   dwRemainder:DWORD
    LOCAL   dwQuotient:DWORD
    LOCAL   strNumber[15]:BYTE
    LOCAL   dwNumber:DWORD
    LOCAL   pCharPosition:DWORD
    LOCAL   dwDivCount:DWORD
    LOCAL   dwDivisor:DWORD
   
   
   
   
    ;## Maximum DWORD value is 4,294,967,295 (0xFFFFFFFF)
    mov     eax, dwNumberIn
    mov     dwNumber, eax
   
    ;## Set the string buffer tracking variable
    lea     eax, strNumber
    mov     pCharPosition, eax
   
    ;## Set the initial divisor to 1 billion and the div count to 9
    mov     dwDivisor, 1000000000     
    mov     dwDivCount, 9
   
    ;## Clear the output buffer with zeros
    pushf
    cld
    mov     al, 0
    mov     ecx, SIZEOF strNumber
    lea     edi, strNumber
    rep     stosb
    popf
     
    ;## Enter the loop to begin dividing down the number by 10's.  The idea is to
    ;## divide the number again and again by descending 10's position and use the
    ;## quotient as the basis for what number goes at that position.  Then we add
    ;## 48 to that number to get to the corresponding ascii character.
    .WHILE (dwDivCount > 0)
        ;## See if this number is divisible by the divisor
        nop
        xor     eax, eax
        xor     edx, edx
        mov     eax, dwNumber
        mov     ebx, dwDivisor
        div     ebx
        mov     dwRemainder, edx
        mov     dwQuotient, eax
       
        .IF (dwQuotient > 0)
        invoke  MessageBox, NULL, ADDR strNumber, ADDR AppTitle, MB_OK   ;## Printf debugger
            ;## This number was larger than the divisor so the quotient
            ;## should tell us what the first character should be.  We need
            ;## to add 48 to that number to get the equivelant ascii char.
            ;## We then store the character in the first byte of the string.
            xor     eax, eax
            mov     eax, dwQuotient
            add     eax, 48
            mov     edi, pCharPosition
            stosb
           
            ;## Increment to the next byte in the string buffer.
            inc     pCharPosition
           
            ;## Now subtract (quotient * divisor) from the original value
            ;## to begin testing the next position.
            .WHILE (dwQuotient > 0)
                mov     eax, dwNumber
                sub     eax, dwDivisor
                mov     dwNumber, eax
                dec     dwQuotient
            .ENDW
        .ENDIF
       
        ;## Decrement the div count and divide the divisor by 10 to get the
        ;## next 10's position to test
        dec     dwDivCount
        xor     eax, eax
        xor     edx, edx
        mov     eax, dwDivisor
        mov     ebx, 10
        div     ebx
        mov     dwDivisor, eax     
    .ENDW
   
    ;## Put the final remainder in the last string position
    xor     eax, eax
    mov     eax, dwNumber
    add     eax, 30
    mov     edi, pCharPosition
    stosb


   
    ;## Print the output
    invoke  Print, hOutput, ADDR strNumber
   
   
    xor     eax, eax
    ret
NumberToString   endp

;## -----End main body of code--------
;## ----------------------------------


;## Pause for keystroke
invoke  Print, hOutput, ADDR strPressAnyKey
invoke  PauseForKey, hInput

;## Quit normally
invoke ExitProcess, NULL


;+----------------------------------------------------------------------------+
;| Extra asm sources libraries:
include confunc.asm

;|
;|
end start
;| End of program.
;+----------------------------------------------------------------------------+
Posted on 2009-03-25 13:52:39 by rdaneel
So, I guess, basically you can't define procedures in-line with the normal code.


I guess you answered your own question. Try debugging your code starting at "invoke NumberToString, 9328" and check what happens after you return from that function.

Plopp all your functions either after the final ExitProcess or before the start: and all should be well.
Posted on 2009-03-25 14:06:16 by JimmyClif
Thanks JC.  Got it working.  I knew I was missing the obvious.  Just couldn't see it.  ;)
Posted on 2009-03-25 15:05:51 by rdaneel