Author Topic: Simple array addressing  (Read 2098 times)

NoCforMe

  • Member
  • *****
  • Posts: 1124
Simple array addressing
« on: January 24, 2022, 04:32:21 PM »
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:
Code: [Select]
RandCounts DD 10 DUP(0)
And I need to access them individually as arguments to a function. I thought I could do this:
Code: [Select]
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:
Code: [Select]
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?

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Simple array addressing
« Reply #1 on: January 24, 2022, 04:58:57 PM »
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.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #2 on: January 24, 2022, 05:41:01 PM »
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.

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Simple array addressing
« Reply #3 on: January 24, 2022, 06:03:32 PM »
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:
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #4 on: January 24, 2022, 06:07:07 PM »
 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:

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

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Simple array addressing
« Reply #5 on: January 24, 2022, 06:55:16 PM »
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.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #6 on: January 24, 2022, 07:21:57 PM »
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.

HSE

  • Member
  • *****
  • Posts: 2501
  • AMD 7-32 / i3 10-64
Re: Simple array addressing
« Reply #7 on: January 24, 2022, 11:12:07 PM »
What am I missing here?

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

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Simple array addressing
« Reply #8 on: January 25, 2022, 01:32:22 AM »
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:
Code: [Select]
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):

Code: [Select]
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

  • Member
  • *****
  • Posts: 2793
Re: Simple array addressing
« Reply #9 on: January 25, 2022, 07:29:57 AM »
Hi NoCforMe,

Here is a quick example for you:

Code: [Select]
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

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #10 on: January 25, 2022, 10:10:20 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):

Code: [Select]
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.

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

NoCforMe

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #11 on: January 25, 2022, 10:12:19 AM »
Hi NoCforMe,

Here is a quick example for you:

Code: [Select]
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.

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Simple array addressing
« Reply #12 on: January 25, 2022, 12:53:42 PM »
Looks 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:

Code: [Select]
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

  • Member
  • *****
  • Posts: 1124
Re: Simple array addressing
« Reply #13 on: January 25, 2022, 01:18:27 PM »
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.

Vortex

  • Member
  • *****
  • Posts: 2793
Re: Simple array addressing
« Reply #14 on: January 26, 2022, 06:17:24 AM »
Hi NoCforMe,

Here is another version of the code :

Code: [Select]
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