I am currently reading about exploiting memory vulnerabilities under Linux and I found it hard to find any information on when the layout of stack frames is decided. In other words, is it something determined at the compile time, before the program's execution or are those built when a function is being called? Does the layout differ between operating systems?
-
possible duplicate of [What is stack frame in assembly?](http://stackoverflow.com/questions/3699283/what-is-stack-frame-in-assembly) – xmojmr Oct 19 '14 at 17:29
-
-1 for no research effort shown. Google points to http://wiki.osdev.org/Stack and http://en.wikipedia.org/wiki/Call_stack#Structure and [Intel® 64 and IA-32 Architectures Software Developer Manuals](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html) explains stack frame at several places etc. – xmojmr Oct 19 '14 at 17:38
-
3+1 to counterbalance @xmojmr. Those documents tell one the layout choices made. OP wants to know how those choices came to be, seems pretty reasonable question to me. – Ira Baxter Oct 19 '14 at 17:43
-
@IraBaxter the linked documents clearly show that in assembly language (the tag OP used) stack frame is created using `push` instructions written by programmer and compiled 1 to 1 into machine code (so stack frame layout is not determined "before program's execution" and not determined "when a function is being called" but determined when programmer writes `push` or `enter` instructions). In my opinion either OP wanted to ask different question or did not show any research effort – xmojmr Oct 19 '14 at 17:48
-
1So there are two implied questions: 1) what is the design of stack frames [what do they all have in common], and 2) what are the details (e.g., offsets) into stack frames [often determined at compile-time specific to a particular subroutine being compiled]. He seems focused on the former, and seems to understand that the latter happents. – Ira Baxter Oct 19 '14 at 18:07
3 Answers
There are several factors. On x86, there's a calling convention that defines how to call a function. I assume other architectures have similar things. The system library (e.g. glibc) can define additional conventions. But ultimately the compiler decides how it uses the stack - at least when it does not need to interface external libraries and needs to follow their stack-layout.

