"Volume C Record" Condensation Pill - Function Stack Frame Understanding Manual

content

1. Front

2. Preliminary knowledge

3. Stack frame creation and destruction

4. Summary


No one in ancient times! Gubiao Lingyun is a friend, and the sword is my life.

 

1. Front

This chapter will look at how the memory of the function stack frame is used and recovered from the perspective of assembly. In order to reduce the cost of understanding assembly language, the effect brought by each step of the assembly instruction will be explained in a graphical way to gradually show the formation of the function stack frame. with the entire process of destruction.

Display environment: win10 && vs2019

2. Preliminary knowledge

The understanding of these preliminary knowledge has little to do with this article. The reason for preparing this knowledge is to make readers more confident that the formation and destruction process of function stack frames is like this.

Stack area : one of the four areas of memory. For use and management, the memory is divided into four parts. The stack area is one of the areas where the memory is divided. The usage of the stack is to use the high address part first, and then use the bottom address part. .

Function stack frame : that is, a piece of memory space opened up for a function when a function is called. Since this memory space is in the stack area, this space is called a function stack frame, or stack frame for short.

The top of the stack : As the name implies, it is the top of the stack, more precisely, it points to the top of the data stored in the stack area.

Bottom of the stack: The bottom of the stack.

Registers : registers are some small storage areas inside the cpu used to store data, which are used to temporarily store the data and operation results involved in the operation. Simply put, it is a device that is independent of memory and used to store small amounts of data.

ebp: stack bottom pointer register

esp: stack bottom pointer register

Other registers: ebx, esi, edi, ecx, eax

Push to the stack (push the stack) : first move the top pointer of the stack up by four bytes of space, and then put the data of the register into the four-byte space. The upward movement here refers to the movement at the lower address.

Push instruction : push a.

Illustration : Take push a as an example.

 Pop out of the stack : Move the top pointer of the stack down by four bytes, where the down is to move the space of four bytes to the lower address. And put these four bytes of data into some register.

Pop instruction : pop a.

Illustration: Take pop a as an example.

Simple assembly operation instructions

mov ab : Assign b to a, the c language means a=b.

sub ab : Assign the result of ab to a, the expression in c language is a=ab.

add ab : Assign the result of a+b to a, the expression in c language is a=a+b.

Due to the cost of understanding, other assembly instructions encountered in this article will directly point out its effect.

3. Stack frame creation and destruction

Take the Add function call as an example

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
	int z = x + y;
	return z;
}
int main()
{
	int a = 10;
	int b = 20;
	int z = 0;
	z = Add(a, b);
	printf("%d\n", z);
	return 0;
}

The assembly instructions corresponding to this code are as follows:

 It should be noted that the main function is also called by other functions. The calling relationship is: __mainCRTStartup calls the main function, and the mainCRTStartup function calls __mainCRTStartup.

Before calling the main function again, the stack area is like this.

 Instructions say:

