The MASM Forum

Microsoft 64 bit MASM => MASM64 SDK => Topic started by: hutch-- on August 03, 2016, 04:50:14 PM

Title: I have noticed something cute about OPATTR.
Post by: hutch-- on August 03, 2016, 04:50:14 PM
Seems if will not recognise a floating point register in ML64. Always returns 0.
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on August 03, 2016, 05:42:24 PM
showop macro args:VARARG
Local tmp$, oa
  for arg, <args>
oa = opattr arg
tmp$ CATSTR <opattr &arg = >, %oa
% echo tmp$
  ENDM
ENDM


showop rax, rcx, rsi, xmm0, xmm1, ST(0), ST(1), ST(2), ST(3), MyR8, MyDw, MyQw
.err


ML64:
opattr rax = 48
opattr rcx = 48
opattr rsi = 48
opattr xmm0 = 48
opattr xmm1 = 48
opattr ST(0) = 48
opattr ST(1) = 48
opattr ST(2) = 48
opattr ST(3) = 48
opattr MyR8 = 42
opattr MyDw = 42
opattr MyQw = 42

ML 6.14:
opattr eax = 48
opattr ecx = 48
opattr esi = 48
opattr XMM(0) = 48
opattr XMM(1) = 48
opattr ST(0) = 48
opattr ST(1) = 48
opattr ST(2) = 48
opattr ST(3) = 48
opattr MyR8 = 42
opattr MyDw = 42
opattr MyQw = 42

ML 10.0:
opattr eax = 48
opattr ecx = 48
opattr esi = 48
opattr xmm0 = 48
opattr xmm1 = 48
opattr ST(0) = 48
opattr ST(1) = 48
opattr ST(2) = 48
opattr ST(3) = 48
opattr MyR8 = 42
opattr MyDw = 42
opattr MyQw = 42

AsmC, 32-bit:
opattr eax = 48
opattr ecx = 48
opattr esi = 48
opattr xmm0 = 48
opattr xmm1 = 48
opattr ST(0) = 48
opattr ST(1) = 48
opattr ST(2) = 48
opattr ST(3) = 48
opattr MyR8 = 810
opattr MyDw = 810
opattr MyQw = 810

AsmC, 64-bit:
opattr rax = 48
opattr rcx = 48
opattr rsi = 48
opattr xmm0 = 48
opattr xmm1 = 48
opattr ST(0) = 48
opattr ST(1) = 48
opattr ST(2) = 48
opattr ST(3) = 48
opattr MyR8 = 1834
opattr MyDw = 1834
opattr MyQw = 1834


AsmC results for comparison. The odd numbers disappear when using oa = (opattr arg) and 127
Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 03, 2016, 05:48:02 PM
Aha, the problem may be that it does not like the short form st0 instead of st(0). Will try it.
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on August 03, 2016, 06:02:20 PM
Hmmm... do you know an assembler that accepts fmul st, st1 instead of fmul st, st(1)?
Check if you don't have an equate st1 equ <st(1)> somewhere in the Masm32 resources.
Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 03, 2016, 06:12:42 PM
The bracketed form works fine.  :biggrin:

This is what I was after.

Byte count of byt = 1
Byte count of wrd = 2
Byte count of dwd = 4
Byte count of qwd = 8
Byte count of flt = 10
Byte count of xwd = 16
Byte count of itm = 16
Byte count of al = 1
Byte count of cx = 2
Byte count of ecx = 4
Byte count of rax = 8
Byte count of st(0) = 10
Byte count of xmm3 = 16
Byte count of ymm9 = 32
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on August 03, 2016, 06:24:00 PM
Sure, but if you've ever successfully used fmul st, st1 it means you have an equate somewhere. Could work for 64-bit code, too...
Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 03, 2016, 06:36:20 PM
I only put in the FP registers as an afterthought as they are not directly supported in x64 but someone may want to use them. Interestingly enough the MM registers use the short form "mmo mm1 mm2 etc ...".

