Seems if will not recognise a floating point register in ML64. Always returns 0.
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
Aha, the problem may be that it does not like the short form st0 instead of st(0). Will try it.
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.
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
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...
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.
"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]
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
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]
> 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.
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
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
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.
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.
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
Why don't you post a complete example, ready for copy & paste? Right now I have no time to add the headers etc myself.
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
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)
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
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
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
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
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
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)
I was a little surprised to see "cute" to describe an assembler function,but it might be my old school brain is all.