Page 1 of 1

2 questions acout hardware stack

Posted: Thu Feb 03, 2011 3:26 pm
by a5498828
1. When i pass arguments on stack to a function, wich contain values i use as counters for loops, whats better, copy them, or modify directly on stack?
I ask this questions, because i dont want to break anything used for debugging, i know how painfull it is to have to copy stack of function before calling it because it modify it.



2. When allocation memory on stack, should i use enter instruction (wich is missing in 8086), rep stos (wich is avaiable on all cpus, and dword version is avaiable on all cpus supporting pmode), or sub sp,X (wich might defeat purpose of guard page if i use too big value).

Re: 2 questions acout hardware stack

Posted: Thu Feb 03, 2011 4:51 pm
by Combuster
1: Arguments on the stack may normally be changed by the called procedure. local variables may not. Obviously, make backups where necessary.

2: rep stos* is only useful when you want to memset a local array. If you need to probe a stack to trigger guard pages, use page-size increments. Using push ebp; mov ebp, esp; sub esp, ...; is faster than using the microcoded ENTER instruction.

Also, guard pages and having a 8086 are mutually exclusive. Why do you need to consider both?

Re: 2 questions acout hardware stack

Posted: Thu Feb 03, 2011 4:55 pm
by Tosi
This belongs in the General Programming forum, but I'll answer it here and then this will all get moved with it.

1. To pass arguments to a function, you push them on the stack in some predefined order and then the function you call knows which order they were pushed. As for local variables, they are allocated on the stack, but in a different manner (using a base pointer) such that it is possible to clean up the stack at the end of a function without knowing how much was allocated.

There are two main ways of cleaning the stack up when returning from a function, C calling convention and PASCAL calling convention. In both of these conventions, arguments are passed from right to left*. There are others as well.
A function declared with C convention looks like this:

Code: Select all

; void some_function(int val)
some_function:
     push ebp
     mov ebp, esp      ; Create a stack frame
     sub esp, 4          ; Allocate a single int-sized local variable
     ; Do things with the variable here
     mov esp, ebp      ; Restore the old ESP
     pop ebp             ; Restore the old EBP
     ret
And it is called like this:

Code: Select all

     push some_value
     call some_function
     add esp, 4          ; The caller is responsible for cleaning up pushed parameters
In PASCAL convention, however, the function cleans up the stack:

Code: Select all

; int PASCAL some_other_function(int val)
some_other_function:
      push ebp
      mov ebp, esp     ; Uses the same kind of stack frame as C
      ; Do something
      mov esp, ebp
      pop ebp
      ret 4                 ; This adjusts ESP so the pushed argument is considered popped
And you call it like this:

Code: Select all

     push some_other_value
     call some_other_function
     ; Stack is cleaned up for us, don't have to do anything.
2. I would use sub sp, xxx. rep stos has nothing to do with setting up a stack frame, and it doesn't even affect ESP. I think you can still use the bound instruction to make sure your stack isn't broken, even if you didn't use enter.

* PASCAL might have been originally the other way around but Microsoft changed it?

Re: 2 questions acout hardware stack

Posted: Thu Feb 03, 2011 6:38 pm
by quok
Aaaand, moved to the General Programming sub-forum.

Re: 2 questions acout hardware stack

Posted: Fri Feb 04, 2011 2:20 am
by qw
Tosi wrote:* PASCAL might have been originally the other way around but Microsoft changed it?
In the C and STDCALL calling conventions, arguments are pushed from right to left. In the PASCAL calling convention they are pushed from left to right.

In the PASCAL and STDCALL calling conventions, the stack is restored by the called function. In the C calling convention it is restored by the calling function.

There are some differences between systems. Agner Fog maintains a very good document about it: http://www.agner.org/optimize/calling_conventions.pdf.

Re: 2 questions acout hardware stack

Posted: Fri Feb 04, 2011 9:19 am
by a5498828
If you need to probe a stack to trigger guard pages, use page-size increments.
How do i know the page size? If i want to write code easly portable between paged and nonpaged mode, page size is 0. Page size might be also 4kb, 4mb, 2mb, 1gb.
I can of course assume 4096, but what if newest cpu would support smaller pages? Can intel/amd guarantee me that if i use max sub sp,4094 i wont skip entire page?

Re: 2 questions acout hardware stack