As far as the equates, I have seen registers done that way but I never wrote them and it could have been anywhere in the last 20 years.
Title: Re: I have noticed something cute about OPATTR.
Post by: mabdelouahab on August 13, 2016, 08:02:11 AM
"OPATTR" & " .TYPE"
OPATTRAndType macro s
% echo s:. [@CatStr(<OPATTR = >,%( OPATTR(s)),<, .TYPE=>,%( .TYPE(s)))]
endm


/////////////////////////////////////////       ML.EXE

MyStruct:.            [OPATTR = 36, .TYPE=36]
DWORD:.               [OPATTR = 36, .TYPE=36]
MyAddr:.            [OPATTR = 37, .TYPE=37]
OFFSET  Mydata:.      [OPATTR = 38, .TYPE=38]
MyConst:.            [OPATTR = 42, .TYPE=42]
Mydata:.            [OPATTR = 42, .TYPE=42]
MyReal:.            [OPATTR = 42, .TYPE=42]
xmm0:.               [OPATTR = 48, .TYPE=48]
st(0):.               [OPATTR = 48, .TYPE=48]
EAX:.               [OPATTR = 48, .TYPE=48]
DWORD PTR [ESP]:.      [OPATTR = 98, .TYPE=98]
Myargument:.         [OPATTR = 98, .TYPE=98]
Mylocal:.            [OPATTR = 98, .TYPE=98]
My_stdcall_Proc:.      [OPATTR = 805, .TYPE=37]
My_C_Proc:.            [OPATTR = 293, .TYPE=37]
GetProcessHeap:.      [OPATTR = 933, .TYPE=165]


/////////////////////////////////////////      ML64.EXE

MyStruct:.            [OPATTR = 36, .TYPE=36]
DWORD:.               [OPATTR = 36, .TYPE=36]
MyAddr:.            [OPATTR = 37, .TYPE=37]
OFFSET  Mydata:.      [OPATTR = 38, .TYPE=38]
MyConst:.            [OPATTR = 42, .TYPE=42]
Mydata:.            [OPATTR = 42, .TYPE=42]
MyReal:.            [OPATTR = 42, .TYPE=42]
xmm0:.               [OPATTR = 48, .TYPE=48]
st(0):.               [OPATTR = 48, .TYPE=48]
EAX:.               [OPATTR = 48, .TYPE=48]
DWORD PTR [RSP]:.      [OPATTR = 98, .TYPE=98]
Myargument:.         [OPATTR = 98, .TYPE=98]
Mylocal:.            [OPATTR = 98, .TYPE=98]
My_Proc:.            [OPATTR = 37, .TYPE=37]
__imp_GetProcessHeap:.   [OPATTR = 171, .TYPE=171]

Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 13, 2016, 10:37:12 AM
This is what I have been testing.

From this,

    tstop invalid argument
    tstop 1234
    tstop entry_point
    tstop gvar
    tstop rax
    tstop lvar
    tstop BYTE PTR [rbp+16]
    tstop rct.top
    tstop szCmp
    tstop SendMessage

I get this result. Interesting how it expands the imports.

:    0 = invalid argument
:    36 = 1234
:    37 = entry_point
:    42 = gvar
:    48 = rax
:    98 = lvar
:    98 = BYTE PTR [rbp+16]
:    98 = rct.top
:    165 = szCmp
:    171 = __imp_SendMessageA
Title: Re: I have noticed something cute about OPATTR.
Post by: mabdelouahab on August 13, 2016, 03:24:57 PM
hutch--
I tried your observations, and in the meantime I noticed that OPATTR in a ML64 do not returns a 16 bit value, I don't know maybe it's because there is no STDCall and C-Call in x64 (=no language type)
Quote
Opattr returns a 16 bit value providing specific information about the expression that follows it. The .type operator is an older version of opattr that returns the L.O. eight bits of this value. Each bit in the value of these operators has the following meaning:


Bit(s)    Meaning
0       References a label in the code segment if set.
1       References a memory variable or relocatable data object if set.
2       Is an immediate (absolute/constant) value if set.
3       Uses direct memory addressing if set.
4       Is a register name, if set.
5       References no undefined symbols and there is no error, if set.
6       Is an SS: relative reference, if set.
7       References an external name.
8-10
   000 - no language type
   001 - C/C++ language type
   010 - SYSCALL language type
   011 - STDCALL language type
   100 - Pascal language type
   101 - FORTRAN language type
   110 - BASIC language type
