News:

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

Main Menu

Simple array addressing

Started by NoCforMe, January 24, 2022, 04:32:21 PM

Previous topic - Next topic

NoCforMe

This seems like an elementary question that I should know the answer to, having coded X86 assembly for decades, but I don't.

I have an array of dwords:
RandCounts DD 10 DUP(0)

And I need to access them individually as arguments to a function. I thought I could do this:
INVOKE wsprintf, ADDR buffer, OFFSET OutFmt, RandCounts, RandCounts[1], RandCounts[2], RandCounts[3],
RandCounts[4], RandCounts[5], RandCounts[6], RandCounts[7], RandCounts[8], RandCounts[9]


but that doesn't work: the assembler takes the subscripts as byte offsets from zero of the base of the array, which is totally wrong. Instead I had to do this:
INVOKE wsprintf, ADDR buffer, OFFSET OutFmt, RandCounts, RandCounts+4, RandCounts+8, RandCounts+12,
RandCounts+16, RandCounts+20, RandCounts+24, RandCounts+28, RandCounts+32, RandCounts+36


which seems really stupid. What am I missing here? Is there some way to declare and access this array so I can use numbers--[1], [2], etc.--to access each element?
Assembly language programming should be fun. That's why I do it.

hutch--

If you are dedicated and hard working, you write a single array with a number of pointer locations at the front and the data storage after with eah being pointed to by a location near the start. I have attached an algo of this type written back in 2010. It in a working example that should be fast enough for most things.

NoCforMe

Thanks, Hutch, but that's waaaaaay too complicated for what I want to do. Isn't there any way of addressing these array elements directly? I'm sure there's some MASM syntax that I'm missing here which would do what I want to do.
Assembly language programming should be fun. That's why I do it.

hutch--

Don't assume there is a simpler way to do it. The algo I posted only needs to be addressed by the array of pointers and it does not get much simpler than that. PS : Its fast too.  :cool:

NoCforMe

 I think I just answered my own question: no, you can't do that. I was expecting (hoping?) there'd be something C-like where array[n] would refer to the nth array element, regardless of size, but in ASM it's always a byte offset, not an index. From the MASM 6.1 Programmer's Guide:

QuoteAssembly-language indexes differ from indexes in high-level languages, where
the index number always corresponds to the element's position. In C, for
example, array[9] references the array's tenth element, regardless of whether
each element is 1 byte or 8 bytes in size.

In assembly language, an element's index refers to the number of bytes between
the element and the start of the array. This distinction can be ignored for arrays
of byte-sized elements, since an element's position number matches its index.
For example, defining the array

prime BYTE 1, 3, 5, 7, 11, 13, 17

gives a value of 1 to prime[0], a value of 3 to prime[1], and so forth.
However, in arrays with elements larger than 1 byte, index numbers (except
zero) do not correspond to an element's position. You must multiply an
element's position by its size to determine the element's index. Thus, for the
array

wprime WORD 1, 3, 5, 7, 11, 13, 17

wprime[4] represents the third element (5), which is 4 bytes from the
beginning of the array. Similarly, the expression wprime[6] represents the
fourth element (7) and wprime[10] represents the sixth element (13).

So nevermind.
Assembly language programming should be fun. That's why I do it.

hutch--

Look up the complex addressing mode, the offset in the notation can use a single register as well as the base address. If you want notation like that, write a macro.

NoCforMe

Yes, it occurred to me that a macro might work; something like array[Didx(5)]. Or I could just write "array+(5*4)". No big deal.
Assembly language programming should be fun. That's why I do it.

HSE

Quote from: NoCforMe on January 24, 2022, 04:32:21 PM
What am I missing here?

A clear notation is: RandCounts[1*4], RandCounts[2*4]
Equations in Assembly: SmplMath

jj2007

Quote from: NoCforMe on January 24, 2022, 04:32:21 PMthe assembler takes the subscripts as byte offsets from zero of the base of the array, which is totally wrong. Instead I had to do this:
INVOKE wsprintf, ADDR buffer, OFFSET OutFmt, RandCounts, RandCounts+4, RandCounts+8, RandCounts+12,
RandCounts+16, RandCounts+20, RandCounts+24, RandCounts+28, RandCounts+32, RandCounts+36


which seems really stupid. What am I missing here? Is there some way to declare and access this array so I can use numbers--[1], [2], etc.--to access each element?

The assembler wants indeed the byte offset. You can see that as a nuisance or a feature. If you want proper indices as in high level languages, you need macros. This works, but it looks equally clumsy (passing so many arguments is never nice):

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Dim RandCounts() As DWORD
  For_ ecx=0 To 9
Rand(-1000, 1000, RandCounts(ecx))
  Next
  buffer equ <edi>
  Let buffer=Space$(100)
  INVOKE wsprintf, buffer, cfm$("Here they are: %i %i %i %i %i %i %i %i %i %i\n"), RandCounts(0), RandCounts(1), RandCounts(2), RandCounts(3), RandCounts(4), RandCounts(5), RandCounts(6), RandCounts(7), RandCounts(8), RandCounts(9)
  Inkey buffer
