hi, newbie here,

Q1: yesterday I finished my small project which included loading certain amout of bytes from file into a memory with help of GlobalAlloc and it worked fine but later I found code snippet where space in memory for exact same purpose is defined with "db 1024 dup(?)"

What is the difference ? Is there any advantage using it one way instead of another?

Q2: In the same code snippet is MessageBox defined but first paramater is set to 0 ie. there is no owner window. Is it better or more efficient? Is there any good reason why the owner handle should be set ?  What's the difference?

Posted on 2007-10-21 04:05:08 by Aeon
db means "define bytes".
You are including a block of 1024 bytes in your exe.
If you allocate it at runtime, you save 1kb in your exe.
This might not seem important now, but just take note.
Wouldn't you rather define a 4-byte pointer in your exe?
hmmz, 4 bytes plus some code, versus 1024 bytes and no code.
Decisions, decisions :)
I am pro-choice.. can you tell?

Actually, 1kb is a funny size to choose for a program running on windows.
It makes a lot more sense to choose 4kb, which is the memory paging granularity.
Furthermore, I am going to suggest you find out about HeapAlloc.
It's cooler than GlobalAlloc, except for HUGE allocations.

Did that sound complicated?
It doesn't have to.
Ask pointed questions, get golden answers.

Windows defines a special meaning for a window handle of NULL = DESKTOP HANDLE.
Its defined as HWND_DESKTOP equ 0
It means the window is literally "a child of the Desktop window".

Posted on 2007-10-21 08:38:29 by Homer
but 1024 bytes block is defined in .data? section therefore does not increase exe size

ok, desktop is the owner of messagebox ,when I use it like that, with zero handle, may it cause some problems or it's perfectly ok ?
Posted on 2007-10-21 09:58:24 by Aeon

but 1024 bytes block is defined in .data? section therefore does not increase exe size


MASM has a funny way of calling uninitialized data as .data? instead of .bss, in which .bss is actually defined in the PE specification itself... go figure :P

At any rate, declaring extra uninitialized data in your program does not bloat the exe in the least since it is allocated at runtime by Windows in the same manner as you would GlobalAlloc it.


ok, desktop is the owner of messagebox ,when I use it like that, with zero handle, may it cause some problems or it's perfectly ok ?


If it wasn't, many of our MessageBox-only examples would be in trouble ;)
Posted on 2007-10-21 10:54:42 by SpooK
The big difference is the way you address the data in the block.

-----

Let's assume your .data? declaration names the block as MemBlock.

You can then access each byte as MemBlock, where register ECX contains the byte position.

-----

If you use GlobalAlloc, the block is unnamed. You store the start (also known as base) address in a DWORD -- let's call it pMemBlock (for pointer to MemBlock).

You now need a preparation step to access a byte in the block. In the following code, assume that ECX already contains the byte position you want.

mov edx,pMemBlock ; get base address
mov al,byte ptr ; get byte
inc al
mov byte ptr,al ; store byte

You can still create a "walking" pointer...

mov eax,pMemBlock ; get base address
lea edx, ; get start position
mov ecx,100 ; set up number of bytes to clear

clear_loop:
mov byte ptr ,0 ; clear MemBlock byte
inc edx ; next MemBlock byte
dec ecx ; count down
jnz clear_loop
Posted on 2007-10-21 10:58:13 by tenkey

but 1024 bytes block is defined in .data? section therefore does not increase exe size
that is correct. memory is allocated in virtual memory of ".data" section (hence the name ".data?")
Posted on 2007-10-21 12:03:08 by drizz
What is the difference ? Is there any advantage using it one way instead of another?
The difference is run-time decisions verses assemble-time decisions. Some software will not know until run-time how much memory is needed. Therefor, there is no way to know how much data to reserve in the BSS segment. For example, if your program sits dormant and only needs the space when active there is no reason to reserve memory at assemble time.

Of course, we have paging and memory mapped files to ease the situation where either technique would work and when working with small programs with little data it really doesn't matter. But if you wanted to make a multi-threaded app that checked for duplicate files on the harddrive then lots of data would need to be in memory, and the .data? section wouldn't help much because we have little idea of the quantity.

It's good to know all these levels of space are availible and how to use them.
Posted on 2007-10-21 13:21:56 by bitRAKE
SpooK, it's a bit misleading to say that .bss/.data? is "allocated at runtime by Windows in the same manner as you would GlobalAlloc it", since it's simply (in the case of non-retarded linkers ;)) added to peheader.SizeOfImage (ie, stored pas past the last section).

Local/GlobalAlloc are deprecated, and on NT end up calling HeapAlloc anyway - so use HeapAlloc. If you need huge buffers (in the megabyte range), check out VirtualAlloc.

For small buffers in the kilobyte range, use stack memory and avoid dynamic memory allocation as well as static .bss allocation - helps with thread safety, too.
Posted on 2007-10-23 03:46:40 by f0dder
I would caution against allocating large buffers on the stack (yes, 1k is large for a stack allocation)

How much stack does your program need? Do you know? Whats the worst case?

Allocating large buffers on the stack makes these questions even harder to answer. Yes, some compilers do this but they do not fail gracefully when the stack is fully consumed (leaving it up to the programmer to catch that exception and try to handle it, which in general isnt possible) You might think the answer is simply to allocate an even larger stack.. but that goes back to the question.. whats the worst case for your program? With some programs this question is trivial to answer .. with others it is extremely non-trivial.

If you only need a single copy of the buffer, it is probably best to throw it in the uninitialized data which allows windows to verify that it can indeed allocate the buffer, and to do so before even a single line of your code ever gets executed. That is failing gracefully.

Other advantages include:

"free" load-time alignment of the static uninitialized buffer
the simplified addressing that has already been mentioned in this thread
as well as much better cache usage
Posted on 2007-10-23 04:26:46 by Rockoon
1kb is a small stack allocation, unless you're deeply nesting / recursing. Allocating on the stack has the advantage that the memory is only "allocated" while needed, as opposed to a static buffer, and stack allocation frames "overlap" so the memory is "re-used". Also, since the stack is used all the time, it has excellent caching properties.

Simplified adressing doesn't matter that much imho. But on the other hand, you usually address stack through EBP+xx , if you can keep those offsets short, you have a smaller encoding (3 bytes) rather than the 5 bytes required for direct addressing. Hardly matters unless you're doing 4k intros, though :)

But sure, you need to handle alignment manually, and I do agree that if you go beyond a few kilobytes, it's better to do dynamic allocation. And if you don't care about multithreading, sure, you can go for static allocation.
Posted on 2007-10-23 04:38:00 by f0dder

1kb is a small stack allocation, unless you're deeply nesting / recursing.


What non-trivial programs do not deeply nest? :)


Also, since the stack is used all the time, it has excellent caching properties.


..untill you allocate a big buffer on it.. at which point the top of stack hasnt been used in a long time..


Simplified adressing doesn't matter that much imho. But on the other hand, you usually address stack through EBP+xx , if you can keep those offsets short, you have a smaller encoding (3 bytes) rather than the 5 bytes required for direct addressing.


The key point being that your loop counter can double as a pointer, but only with a static buffer ..

ie,

mov ecx, 1023
@@do:
mov al,
; ..process al..
dec ecx
jns @@do

a single register used to manage the looping through the buffer as well as the addressing of it

with stack or heap allocation, you've gotta use two registers .. there is really no way around it (pointer + loop counter)

With the static uninitialized buffer, you can use the single register methodology or the double register methodology .. there is no downside in regards to addressing
Posted on 2007-10-23 05:15:31 by Rockoon