[/tt]
My_C_Proc proc C 

ret
My_C_Proc endp
My_stdcall_Proc proc STDCALL 

ret
My_stdcall_Proc endp


Quote
My_stdcall_Proc:.         [OPATTR = 37, .TYPE=37]
My_C_Proc:.                  [OPATTR = 37, .TYPE=37]
[/tt]
Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 13, 2016, 04:09:52 PM
> I noticed that OPATTR in a ML64 do not returns a 16 bit value, I don't know maybe it's because there is no STDCall and C-Call in x64 (=no language type)

This seems to be correct, Win 64 only has one calling convention, 4 regs then stack but from experimenting so far you can do a C style calling convention with a variable number of arguments if you pass the argument count as one of them. Writing directly to RSP based memory at the calling level solves a number of problems in that any data size up to QWORD is written to the same memory location and even if you pass BYTE data the arguments are still QWORD aligned. If you use an arg list for the proc where you specify the data size like normal, they can be used in the proc at the specified data size.
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on August 13, 2016, 07:46:00 PM
Try this:tstop macro arg
Local oa, ox, tmp$
  oa = opattr arg
  ox=oa and 127
.radix 2
  tmp$ CATSTR %ox, < >, %oa, < &arg>
  % echo tmp$
.radix 10
endm
Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 13, 2016, 08:33:54 PM
It works fine but it does not make me any the wiser. I don't see the use of the bin data in the first 2 columns.

0       0       invalid argument
100100  100100  1234
100101  100101  entry_point
101010  101010  gvar
110000  110000  rax
1100010 1100010 lvar
1100010 1100010 BYTE PTR [rbp+16]
1100010 1100010 rct.top
100101  10100101        szCmp
101011  10101011        __imp_SendMessageA

Title: Re: I have noticed something cute about OPATTR.
Post by: hutch-- on August 13, 2016, 09:25:56 PM
Just as a humerous aside, ml64 gets this data in its first pass as it does not allow any forward referencing.

Put a label before the test so it has been read in the first pass and you get a result, put if after so it has not been read yet and it returns 0.
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on August 14, 2016, 04:40:36 AM
Quote from: hutch-- on August 13, 2016, 08:33:54 PMI don't see the use of the bin data in the first 2 columns.
100101  10100101        szCmp
101011  10101011        __imp_SendMessageA

Only the latter two have bit 7 set, i.e. external references.

;     Bit    Set If...
;     0      References a code label
;     1      Is a memory expression or has a relocatable data label
;     2      Is an immediate expression
;     3      Uses direct memory addressing, i.e. is an absolute memory reference
;     4      Is a register expression
;     5      References no undefined symbols and is without error
;     6      References a stack location (usually a LOCAL variable or parameter)
;     7      References an external label
;     8-10   Language type (0=no type)
                    ; 76543210    ; use and 127 to mask external label and language bits
atMemory    = 34    ; 00100010    ; [edx+20], [ebx+20], [eax+edx+20], JWasm: [eax+4*eax+20], [eax+20]
atImmediate = 36    ; 00100100
atLabel     = 37    ; 10100101
atOffset    = 38    ; 10100110    ; offset CrLf$ (immediate and mem expression)
atGlobal    = 42    ; 10101010    ; CrLf$, Masm: [eax+4*eax+20], [eax+20]
atRegLabel  = 43    ; 10101011    ; Masm: [eax+start] (Jwasm yields 37)
atRegister  = 48    ; 00110000    ; also xmm
atXmm       = 77    ; xxxxxxxx    ; reg starting with x
atLocal     = 98    ; 01100010    ; [esp+20], [ebp+20]


The JWasm remarks might be obsolete, no time right now to test it. And this is 32-bit, of course. For practical purposes, and 127 is the way to go.
Title: Re: I have noticed something cute about OPATTR.
Post by: Relvinian on May 10, 2018, 05:27:08 PM
Hey all,

I am glad threads like this are still around for reference and knowledge. They help a lot for my understanding my massive "fun" project that I do when I have spare time.