- 3,330
- 2
- 23
- 28
-
-
@IraBaxter OP asked about **stack frame** on **x86** from the **assembly language** perspective, not about arbitrary activation records implemented on stack modeled as linked lists as you suggest in your answer. So if question is **stack** then answer is **stack** – xmojmr Oct 19 '14 at 19:04
-
@xmojmr: he asked about things that run on x86 under Linux, in a very general way. I answered in a very general way. "There are more things in heaven and earth..." – Ira Baxter Oct 19 '14 at 19:21
-
@IraBaxter what did you mean by your "Doesn't have to be a stack" comment? – xmojmr Oct 19 '14 at 21:24
-
@xmojmr: I thought you understood my answer: the "stack frame" doesn't have to be "in a stack". Linked activation records are another way to do it. My point is there are a huge variety of ways to *design* runtime environments, and the rationale behind most isn't often written down in a place easily found. – Ira Baxter Oct 19 '14 at 21:25
-
@IraBaxter yes, some high-level languages, e.g. [Squeak](http://www.squeak.org/VirtualMachine) implement "stack frame" dynamically and stack can be a linked list of activation records. But this is **not what OP asked about**. OP's question is specifically tagged with `assembly` and `low-level` so Tim's explanation seems completely valid and your comment does not apply here and that was my point – xmojmr Oct 19 '14 at 21:35
-
@xmojmr: You don't think the byte layout of parallel activations records is low level? You don't think assembly code doesn't interface with it? I think you protest too much. Look, we disagree. OP is going to vote, let's go with that, huh? – Ira Baxter Oct 20 '14 at 00:02
I doubt you will generally or easily find an documented answer to how stack frames were designed. As others have observed, what gets documented is the result of that design process, often without a lot of associated rationale which I agree would be pretty interesting.
Each design of a stack frame layout comes from presumably people designing a compiler or a set of interoperable compilers for a particular processor architecture and maybe even for the particular OS. This will be influenced by what subroutine needs to access information from callers (arguments? lexical scopes?), what the instruction set does well (lots of registers? easy to push arguments?), strengths or weaknesses of the compilers, etc. Microsoft, as an example, did this design several times over decades, as their compilers and the x86 evolved; their conventions for the x86-32 are really different than they are for x86-64. You can guess at the rationale from the documented result and sometimes there are hints, but not always.
I can give you some ideas, having designed "stack frames" for my company's parallel programming language that runs on an x86.
- Because the language is parallel, stack frames are heap allocated (from an extremely fast, thread-local block allocator), not stack allocated; so "stack frame" isn't quite the right term, we call them "activation records". (I'll continue to call them "stack frames" in this discussion). This scheme supports parallel programming, where one function can fork multiple parallel subcomputations, each of which needs own stack frame; they obviously can't share a single stack. This means each stack frame has to contain an explicit pointer to the previous frame to enable a callee to return. So there is a slot at low offset in the stack frame to hold the callers stack frame pointer. Similarly, there is a slot to hold the caller's stack pointer. These two slots are used instead of the traditional PUSH EBP/ LEA ESP, k[ESP] traditionally used by x86 calling conventions.
- Lexical scoping requires each callee have access to lexical scopes of parents. This is accomplished by setting aside a set of low-offset points in the stack frame to hold a classic "display" (set of pointers to containing scopes), and passing a pointer to the caller's display in ECX to a callee. The callee copies what it needs of the parent's display, perhaps augmenting if the callee is not a leaf procedure.
- The CPU having a limited number of registers meant you couldn't pass all the parameters or even many of them in the registers. We chose to pass one 32 bit argument in EAX, a second in EDX, or a 64 bit argument in EAX/EDX; larger argument lists are passed by pushing the arguments in the stack and simply calling the subroutine. The callee wants access to the arguments; we chose to allocate 2 slots at low offsets in the stack frame to hold EAX/EDX.
- Unlike single-thread code, each PARLANSE stack frame represents a function with a possibly large number of statically-defined parallel computations. The stack frame thus contains a set of "grain" (parallel thread) context blocks with associated fixed sized stacks that each accesses by its ESP register. This scheme allows the compiler to do much of the work of allocating space and setting up parallel grains, minimizing the time to create a "grain", in turn allowing much smaller computations to usefully run in parallel. There's a lot of detail about what goes into each grain control block that isn't worth explaining here; the point is there is a lot of detail that is part of the stack frame design.
My point is the rationale for stack frame design is driven by the machine architecture and the goal of the programming language it is supposed to support. Rationale such as the above doesn't appear in many documents, and yes, that makes it pretty hard to find.
Given a stack frame design, the compiler for a language then allocates space within the frame, for a particular subroutine being compiled.

- 93,541
- 22
- 172
- 341
It is a compiler choice at compiler time, if you use the same compiler with the same built choices on different operating systems for the same processor/target you may get the same types of results for stack frames or not.
Stack frames make it easier for the compiler developer to debug the code as well as others to read the code, it is debatable as to whether it costs more or not to use a stack frame. It also might make life easier on the debugger (software) as well, but you would have to be closely in sync with the compiler for that to work.
They are generally not required, cant imagine why a calling convention would ever care, it is simply an implementation thing, do I constantly have to keep track at every point in the function where things are relative to my changing the top of stack, or do I want to pre-compute all the stack I will need for the whole function, and consume it one time, then for the remainder of the function I can hardcode where everything is relative to that, making it easier to read and debug the code sometimes at the cost of another register, sometimes not depending on implementation.
Stack frames are a design choice by the compiler folks and is a compile time thing not a runtime thing. If yo use the same compiler with the same choices you can get the same layout across operating systems, use a different compiler on the same operating system or different operating systems and there are no guarantees the same layout is used or if both even use a stack frame.

- 69,149
- 8
- 89
- 168