Basic Introduction about Stack
How a process is organized in memory?
Processes are divided into three regions: Text, Data and Stack.
Text Region
The text region is fixed by the program and includes code (instructions) and read-only data. This region corresponds to the text section of the executable file. This region is normally marked read-only and any attempt to write to it will result in a segmentation violation.
Data Region
The data region contains initialized and uninitialized data. Static variables are stored in this region. The data region corresponds to the data-bss(Data segment space) of the executable file.
The region’s size can be changed with the
brk()
system call. If the expansion of the bss data or the user stack exhausts available memory, the process is blocked and is rescheduled to run again with a larger memory space. New Memory is added between the data and stack segments.Stack Region
A stack is a contiguous block of memory containing data. A register called the stack pointer(
SP
) points to the top of the stack. The bottom of the stack is at a fixed address. Its size is dynamically adjusted by the kernel at runtime. The CPU implements instructions toPUSH
onto andPOP
off of the stack.
Introduction to Some Important Register
SP
The stack pointer(SP
) is implementation dependent. It may point to the last address on the stack, or to the next free available address after the stack.
LB
or FP
A local base pointer(LB
), which sometimes is also referred to as a frame pointer(FP
), points to a fixed location within a frame. In principle, local variables could be referenced by giving their offsets from SP. However, as words are pushed onto the stack and popped from the stack, these offsets change.
As a result, many compilers use the register, FP
, for referencing both local variables and parameters because their distances from FP do not change with PUSHes and POPs.
On Intel CPUs, BP(EBP) is used for this purpose. On the Motorola CPUs, any address register except A7(the stack pointer) will do. Because the way our stack grows, actual parameters have positive offsets and local variables have negative offsets from FP.
Something Needs to Be Done When Calling a Function
Actually, this is called the procedure prolog.
- Save the previous
FP
We need to restore previous stack at procedure exit.1
pushl %ebp
Copy
SP
to theFP
We need to create newFP
1
movel %esp, %ebp
Advance
SP
to reserve space for the local variables
Space is reserved for local variable. For function like this:1
2
3
4
5void function(int a, int b, int c)
{
char buffer1[5];
char buffer2[10];
}Consider memory align, we need to reserve 20 bytes for buffers.
1
subl $20, %esp
Buffer Overflow and How it Works
Consider code like this:
1 | void function(int a, int b, int c) |
This program would print “0” in the command window(for a 32-bit system). But how does this work?
Let’s first take a look at the stack:
It is clear that buffer1
takes 8 bytes of space. And pointer sfp
is a 4-byte pointer. Thus ret = buffer1 + 12;
would get a correct ret
address.
Eventually, (*ret) += 8;
would skip x = 1;
statement in the main function.
And this is really cool! We can influence code execution outside the current stack.