Anyway, I have spent a while trying to solve a MACRO problem based on ideas and code snippets from this thread.  Overall, I have the general macros written but having problems getting one to work. It is the new one I just wrote tonight.

Anyway, my macro code is below with a few lines of ASM code. These are the full macros, comments and all.  :icon_eek:

The macro I am having trouble with is called:  IsTypeOf.   It ALWAYS returns 0, according to the disassembly view through VS17 debugger.  No matter what I do, I cannot seem to get it to return a 1 when the condition is true. 

What am I missing.   :icon_redface:



;; ============================================================================
;; TTLIB_ASM fundamental MACROS
;; ============================================================================
OPC_MEM   equ < 34 >
OPC_IMM   equ < 36 >
OPC_STRUC equ < 36 >
OPC_GVAR  equ < 42 >
OPC_REG   equ < 48 >
OPC_LVAR  equ < 98 >
OPC_SVAR  equ < 98 >
OPC_FN    equ < 165 >

IsTypeOf MACRO OpCodeUnknown:REQ, OpCodes:VARARG
   ; possible OPCODEs that are valid parameters to macros that create/destory
   ; memory or objects will be the following for 64-bit compilation:
   ;
   ;  34: memory opcode value (ie: [r15+10h])
   ;  36: immediate opcode value (ie: 127, sizeof)
   ;  42: global address opcode value (ie: .data or .data? variable)
   ;  48: register opcode value (ie: rax, rsi, r11)
   ;  98: stack (local) opcode value (ie: [rsp+10h])
   ; 165: function address opcode value (ie: HeapAlloc)
   FOR arg, <OpCodes>
      IF .TYPE(OpCodeUnknown) EQ .TYPE(arg)
         EXITM <TRUE>
      ENDIF
   ENDM
   EXITM <FALSE>
ENDM


;; ----------------------------------------------------------------------------
;; Two macros to create an object and call the Constructor and Destructor. To
;; alloc an array or another type of memory, just use 'new' and 'del' macros.
;; ============================================================================
TTCreateObject MACRO objName:REQ, ctor:REQ
   IF IsTypeOf(dtor, OPC_FN) EQ TRUE
      IF IsTypeOf(objName, OPC_IMM) EQ TRUE
         new objName       ;; allocate memory of specified size
      ELSE
         .ERR <"1st parameter (obj) is not an immediate.">
      ENDIF
      mov rcx, rax      ;; move instance object to 1st parameter
      call ctor         ;; call the constructor function
      EXITM <rax>       ;; return this$ pointer to instance
   ELSE
      .ERR <"2nd parameter (ctor) is not correct.">
   ENDIF
   EXITM <NULL>
ENDM

TTDestroyObject MACRO memPtr:REQ, dtor:REQ
   IF IsTypeOf(dtor, OPC_FN) EQ TRUE
      mov rcx, memPtr   ;; set parameter for destructor
      call dtor         ;; call the destructor function
   ELSE
      .ERR <"Second parameter must be a function address">
   ENDIF
   IF IsTypeOf(memPtr, OPC_MEM,OPC_GVAR,OPC_REG,OPC_LVAR,OPC_SVAR) EQ TRUE
      del memPtr        ;; free the memory pointer
   ELSE
      .ERR < "First parameter must be a register or memory type." >
   ENDIF
   EXITM <>
ENDM



;; ----------------------------------------------------------------------------
;; Macro to call a function. This is an enhance call macro that will
;; call WinAPI functions, TTAPI functions, TTAPI virtual functions, and
;; finally, user defined functions - virtual or not.
;;
;; Note:  When calling a function that is part of an object and has "instance"
;;        data associated to the function, the first parameter (rcx) must have
;;        the instance pointer.
externdef TTObject_CallVirtualFN :proc
jsr MACRO fnORid:REQ, Virtual:=<FALSE>
   IFIDNI <Virtual>,<TRUE>
      ;; transfer the ID over to the function without destroying
      ;; any of the possible parameters passed through the registers.
      mov rax, fnORid   ; id of virtual function
      call TTObject_CallVirtualFN
      ;; now call the virtual mapped function
      call rax
   ELSE
      ;; no virtual function to call, just call normally
      call fnORid
   ENDIF
