Stack Operations and Function Invocation

Stack Operations and Function Invocation – The stack is a fundamental data structure in programming languages and operating systems. For example, local variables in C are stored on the functions’ stack space. When the operating system transitions from ring 3 to ring 0, it saves state information on the stack. Conceptually, a stack is a last-in first-out data structure supporting two operations: push and pop. Push means to put something on top of the stack; pop means to remove an item from the top. Concretely speaking, on x86, a stack is a contiguous memory region pointed to by ESP and it grows downwards. Push/pop operations are done through the PUSH/POP instructions and they implicitly modify ESP . The PUSH instruction decrements ESP and then writes data at the location pointed to by ESP ; POP reads the data and increments ESP . The default auto increment/decrement value is 4, but it can be changed to 1 or 2 with a prefi x override. In practice, the value is almost always 4 because the OS requires the stack to be double-word aligned.

Stack Operations and Function Invocation

ESP can also be directly modifi ed by other instructions, such as ADD and SUB. While high-level programming languages have the concept of functions that can be called and returned from, the processor does not provide such abstraction. At the lowest level, the processor operates only on concrete objects, such as registers or data coming from memory. How are functions translated at the machine level? They are implemented through the stack data structure! Consider the following function:

Stack Operations and Function Invocation

A calling convention is a set of rules dictating how function calls work at the machine level. It is defi ned by the Application Binary Interface (ABI) for a particular system. For example, should the parameters be passed through the stack, in registers, or both? Should the parameters be passed in from left to-right or right-to-left? Should the return value be stored on the stack, in registers, or both? There are many calling conventions, but the popular ones are CDECL , STDCALL , THISCALL , and FASTCALL . (The compiler can also generate its own custom calling convention, but those will not be discussed here.) Table 1-2 summarizes their semantic.

Stack Operations and Function Invocation

We now return to the code snippet to discuss how the function addme is invoked. In line 1 and 3, the two parameters are pushed on the stack; ECX and EAX are the fi rst and second parameter, respectively. Line 4 invokes the addme function with the CALL instruction. This immediately pushes the return address, 0x4129FE, on the stack and begins execution at 0x4113A0.

After line 4 executes, we are now in the addme function body. Line 1 pushes EBP on the stack. Line 2 sets EBP to the current stack pointer. This two instruction sequence is typically known as the function prologue because it establishes a new function frame. Line 4 reads the value at address EBP+8 , which is the first parameter on the stack; line 5 reads the second parameter. Note that the parameters are accessed using EBP as the base register. When used in this context, EBP is known as the base frame pointer (see line 2) because it points to the stack frame for the current function, and parameters/locals can be accessed relative to it. The compiler can also be instructed to generate code that does not use EBP as the base frame pointer through an optimization called frame pointer omission. With such optimization, access to local variables and parameters is done relative to ESP , and EBP can be used as a general register like EAX , EBX , ECX , and soon. Line 6 adds the numbers and saves the result in EAX . Line 8 sets the stack pointer to the base frame pointer. Line 9 pops the saved EBP from line 1 into EBP . This two-instruction sequence is commonly referred to as the function epi-
logue because it is at the end of the function and restores the previous function frame. At this point, the top of the stack contains the return address saved by the CALL instruction at 0x4129F9. Line 10 performs a RET , which pops the stack and resumes execution at 0x4129FE. Line 5 in the snippet shrinks the stack by 8 because the caller must clean up the stack per CDECL’s calling convention. If the function addme had local variables, the code would need to grow the stack by subtracting ESP after line 2. All local variables would then be accessible through a negative offset from EBP.

If You Like This Please Comment Down For More Post exploitbyte.com/

Related posts

Leave a Comment