News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Passing structure variable to procedure

Started by NUMBSKULL2, February 06, 2009, 09:54:55 PM

Previous topic - Next topic

NUMBSKULL2

I defined a structured variable as follows in MASM32

           Time STRUCT
            Hour  DW ?
            Minute DW ?
            Second Dw ?
End Time

I create multiple instances of time like:

           Time1 Time <>
           Time 2 Time <>

I want to call a procedure using the Time instances:
Something like:
Call TimeConvert,??Time1or Time2


I want to write a Procedure which will make conversions of Time instances

Something like:

TimeConverter     PROC NEAR
                         ? arg:STRUCT

How do you pass the Time instances to a procedure ?

jj2007

This might do the job.

include \masm32\include\masm32rt.inc

TIME STRUCT
Hour  DW ?
Minute DW ?
Second DW ?
TIME ENDS

Convert PROTO: TIME

.code
timeA TIME <10, 15, 30>
timeB TIME <15, 30, 00>
timeC TIME <21, 15, 30>

start:
invoke Convert, timeA
invoke Convert, timeB
invoke Convert, timeC

getkey
exit

Convert proc uses edi esi locTime:TIME
LOCAL buffer[80]:BYTE
lea edi, buffer
invoke lstrcpy, edi, chr$("Hours=")
invoke lstrcat, edi, str$(locTime.Hour)
invoke lstrcat, edi, chr$(", minutes=")
invoke lstrcat, edi, str$(locTime.Minute)
invoke lstrcat, edi, chr$(", seconds=")
invoke lstrcat, edi, str$(locTime.Second)
invoke lstrcat, edi, chr$(13, 10, 10)
print edi
ret
Convert endp
end start


By the way: posting in UPPERCASE is considered SHOUTING for help :wink

MichaelW

The method to use would depend in part on whether or not the procedure must be able to modify the structure members. If you pass a pointer to the structure then the procedure must access the structure members through the pointer, but using this method it can readily modify the structure members. If you pass the structure directly on the stack, then the procedure can access the structure members more easily, but any modifications will affect only the copies of the structure members on the stack. For this code I used DWORDs for the structure members so MASM would have no problems getting the stack operations right. There may be ways to use other member sizes, but in the time I had to spend on this I could not find any that would actually work. If my explanations regarding modifying the structure members are not clear, take a look at the disassembled code for the procedures.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc

    TIME struct
      hour    dd ?
      minute  dd ?
      second  dd ?
    TIME ends

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data

      time1 TIME <1,2,3>
      time2 TIME <4,5,6>

    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

PrintTimePointer proc ptime:DWORD
  push ebx
  mov ebx, ptime

  ;------------------------------------------------------
  ; For this method the access code is a little shorter,
  ; but the ASSUME statements are required.
  ;------------------------------------------------------

  ASSUME ebx:ptr TIME
  print str$([ebx].hour),":"
  print str$([ebx].minute),":"
  print str$([ebx].second),13,10
  ASSUME ebx:NOTHING

  ;-----------------------------------------------------
  ; For this method the access code is a little longer,
  ; but no additional statements are required.
  ;-----------------------------------------------------

  print str$([ebx].TIME.hour),":"
  print str$([ebx].TIME.minute),":"
  print str$([ebx].TIME.second),13,10
  inc [ebx].TIME.second

  pop ebx
  ret
PrintTimePointer endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
PrintTimeDirect proc ts:TIME

  print str$(ts.hour),":"
  print str$(ts.minute),":"
  print str$(ts.second),13,10
  dec ts.second

  ret
PrintTimeDirect endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke PrintTimePointer, ADDR time1
    invoke PrintTimePointer, ADDR time2

    invoke PrintTimeDirect, time1
    invoke PrintTimeDirect, time2

    invoke PrintTimeDirect, time1
    invoke PrintTimeDirect, time2

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


jj,

str$ expects a DWORD argument
eschew obfuscation

BlackVortex


jj2007

Quote from: MichaelW on February 06, 2009, 11:38:19 PM

jj,

str$ expects a DWORD argument


What you write is indeed correct. Interestingly enough, it works fine.
At least dwtoa should have complained... :dazzled:

    str$ MACRO DDvalue
      LOCAL rvstring
      .data
        rvstring db 20 dup (0)
        align 4
      .code
      invoke dwtoa,DDvalue,ADDR rvstring
      EXITM <ADDR rvstring>
    ENDM


Probably, that has to do with recent progress re type-checking etc.; the old Masm 6.14 chokes indeed with an exception, but JWasm and ml 9.0 have become tolerant. They read my thoughts, and know that I mistook "dw" for "dword". It's called old age, but Microsoft and Japheth can deal with that :bg

japheth

Quote from: jj2007 on February 07, 2009, 01:29:54 AM
Probably, that has to do with recent progress re type-checking etc.; the old Masm 6.14 chokes indeed with an exception, but JWasm and ml 9.0 have become tolerant. They read my thoughts, and know that I mistook "dw" for "dword". It's called old age, but Microsoft and Japheth can deal with that :bg

But this would mean that MS has managed to fix the 18-year-old, well-known "invoke" bug in Masm v9.0 - almost impossible to believe; if true, it's a good reason for celebrations.

jj2007

Quote from: japheth on February 07, 2009, 02:32:14 AM
But this would mean that MS has managed to fix the 18-year-old, well-known "invoke" bug in Masm v9.0 - almost impossible to believe; if true, it's a good reason for celebrations.