EndOfCode


P.S.: I support HSE's simple and clear notation :thumbsup:

Vortex

Hi NoCforMe,

Here is a quick example for you:

include     \masm32\include\masm32rt.inc

.data

string1     db 'Banana',0
string2     db 'Apple',0
string3     db 'Cherry',0
string4     db 'Melon',0

msg         db '%s',13,10,0

StringTable dd  string1,string2,\
                string3,string4
.code

start:

    call    main
    invoke  ExitProcess,0

main PROC uses esi ebx

    mov     ebx,4
    mov     esi,OFFSET StringTable
@@:
    invoke  crt_printf,ADDR msg,\
            DWORD PTR [esi]
           
    add     esi,4
    dec     ebx
    jnz     @b

    ret

main ENDP

END start


NoCforMe

Quote from: jj2007 on January 25, 2022, 01:32:22 AM

The assembler wants indeed the byte offset. You can see that as a nuisance or a feature. If you want proper indices as in high level languages, you need macros. This works, but it looks equally clumsy (passing so many arguments is never nice):

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Dim RandCounts() As DWORD
  For_ ecx=0 To 9
Rand(-1000, 1000, RandCounts(ecx))
  Next
  buffer equ <edi>
  Let buffer=Space$(100)
  INVOKE wsprintf, buffer, cfm$("Here they are: %i %i %i %i %i %i %i %i %i %i\n"), RandCounts(0), RandCounts(1), RandCounts(2), RandCounts(3), RandCounts(4), RandCounts(5), RandCounts(6), RandCounts(7), RandCounts(8), RandCounts(9)
  Inkey buffer
EndOfCode
}

But but but ... that (Dim X as ...] doesn't look like MASM at all to me. Looks like MasmBasic. I appreciate you pushing your "brand" here, but since I don't use it, doesn't do me any good.

QuoteP.S.: I support HSE's simple and clear notation :thumbsup:

You'll notice that I proposed that myself in my reply above. Better than nothing.
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: Vortex on January 25, 2022, 07:29:57 AM
Hi NoCforMe,

Here is a quick example for you:

include     \masm32\include\masm32rt.inc

.data

string1     db 'Banana',0
string2     db 'Apple',0
string3     db 'Cherry',0
string4     db 'Melon',0

msg         db '%s',13,10,0

StringTable dd  string1,string2,\
                string3,string4
.code

start:

    call    main
    invoke  ExitProcess,0

main PROC uses esi ebx

    mov     ebx,4
    mov     esi,OFFSET StringTable
@@:
    invoke  crt_printf,ADDR msg,\
            DWORD PTR [esi]
           
    add     esi,4
    dec     ebx
    jnz     @b

    ret

main ENDP

END start


Thanks, but that's not what I want at all. I'm not addressing these elements programatically, and I do know how to do that. I was addressing them directly, explicitly, as in element[1], element[2], etc.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on January 25, 2022, 10:10:20 AMLooks like MasmBasic. I appreciate you pushing your "brand" here, but since I don't use it, doesn't do me any good.

That was just to demonstrate that it can be done. Anyway, I hacked something together, plain Masm32:

include \masm32\include\masm32rt.inc

RandCounts MACRO arg
  EXITM <_RandCounts[4*arg]>
ENDM

.data
_RandCounts DD 100, 101, 102, 103, 104, 105, 106, 107, 108, 109
OutFmt db "What a mess: %i %i %i %i %i %i %i %i %i %i", 0

.data?
buffer db 100 dup(?)

.code
start:
  INVOKE wsprintf, ADDR buffer, OFFSET OutFmt, RandCounts(0), RandCounts(1), RandCounts(2), RandCounts(3),
RandCounts(4), RandCounts(5), RandCounts(6), RandCounts(7), RandCounts(8), RandCounts(9)
  inkey offset buffer
  exit

end start


RandCounts(index) is not as powerful as the Dim macro (290 lines), but it will do the job for you.

NoCforMe

JJ, you the man. Thank you for actually answering the question that was asked, and doing so elegantly. This is not a bad solution at all.
Assembly language programming should be fun. That's why I do it.

Vortex

Hi NoCforMe,

Here is another version of the code :

include     \masm32\include\masm32rt.inc

.data

string1     db 'Banana',0
string2     db 'Apple',0
string3     db 'Cherry',0
string4     db 'Melon',0

msg         db '%s',13,10,0

StringTable dd  string1,string2,\
                string3,string4
.code

start:

    call    main
    invoke  ExitProcess,0

main PROC uses esi ebx

    mov     ebx,4
    xor     esi,esi
@@:
    invoke  crt_printf,ADDR msg,\
            StringTable[esi*4]
           
    inc     esi
    dec     ebx
    jnz     @b

    ret

main ENDP

END start