ENDM


;; ----------------------------------------------------------------------------
;; Macros to allocate and destroy a memory object from the Windows Heap.
;; The memory allocation is also zeroed out upon allocation.
;; If the ctor is defined, will call the constructor for the allocated object.
;; ============================================================================
externdef G_hWinHeap :HANDLE
new MACRO s:REQ
   IF IsTypeOf(s, OPC_MEM, OPC_GVAR, OPC_REG, OPC_LVAR, OPC_SVAR) EQ TRUE
   mov r8, s ;; size of memory to allocate
   mov rdx, (HEAP_GENERATE_EXCEPTIONS or HEAP_ZERO_MEMORY)
   mov rcx, G_hWinHeap ;; handle to the process' heap
   jsr HeapAlloc ;; Win32 API call
   ELSE
      .ERR <"Parameter is not correct type.">
   ENDIF
ENDM

del MACRO m:REQ
   IF IsTypeOf(s, OPC_MEM, OPC_GVAR, OPC_REG, OPC_LVAR, OPC_SVAR) EQ TRUE
   mov r8, m ;; pointer to memory
   xor rdx, rdx ;; no flags for HeapFree
   mov rcx, G_hWinHeap ;; handle to the process' heap
   jsr HeapFree ;; Win32 API call (includes space for shadow registers)
   ELSE
      .ERR <"Parameter is not correct type.">
   ENDIF
ENDM



The ASM lines I am using for testing are the following:


   mov rax, IsTypeOf(TTWinApp_Constructor, OPCODE_FUNCTION)   ; should return TRUE (1)
   mov rax, IsTypeOf(ttAplication.bHiColorIcons, OPC_MEM, OPC_GVAR, OPC_REG, OPC_LVAR, OPC_SVAR)   ; should return TRUE (1)
   mov rax, IsTypeOf(this$, OPC_IMM, OPC_FN) ; should return FALSE (0)

   ; actual line of code in my source file.
   mov oObject.vtable, TTCreateObject(TTMap, TTMap_ctor)



Thank you all for any help with debugging/solving my mistakes.

Relvinian
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on May 10, 2018, 06:32:08 PM
Why don't you post a complete example, ready for copy & paste? Right now I have no time to add the headers etc myself.
Title: Re: I have noticed something cute about OPATTR.
Post by: Relvinian on May 10, 2018, 07:18:11 PM
Quote from: jj2007 on May 10, 2018, 06:32:08 PM
Why don't you post a complete example, ready for copy & paste? Right now I have no time to add the headers etc myself.

I stripped out the extra MACROs that work (other than the code for the new Macro), so it is as simple example I can get to illustrate the problem.


includelib kernel32.lib


OPC_MEM   equ < 34 >
OPC_IMM   equ < 36 >
OPC_STRUC equ < 36 >
OPC_GVAR  equ < 42 >
OPC_REG   equ < 48 >
OPC_LVAR  equ < 98 >
OPC_SVAR  equ < 98 >
OPC_FN    equ < 165 >

IsTypeOf MACRO OpCodeUnknown:REQ, OpCodes:VARARG
   ; possible OPCODEs that are valid parameters to macros that create/destory
   ; memory or objects will be the following for 64-bit compilation:
   ;
   ;  34: memory opcode value (ie: [r15+10h])
   ;  36: immediate opcode value (ie: 127, sizeof)
   ;  42: global address opcode value (ie: .data or .data? variable)
   ;  48: register opcode value (ie: rax, rsi, r11)
   ;  98: stack (local) opcode value (ie: [rsp+10h])
   ; 165: function address opcode value (ie: HeapAlloc)
   FOR arg, <OpCodes>
      IF .TYPE(OpCodeUnknown) EQ .TYPE(arg)
         EXITM <1>
      ENDIF
   ENDM
   EXITM <0>
ENDM


PUBLIC start

externdef ExitProcess: proc

this$ TEXTEQU < r15 > ; define a "this" pointer for instances of objects

.data
   bHiColorIcons  byte 1

.code

myProc PROC

   xor rax, rax

myProc ENDP

