Function stack frame (analyzed by assembly), function Assembly Analysis
I haven't written a blog for a long time. I started my internship at the school and found a very bad place. I took the bus for nearly two hours and went back and forth in a day. I said it was an internship, but it was just like a training, I don't mean any internship at all, spicy chicken.
This time I will explain how to call C ++ functions. After studying C language for so long, I must have heard of stacks (data structures, address space stacks, and so on ), function calls are closely related to stacks.
BecauseThe stack in the address space is grown from a high address to a low address.That isThe address of the back end of the stack is relatively low, and the address at the bottom of the stack is higher than the address at the top of the stack., The following is a test code
1 #include<stdio.h> 2 3 #include<stdlib.h> 4 5 void bug() 6 { 7 printf("haha I ma a bug!!"); 8 exit(100); 9 }10 int func(int x, int y)11 {12 int *p = &x;13 p--;14 *p = (int)bug;15 printf("x:%d,y:%d\n", x, y);16 int c = 0xcccc;17 return c;18 }19 20 21 22 int main()23 {24 25 printf("I am main\n");26 int a = 0xaaaa;27 int b = 0xbbbb;28 func(a, b);29 printf("I should run here\n");30 return 0;31 }
The running result of this Code does not execute the second printf of the main function, but runs to the bug function. This is because I modified the return address part of the function stack frame.
It was originally intended to be viewed through the linux system, but the stack frame Implementation of centos7 seems to be somewhat different, and the same code cannot run on centos7.
The following is a Disassembly
1 int main() 2 { 3 00A118E0 push ebp 4 00A118E1 mov ebp,esp 5 00A118E3 sub esp,0D8h 6 00A118E9 push ebx 7 00A118EA push esi 8 00A118EB push edi 9 00A118EC lea edi,[ebp-0D8h] 10 00A118F2 mov ecx,36h 11 00A118F7 mov eax,0CCCCCCCCh 12 00A118FC rep stos dword ptr es:[edi] 13 14 printf("I am main\n");15 00A118FE push offset string "I am main\n" (0A16CF0h) 16 00A11903 call _printf (0A1132Ah) 17 00A11908 add esp,4 18 int a = 0xaaaa;19 00A1190B mov dword ptr [a],0AAAAh 20 int b = 0xbbbb;21 00A11912 mov dword ptr [b],0BBBBh 22 func(a, b);23 00A11919 mov eax,dword ptr [b] 24 00A1191C push eax 25 00A1191D mov ecx,dword ptr [a] 26 00A11920 push ecx 27 00A11921 call func (0A11366h) 28 00A11926 add esp,8 29 printf("I should run here\n");30 00A11929 push offset string "I should run here\n" (0A16CFCh) 31 00A1192E call _printf (0A1132Ah) 32 00A11933 add esp,4 33 return 0;34 00A11936 xor eax,eax 35 }
BecauseThe main function itself is really a function! Therefore, before executing the program, the operating system needs to save the current running status, which is similar to function call.
1 00A118E0 push ebp is to press the operating system status to stack
2 00A118E1 mov ebp, esp and move the bottom pointer of the stack to a new position
3 00A118E3 sub esp, 0D8h extends the new stack frame. You cannot always bring the new stack bottom together with the stack top?
The process diagram will be provided when talking about the func function, which is easier to understand. The subsequent push is to save the scene and prepare for execution.
1 printf("I am main\n");2 00A118FE push offset string "I am main\n" (0A16CF0h) 3 00A11903 call _printf (0A1132Ah) 4 00A11908 add esp,4
This part is the system call to call printf, because library functions are more of a second call to the Operating System (encapsulation? Because I do not understand this part very well, I will not explain in detail how _ printf's system calls actually work.
int a = 0xaaaa;00A1190B mov dword ptr [a],0AAAAh int b = 0xbbbb;00A11912 mov dword ptr [b],0BBBBh
In the assignment phase, dual characters are given here, So dword assigns values through pointers ~, Ptr is the pointer, and mov dst src is the pointer given to the front, that is, dst = src.
1 func (a, B); 2 00A11919 mov eax, dword ptr [B] 3 00A1191C push eax join the value assignment statement in the previous sentence to form the parameter pressure stack y = b4 00a111_mov ecx, dword ptr [a] 5 00A11920 push ecx combined with the value assignment statement of the previous sentence to form a parameter pressure stack x = a6 00A11921 call func (0A11366h) call function call, call the address of the fun function 7 00A11926 add esp, 8 push so many don't move the top pointer of the stack?
This is the main part of the story. The stack frame during function call! Surprisingly, the passed arguments are placed in the frame of the main function stack. Let's take a look at the compilation of func.
1 int func(int x, int y) 2 { 3 00A11770 push ebp 4 00A11771 mov ebp,esp 5 00A11773 sub esp,0D8h 6 00A11779 push ebx 7 00A1177A push esi 8 00A1177B push edi 9 00A1177C lea edi,[ebp-0D8h] 10 00A11782 mov ecx,36h 11 00A11787 mov eax,0CCCCCCCCh 12 00A1178C rep stos dword ptr es:[edi] 13 int *p = &x;14 00A1178E lea eax,[x] 15 00A11791 mov dword ptr [p],eax 16 p--;17 00A11794 mov eax,dword ptr [p] 18 00A11797 sub eax,4 19 00A1179A mov dword ptr [p],eax 20 *p = (int)bug;21 00A1179D mov eax,dword ptr [p] 22 00A117A0 mov dword ptr [eax],offset bug (0A1127Bh) 23 printf("x:%d,y:%d\n", x, y);24 00A117A6 mov eax,dword ptr [y] 25 00A117A9 push eax 26 00A117AA mov ecx,dword ptr [x] 27 00A117AD push ecx 28 00A117AE push offset string "x:%d,y:%d\n" (0A16B3Ch) 29 00A117B3 call _printf (0A1132Ah) 30 00A117B8 add esp,0Ch 31 int c = 0xcccc;32 00A117BB mov dword ptr [c],0CCCCh 33 return c;34 00A117C2 mov eax,dword ptr [c] 35 }
1 int func(int x, int y) 2 { 3 00A11770 push ebp 4 00A11771 mov ebp,esp 5 00A11773 sub esp,0D8h 6 00A11779 push ebx 7 00A1177A push esi 8 00A1177B push edi 9 00A1177C lea edi,[ebp-0D8h] 10 00A11782 mov ecx,36h 11 00A11787 mov eax,0CCCCCCCCh 12 00A1178C rep stos dword ptr es:[edi]
That's right. This part stores the status of the main function, which registers are saved here are not described in detail (the push command is usually used to save the status). Here, it is better to read the information by step.
In simple terms, this is probably the case of two stack frames.
So it's easy. We don't have to use statements like y = 100 to assign values to y and change the code.
1 int func(int x, int y)2 {3 int *p = &x;4 p++;5 *p = 100;6 printf("x:%d,y:%d\n", x, y);7 int c = 0xcccc;8 return c;9 }
Don't worry! It's not over yet! The compilation is explained!
1 int * p = & x; 2 0009178E lea eax, [x] This is the offset address, Get x for the current ebp offset address 3 00091791 mov dword ptr [p], eax simply assigns a value of 4 p --; 5 00091794 mov eax, dword ptr [p]. He assigns a value back and forth to the register. In fact, the address is reduced by 4 6 00091797 sub eax, 4 7 0009179A mov dword ptr [p], eax 8 * p = (int) bug; 9 0009179D mov eax, dword ptr [p] transfers the address of the Function bug with a value of 10 000917A0 mov dword ptr [eax] and offset bug (09127Bh) offset is also used to take the offset or is it different from lea's 11 printf ("x: % d, y: % d \ n", x, y); 12 000917 A6 mov eax, dword ptr [y] This is not a system call, because I do not know very well 13 000917A9 push eax 14 000917AA mov ecx, dword ptr [x] 15 000917AD push ecx 16 000917AE push offset string "x: % d, y: % d \ n" (096B3Ch) 17 000917B3 call _ printf (09132Ah) 18 000917B8 add esp, 0Ch 19 int c = 0 xcccc; 20 000917BB mov dword ptr [c], 0 CCCCh local variable created under ebp ~ Look at the picture! 21 return c; 22 000917C2 mov eax, dword ptr [c]
The parameter is not displayed, right? There are only two real parameters. Will they be changed after writing? No ~
x = 10;000A178E mov dword ptr [x],0Ah y = 10;000A1795 mov dword ptr [y],0Ah
I changed the code to this and it will change. Here, I didn't change the items in the previously saved registers, so I got a new part.
Dword ptr [x] is no longer an eax or ebx ~