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

jj2007

Following a heated debate on the virtues of recursion, here a snippet showing that the lowest possible stack address is 33000h, at least on Windows XP:

include \masm32\include\masm32rt.inc

.code
start:
xor ecx, ecx
mov ebx, esp
.Repeat
push eax
add ecx, 4
.Until esp<=33000h ; decimal 208896
mov esi, esp
mov esp, ebx
print hex$(ecx), 9, " bytes of stack available", 13, 10
inkey hex$(esi), 9, " lowest possible stack without crashing"
exit
end start


Try replacing esp<=33000h with esp<33000h...

Now my question: I have googled a lot for this 33000h limit, as it would be the ideal way to test a recursion limit, but I found practically nothing. It seems not to be documented anywhere. Does somebody have insider knowledge?

redskull

When you get down that low, the kernel probably has parts of it reserved for whatever, so you are crashing into whatever's already there.  You've piqued my curiosity, so i'll look into further when I have some time.

However, you can easily get around this limit via a linker switch; try the same thing with /STACK:1000000000, and it will put the stack way up high in memory where it can grow as needed (or, at least until it crashes into your code at the other end)

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

redskull

Yah, there's defentily something there; 3 pages ranging from 30000 to 33000, of "shareable" memory.  It has some unicode strings in it, with some side-by-side assembly stuff, networking stuff, GDI+... defenitly O/S crap.

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

BogdanOntanu

The correct question is not "how low can you go with the stack address" :D

The correct questions are:
a) how big you can go with the stack size if you need it for recursion
b) how small you can go with the stack size if you want to have many many threads each with it's own stack space

Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

jj2007

Quote from: redskull on December 16, 2010, 08:23:32 PM
However, you can easily get around this limit via a linker switch; try the same thing with /STACK:1000000000, and it will put the stack way up high in memory where it can grow as needed (or, at least until it crashes into your code at the other end)
Interesting idea. The 'high' stack will be reserved, not committed, so there should be no speed penalty.

Quote from: redskull on December 16, 2010, 08:34:32 PM
Yah, there's defentily something there; 3 pages ranging from 30000 to 33000, of "shareable" memory.  It has some unicode strings in it, with some side-by-side assembly stuff, networking stuff, GDI+... defenitly O/S crap.

Can't see that with Olly - how did you see this memory range?
mov esi, esp ; 33000h
mov esp, ebx
mov eax, [esi] ; OK
mov eax, [esi-4] ; stack overflow exception


@Bogdan: Think about some more intelligent questions, always appreciated :U

redskull

I'm thinking it's the page table directory, but that's only a gut feeling.  I'll have to look at it more later.

Also, yes, the first number is the reserved, which is allocated page by page as you access it; technically you get get a speed penalty once every 1024 pushes, instead of one big one all up front, but if you prefer the latter you can specify to commit the whole thing at once via the same linker switch.  But either way, the stack should grow until it hits something else.  When i reserved a gig, the stack got put all the way at 3BDBE000!

In Olly, under the memory page, the third line, the range at 00030000; i just double clicked the line.  But you should be able to just dump the same range any which way you choose

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

jj2007

Quote from: redskull on December 16, 2010, 09:00:49 PMIn Olly, under the memory page, the third line, the range at 00030000; i just double clicked the line.

Thanks. For others who read this post: Click View, Memory Map, then double-click the desired range. For example, 20000h yields this:
Dump - 00020000..00020FFF
Address   Hex dump     Decoded data             Comments
00020000  Ú.  00100000 dd 00001000              ; MaximumLength = 4096.
00020004  ³.  80070000 dd 00000780              ; Length = 1920.
00020008  ³.  01000000 dd 00000001              ; Flags = 1
0002000C  ³.  00000000 dd 00000000              ; DebugFlags = 0
00020010  ³.  02006711 dd 11670002              ; ConsoleHandle = 11670002
00020014  ³.  00000000 dd 00000000              ; ConsoleFlags = 0
00020018  ³.  03000000 dd 00000003              ; StdInputHandle = 00000003
0002001C  ³.  07000000 dd 00000007              ; StdOutputHandle = 00000007
00020020  ³.  0B000000 dd 0000000B              ; StdErrorHandle = 0000000B
00020024  ³.  2600     dw 26                    ; CurrentDir_Size = 38.
00020026  ³.  0802     dw 208                   ; CurrentDir_Maxsize = 520.
00020028  ³.  90020200 dd 00020290              ; CurrentDir = "D:\masm32\RichMasm\"
0002002C  ³.  0C000000 dd 0000000C              ; CurrentDirectoryHandle = 0000000C


