News:

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

Creating compile-time arrays

Started by Randall Hyde, October 18, 2005, 06:08:25 PM

Previous topic - Next topic

Randall Hyde

Hi All,
I'm trying to simulate something in MASM that I can do in HLA -- define an array of compile-time values. One approach, creating text objects and separating items in the text constant with a special character, will work, but it's really inaesthetic when trying to manipulate items in the "array". E.g.,

someArray textequ <0 : 1 : 5 : 7 : 8 : 3 : 19 : 13 >

As you can probably imagine, manipulating elements of this "array" is rather ugly.

A second scheme I've come up with is to automatically generate a list of equates using a declaration macro. Here's some code that demonstrates how to do this:



            .686p
            .mmx
            .xmm
            .model  flat, syscall

; makeName -
;   Creates an identifier by concatenating the second numeric operand converted to
;   string form to the end of the name passed as the first operand, with "$$" between
;   them (just to help make the name unique).
;
; Syntax (used as a macro function):
;
;   makeName( someName, someValue )
;
; e.g.,
;
;   makeName( i, %(5+1)) = 0
;
; produces
;
;   i$$6 = 0

makeName    macro   theName,theSuffix
            exitm   <theName&$$&theSuffix>
            endm



; dclNArray-
;
;   Declares a compile-time Numeric array.

dclNArray               macro   aryName, arySize
                        local   i, elementName
i                       =       0
                        while   i lt arySize
makeName( aryName, %i ) =       0
i                       =       i + 1
                        endm
&aryName&$$size         =       arySize

; Create an accesor macro for this constant array:

aryName     macro   aryIndex
            exitm   <makeName(%&aryName&,aryIndex )>
            endm
           
            endm
   

   

        .data
       
dclNArray constArray, 10

constArray(5) = 5
constArray(6) = constArray(5)+1
constArray(7) = constArray(<size>)



        .code
Main    proc    near32


Main    endp

        end     Main


Assemble with the /Fl option to get the symbol table listing so you can see the array "element" values, e.g.,

constArray$$0  . . . . . . . . .        Number   00000000h
constArray$$1  . . . . . . . . .        Number   00000000h
constArray$$2  . . . . . . . . .        Number   00000000h
constArray$$3  . . . . . . . . .        Number   00000000h
constArray$$4  . . . . . . . . .        Number   00000000h
constArray$$5  . . . . . . . . .        Number   00000005h
constArray$$6  . . . . . . . . .        Number   00000006h
constArray$$7  . . . . . . . . .        Number   0000000Ah
constArray$$8  . . . . . . . . .        Number   00000000h
constArray$$9  . . . . . . . . .        Number   00000000h
constArray$$size . . . . . . . .        Number   0000000Ah


