In general, the process of calling function is put the parameters into the stack, move the EBP and ESP (jump into another function), protect the information of father function, restore the information of father function. (參數入棧、函數跳轉、保護現場、回復現場)
There are three special pointer in compiler:EIP(Instruction pointer)是指令指針,point to the address of next instrction (即指向下一條即將執行的指令的地址);EBP (bottom pointer) 為基址指針,point to the bottom of stack 常用來指向棧底;ESP (stack pointer) 為棧指針,point to the top of stack 常用來指向棧頂.
For example, here is the code:
First, we are at the main function. Every function has itsEBX (basic register),ESI,EDI (destination register)分別為基址寄存器,源變址寄存器,目的變址寄存器. They are some important information of a particular function. When we call the g_func, we firstly need to transport the parameters into it. As I mentioned in my C++ note, when we are using the transportation of value, we will create copies of the parameters for the function. Therefore, here is the first step: put the parameters into the function stack.
三條push指令,分別將三個參數壓入棧中,可以發現參數的壓棧順序是從右向左的。這時我們可以查看棧中的數據驗證一下。如圖3所示,從右邊的實時寄存器表中我們可以看到ESP(棧頂指針)值為0x0012FEF0,然後從中間的內存表中找到內存地址0x0012FEF0處,我們可以看到內存中依次存儲了0x00000001(即參數1),0x00000002(即參數2),0x00000003(即參數3),即此時棧頂存儲的是三個參數值,說明壓棧成功。
If we translate the code into instructions, we will get:
We firstly push three parameters into stack. Then we call a instruction at the address of 00401005. Following this address, we can see this:
We can see this is a jump instruction at the instruction address of 00401005. It jumps to 00401030. That is the begin instruction address of g_func.
Until now, we see how the instructions like before entering the instructions of function. Firstly push the parameters into stack, then use a call instruction to a jump instruction to jump to the actual instruction address of the function. So, until now, the stack is like above. It has three parameters in it now.
Now, we turn to protect information before really entering function.
This step consists of three actual movement:
1)第一步的隱含的,並沒有顯式的指令去指揮其完成。就是將之前的call 指令之後EIP地址(main 函數的下一個指令的地址)壓進去棧中。在這個例子中,call之後則為add。地址是00401093.
2) ebp is the original bottom pointer of the main function. 變了函數的話,棧底都是要變化的。我們要保存之前的函數的棧底地址,作為保護現場的第一步. 所以第二步就是將之前的函數的EBP壓進棧中。
下一條mov ebp, esp 將此時的棧頂地址作為該函數的棧基址,確定g_func函數的棧區域(ebp為棧底,esp為棧頂)。再往下的指令是sub esp, 48h,指令的字面意思是將棧頂指針往上移動48h Byte。那為什麼要移動呢?這中間的內存區域用來做什麼呢?這個區域為間隔空間,將兩個函數的棧區域隔開一段距離,如圖7所示。而該間隔區域的大小固定為40h,即64Byte,然後還要預留出存儲局部變量的內存區域。g_func函數有兩個局部變量x和y,所以esp需移動的長度為40h+8=48h。
注意,存放局部變量的區域是64Bytes另外移出來的。並不會占用64Byte的空間。確保至少函數的棧空間之間至少有64Bytes的間隔。
移動之後的棧空間分布如圖:
3) 將之前提到的EBX (basic register),ESI,EDI (destination register)分別為基址寄存器,源變址寄存器,目的變址寄存器壓進去當前ESP的上面的地址。作為保存現場的第三步。
此時我們可以知道,棧內存是這樣的:
The following content is talking about how to restore the information, I just directly copied formhttp://www.xuebuyuan.com/528715.html