News:

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

Lowest possible stack address

Started by jj2007, December 16, 2010, 08:01:59 PM

Previous topic - Next topic

Antariy

Quote from: jj2007 on December 18, 2010, 04:40:18 PM
Not bad, Alex, and it seems to work, but in real life the app needs to know how much stack has been assigned. Attached what I consider "foolproof" - it crashes only if you give it one more push than allowed.

Jochen, it not *seems to work* - it *work*. And this is real life app - look into big local buffer.
This method I have suggested, is only one method fastest + compatible method of calculation of further stack end. One thing which is required by macro - you should know the allocation size of the stack. If you don't specify any size, then default value (1 MB) is used.

If you want to know *the size* of the stack (i.e. when you did not know it), or if you want to know the lowest addrress without having a size, then Japheth's method is good way to go.

jj2007

Alex,

If you had bothered to look into my code, you would have discovered that it calculates the allocated stack size, instead of asking the user.

Antariy

Quote from: jj2007 on December 19, 2010, 12:03:24 AM
Alex,

If you had bothered to look into my code, you would have discovered that it calculates the allocated stack size, instead of asking the user.

No, if you will bothered to look into my code, then you will see that I ask the size of stack for *newly* created threads. The asking is needed only to prove to you that method is work :P

Main point is: I just let you to specify the size of stack which will be allocated for new thread, and I let you do this in simple and fast way for multiple threads, insted of changing LINKers switch.

