I must be the dumbest programmer to have ever lived. :eek
There are actually two questions, semi-related in purpose. First, structures.
As an example, if I have the following structure:
SomeStruct struct
hHandleToSomething DWORD ?
Data1 DWORD ?
Data2 DWORD ?
SomeArrayOfBytes BYTE 100 DUP (?)
SomeStruct ends
The size of the structure is (3 * DWORD) + (100 * BYTE) = 112 bytes.
If I then define:
.data?
ptrSomeStruct SomeStruct <?>
and access it in the code as:
mov [ptrSomeStruct].Data1,50h
...this works (if I haven't screwed up when to use brackets etc...) to access the single element Data1.
However... my problem arises when I have an array of say 50 structures.
I define it thus:
.data?
ptrSomeStruct SomeStruct <>
Is this correct?
Assuming it is, I then need to iterate the array in a loop, doing some processing on the elements as I go.
.code
; code ... blah ...
mov StructOffset,70h ; sizeof struct = 112 bytes
mov ecx,0 ; first index
SomeLoop:
mov eax,[ptrSomeStruct].Data1+StructOffset*ecx ; this line fails - invalid use of (ecx) register
inc ecx
cmp ecx,MaxCount
jnz SomeLoop
I also tried more simply:
mov eax,[ptrSomeStruct].Data1+112*ecx
...with all manner of combinations of [ and ] for the +112*ecx part but to no avail.
My intention is to create an offset based upon 0*112 = 0 for the first element, etc..
I've yet to test:
mov ebx,112*ecx
;...
mov eax,[ptrSomeStruct].Data1+ebx
...but I'm not hopeful.
Seperately, I need to allocate sufficient memory for the array, which appears to simply be a call to HeapAlloc, providing ptrSomeStruct as the subject of the memory allocation. Again, this wants to be based on the format MaxCount * 112.
I'm sure I've seen code formatted similarly, that appears to be working, valid code, but for some reason when I tried it I got compiler errors, or it simply crashed.
I've tried just about everything I can think of (except the method I mention above using ebx).
Thanks in advance for any help.
If anyone has any tips for not getting confused over when to use [ and ] as well, I'd appreciate it. Oddly, I understand the "why", I just don't quite see the "when" yet (especially when dealing with registers).
Best regards,
Astro.
This should work:
include \masm32\include\masm32rt.inc
SomeStruct struct
hHandleToSomething DWORD ?
Data1 DWORD ?
Data2 DWORD ?
SomeArrayOfBytes BYTE 100 DUP (?)
SomeStruct ends
.data?
ptrSomeStruct SomeStruct 99 dup(<?>)
.code
start:
Element = 30 ; test
mov esi, offset ptrSomeStruct
mov ebx, SIZEOF SomeStruct
mov eax, Element
mul ebx
mov [eax+esi.SomeStruct.Data1], 50h
inkey "Press any key"
exit
end start
That's great! Thanks! I shall examine your code! :U
A question:
ptrSomeStruct SomeStruct 99 dup(<?>)
This obviously allocates memory for 99 structures, but I want to dynamically assign this at run-time for two reasons:
1) So I'm not using more memory than required
2) I've no idea what the upper limit is, and by fixing it like this I could potentially run out of space if I under-estimate it.
How would I particularly solve (2)?
Best regards,
Astro.
allocated blocks may be resized
but, that can get sloppy if you have a lot of dynamic allocation going on
it's best if you can find some indicator to early predict usage and allocate the block, say 5 to 10 % larger than estimated
I anticipate maybe 2 elements in the array, but from testing I only need 1 (so far...), but I must account for the case whereby I get a return of say, 10. The actual number is unknown and must account for this.
How would I dynamically re-allocate the memory? I figured it might be easier to just start with one structure and allocate based upon MaxCount prior to filling the structure.
Is my syntax in the OP for structure definition correct? Specifically:
.data?
ptrSomeStruct SomeStruct <>
Best regards,
Astro.
well, first of all, that whole thing sounds mighty small
you have 4 gb of memory space to play with
if it is let's say, 40 to 100 bytes, resizing is a bad idea
just allocate 1 kb - that doesn't even put a dent in the available workspace
you could even place it on the stack
sub esp,1024
mov BufferSpacePointer,esp
.
.
.
add esp,1024
HeapReAlloc
http://msdn.microsoft.com/en-us/library/aa366704(VS.85).aspx
Am I taking this whole "assembler is small and fast" too far?
Quote sub esp,1024
mov BufferSpacePointer,esp
.
.
.
add esp,1024
Simplicity at its finest.
Are there any limits to stack size (e.g. is it the same as the process memory) or is this a bad method for larger allocation (e.g. 512 Mb)?
Tomorrow I'm going to go try and answer these questions.
Best regards,
Astro.
i think stack is default 1 gb - knock yourself out
:8)
Thanks for your patience with my questions. :thumbu
Best regards,
Astro.
no prob
we all hafta learn somehow
AFAIK the default stack sizes are 4096 bytes committed and 1048576 bytes reserved. The system maintains a guard page at the end of the committed stack, and accessing into the guard page will cause the system to increase the committed size, but only until is reaches the reserved size. Your application will die if the stack exceeds the reserved size, or if the stack beyond the guard page is accessed. The stack sizes can be controlled from the linker command line.
my bad, Michael - thanks for correcting me
i got 1 gb mixed with 1 mb
quite a difference - lol
if you are unsure how many instances of the structure you're going to need then perhaps you could consider something like a linked list. as you need a new structure, allocate it then link it to the end of the original list
:bg
Dave,
Its just extreme forward thinking to attribute 1 gig to the stack, just wait for Windows 9.0.
Quote from: Astro on August 09, 2009, 11:36:41 PM
...
This obviously allocates memory for 99 structures, but I want to dynamically assign this at run-time for two reasons:
1) So I'm not using more memory than required
2) I've no idea what the upper limit is, and by fixing it like this I could potentially run out of space if I under-estimate it.
How would I particularly solve (2)?
Just allocate a generous amount in the .data? section, it doesn't cost anything. The 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. But for a thousand or so elements, you will not run into problems - see below some timings. Of course, you can use HeapAlloc etc, too, but why bother?
:wink
; 10000 13 seconds
; 5000 3.8
; 2000 1.1
; 1000 0.8
.data?
ptrSomeStruct SomeStruct 1000 dup(<?>)
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 (http://msdn.microsoft.com/en-us/library/aa366887%28VS.85%29.aspx)
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
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.
just allocate memory that is sizeof your structure. then take the pointer and ASSUME it as a pointer to your structure
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.
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
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...
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
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.
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
* 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.
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
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.
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
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
Quote200000005h
:eek
How does 0x2 translate to 0x200000000 ???? :eek
Oh... wait... EDX
:EAX = 0x2:0x0 = 2000000000h ?
Arrghhh so I was trying to divide 200000000h by 5 ?
OMG... I'm destined to never get this. :'(
Best regards,
Astro.
sounds like you got it, to me :U
anything faster than simply doing add edi,sizeof struct to point to the next entry? even if that means making the structure larger, e.g divisiable by 16 exactly?
:dazzled:
I'll be back tomorrow to have a good read.
Best regards,
Astro.
:dazzled:
; Allocate memory for ServiceTable structure
push 8h
push 8h
push hProcHeap
call HeapAlloc
mov ServiceTable,eax
; Populate structure with data
mov ServiceTable, offset ServiceName
mov ServiceTable+4, ServiceMain
The handle to the memory stored in ServiceTable from HeapAlloc is being trashed.
After HeapAlloc call:
eax = 001429D0
00403000 00 00 14 00 00 00 00 00 .......
00403008 00 00 00 00 00 00 00 00 ........
After storing of pointer:
00403000 00 00 14 00 D0 29 14 00 ...Р).
00403008 00 00 00 00 00 00 00 00 ........
After moving offset to the string to the first dword of the memory block (I hoped) pointed to by ServiceTable:
00403000 00 00 14 00 00 10 40 00 ....@.
00403008 00 00 00 00 00 00 00 00 ........
You will see the location was trashed and over-written.
I can't see how to reference the new memory. :(
Best regards,
Astro.
first of all, HeapCreate returns a handle
INVOKE HeapCreate,NULL,dwInitialSize,dwMaximumSize
mov hHeap,eax
secondly, if you are creating a heap of only 8 bytes, you don't need a heap
but, if you DID need a heap, you now have a handle for one
after that, you need to allocate a block in the heap
INVOKE HeapAlloc,hHeap,NULL,dwBytes
mov ServiceTablePointer,eax
finally, you are still trying to access memory through an address that is stored in memory
no, no, no ! - can't do that
mov edx,ServiceTablePointer
mov [edx],offset ServiceName
mov [edx+4],offset ServiceMain
Quotefinally, you are still trying to access memory through an address that is stored in memory
no, no, no ! - can't do that
OK.
So to ensure I finally get this - memory can only *store* pointers, they can't be used directly, ever?
To be more technical, I think I'm attempting to use indirect memory addressing?
Best regards,
Astro.
call HeapAlloc
mov ServiceTable,eax
; Populate structure with data
mov edx, ServiceTable
mov [edx], offset ServiceName
mov [edx+4], offset ServiceMain
:U
Best regards,
Astro.
the problem you are having, my friend, is this:
when you define data in the data segments, you can assign a label to it and access it with that label
.data
SomeData dd 7
.code
mov eax,SomeData ;eax = 7
BUT, when you allocate memory in the heap, the assembler cannot assign labels to those addresses
because the assembler has no idea where they will be located
SO, you must use some other form of addressing to access that memory :U
OK! :thumbu
Thanks.
Best regards,
Astro.