This scheme works great, as long as all your array elements are simple numeric values. If you need a textual object (to represent strings or struct objects), this approach seems to fall apart. It would be cool if I could reassign TEXTEQU objects, but (assuming you've done text equates rather than numeric equates with"=") when you attempt something like


constArray$$5 textequ <.....>


MASM will substitute the prior value of the "constArray$$5" value for the symbol. So you wind up with a syntactically incorrect statement like


0 textequ <.....>

(Because MASM substitutes the initial definition for constArray$$5 in place of the symbol in this text equate.)

Any suggestions? It would be cool if I could turn off the text expansion in this instance.

It would be a real bummer to have to stick with just numeric equates, or have to go through the ugliness of manipulating text values to gain access to array "elements".  Help!
Thanks,
Randy Hyde

Randall Hyde

Nevermind, I figured it out.
Here's an example that creates arrays of text equate data:



            .686p
            .mmx
            .xmm
            .model  flat, syscall

; makeName -
;   Creates an identifier by concatenating the second numeric operand converted to
;   string form to the end of the name passed as the first operand, with "$$" between
;   them (just to help make the name unique).
;
; Syntax (used as a macro function):
;
;   makeName( someName, someValue )
;
; e.g.,
;
;   makeName( i, %(5+1)) = 0
;
; produces
;
;   i$$6 = 0

makeName    macro   theName,theSuffix
            exitm   <theName&$$&theSuffix>
            endm


; dclNArray-
;
;   Declares a compile-time Numeric array.

dclArray                macro   aryName, arySize
                        local   i, elementName
i                       =       0
                        while   i lt arySize
makeName( aryName, %i ) textequ <0>
i                       =       i + 1
                        endm
&aryName&$$size         =       arySize

; Create an accesor macro for this constant array:

aryName     macro   aryIndex
            exitm   makeName(%&aryName&,aryIndex )
            endm
           
            endm
   

   

        .data
       
dclArray constArray, 10

;constArray(5) = 5
;constArray(6) = constArray(5)+1
;constArray(7) = constArray(<size>)

constArray(5) textequ <5>
constArray(3) textequ <7>
constArray(4) textequ %(constArray(3)+1)

            byte    constArray(4)

        .code
Main    proc    near32


Main    endp

        end     Main

Cheers,
Randy Hyde

Randall Hyde

Here's another improvement to the constant array macro. It now creates a symbol of the form "arrayname$$all" that is a list of all the constant array elements. You could use this, for example, to initialize a run-time memory variable (as is done in the following example):



            .686p
            .mmx
            .xmm
            .model  flat, syscall

; makeName -
;   Creates an identifier by concatenating the second numeric operand converted to
;   string form to the end of the name passed as the first operand, with "$$" between
;   them (just to help make the name unique).
;
; Syntax (used as a macro function):
;
;   makeName( someName, someValue )
;
; e.g.,
;
;   makeName( i, %(5+1)) = 0
;
; produces
;
;   i$$6 = 0

makeName    macro   theName,theSuffix
            exitm   <theName&$$&theSuffix>
            endm


; dclArray-
;
;   Declares a compile-time Numeric array.
;
; This macro generations the following symbols:
;
; Elements of the array:
;
;   <aryName>$$0..<aryName>$$n, where arySize = n+1
;
; Size of the array (# of elements)
;
;   <aryName>$$size
;
;
; Text constant listing all the element names, separated by commas (e.g., for use
; when initializing a memory variable with the array's values):
;
;   <aryName>$$all
;
;
; Example of usage:
;
;   ; Array Declaration:
;
;   dclArray myArray, 16
;
;
;   ; Accessing individual elements of the array:
;
;   myArray(5) textequ %(myArray(4) + 2)
;
;
;   ; Using the array size:
;
;   mov ecx, myArray(<size>)
;
;
;   ; Initializing a memory variable with the array's data:
;
;   memArray    dword   myArray(<all>)

   
dclArray                macro   aryName, arySize
                        local   i, elementName, names
i                       =       0
                        while   i lt arySize
makeName( aryName, %i ) textequ <0>
i                       =       i + 1
                        endm
                       
; Create a constant we can use to determine the # of array elements:
                       
&aryName&$$size         =       arySize

; Create a constant we can use to specify *all* the array elements:

&aryName&$$all          textequ makeName(names,0)
i                       =       1
                        while   i lt arySize
&aryName&$$all          catstr  &aryName&$$all, <,>, makeName(names,%i)
i                       =       i + 1
                        endm

i                       =       0
                        while   i lt arySize
makeName(names,%i)      textequ makeName(aryName, %i)
i                       =       i + 1
                        endm


; Create an accesor macro for this constant array:

aryName     macro   aryIndex
            exitm   makeName(%&aryName&,aryIndex )
            endm
           
            endm
   

   

; Quick demo of the above macros:

                .data
       
; Declare a constant array:

                dclArray constArray, 10

; Initialize all the elements of this array:

                    for i,<1,2,3,4,5,6,7,8,9,10>
constArray(%(i-1))  textequ %(11-i)
                    endm

; Create a memory variable, initialized with all the array elements:
       
memArray        byte    constArray(<all>)
       

        .code
Main    proc    near32


Main    endp

        end     Main


Pertinent output from the listing file:



            ; Create a memory variable, initialized with all the array elements:

00000000 0A 09 08 07 06        memArray                byte    constArray(<all>)
         05 04 03 02 01


More to come as I think about this problem some more,
Cheers,
Randy Hyde

Randall Hyde

The <arrayName>$$all feature will not survive as-is, I'm afraid. Line length limitations prevent it from working as arrays start to get larger.
Cheers,
Randy Hyde

Mark Jones

Any chance Pelle can work around this with POASM? :U
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

u

text variables in MASM are tricky, it took me some time to get used to fighting things like "unknown symbol: @@54Z" while making the MASM OOP extention "ATC"   ^^"
Please use a smaller graphic in your signature.

Human

yeah but it will just work for small tables, masm really suxx at creating tables or empty arrays, try for example sometab db 700000 dup (0) or (?) on my athlon xp1700 it takes 20s for masm 6.14 and 4.13s for masm 7.10.4035, cant say how long with 8.0 due its .net infected, when tried db 64*1024*1024 dup (?) i give up after 15 minutes doing food and come back, for tasm it doesnt matter what you will give, its less than 1 second. that how microsoft writes their programs, even nasm has workaround for it with resb, and sometimes we need empty tables than will be in data section allocated on load and exe is small, due i need it for code optimizalization, and i need all regs and cant afford loosing one as pointer due faster will be mov eax,[ebx+offset ourtab] than mov ecx,[ourtab]
mov eax,[ebx+ecx]
slower and we lost 1 register

MichaelW

Quotemasm really suxx at creating tables or empty arrays

This is a known problem with MASM, and there is workaround for it. The main article that discussed the problem and the workaround appears to be gone, but there is some information in these two threads:

http://www.old.masmforum.com/viewtopic.php?t=2575

http://www.old.masmforum.com/viewtopic.php?t=2124
eschew obfuscation

Human

well those are not all issues of masm, masm has too ideal mode, in tasm we dont need to give size of write for example with
mov b [edx+edi+o huff_num],al
because tasm knows al is a byte and does it automaticly, masm needs byte ptr.
another thing is forward refferences, i have to use proto and putt all data before code, because it will not find them, and in one case it worked, case was invoke does all problems but i dont wanna return to push push call syntax, same is with multi push
masm doesnt know what to do with push eax ebx, gives missing operator in expression, tasm splits it into 2 pushes,same with pop.
dont wanna also only protect tasm, its outdated no includes you have to do them alone, no small modplayers only for xm, no sse sse2 support, even borland 2006 has old tasm 5.3 from 2002, also no support for amd64, masm already have ml64.exe

zooba

Quote from: Human on February 04, 2006, 01:44:08 PM
well those are not all issues of masm, masm has too ideal mode, in tasm we dont need to give size of write for example with
mov b [edx+edi+o huff_num],al
because tasm knows al is a byte and does it automaticly, masm needs byte ptr.

Bad example. MASM does this unless you use an immediate, in which case it doesn't have any way of knowing what you mean.

Quote from: Human on February 04, 2006, 01:44:08 PManother thing is forward refferences, i have to use proto and putt all data before code, because it will not find them, and in one case it worked, case was invoke does all problems but i dont wanna return to push push call syntax, same is with multi push

Fair point, though it's easy enough to work around and actually promotes better style in your code :wink

Quote from: Human on February 04, 2006, 01:44:08 PM
masm doesnt know what to do with push eax ebx, gives missing operator in expression, tasm splits it into 2 pushes,same with pop.

That's because 'push eax ebx' isn't a real assembly instruction. You actually do have to use two instructions. If you want to avoid having to tell the computer exactly what to do, use a HLL.

Quote from: Human on February 04, 2006, 01:44:08 PM
dont wanna also only protect tasm, its outdated no includes you have to do them alone, no small modplayers only for xm, no sse sse2 support, even borland 2006 has old tasm 5.3 from 2002, also no support for amd64, masm already have ml64.exe