Yes indeed. And they don't even trash eax like JWasm does :bg

ML 6.14:
00401074              ³. 68 07204000                 push offset TimeStruct.00402007
00401079              ³. 6A 00                       push 0
0040107B              ³. 66:FF75 08                  push word ptr [arg.1]

ML 9.0:
00401074              ³. 68 07204000                 push offset TimeStruct.00402007
00401079              ³. 66:6A 00                    push word 0
0040107C              ³? 66:FF75 08                  push word ptr [ebp+8]

JWasm:
00401074              ³. 68 07204000                 push offset TimeStruct.00402007
00401079              ³. 0FB745 08                   movzx eax, word ptr [arg.1]
0040107D              ³? 50                          push eax


Anyway, all this problems could have been avoided with a slightly more intelligent version of str$:

str$ MACRO DDvalue
      LOCAL rvstring
      .data?
        rvstring db 20 dup (?)
      .code
      if SIZEOF DDvalue lt 4
movzx eax, DDvalue
invoke dwtoa, eax, offset rvstring
      else
invoke dwtoa, DDvalue, offset rvstring
      endif
      EXITM <offset rvstring>
ENDM


Compared to the old version, this str$
- knows about non-dword integers
- does not waste space in the initialised data section
- and allows the mov esi, str$(eax) syntax

MichaelW

QuoteYes indeed. And they don't even trash eax like JWasm does

But they do trash the sign, silently. All three methods are replacing one quirk with another.
eschew obfuscation

jj2007

Quote from: MichaelW on February 07, 2009, 01:05:52 PM
QuoteYes indeed. And they don't even trash eax like JWasm does

But they do trash the sign, silently. All three methods are replacing one quirk with another.


Point taken :U

str$ MACRO DDvalue
      LOCAL rvstring
      .data?
        rvstring db 20 dup (?)
      .code
      if SIZEOF DDvalue lt 4
         ifdifi <eax>, <DDvalue>   ; avoids a rather useless mov eax, eax
                  movsx eax, DDvalue      ; preserves the sign
         endif
         invoke dwtoa, eax, offset rvstring
      else
         invoke dwtoa, DDvalue, offset rvstring
      endif
      EXITM <offset rvstring>
ENDM

japheth

Quote from: jj2007 on February 07, 2009, 02:37:52 PM
      movsx eax, DDvalue      ; preserves the sign

This preserves the sign if the value is "signed". If the value is unsigned and >= 8000h (or > 80h for bytes), it'll be wrong.

MichaelW

I agree that movsx would be wrong for unsigned values, but in this case dwtoa expectes signed values.
eschew obfuscation

hutch--

NUMBSKULL2,

One request, please do not post topics in upper case to attract atention, its is classed as bad manners, something like SHOUTING.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: MichaelW on February 07, 2009, 03:09:35 PM
I agree that movsx would be wrong for unsigned values, but in this case dwtoa expectes signed values.

It is a pity that opattr does not tell us whether a variable is signed or unsigned. The only workaround I see is to have two macros instead of one:
str$ MACRO DDvalue
      LOCAL rvstring
      .data?
        rvstring db 20 dup (?)
      .code
      if SIZEOF DDvalue lt 4
      ifdifi <eax>, <DDvalue> ; avoids a rather useless mov eax, eax
movsx eax, DDvalue ; preserves the sign
endif
invoke dwtoa, eax, offset rvstring
      else
invoke dwtoa, DDvalue, offset rvstring
      endif
      EXITM <offset rvstring>
ENDM

ustr$ MACRO DDvalue
      LOCAL rvstring
      .data?
        rvstring db 20 dup (?)
      .code
      if SIZEOF DDvalue lt 4
      ifdifi <eax>, <DDvalue> ; avoids a rather useless mov eax, eax
movzx eax, DDvalue ; keeps the value unsigned
endif
invoke udw2str, eax, offset rvstring
      else
invoke udw2str, DDvalue, offset rvstring
      endif
      EXITM <offset rvstring>
ENDM

NUMBSKULL2

Thanks for the help
I apologize for shouting. I won't do i t anymore.

Pat

NUMBSKULL2

I was able to get the code you all wrote to run.
Both methods passed the members of the structure on the stack which requires code to copy any modified values on the stacks back to the structure members after the procedure is invoked.

I want to pass a pointer to the structure so that I can modify the members within the procedure and be done with it.
I have never worked with the Invoke method and I can't figure out how to pass the pointer.

I tried the following:

Time  STRUCT
       Hour             DB ?
       Minute          DB ?
       Second         DB ?
       HourTick       DW ?
       MinuteTick    DW ?
       SecondTick   DW ?
Time  ENDS

TickConvert        PROTO  :Time

                       .DATA
StartTime  < >
EndTime   <>

                        .CODE
Start:          INVOKE TickConvert, ADDR StartTime

;*****************************************************************

TickConvert        PROC NEAR  Loctime:Time
                        mov al,Loctime.Second
                        mov bl, 64h
                        mul bl
                        mov Loctime.SecondTick,ax
                        ret
TickConvert        ENDP

End Start

When the code above is assembled I get an error 2114: Invoke Argument type mismatch.
I think the Invoke statement is correct even though the error is on this statement.
I just can't figure out how to modify the PROTO statement or the PROC statement.