start:
   int 3 ; for WinDbg

   mov rax, IsTypeOf(myProc, OPC_FN)
   mov rax, IsTypeOf(bHiColorIcons, OPC_MEM, OPC_GVAR, OPC_REG, OPC_LVAR, OPC_SVAR)
   mov rax, IsTypeOf(this$, OPC_IMM, OPC_FN)


   mov eax, 1
   call ExitProcess
END


Just cut and paste into your own file and compile in 64-bit mode.  If you compile in 32-bit, I am not sure if the OPCODES I have defined will match.  If not, change them.  ;)

Just to repeat my problem, the "rax' values on the first two should have a 1.  The third should be 0, since it should not match.

Relvinian
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on May 10, 2018, 08:05:41 PM
Hi Relvinian,

This is odd indeed. Where did you get the info on 165: function address opcode value?

Here are some little helper lines for your macro, see tmp$:
OPC_FN=165

IsTypeOf MACRO OpCodeUnknown:REQ, OpCodes:VARARG
Local tmp$, tx
   ; possible OPCODEs that are valid parameters to macros that create/destory
   ; memory or objects will be the following for 64-bit compilation:
   ;
   ;  34: memory opcode value (ie: [r15+10h])
   ;  36: immediate opcode value (ie: 127, sizeof)
   ;  42: global address opcode value (ie: .data or .data? variable)
   ;  48: register opcode value (ie: rax, rsi, r11)
   ;  98: stack (local) opcode value (ie: [rsp+10h]) ; OxPT_Assembler ML
   ; 165: function address opcode value (ie: HeapAlloc) ; OPT_Errlines 0
   FOR arg, <OpCodes>
tx=type(OpCodeUnknown) and 255
tmp$ CATSTR <_TYPE(>, <OpCodeUnknown>, <)=>, %tx
% echo tmp$
tx=.TYPE(OpCodeUnknown) and 255
tmp$ CATSTR <.TYPE(>, <OpCodeUnknown>, <)=>, %tx
% echo tmp$
tx=type(arg) and 255
tmp$ CATSTR <_type(>, <arg>, <)=>, %tx
% echo tmp$
tx=.type(arg) and 255
tmp$ CATSTR <.type(>, <arg>, <)=>, %tx
% echo tmp$
      IF .TYPE(OpCodeUnknown) EQ .TYPE(arg)
         EXITM <1>
      ENDIF
   ENDM
   EXITM <0>
ENDM


For mov rax, IsTypeOf(myProc, OPC_FN) I get these...

... results for ML64 (no error thrown):
_TYPE(myProc)=8
.TYPE(myProc)=0
_type(OPC_FN)=0
.type(OPC_FN)=36


... results for UAsm (which actually throws an error):
_TYPE(myProc)=8
.TYPE(myProc)=37
_type(OPC_FN)=0
.type(OPC_FN)=36


The "_" is just to align the results obtained by TYPE without the dot. Not to be confused with .TYPE, which yields the lobyte of opattr, as you certainly know.

8 is not defined anywhere.
37 is a label (OK for a proc)
36 means immediate value (OK for OPC_FN, which is an immediate)
Title: Re: I have noticed something cute about OPATTR.
Post by: Relvinian on May 10, 2018, 08:16:18 PM
Quote from: jj2007 on May 10, 2018, 08:05:41 PM
This is odd indeed. Where did you get the info on 165: function address opcode value?

By just doing a mov rax, .TYPE(myFunc).    Once the line was executed, I had a 165 value.  One thing to note about the 165 value on my own system.  I was using a function that had a full frame, stack and exception code in the prologue for stack unwinding.  Do not know if that makes a difference. 

Btw:  All the defines at the top where generated using that method.  I just did a whole bunch of mov rax, ????  to find the value.

I am running Windows 10, latest version with updates.  Do not know if that makes a difference.

As for your output, interesting that the case sensitivity and underscore on the built-in 'type' pre-processor define makes a difference in the values you are getting back.  I wonder if using OPATTR would have the same effect?

Anyway, I will examine your code and the extra "helpers",  as you called it, and hopefully with those, they will help me try and figure out what is going on with my system.

Thank you.

Relvinian
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on May 10, 2018, 08:20:29 PM
case sensitivity doesn't play a role there, and the underscore, as written above, is just there to visualise better (a space gets swallowed by echo).