int main()
{
00F71E40  push        ebp  
00F71E41  mov         ebp,esp  
00F71E43  sub         esp,0E4h  

The above picture is for reference.

The first instruction : push the value of register ebp onto the stack

The second instruction : assign the value of register esp to ebp

The third instruction : assign esp-0E4h to the register esp. The image expression is that esp moves 4 bytes to the low address direction, the upper end is the low address, and the lower end is the high address, that is, it moves up 4 bytes of space.

The stack view becomes:

 These three instructions simply open up a space for the main function in the stack area (the system will automatically open up this space for us.)

Instructions say:

00F71E49  push        ebx  
00F71E4A  push        esi  
00F71E4B  push        edi  

Push the values ​​of the three registers onto the stack

The stack view becomes:

Instructions say:

00F71E4C  lea         edi,[ebp-24h]  
00F71E4F  mov         ecx,9  
00F71E54  mov         eax,0CCCCCCCCh  
00F71E59  rep stos    dword ptr es:[edi] 

We interpret these four instructions. The effect is to fill the stack frame space of the main function with the hexadecimal value cccccccc.

The stack view becomes:

Instructions say:

00F71E5B  mov         ecx,0F7C003h  
00F71E60  call        00F7130C 

These two instructions are used by the compiler to check, and beginners do not need to spend more time to understand the more detailed parts.

vs2013 doesn't have this check part, vs2019 check is strict.

Instructions say:

int a = 10;
00F71E65  mov         dword ptr [ebp-8],0Ah  
	int b = 20;
00F71E6C  mov         dword ptr [ebp-14h],14h  
	int z = 0;
00F71E73  mov         dword ptr [ebp-20h],0  

The first assembly instruction: put 0Ah into the space of [ ebp-8 ], that is, put a into that space.

The second assembly instruction: put 14h into the space [ ebp-14h ], that is, put b into that space.

The third assembly instruction: put 0 into the space [ ebp-20h ]. That is, put z into that space.

Stack area icon:

 Simply put: it is to put local variables into the corresponding function stack frame.

Instructions say:

z = Add(a, b);
00F71E7A  mov         eax,dword ptr [ebp-14h]  
00F71E7D  push        eax  
00F71E7E  mov         ecx,dword ptr [ebp-8]  
00F71E81  push        ecx  

The first instruction : Put [ebp-20] 4 bytes of data in this space into eax. That is, put the data of b=20 into eax.

The second instruction : push the data of eax onto the stack.

The third instruction : put [ebp-8] 4 bytes of data in this space into ecx. That is, put the data of a=10 into ecx.

The fourth instruction : push the data of ecx onto the stack.

Stack area view:

 The 20 and 10 here are the actual parameters we passed in the past, and the x and y called by the Add function later refer to these two spaces.

Then we can know: function parameters are passed from right to left. Here is the b passed first and then the a passed.

Instructions say:

00F71E82  call        00F710B4 

调用的函数:
int Add(int x, int y)
{
00F71740  push        ebp  
00F71741  mov         ebp,esp  
00F71743  sub         esp,0CCh  
00F71749  push        ebx  
00F7174A  push        esi  
00F7174B  push        edi  
00F7174C  lea         edi,[ebp-0Ch]  
00F7174F  mov         ecx,3  
00F71754  mov         eax,0CCCCCCCCh  
00F71759  rep stos    dword ptr es:[edi]  
00F7175B  mov         ecx,0F7C003h  
00F71760  call        00F7130C  
	int z = x + y;
00F71765  mov         eax,dword ptr [ebp+8]  
00F71768  add         eax,dword ptr [ebp+0Ch]  
00F7176B  mov         dword ptr [ebp-8],eax  
	return z;
00F7176E  mov         eax,dword ptr [ebp-8]  
}
00F71771  pop         edi  
00F71772  pop         esi  
00F71773  pop         ebx  
00F71774  add         esp,0CCh  
00F7177A  cmp         ebp,esp  
00F7177C  call        00F71235  
00F71781  mov         esp,ebp  
00F71783  pop         ebp  
00F71784  ret  

The first assembly instruction: call is a call instruction that calls the Add function.

After the last instruction, here I will directly introduce the effect.

00F71740  push        ebp  
00F71741  mov         ebp,esp  
00F71743  sub         esp,0CCh  

These three instructions open up the corresponding space size in the stack area for the Add function.

Stack area icon:

00F71749  push        ebx  
00F7174A  push        esi  
00F7174B  push        edi  

Push ebx, esi, edi onto the stack.

Icon: 

00F7174C  lea         edi,[ebp-0Ch]  
00F7174F  mov         ecx,3  
00F71754  mov         eax,0CCCCCCCCh  
00F71759  rep stos    dword ptr es:[edi]  

Initialize the stack frame of the Add function and replace the data in it with cccccccc. (The exact value used to initialize the stack frame depends on the compiler)

00F7175B  mov         ecx,0F7C003h  
00F71760  call        00F7130C  

The checks made by the compiler are ignored.

int z = x + y;
00F71765  mov         eax,dword ptr [ebp+8]  
00F71768  add         eax,dword ptr [ebp+0Ch]  
00F7176B  mov         dword ptr [ebp-8],eax  

Take the data in the [ebp+8] space and put it in eax

Take [ebp+0Ch] and add the data of eax and put it in eax.

Put the value of eax into ptr[ebp-8].

Icon:

 return z;
00F7176E  mov         eax,dword ptr [ebp-8]  

When returning, the return value is given to the register by means of the register.

00F71771  pop         edi  
00F71772  pop         esi  
00F71773  pop         ebx  
00F71774  add         esp,0CCh  
00F7177A  cmp         ebp,esp  
00F7177C  call        00F71235  
00F71781  mov         esp,ebp  
00F71783  pop         ebp  
00F71784  ret  

Code breakdown:

00F71771  pop         edi  
00F71772  pop         esi  
00F71773  pop         ebx  

Pop edi, esi, ebx from the stack

Icon


 

00F71774  add         esp,0CCh 

00F7177A  cmp         ebp,esp  
00F7177C  call        00F71235  
00F71781  mov         esp,ebp  
00F71783  pop         ebp  

0CCh is the size of the stack frame of the Add function

So esp moves down to the position of dbp.

 After pop ebp, since the top of the stack points to the bottom of the stack frame of the main function, the pop ebp points to the bottom of the stack of the main function stack frame.

Icon:

After calling Add returns, continue to execute the following instructions.

00A717F7  add         esp,8  
00A717FA  mov         dword ptr [ebp-20h],eax  
	return 0;
00A717FD  xor         eax,eax  
}
00A717FF  pop         edi  
00A71800  pop         esi  
00A71801  pop         ebx  
00A71802  add         esp,0E4h  
00A71808  cmp         ebp,esp  
00A7180A  call        00A71235  
00A7180F  mov         esp,ebp  
00A71811  pop         ebp  
00A71812  ret  

