News:

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

Main Menu

How to access structure array elements

Started by NoCforMe, June 28, 2012, 07:05:57 AM

Previous topic - Next topic

Ghandi

I remember running into this when i was writing some code that accessed the data directories in the PE header, i wondered why in C i could simply give the directory equate yet in MASM it was failing. I debugged it and saw the memory accesses weren't correct and realized that i had to multply the directory index by the size of IMAGE_DATA_DIRECTORY to get it back to the correct values.

HR,
Ghandi

Ryan

Quote from: jj2007 on June 28, 2012, 07:20:35 AM
   print str$(TestStructs[3*$test].s2), 9, "value", 13, 10
The SIZEOF operator is assumed when using the name of the struct in a calculation?

dedndave

test$ STRUCT
  member db ?
test$ ENDS

TestStruct test$ <>


yes - test$ is a type definition and the assembler will use the size, as it has no address
TestStruct has an address, so the assembler will use that

MichaelW

Yes, in my code I was able to reduce:
    I = sizeof $test
To:
    I = $test
And the app produced the same output as it did with the sizeof operator.



Well Microsoft, here's another nice mess you've gotten us into.

NoCforMe

#19
Quote from: tenkey on June 28, 2012, 05:03:29 PM
In most cases, you don't want to use hard-coded subscripts.

I agree; usually, one doesn't. However, in this case, hard-coded subscripts are  what's needed, which is what prompted my question in the first place.

What  I'm doing is placing addresses within one one array of structures (pointers to text buffers)into another array. It's much easier to hard-code this at assemble-time (since there's a 1:1 correspondence between the two elements), rather than have to programmatically loop through the the structures at runtime and plug in addresses.

TBRANSO1

#20
Quote from: hutch-- on June 28, 2012, 09:36:04 PM
A technique that does work well and is no big deal to write in assembler is an array of pointers to other array elements. The target array can be of uneven size, IE: an array of variable length strings for example but what makes it fast and easy to work with is an array of predictable size (DWORD ARRAY) where each DWORD member is a pointer to the uneven size elements.

High level languages do this all the time but its easy enough to create an array of variable length elements that is addressed by an array of pointers.

I edited this as I figured out how to do this with pain and patience.


.NOLIST
include \masm32\include\masm32rt.inc
.LIST

ThreadFunction PROTO :DWORD
ErrorHandler PROTO :LPTSTR
ExitProcess PROTO :DWORD
Main PROTO

MYDATA STRUCT
val1 DWORD ?
val2 DWORD ?
MYDATA ENDS

public start

.CONST
   max_threads   EQU 10
   buff_size   EQU 0FFh

.DATA
  threadMsg   DB     "CreateThread ", 0
          rtlMsg      DB      "Parameters = %d, %d", 10, 0
          rtlMsg2     DB      "%s failed with error %d: %s", 0
          errMsg      DB      "Error", 0

.DATA?
gData MYDATA <?>

.CODE

start:
INVOKE Main
        ;inkey
push 0
call ExitProcess

ThreadFunction PROC lpParam:DWORD
    LOCAL hStdOut:DWORD
    LOCAL msgBuf[buff_size]:BYTE
    LOCAL cchStringSize:DWORD
    LOCAL dwChars:DWORD

    push STD_OUTPUT_HANDLE
    call GetStdHandle
    mov hStdOut, eax
    cmp hStdOut, INVALID_HANDLE_VALUE
    je _ERROR
    ;printf("I am inside\n")
mov ecx, lpParam
mov ebx, DWORD PTR [ecx]
mov edx, DWORD PTR [ecx+4]
    INVOKE crt__snprintf, addr msgBuf, buff_size, addr rtlMsg, ebx, edx
mov cchStringSize, eax
    INVOKE WriteConsoleA, hStdOut, addr msgBuf, cchStringSize, addr dwChars, 0
    ret
_ERROR:
    printf("I didn't make it that far inside the thread function\n")
    mov eax, 1
    ret
ThreadFunction ENDP

ErrorHandler PROC lpszFunction:LPTSTR
    LOCAL lpMsgBuf:LPVOID
    LOCAL lpDisplayBuf:LPVOID
    LOCAL dwordage:DWORD

    mov dwordage, rv(GetLastError)
    INVOKE FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER or \
                        FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS,
                        0, dwordage, 0, lpMsgBuf, 0, 0
    mov eax, rv(lstrlen, lpszFunction)
    mov ebx, eax
    mov eax, rv(lstrlen, lpMsgBuf)
    add eax, ebx
    add eax, 028h
    push eax
    push 0
    call LocalAlloc
    mov lpDisplayBuf, eax
    INVOKE wsprintf, lpDisplayBuf, eax, addr rtlMsg2, lpszFunction, dwordage, lpMsgBuf
    INVOKE MessageBoxA, 0, lpDisplayBuf, addr errMsg, 0
    push lpMsgBuf
    call LocalFree
    push lpDisplayBuf
    call LocalFree
    ret
ErrorHandler ENDP

Main PROC
LOCAL localStrucArray[max_threads]:DWORD
LOCAL dwThreadIdArray[max_threads]:DWORD
LOCAL hThreadArray[max_threads]:HANDLE
LOCAL i:DWORD

mov i, 0
.WHILE i < max_threads
INVOKE GetProcessHeap
INVOKE HeapAlloc, eax, HEAP_ZERO_MEMORY, SIZEOF(MYDATA)
mov ecx, DWORD PTR i
mov DWORD PTR localStrucArray[ecx*4], eax
cmp DWORD PTR localStrucArray[ecx*4], 0
jz _EXIT
jne @F
INVOKE ErrorHandler, addr threadMsg
printf("Here @ErrorHandler\n")
push 2
call ExitProcess
@@:
mov ecx, DWORD PTR i
ASSUME eax:PTR MYDATA
mov eax, DWORD PTR localStrucArray[ecx*4]
mov edx, DWORD PTR i
add edx, 10
mov (MYDATA PTR [eax]).val1, edx
add edx, 90
mov (MYDATA PTR [eax]).val2, edx
ASSUME eax:NOTHING
mov edx, DWORD PTR dwThreadIdArray[ecx*4]
mov ecx, DWORD PTR localStrucArray[ecx*4]
INVOKE CreateThread, 0, 0, offset ThreadFunction, ecx, 0, edx
mov ecx, DWORD PTR i
mov DWORD PTR hThreadArray[ecx*4], eax
cmp DWORD PTR hThreadArray[ecx*4], 0
jz _EXIT
inc i
.ENDW

INVOKE WaitForMultipleObjects, max_threads, addr hThreadArray, TRUE, -1

mov i, 0
.WHILE i < max_threads
mov ecx, DWORD PTR i
mov ebx, DWORD PTR hThreadArray[ecx*4]
INVOKE CloseHandle, ebx
mov ecx, DWORD PTR i
cmp localStrucArray[ecx*4], 0
je @F
call GetProcessHeap
mov ecx, DWORD PTR i
mov edx, DWORD PTR localStrucArray[ecx*4]
INVOKE HeapFree, eax, 0, edx
mov ecx, DWORD PTR i
mov DWORD PTR localStrucArray[ecx*4], 0
@@:
inc i
.ENDW
xor eax, eax
ret
_EXIT:
        printf("Here @exit\n")
push 3
call ExitProcess
Main ENDP
end start


The first time I attempted to tackle this bit of Heap Allocation.