Google for Microsoft MASM Programmer's Guide, and check the "using macros" chapter. Or search MasmBasic.inc for atLabel

One important thing there is that type(something) is also a numeric value but not only. Test this:
include \masm32\include\masm32rt.inc

.data
WhichType MACRO arg
Local tmp$
  if (type(arg) eq REAL4)
echo arg is a REAL4
  elseif type(arg) eq DWORD
echo arg is a DWORD
  else
echo arg is something different
  endif
  tmp$ CATSTR <... but the numerical value of type(x) is >, %type(arg)
  % echo tmp$
ENDM

SomeDword dd ?
SomeReal4 REAL4 ?

.code
start:
  WhichType SomeDword
  WhichType SomeReal4
  .err  ; we want to see the assembler output
  exit

end start


Output:SomeDword is a DWORD
... but the numerical value of type(x) is 4
SomeReal4 is a REAL4
... but the numerical value of type(x) is 4
Title: Re: I have noticed something cute about OPATTR.
Post by: Relvinian on May 10, 2018, 08:47:23 PM
Quote from: jj2007 on May 10, 2018, 08:20:29 PM
case sensitivity doesn't play a role there, and the underscore, as written above, is just there to visualise better (a space gets swallowed by echo).

Google for Microsoft MASM Programmer's Guide, and check the "using macros" chapter. Or search MasmBasic.inc for atLabel

One important thing there is that type(something) is also a numeric value but not only. Test this:

Gotcha.

I changed the .TYPE to OPATTR in your macro that output the ECHO to the console window.  I did NOT change any of the text portion in the macro so it still has the strings of "_TYPE", etc.  Here are my result for the same code.


Microsoft (R) Incremental Linker Version 14.13.26128.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/DEBUG
/OUT:test.exe
test.obj
/subsystem:windows
/defaultlib:kernel32.lib
/entry:start
/largeaddressaware
/machine:x64
/debug
Assembling: test.asm
_TYPE(myProc)=8
.TYPE(myProc)=0
_type( 165 )=0
.type( 165 )=36
_TYPE(bHiColorIcons)=1
.TYPE(bHiColorIcons)=0
_type( 34 )=0
.type( 34 )=36
_TYPE(bHiColorIcons)=1
.TYPE(bHiColorIcons)=0
_type( 42 )=0
.type( 42 )=36
_TYPE(bHiColorIcons)=1
.TYPE(bHiColorIcons)=0
_type( 48 )=0
.type( 48 )=36
_TYPE(bHiColorIcons)=1
.TYPE(bHiColorIcons)=0
_type( 98 )=0
.type( 98 )=36
_TYPE(bHiColorIcons)=1
.TYPE(bHiColorIcons)=0
_type( 98 )=0
.type( 98 )=36
_TYPE( r15 )=8
.TYPE( r15 )=0
_type( 36 )=0
.type( 36 )=36
_TYPE( r15 )=8
.TYPE( r15 )=0
_type( 165 )=0
.type( 165 )=36


The following code is what generated the above data:

   mov rax, IsTypeOf(myProc, OPC_FN)
   mov rax, IsTypeOf(bHiColorIcons, OPC_MEM, OPC_GVAR, OPC_REG, OPC_LVAR, OPC_SVAR)
   mov rax, IsTypeOf(this$, OPC_IMM, OPC_FN)


Relvinian
Title: Re: I have noticed something cute about OPATTR.
Post by: sinsi on May 10, 2018, 09:44:58 PM
Not sure if this works properly, but...

OPC_FN    = 37

IsTypeOf MACRO OpCodeUnknown:REQ, OpCodes:VARARG
local result,s,t
   result = 0
   FOR arg, <OpCodes>
      s = opattr(OpCodeUnknown)
      t = arg
      IF s EQ t
         result = 1
         exitm
      ENDIF
   ENDM
   EXITM <result>
ENDM

From my "extensive" macro experience  :badgrin:
- you should be testing against arg, not .type(arg)
- exitm 1 exits the for loop (not the macro) then the final exitm 0 overwrites it
Title: Re: I have noticed something cute about OPATTR.
Post by: Relvinian on May 10, 2018, 11:10:55 PM
Sinsi and JJ207,

