News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

I have noticed something cute about OPATTR.

Started by hutch--, August 03, 2016, 04:50:14 PM

Previous topic - Next topic

hutch--

Seems if will not recognise a floating point register in ML64. Always returns 0.

jj2007

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

hutch--

Aha, the problem may be that it does not like the short form st0 instead of st(0). Will try it.

jj2007

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.

hutch--

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

jj2007

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...

hutch--

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.

mabdelouahab

"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]


hutch--

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

mabdelouahab

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]

hutch--

> 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.

jj2007

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

hutch--

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


hutch--

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.

jj2007

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.