Posted: Fri Feb 04, 2011 4:15 pm
by Tosi
What I meant is that I've seen some functions in older Windows code that are declared PASCAL but the arguments are pushed in the order of STDCALL.
How do i know the page size? If i want to write code easly portable between paged and nonpaged mode, page size is 0. Page size might be also 4kb, 4mb, 2mb, 1gb.
I can of course assume 4096, but what if newest cpu would support smaller pages? Can intel/amd guarantee me that if i use max sub sp,4094 i wont skip entire page?
Use CPUID or some similar functionality to figure out which paging extensions the CPU supports. If it doesn't support CPUID at all then it's probably good to stick with only 4kb pages.

Re: 2 questions acout hardware stack

Posted: Fri Feb 04, 2011 4:39 pm
by Combuster
a5498828 wrote:
If you need to probe a stack to trigger guard pages, use page-size increments.
How do i know the page size? If i want to write code easly portable between paged and nonpaged mode, page size is 0. Page size might be also 4kb, 4mb, 2mb, 1gb.
I can of course assume 4096, but what if newest cpu would support smaller pages? Can intel/amd guarantee me that if i use max sub sp,4094 i wont skip entire page?
Is this an exercise in pendacy, because I think the is entire problem is moot - if you want portable code, use C. If you disagree and want portable code, do not allocate large structures on the stack. If you want fast code, use per-platform conditionals.

In your exceptional case, I recommend not using the stack :roll:

Re: 2 questions acout hardware stack

Posted: Fri Feb 04, 2011 9:00 pm
by a5498828
In your exceptional case, I recommend not using the stack
Ok, lets say i want to create extensive function, wich make use of many temporary values.
The only thing i can think of is using stack with push/pop instructions, storing temporary data on stack. For example, when making a loop store its counter on stack, load it only for tests/changes. What is i have multiple data, and want to access oldest? i have to pop everything, or address a stack.
For example, i can divide my function into sub functions each diffrent from the other by its own stack frame. When nesting another function i need to push bp and store current sp in bp in order to address stack in predictable manner. I could also place after bp previous bp, or even multiple bps to allow accessing higher stack frames. I belive its what enter instruction does. I only imagine how hard would be to manage the code then, must have keep track of every single item on stack, when removing position i would have to alter others, ehh... But i think its the only way to avoid 'push ax' multiple times.

Re: 2 questions acout hardware stack

Posted: Sat Feb 05, 2011 9:25 am
by Tosi
If you have a function which calls another function which calls another function and so on, you don't have to worry about cleaning up the stack when you are done in each function. The prologue, which sets up the stack frame, and the epilogue, which restores the old ESP value, do that for you. Also, local variables are only necessary if you run out of registers, which can happen easily in 32-bit assembly, or if you need some kind of array or structure that doesn't fit into a single 32-bit register. The stack frame makes it easy to access local variables once you have it set up.

Here is a skeleton for a function that uses a single local variable of DWORD size:

Code: Select all

local_variable_function:
    push ebp
    mov ebp, esp           ; Set up stack frame
    sub esp, 4               ; Allocate 4 bytes for local memory
    ; Do something that uses all the registers here
    ...
    mov [ebp - 4], eax   ; Store the value in eax in the local variable
    ...
    mov eax, [ebp - 4]   ; Restore the local variable
    ...
    mov esp, ebp          ; This restores the old ESP since EBP isn't modified
    pop ebp
    ret
If you still don't understand about stack frames and local variables in assembly, I would recommend learning more while sticking to a higher-level language like C In the interim.

Re: 2 questions acout hardware stack

Posted: Tue Feb 08, 2011 8:00 am
by qw
Tosi wrote:What I meant is that I've seen some functions in older Windows code that are declared PASCAL but the arguments are pushed in the order of STDCALL.
Functions for Win16 programs were declared PASCAL. In the Win32 headers, the PASCAL macro is defined as __stdcall so existing code needed less or no modification.

Re: 2 questions acout hardware stack

Posted: Tue Feb 08, 2011 8:44 am
by Tosi
Oh, I never programmed 16-bit windows so I didn't know that.
I can't help but feel some sense of respect for Intel and Microsoft for maintaining backwards compatibility for so long, even if it is only for outdated software.

Re: 2 questions acout hardware stack

Posted: Tue Feb 08, 2011 2:36 pm
by qw
Tosi wrote:I can't help but feel some sense of respect for Intel and Microsoft for maintaining backwards compatibility for so long, even if it is only for outdated software.
Some forum members would say they don't feel any respect, for the very same reasons...

Re: 2 questions acout hardware stack

Posted: Tue Feb 08, 2011 4:13 pm
by Tosi
I don't want to be put into a position where I have to defend Microsoft, so I will retroactively make that last post sarcastic.
And I'm getting off topic.