flat assembler
Message board for the users of flat assembler.

Index > Windows > getting stack size function problem :(

Author
Thread Post new topic Reply to topic
mns



Joined: 20 Dec 2007
Posts: 155
Location: Piliyandala,Sri lanka
mns 25 Sep 2025, 14:22
Can someone please help me?
I have written function to get stack size as below, first it checks 'GetCurrentThreadStackLimits' api is available in current windows version("kernel32.dll") or not, if not it uses fs registers to get values.
In windows 7 it assembled but giving an error when tried to run.
Problem seems to be 'invoke GetCurrentThreadStackLimits...' part.
Is there any way to do this correctly?

Code:
;------------------------------getStackSize--------------------------------------------------
proc   getStackSize  stdcall  uses ebx esi edi
;call GetModuleHandle for "kernel32.dll" 
;Call GetProcAddress to see if GetCurrentThreadStackLimits exists.
;If not direct limits via fs register(Thread Environment Block -TEB)
;if yes call GetCurrentThreadStackLimits
          invoke              GetModuleHandle, kernel32_s
          cmp                 eax, 0
          jne                    @f
          mov                 eax, -1
          ret
          
     @@:
          invoke               GetProcAddress,eax,GetCurrentThreadStackLimits_s
          cmp                 eax,0
          je                       @f
          
          invoke              GetCurrentThreadStackLimits,StackLow,StackHigh 
          mov                      eax, 0
          ret
          
     @@:
          ;if pre windows 8 OS-------------------
          push                     dword[fs:04h] 
          pop                      [StackHigh]
          push                     dword[fs:08h]
          pop                      [StackLow]
          mov                      eax, 0
          ret
   endp
;----------------------------------------------------------------------------------------------
    
Post 25 Sep 2025, 14:22
View user's profile Send private message Send e-mail Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1735
Location: Toronto, Canada
AsmGuru62 25 Sep 2025, 16:05
It looks like you need to call a function which pointer was returned by GetProcAddress:
Code:
     @@:
          invoke               GetProcAddress,eax,GetCurrentThreadStackLimits_s
          cmp                 eax,0
          je                       @f

mov [pfn_GetLimits],eax

          invoke              pfn_GetLimits,StackLow,StackHigh 
          mov                      eax, 0
          ret
    

I was not able to test it in debugger, only part of code is provided, no variables like 'StackLow' ... etc.
Post 25 Sep 2025, 16:05
View user's profile Send private message Send e-mail Reply with quote
mns



Joined: 20 Dec 2007
Posts: 155
Location: Piliyandala,Sri lanka
mns 26 Sep 2025, 18:14
Thank you AsmGuru62 for your kind response. I have attached full .asm file.
Here I want to call my "getStackSize" function (procedure) at WM_CREATE (wmcreate in the file).
"getStackSize" will first call 'GetModuleHandle' for the "kernel32.dll", then using returned handle, program will call 'GetProcAddress' for the 'GetCurrentThreadStackLimits' (a win32 API which is available only from windows 8 )
If it is not in current "kernel32.dll" (eax=0), I will get the stack limits from FS register(which is not a reliable way for newer windows versions). if eax = not 0, that API is available, So I will call that API for the stack limits.

My problem is, in windows 7 program assembled without problem, when try to run, It gives a error saying 'The procedure entry point GetCurrentThreadStackLimits could not be located in the dynamic link library KERNEL32.DLL'
As I said earlier 'GetCurrentThreadStackLimits' API will not be called in windows 7 since GetProcAddress will return 0, so ideally this error msg should not have shown
. Confused


Description:
Download
Filename: StackLimit.ASM
Filesize: 9.23 KB
Downloaded: 24 Time(s)

Post 26 Sep 2025, 18:14
View user's profile Send private message Send e-mail Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1185
Location: Russia
macomics 26 Sep 2025, 20:21
mns wrote:
My problem is, in windows 7 program assembled without problem, when try to run, It gives a error saying 'The procedure entry point GetCurrentThreadStackLimits could not be located in the dynamic link library KERNEL32.DLL'
As I said earlier 'GetCurrentThreadStackLimits' API will not be called in windows 7 since GetProcAddress will return 0, so ideally this error msg should not have shown.

You have already been pointed out the solution to the problem.

You are currently using two import mechanisms for the GetCurrentThreadStackLimits function. Dynamic import via GetModuleHandle/GetProcAddress and static import via the name of GetCurrentThreadStackLimits function in the import section of your exe file. Dynamic import allows you to check for a function in the library and call it if necessary, but static import does not. Due to the static import of this function, your error occurs when loading the exe into memory on Windows 7.

As mentioned above (AsmGuru62), you just need to call the function using the pointer obtained from GetProcAddress instead of calling it by name.

Code:
.data
myGetCurrentThreadStackLimits dd ?
.code
;------------------------------getStackSize--------------------------------------------------
proc   getStackSize  stdcall  uses ebx esi edi
;call GetModuleHandle for "kernel32.dll" 
;Call GetProcAddress to see if GetCurrentThreadStackLimits exists.
;If not direct limits via fs register(Thread Environment Block -TEB)
;if yes call GetCurrentThreadStackLimits
          invoke              GetModuleHandle, kernel32_s
          cmp                 eax, 0
          jne                    @f
          mov                 eax, -1
          ret
          
     @@:
          invoke               GetProcAddress,eax,GetCurrentThreadStackLimits_s
          cmp                 eax,0
          je                       @f

          mov                 [myGetCurrentThreadStackLimits], eax
          invoke              myGetCurrentThreadStackLimits,StackLow,StackHigh 
          mov                      eax, 0
          ret
          
     @@:
          ;if pre windows 8 OS-------------------
          push                     dword[fs:04h] 
          pop                      [StackHigh]
          push                     dword[fs:08h]
          pop                      [StackLow]
          mov                      eax, 0
          ret
   endp
;----------------------------------------------------------------------------------------------    
Post 26 Sep 2025, 20:21
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4288
Location: vpcmpistri
bitRAKE 26 Sep 2025, 22:33
Code:
; Although undocumented, ALL known versions of have the exact same form:
struct NT_TIB
        ExceptionList           PTR ?   ;*EXCEPTION_REGISTRATION_RECORD
        StackBase               PTR ?   ;*VOID
        StackLimit              PTR ?   ;*VOID
        SubSystemTib            PTR ?   ;*VOID

        union
                FiberData       PTR ?   ;*VOID
                Version         dd ?    ; u32
        end union

        ArbitraryUserPointer    PTR ?   ;*VOID
        Self                    PTR ?   ;*NT_TIB
end struct

assert sizeof NT_TIB = 7 * sizeof PTR ; 28/56    
Alternately, there is no reason to call the API function as the start of the TEB/TIB structure (NT_TIB) has been exactly the same from Win 9x onward.

_________________
¯\(°_o)/¯ AI may [not] have aided with the above reply.
Post 26 Sep 2025, 22:33
View user's profile Send private message Visit poster's website Reply with quote
mns



Joined: 20 Dec 2007
Posts: 155
Location: Piliyandala,Sri lanka
mns 27 Sep 2025, 06:38
Thank you very much macomics for the response and explanation.
And bitRAKE thank you for your response too. Microsoft site says TEB/TIB structures may be altered in future versions of Windows, so doesn't recommend using them directly.("https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-teb").
Post 27 Sep 2025, 06:38
View user's profile Send private message Send e-mail Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1735
Location: Toronto, Canada
AsmGuru62 27 Sep 2025, 12:40
I am curious to know how are these values (StackHigh, StackLow) to be used in the code?
In the Remarks section for GetCurrentThreadStackLimits Microsoft mentions that this function is used
to verify if a current stack pointer is within those limits.

I find it strange, I mean, the only thing affecting stack pointer is how deep is level of your leaf functions is
and how many local variables in each function your own code is allocating.
So, your own code will define if somehow stack pointer would go out of range.

Of course, there is a case of a recursive function calls, like sorting code.
And, of course, if you are invoking Windows API, these API functions may have its own local variables.

In my opinion, the large enough stack can be defined in FASM source code.
In the posted code, there is no definition for stack.
It means that stack = 1Mb of room with 4Kb committed.

You can use the below statement to declare a good stack of 2Mb for both reserved and committed room:
Code:
format  PE GUI 4.0
entry   start
stack   200000h, 200000h   ; <--- 2Mb of stack room
    

2Mb stack should be enough for everyone! Wink
Post 27 Sep 2025, 12:40
View user's profile Send private message Send e-mail Reply with quote
mns



Joined: 20 Dec 2007
Posts: 155
Location: Piliyandala,Sri lanka
mns 01 Oct 2025, 14:14
Thank you very much AsmGuru62 (and I am sorry for the delay in response).
I am trying to make memory safe custom string concatenate function (actually created).
Output of the function(destination) always in the heap memory. First Input (address of first string) will be checked for whether it is in stack or static space or heap (for that I need heap boundaries).
For stack or static or heap(created out side function) strings, new destination will be created in the heap. For heap strings created previous call to the function, only reallocation done. Also there will be a array of memory addresses created by the function. which will be used to free everything when program closes. If you are interested I can share the source(mind you I am not a professional or advance programmer so there will be lot of errors, but it works).
Thank you.
Post 01 Oct 2025, 14:14
View user's profile Send private message Send e-mail Reply with quote
Core i7



Joined: 14 Nov 2024
Posts: 135
Location: Socket on motherboard
Core i7 01 Oct 2025, 17:04
I once analyzed the Windows stack and found the following data.
By default, the system allocates 8 KB of stack space, after which a PAGE_GUARD exception occurs, and the system allocates another 4 KB page. This continues until a STACK_OVERFLOW exception is thrown, which means the limit is finally reached. At this point, the system kills the application without warning. On my Windows 7, I get a limit of not 1 MB, but only 256 KB, or 64 pages. This is easy to verify by setting your SEH handler to STACK_OVERFLOW=0xC00000FD. Here's an example I tested on Win7 x32, although it can be adapted for Win10 x64:

Code:
format   pe console
include 'win32ax.inc'
entry    start
;stack    200000h, 200000h
;//-------
.data
capt    db  13,10,' STACK OVER-FLOW v0.1'
        db  13,10,' ********************'
        db  13,10,' Stack Base: 0x%X'   ,10
        db  13,10,' Allocate    Address'
        db  13,10,' -------------------',0
limit   db  13,10,' Page: %02d    0x%X' ,0
over    db  13,10,' ------------------------------'
        db  13,10,' == Exception Stack_OverFlow =='
        db  13,10,' System stack reserve = %d Kb',0

count   dd  0                     ;// PageGuard alloc counter
frmt    db  '%s',0
buff    db  0
;//-------
.code
start:
;// Set SEH to 'StackOverflow'
        push    @trap
        push    dword[fs:0]
        mov     [fs:0],esp

        mov     eax,[fs:04]       ;// EAX = TEB --> StackBase
       cinvoke  printf,capt,eax

;// Main ======================
        mov     eax,[fs:08]       ;// EAX = TEB --> StackLimit
@cycle: push    'DEAD'            ;// fill stack
        cmp     [fs:08],eax
        je      @cycle

        mov     ebp,esp           ;// PAGE_GUARD exception
        add     ebp,4
        inc     [count]
       cinvoke  printf,limit,[count],ebp
        mov     eax,[fs:08]       ;// EAX = new limit
        jmp     @cycle            ;// wait 'StackOverflow'
;//=============================
@exit: cinvoke  _getch
       cinvoke  exit,0

;//=== 'StackOverflow' handler
@trap:  mov     esi,[esp+12]      ;// ESI = CONTEXT struct
        mov     eax,@exit
        mov    [esi+0xb8],eax     ;// 0xb8 = change EIP!

        mov     eax,[count]
        mov     ebx,4096          ;// EBX = Page size
        mul     ebx               ;// EAX = Alloc size
        add     eax,4096*2        ;// add COMMIT page
        shr     eax,10            ;// Byte to Mbyte
       cinvoke  printf,over,eax
        xor     eax,eax
        ret
;//-------
section '.idata' import data readable
library  msvcrt,'msvcrt.dll'
import   msvcrt, printf,'printf',_getch,'_getch',exit,'exit'    
Post 01 Oct 2025, 17:04
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4288
Location: vpcmpistri
bitRAKE 02 Oct 2025, 05:40
msvcrt.dll has it's own exception handlers and a stack overflow has the stack in a damaged state (no guard page). See SetThreadStackGuarantee.

One way to get MSVCRT to stay out the way is just to touch the stack. This will repair the stack and report the correct size (minus the guard page). It's important to note that the overflow exception happens before the last page - to insure the overflow guarantee is met. Another major note would be that potentially no guard page exists if commit/reserve are the same!
Code:
format   pe console
include 'win32ax.inc'
entry    start

;stack    0x40000, 0x40000 ; results in 1MB reserve
;stack    0x10_0000, 0x10_0000 ; results guard page!
; Note: potentially no guard page if commit/reserve are the same.
stack    0x20_0000, 0x20_0000 ; results in no guard page!

.data
capt    db  13,10,' STACK OVER-FLOW v0.2'
        db  13,10,' ********************'
        db  13,10,' Base: 0x%X',10
        db  13,10,' Allocate    Address'
        db  13,10,' -------------------',0
limit   db  13,10,' Page: %02d    0x%X' ,0
over    db  13,10,' ------------------------------'
        db  13,10,' == Exception Stack_OverFlow =='
        db  13,10,' System stack reserve = %d Kb',0

under   db  13,10,' == Exception Access Violation =='
        db  13,10,' System stack = %d Kb',0

count   dd  0

; We touch the stack without modify ESP to insure MSVCRT functions always have
; sufficent stack.

.code
start:
        cinvoke  printf,capt,[fs:04]

        push    stack_handler
        push    [fs:0]
        mov     [fs:0], esp

@outer: mov     eax,[fs:08]
        or      ecx, -1

@cycle: test    byte[eax+ecx], -1
        dec     ecx
        cmp     [fs:08], eax
        je      @cycle

        inc     [count]
        cinvoke printf,limit,[count],[fs:08]
        jmp     @outer

@exit1: lea     ecx, [under]

        mov     eax, [fs:04]
        sub     eax, [fs:08]
        jmp     @F

@exit0: lea     ecx, [over]

        pop     [fs:0]
        pop     eax
        imul    eax, [count], 4096
@@:
        shr     eax, 10
        cinvoke  printf,ecx,eax

        cinvoke  _getch
        cinvoke  exit,0



stack_handler:
        mov eax, [esp+4]                ; EXCEPTION_RECORD*
        mov ecx, [esp+12]               ; CONTEXT*

        cmp dword [eax], 0xC0000005     ; EXCEPTION_ACCESS_VIOLATION
        jz .vila
        cmp dword [eax], 0xC00000FD     ; EXCEPTION_STACK_OVERFLOW
        jz .ovfl
@@:     mov eax, 1                      ; EXCEPTION_CONTINUE_SEARCH
        retn

; An access violation can occur below the stack bottom if there is no guard
; page. The loader doesn't create the guard page in some cases. *RARE*

.vila:  cmp dword [ecx+0xB8], @cycle
        jnz @B
        mov dword [ecx+0xB8], @exit1
        xor eax, eax                    ; EXCEPTION_CONTINUE_EXECUTION
        retn

.ovfl:  cmp dword [ecx+0xB8], @cycle
        jnz @F
        mov dword [ecx+0xB8], @exit0

@@:     call [_resetstkoflw]

        xor eax, eax                    ; EXCEPTION_CONTINUE_EXECUTION
        retn


section '.idata' import data readable
library msvcrt,'msvcrt.dll'
import  msvcrt,\
        _getch,'_getch',\
        _resetstkoflw,'_resetstkoflw',\
        exit,'exit',\
        printf,'printf'    
Edit: fixed code to cover all weird cases locally.


Last edited by bitRAKE on 02 Oct 2025, 19:27; edited 1 time in total
Post 02 Oct 2025, 05:40
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1735
Location: Toronto, Canada
AsmGuru62 02 Oct 2025, 15:45
mns, thanks for the explanation.
So, you are building a kind of string library, where text can be stored, concatenated, etc.
I once did that, but all strings were on heap.
When a new string was created, it was allocated in 64 characters pieces, so there was room for concatenation.
Say, you need to make a new string "HELLO", you will get 64 characters on heap and then copy "HELLO" into it.
In case, you wish to append ", WORLD!" to it --- there will be no re-allocation.
I did not use stack, however, I think it is an unnecessary complication.
Every one of my strings were represented by the structure:
Code:
struct TString
    Length      dw ?    ; # of UNICODE characters until 0x0000 is placed
    Room        dw ?    ; # of UNICODE characters after 'Flags' (including 0x0000)
    Flags       dw ?    ; Some bits on what type of string is it
    ;
    ; UNICODE buffer follows here...
    ;
ends
    

I could access the text buffer with a simple macro:
Code:
macro StrGetBuf r32_TextBuf, r32_TString
{
    lea     r32_TextBuf, [r32_TString + sizeof.TString]
}
    

To concatenate two TString objects --- fast operation if no re-allocation needed.
Because both lengths are known, no need to count characters until 0x0000.
Post 02 Oct 2025, 15:45
View user's profile Send private message Send e-mail Reply with quote
mns



Joined: 20 Dec 2007
Posts: 155
Location: Piliyandala,Sri lanka
mns 04 Oct 2025, 09:20
AsmGuru62 Thank you very much for the valuable Insight.
Post 04 Oct 2025, 09:20
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.