Article directory
runtime stack
The stack is a data structure: we can store data into this structure, and we can also pop data in this structure. The characteristics of this structure are: the data pushed later is popped first, and the data pushed first is popped.
In computer systems, the stack is a dynamic memory area with the above attributes. Programs can push data onto the stack or pop data from the stack. The stack increases during the push operation, and the stack decreases during the pop operation.
This memory management principle is also used in C language procedure calls - first in, last out
Memory layout in a computer system:
It can be seen that the stack grows from high address to low address, the top of the stack is at the low address, and the bottom of the stack is at the high address.
function stack frame
Every time a program calls a function, it creates a space in the stack area, and this space is called the stack frame of the function.
This space generally includes the following information:
- The return address and parameters of the function
- Temporary variables: including non-static local variables of functions and other temporary variables generated by the compiler
- saved register
When a running program calls another function, it will enter a new stack frame. The stack frame of the original function is called the caller's frame, and the new stack frame is called the current frame. After the called function finishes running, the current frame is all recycled and returns to the caller's frame.
For example: when function A calls function B, it pushes the return address onto the stack. We treat the return address as part of the stack frame of function A because it stores the state related to A.
Note:
esp
The register always points to the top of the current stack frame (esp
the address of the top of the stack is saved).
You can see that this mechanism of pushing the return value onto the stack allows the function to return to the correct place in the program later.
Little knowledge:
We sometimes get "hot" when debugging, what is the reason for this?
In fact, it is because we will assign the stack frame to 0xcccccccc after creating the function stack frame in the debug case,
and the Chinese character encoding of two consecutive 0xcc is hot, so 0xcccc is regarded as "hot" as text.
Registers and Machine Instructions
To understand the stack frame of a function, you should understand some concepts about registers and simple machine instructions.
register:
A CPU contains a set of registers that can store integer data and pointers, each register has a special purpose
On IA32-bit systems, these registers can store 32-bit values, and on 64-bit systems, these registers can store 64-bit values
Below are the registers in the 32-bit case
name | use |
---|---|
eax |
return value |
ebp |
stack bottom pointer |
esp |
stack pointer |
rdi |
|
rsi |
|
rdx |
|
rcx |
Among the above registers, the most special one is esp
that this register is called the stack pointer, also called the stack top pointer (which stores the address of the top of the stack), which is used to indicate the end position of the stack at runtime.
The ebp
register is used to point to the bottom of the stack frame (the address of the bottom of the stack is stored). Call it the bottom of the stack pointer.
machine instructions
At this point we need to understand some simple machine instructions and assembly code (the part related to stack frames)
Arithmetic operations :
instruction | Effect | describe |
---|---|---|
ADD S,D | D = D + S | addition |
SUB S,D | D = D - S | subtraction |
lea S,D | D <-- &S | load valid address |
MOV S,D | D <-- S | transfer (copy) |
Pop and push data on the stack:
instruction | Effect |
---|---|
push | push the stack |
pop | pop stack |
push
The function of the instruction is to push data onto the stack and at the same time change the stack pointer:
Each push
operation decrements the stack pointer
On the system: the stack pointer is decremented 32位
every time ;push
4
On the 64位
system, the push
stack pointer is decremented each time8
pop
The function of the instruction is to pop data from the stack and change the frame pointer at the same time
A pop will increase the stack pointer
In the 32位
system: each time pop
the stack pointer will be incremented4
In the 64位
system: each time pop
the stack pointer will be incremented8
program counter
Usually called a PC, giving the address in memory of the next instruction to be executed
transfer of control
In fact, control transfer means that after we call another function in one function, we start to execute the operation of the called function. It can also be understood as setting the value of PC to the address of the first statement of the called function.
The instructions required to transfer control are:
instruction | Effect |
---|---|
call |
Call functions |
ret |
return from function |
instruction call—calls a function
Step 1: Push the address of the next instruction to be executed onto the stack
The second step is to set the program counter to the starting position of the called function
Instruction ret - return from a function
Pop the address from the stack and set the value to pc to that address
It can be found that this mechanism of pushing the return address onto the stack allows the function to return to the correct place in the program later
data transmission
When we call a procedure, we often need to pass some data as parameters to the procedure, and the procedure may also return a value. How can we relate the data between the two processes?
passing of parameters
When one procedure calls another procedure, the code in the first procedure must first assign the parameters to the appropriate registers.
Passing the return value
The return value of a function is usually eax
stored in a register
When the latter procedure returns to the former procedure, the content to be returned will be saved in the register . After the function call ends, the code in the former procedure can obtain the return value eax
by accessing the value in the registereax
Example: The whole process of creating and destroying function stack frames
We use the following code snippet to analyze the creation and destruction of function stack frames
In this code snippet, the main function calls a summation function ADD:
#include<stdio.h>
int ADD(int x,int y)
{
int z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int sum = 0;
sum = ADD(a,b);
return 0;
}
Here is the assembly code for these two functions:
What we need to know is that the main function is also called by other functions, so when the main
stack frame has not been created for the function in the stack, the esp
register points to the top of the stack of the previous function:
After calling main
the function, start main
creating a function stack frame for the function:
Push ebp
the address to the stack, and then open up a space:
Then push the registers that need to be saved onto the stack and assign values to the newly opened up.
In this way main
, the function stack frame of the function is created, and then main
the statements in the function are executed:
int a = 10;
int b = 20;
int sum = 0;
sum = ADD(a,b);
When the execution arrives sum = ADD(a,b)
, the parameters are passed first and the return address is pushed onto the stack:
Push return value:
After that ADD
, the function stack frame of the function can be created (the preparation process main
is very similar to the function creation process):
Execute ADD
the operations in the function:
After calling ADD, the stack frame of the function will be destroyed.
:
After that, the main function gets the return value: the calculation and storage are performed, and then the main function is called, and the stack frame of the main function is destroyed.
summary
We use some questions to reflect the details in the runtime stack:
How are local variables created?
The creation of local variables first allocates the stack frame space for the function where the bit is located. A part of the space is initialized in the stack frame space, and then a little space is allocated to the local variables in the stack frame.
Why is the value of a local variable random when it is not initialized?
When the stack frame of the function is created, the initialized space stores random values. If the local variables are not initialized when they are created, the random values of the space will not change. If they are initialized when they are created local variable, the initialized value will overwrite the random value.
How do functions pass parameters? What is the order in which the parameters are passed?
When the function has not been called, the actual parameters have been pushed from right to left on the stack. When the function is actually entered, the pointer offset in the function is retrieved to find the formal parameter.
The relationship between formal parameters and actual parameters?
A formal parameter is a temporary copy of an actual parameter, and changing the formal parameter does not affect the actual parameter.
How is the result of a function call returned?
Before the call, the address of the next instruction of the call instruction has been remembered, and the previous function of this function ebp
has been stored in it. When the function is used to return, the ebp
last function call can be found by popping up. , ebp
and then the address that can be found when the pointer goes down esp
, so that it has returned to the stack frame space of a function in Korea, and because the address of the next instruction to call is remembered before the call, so that we can call the function when we call it. Return, the return value is brought back by saving it in a register.