Still, I'd like to see an official Microsoft documentation saying "tell your app to stop when esp falls below 33000h". It's exciting to see this stuff, but it's called "undocumented behaviour" :bg

Unless you consider this May 1996 "Under the Hood" article on the Thread Information Block an official Microsoft documentation.

hutch--

 :bg

There is another wildcard on the way, later OS designs randomises the stack address to decrease the viability of stack exploits. If you need much more stack room for recursive algos, set it with the linker and code a recursion depth limiter.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

I am trying to imagine how "randomising" the stack address would work in this context. By default, an app has 1MB of stack. A randomised version would add a multiple of DWORD to that, in order to confuse exploiters. The question is whether the lowest possible address, 33000h, would also change...

Win XP SP3:
0012FFC4         stack on entry
000FCFC4         bytes of stack available
00033000         lowest possible stack without crashing
0000303C         difference to 1 MB


include \masm32\include\masm32rt.inc

.code
start:
mov ebx, esp
print hex$(ebx), 9, " stack on entry", 13, 10
xor edi, edi
.Repeat
push eax
add edi, 4
.Until esp<=33000h ; decimal 208896
xchg esp, ebx
print hex$(edi), 9, " bytes of stack available", 13, 10
print hex$(ebx), 9, " lowest possible stack without crashing", 13, 10
mov eax, 100000h ; 1 MB
sub eax, edi
inkey hex$(eax), 9, " difference to 1 MB"
exit
end start

Antariy

Quote from: jj2007 on December 17, 2010, 01:23:08 AM
Win XP SP3:

Also add:

mov eax,fs:[4] ; the top of the stack
add eax,-(1024*1024) ; or value which you pass to the linker
; in EAX - lowest possible address lower than stack doesn't exist
mov eax,fs:[8] ; the current end of the stack (page granularity)


Have a look into second line of the snippet - there is a way to determine "the end" of the stack of the thread. You should substract the value of the stack size (reserved) which you specify to the linker for the main thread.
For the newly created threads, you should specify the same value as for main thread, OR value which you pass (if do) to the CreateThread.

jj2007


Antariy

Quote from: jj2007 on December 17, 2010, 01:36:44 AM
Quote from: Antariy on December 17, 2010, 01:28:13 AM
Quote from: jj2007 on December 17, 2010, 01:23:08 AM
Win XP SP3:

Also add:

mov eax,fs:[4] ; the top of the stack


error A2108:use of register assumed to ERROR




assume fs:nothing

... do anything...

assume fs:error




Also I have made addition in original post - have a look into it.

jj2007

Yes I looked but your assumption is incompatible with my test results.

0012FFC4         stack on entry
000FCFC4         bytes of stack available
00130000         top of the stack
00033000         lowest possible stack without crashing
0000303C         difference to 1 MB


My theory is that there are guard pages above 33000h; they are committed until esp hits 33000h minus -1, in which latter case the exception handler says stop. The question is, I repeat, whether the 33000h changes for randomising Windows versions.

Antariy

Quote from: jj2007 on December 17, 2010, 01:44:28 AM
Yes I looked but your assumption is incompatible with my test results.

0012FFC4         stack on entry
000FCFC4         bytes of stack available
00130000         top of the stack
00033000         lowest possible stack without crashing
0000303C         difference to 1 MB


Can you post total code?

Antariy

Quote from: jj2007 on December 17, 2010, 01:44:28 AM
My theory is that there are guard pages above 33000h; they are committed until esp hits 33000h minus -1, in which latter case the exception handler says stop. The question is, I repeat, whether the 33000h changes for randomising Windows versions.

Last guard page worked as flag to raise "stack overflow" exception.
Post total code, please, at this moment I'm far from writing anything.