News:

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

Arrgggh! Arrays of structures

Started by Astro, August 09, 2009, 11:05:11 PM

Previous topic - Next topic

donkey

If you want to dynamically allocate memory you should be using the Virtual memory API supplied by Windows. For the stack, growing it is not easily accomplished nor is keeping the array in data or data? sections. With VirtualAlloc you can reserve and commit memory as well as expand the array when necessary.

VirtualAlloc
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

i prefer the heap functions
VirtualAlloc always initializes the data to 0
with the heap functions, it is an option
the advantage to the virtual functions is essentially unlimited space
but, i haven't written anything yet that needs more than the heap can give me - lol

Astro

QuoteThe only thing to keep in mind is that there is a bug in the dup macro that makes assembly (not the code) slow for large numbers.
You confused me there!

http://msdn.microsoft.com/en-us/library/aa366533(VS.85).aspx

If I used:

SomeStruct struct ;16 bytes
    Data1 DWORD ?
    Data2 DWORD ?
    Data3 DWORD ?
    Data4 DWORD ?
SomeStruct ends

.data?
ptrSomeStruct SomeStruct <?>


is the following valid?

.code
start:
    push 20h ;32 bytes (2 struct)
    push 8h ;zero memory
    push hHandleToPrivateHeap
    call HeapAlloc
    mov SomeStruct,eax ;assign new allocated memory to the structure


I think I might even forget defining the structure and just allocate the memory anyway and use it directly.  :dazzled:

Best regards,
Astro.

Slugsnack

just allocate memory that is sizeof your structure. then take the pointer and ASSUME it as a pointer to your structure

Astro

Quote from: Slugsnack on August 10, 2009, 05:49:37 PM
just allocate memory that is sizeof your structure. then take the pointer and ASSUME it as a pointer to your structure
I was considering doing that. Seems a lot easier.

Best regards,
Astro.

dedndave

what Jochen meant was, that if you declare a very large number of structures,
masm (for some buggish reason) takes a long time to assemble the program
it has no effect on the resultant exe, other than it takes longer to develop it - lol

jj2007

Quote from: Astro on August 10, 2009, 05:54:31 PM
Quote from: Slugsnack on August 10, 2009, 05:49:37 PM
just allocate memory that is sizeof your structure. then take the pointer and ASSUME it as a pointer to your structure
I was considering doing that. Seems a lot easier.

This is basically what I proposed above. Once you have the pointer to the start of the first element of your structure, either in the .data or .data? section or as a result of an allocXX call, you address your elements relative to this pointer. ASSUME is one way to do it, but not necessarily the most elegant one:

Quote   Element = 30   ; test
   mov esi, offset ptrSomeStruct   ; esi points now to element 0 of the array

   mov ebx, SIZEOF SomeStruct
   mov eax, Element      ; we want No. 30, so we multiply 30 with the
   mul ebx            ; size, 112, and get 30*112=3360 in eax

   mov [eax+esi.SomeStruct.Data1], 50h   ; moves 50 h into Data1 of element 30

   ASSUME esi:PTR SomeStruct
   mov [eax+esi].Data1, 50h      ; these three lines do exactly the same
   ASSUME esi:nothing


@DednDave: Thanks, you described the problem correctly. Apparently he expects a maximum of around ten elements, for which the .data? section is more than enough. HeapAlloc is an overkill for such a small amount...

dedndave

hard to know what his exact application is
but, you are right - declare it as data? - simple
what i do like about using the heap is, once you are done, you can trash it and leave it open for something else
while that may also be true for declared data, it becomes a little harder to keep it neatly organized
when i started writing 32-bit code, i was doing the same stuff
it is a throw-back to 16-bit code where 640 Kb can disappear rather quickly
old hobits die hard, as Bilbo would say - lol
it is hard to become accustomed to "wasteful" practices, and then complain about "bloat-ware"
there are times, when you just don't know how large something is going to be, too
like a file or even a registry entry can surprise you sometimes

Astro

I'm calling a 3rd party function that will return a number of devices attached to the system. I then use this number to allocate sufficient structures for the next call that will populate the array of structures with data, but it is up to me to ensure the correct size is allocated.

My thoughts are in the direction of "if I'm not using it, why keep it allocated?". I love assembler for two reasons: it's small, and I actually understand it!  :U

The docs are confusing me (you'll notice it is easily done! haha) on the mul operand. Is it always of the format:

mul reg ; eax * reg -> eax ?

The docs state that for 32-bit the result is in EDX:EAX. Huh?

Best regards,
Astro.

dedndave

sure - if you mul a 32-bit value by another 32-bit value, the result can be as large as 64-bits
so, if you mul byte operands, you get a word, mul word operands, you get a dword, mul dwords, you get a qword
the reverse is true for division

        div     ecx

divides edx:eax by ecx
afterwards, the quotient is in eax and the remainder is in edx

this is Randall Hyde's instruction set reference from Wash Univ at St Louis...
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-2.html#HEADING2-451

Astro

* Bashes head on table *

So the minimum registers I can get away with are edx and eax, and both are trashed with the result. OK...

I'm realizing I learned more as a kid messing around than I ever did in formal courses.

Quotethe result can be as large as 64-bits
I hadn't considered the case where the answer could exceed the (32-bit) register size.

If

div ecx

= edx:eax / ecx

is it legal to write:

div ebx:ecx

= edx:eax / ebx:ecx

...and is this faster than moving it into the FPU to get it to do its thing?

Best regards,
Astro.

dedndave

nope - not even going to work - lol
dividing by 64-bits is a bit of fun - not simply done at all

QuoteSo the minimum registers I can get away with are edx and eax, and both are trashed with the result.
not sure what you meant by "minimum" registers, but

        div cl

divides ax by cl - afterward, quotient in al, remainder in ah

i should also tell you that divide by 0 is a bad thing - it generates a divide-by-zero interrupt, and generally crashes a program
also, if you divide a large number by a small one, it is possible that the quotient overflows the register size
this is similar to divide-by-zero, only it's called divide overflow - crashes a program
take care to make sure the numbers you want to divide cannot result in these errors
many programmers opt to use the fpu for some integer division because it can handle a larger range of values without overflow
you can also daisy-chain or "cascade" div instructions to work with larger dividends and quotients
larger divisors (and, subsquently, remainders) is more difficult and may be handled by long division - very clock-consuming

Astro

An example:

mov edx,2
mov eax,5
div edx

= 5 / 2 = 2.5

eax = 2
edx = 1

?

Uses only two registers for the whole operation.

Quotei should also tell you that divide by 0 is a bad thing - it generates a divide-by-zero interrupt, and generally crashes a program
Hmm.

Best regards,
Astro.

dedndave

Quotemov edx,2
mov eax,5
div edx
oops
whenever the divisor is a dword, the dividend is edx:eax
i have never tried what you did there, but it should be 200000005h / 2
that should generate a divide overflow exception, as 100000002 is too large for a dword register

dedndave

for an example of daisy-chaining div instructions, this is a simple 64-bit unsigned integer to ascii string routine
http://www.masm32.com/board/index.php?topic=11741.msg88697#msg88697