I tried to make it just as conveniece, but you did not understand this :(

Antariy

P.S. SizeOfStackReserve is applied only for main thread of the program. Or for newly created threads with zero specified as stack size.
But usually, threads created with specified stack size, and which is smaller than 1 MB. Because some "handy" background threads without GUI etc can work fine with small stack size.

Code which Japheth was posted is perfect to get the stack size for current thread at runtime. Even if you do not know which size of the thread is (for example if you determine this in code which is can be called from anything thread with anything stack size).
By the way, I usually use VirtualQuery in SEH to get the name of module which was crashed. Get AllocationBase, and pass it as handle to GetModuleFileName.

jj2007

Alex,
If I double the stack size with an add ecx, ecx as below, the thread still performs the # of iterations that corresponds to the stack size entered by the user. Which implies that you pass the stack size twice. Well hidden :U

Quote
add ecx, ecx   ; requested stack size doubled
invoke CreateThread,0,ecx,offset TheThread,edx,0,esp

Your macro relies on the second para:
AxGetStackBottom MACRO thereg:REQ, theallocationsize
ASSUME fs:NOTHING
mov thereg, fs:[4]
ifdif <theallocationsize>,<>
sub thereg,theallocationsize
add thereg,1024*32
else
sub thereg,(1024*1024-(1024*32))
endif
ASSUME fs:ERROR
EXITM<thereg>
ENDM


In contrast, my code gets the reserved size independently of linker settings and/or extra paras passed by the user.

Antariy

Quote from: jj2007 on December 19, 2010, 12:42:37 AM
Alex,
If I double the stack size with an add ecx, ecx as below, the thread still performs the # of iterations that corresponds to the stack size entered by the user. Which implies that you pass the stack size twice. Well hidden :U

Quote
add ecx, ecx   ; requested stack size doubled
invoke CreateThread,0,ecx,offset TheThread,edx,0,esp

Your macro relies on the second para:
AxGetStackBottom MACRO thereg:REQ, theallocationsize
ASSUME fs:NOTHING
mov thereg, fs:[4]
ifdif <theallocationsize>,<>
sub thereg,theallocationsize
add thereg,1024*32
else
sub thereg,(1024*1024-(1024*32))
endif
ASSUME fs:ERROR
EXITM<thereg>
ENDM


In contrast, my code gets the reserved size independently of linker settings and/or extra paras passed by the user.

I'm not hide that. I just load ECX from the place, *where* is located size of stack which would be used in the RecursiveFunction. I just construct dynamical structure on the stack.

Your method would not work for threads which created with different size of the stack. If you did not believe, then try to determine stack size with your method, and use it in the thread created as that:

invoke CreateThread,0,262144,offset TheThread,0,0,offset dwThrId


In "TheThread" proc run the recursive function.
You will fastly found that you have 4 times stack smaller that your method was "calculated".

Only one compatible way to get stack size of anything thread at runtime, is VirtualQuery.

jj2007

Quote from: Antariy on December 19, 2010, 12:55:29 AMYour method would not work for threads which created with different size of the stack.
Yes, that's correct.

QuoteOnly one compatible way to get stack size of anything thread at runtime, is VirtualQuery.

How would you do that?
typedef struct _MEMORY_BASIC_INFORMATION {
  PVOID  BaseAddress;
  PVOID  AllocationBase;
  DWORD  AllocationProtect;
  SIZE_T RegionSize;
  DWORD  State;
  DWORD  Protect;
  DWORD  Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

Antariy

Quote from: jj2007 on December 19, 2010, 12:42:37 AM
Alex,
If I double the stack size with an add ecx, ecx as below, the thread still performs the # of iterations that corresponds to the stack size entered by the user. Which implies that you pass the stack size twice. Well hidden :U

1. Code have comments at that part. So, if you did not tried to read my cyrillic English...
Stack size are placed at stack-dynamically-constructed object. If you want to have specify wrong size twice bigger, you should not only increase ECX, but "inform" and constucted object (structure).

Now:

mov ecx,[esp] ; thread stack size a second parameter of the structure


Your "trick"

mov ecx,[esp]
add ecx,ecx
mov [esp],ecx


2. Now I understand that I've made right decision to NOT post code of AxMsgTableViewer.
In AxMsgTableViewer I have written code of such style...  So, it is right that I not post it, the stake is not go away from the world yet.

If you want, I'll post one part of the AxMsgTableViewer. The nice-buttons code, which draws the icon on the button. Icon is interact with a button - it is sunken when you press a button.
I'll post this part only if you will ask, and only for showing that I've not tried to hide anything in the TestStack program. This is just a style.

3. Japhet's code with small changement.

local mbi:MEMORY_BASIC_INFORMATION
invoke VirtualQuery, addr mbi, addr mbi, sizeof MEMORY_BASIC_INFORMATION
               mov eax,mbi.AllocationBase ; in EAX - the hard end of the stack. "Soft" end is ~12 KB upper
               mov ecx,fs:[4] ; get top of the stack
               sub ecx,eax ; now in ECX the size of the stack


And only this code would work even on Win95, and would work in anything environment. If your code work in the thread which created not by you, if your code is work in the DLL which is called by unknown code, etc.

Antariy

Quote from: jj2007 on December 19, 2010, 01:17:27 AM
How would you do that?

Above is post which I have long written, and you post before I have posted.

Code which prints the size of the stack. Independedly from where it would be called, and in which thread.


include \masm32\include\masm32rt.inc

.code

start proc

local mbi:MEMORY_BASIC_INFORMATION
invoke VirtualQuery, addr mbi, addr mbi, sizeof MEMORY_BASIC_INFORMATION
                mov eax,mbi.AllocationBase ; in EAX - the hard end of the stack. "Soft" end is ~12 KB upper
                assume fs:nothing
                mov ecx,fs:[4] ; get top of the stack
                sub ecx,eax ; now in ECX the size of the stack

invoke crt_printf,CTXT("The size of the stack: %u",10,10),ecx

invoke crt_printf,CTXT("Find and press [Any] key to exit..."),esi
invoke crt__getch

ret

start endp

end start



jj2007

OK, great :U
So for threads, VQ is the only way to get the reserved size. For the ordinary exe, the GetModuleHandle plus IMAGE_NT_HEADERS will do the job, it is slightly shorter.
:thumbu

Antariy

Quote from: jj2007 on December 19, 2010, 01:38:21 AM
OK, great :U
So for threads, VQ is the only way to get the reserved size. For the ordinary exe, the GetModuleHandle plus IMAGE_NT_HEADERS will do the job, it is slightly shorter.
:thumbu

Yes, info from PE header is applied for only the main thread of the program (i.e. thread which starts in program's entry point, usually "start:" label).
For any new threads used or value specified by user, or value of size of the main thread stack (if zero is specified).
But in re-usable code for general purpose that's not reliable to rely on the anything assumptions - is better to just calculate it in runtime. :thumbu

Antariy

Now I'm suggest to make a great banquet for a case of solving these debates :bg

Who is voting for?

jj2007

Quote from: Antariy on December 19, 2010, 01:46:56 AM
Now I'm suggest to make a great banquet for a case of solving these debates :bg

Who is voting for?

:U