JJ207,

Thank you so much for your help.  The output to the console screen really help with trying to figure out what I was doing and what was wrong.


Sinsi,

That is what I basically ended up with after a lot of playing around.  Below is my macro now that fully works that way I wanted it to.


Both,
  Sinsi had the right idea by assigning a variable to the result of OPATTR, which you had done through the ECHO and tmp$, JJ2207.  By assigned a variable and then comparing the variable to the varargs (arg), the match was correct.  As for the 'and 255', I understand normally that strips any bits (sets to zero) which are above 8, but somehow that was messing up the actual return value by OPATTR.  What was your purpose on that JJ2207?

Anyway, thank you both again VERY much for the help.  I am a happy camper now after spending over two days on trying to get this macro to work. Now I can continue on with my project.  Basically, I am taking the "concept" of the Microsoft Foundation Classes (MFC) written in C++, which is Object Oriented programming and class designs, and creating my own simple versions of those in ASM.  So, writing a Windows GUI application that deal extensively with Messages (using ::sendmessage / ::postmessage) will be a much simpler task.  Still a LONG way to go but coming along.


;; ----------------------------------------------------------------------------
; These values were created in Windows 10 using ML64.EXE
; Microsoft (R) Incremental Linker Version 14.13.26128.0
;
; OPCODEs of various labels, functions, register and memory attributes
; Example on how they were defined:  mov rax, opattr(GetProcessHeap)
;; ============================================================================
OPC_MEM     equ < 34 >  ; memory address using LEA or [rcx+rdx*8]
OPC_IMM     equ < 36 >  ; Immediate operands that equate at assembly to values: ie: 1234
OPC_STRUC   equ < 36 >  ; STRUCT and UNION definitions
OPC_ENTRY   equ < 37 >  ; function label - local to ASM file
OPC_OFFSET  equ < 38 >  ; immediate and mem expression
OPC_GVAR    equ < 42 >  ; .data or .data? segment variable
OPC_REG      equ < 48 >  ; register, like RAX, ESI, RSP, etc
OPC_XMM     equ < 77 >  ; XMM registers
OPC_MVAR   equ < 98 >  ; variable in memory using the address
OPC_LVAR    equ < 98 >  ; local variable using keyword LOCAL or another method
OPC_SVAR   equ < 98 >  ; variable on the stack
OPC_FN       equ < 165 > ; function label - external to ASM file or in imported library

IsTypeOf MACRO OpCodeUnknown:REQ, OpCodes:VARARG
   ; opattr superceded the .type in ML.EXE (32-bit) and returns a WORD value
   ; for 64-bit, opattr only returns a BYTE value
   ; .type in either 32-bit or 64-bit returns only a BYTE value.
   rc = 0
   FOR arg, <OpCodes>
      ; IF opattr(OpCodeUnknown) EQ arg
      ; the above does not compute correctly - so changed to below
      opc = opattr(OpCodeUnknown)
      IF opc EQ arg
         rc = 1
         EXITM
      ENDIF
   ENDM
   EXITM <rc>
ENDM


For anyone else that needs or is playing around with OPATTR and .TYPE -- please feel free to my macro and modify it any way you want. 

Relvinian
Title: Re: I have noticed something cute about OPATTR.
Post by: jj2007 on May 10, 2018, 11:46:06 PM
Quote from: Relvinian on May 10, 2018, 11:10:55 PMAs for the 'and 255', I understand normally that strips any bits (sets to zero) which are above 8, but somehow that was messing up the actual return value by OPATTR.  What was your purpose on that JJ2207?

Just testing. Normally, I use and 127 to strip bit 7 (and higher), which is irrelevant for determining the type of the variable. If bit 7 is set, opattr says "references an external label" - and I just see that label is 37. Add 128, and you have "your" 165:
165: function address opcode value (ie: HeapAlloc)
Title: Re: I have noticed something cute about OPATTR.
Post by: anunitu on May 11, 2018, 07:02:19 AM
I was a little surprised to see "cute" to describe an assembler function,but it might be my old school brain is all.