The first instruction : move esp down by 8 bytes, that is, destroy the two consecutive formal parameters of x and y.

The second instruction : Give the return value of the Add function stored in the register eax to z.

Icon:

 The next instruction is to recycle the stack frame of the main function. The recycling process is similar, so I will not explain it in detail.

4. Summary

The following function call is an example.

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Add(int x, int y)
{
	int z = x + y;
	return z;
}
int main()
{
	int a = 10;
	int b = 20;
	int z = 0;
	z = Add(a, b);
	return 0;
}

Initial : The mainCRTStartup function calls __mainCRTStartup, and __mainCRTStartup calls the main function.

First allocate function stack frames for the above two functions on the stack area.

When calling the main function, allocate the function stack frame for the main function (the size is automatically opened up), and then fill the main function stack frame with the cccccccc value. (The specific value to initialize the function stack frame depends on the compiler).

When int a = 10 is executed, the value of the local variable a is put into a certain space of the main function stack frame, the same is true for int b = 20 and int z = 0, and their spaces are all in the function stack frame of the main function. .

When z=Add(a,b) is executed.

The parameters are passed first, and the order of parameter passing is from right to left. All first push b onto the stack, and then push a onto the stack.

These two spaces are y and, x. Note that y and x are not in the Add function stack frame, but in a separate space between the main function stack frame and the Add function stack frame.

Then open up the function stack frame for the Add function, and fill the Add function stack frame with the ccccccc value. (The specific value to initialize the function stack frame depends on the compiler).

When z=x+y is executed, a space is taken in the stack frame of the Add function as a local variable z, and the values ​​of the y and x spaces are taken out and placed in z. (z is in the stack frame of the Add function).

When execution reaches return z, put the value of z into a register.

After that, the stack frame of the Add function is destroyed, the formal parameters x and y are destroyed, and the value of the register is given to z.

The same goes for destroying the main function afterwards.

The destruction here is not to set the stack frame data of the Add function to 0 or other numbers. The data in it is not directly lost, but directly tells the operating system that I don’t need this space anymore. The data in the stack frame of the Add function It still exists, but when you call a new function, the space of the Add function stack frame will be occupied by the new function and initialized to a value such as cccccccc, then the Add function stack frame space data will be lost.

Guess you like

Origin blog.csdn.net/m0_62171658/article/details/123747765