汇编语言分析C语言的函数调用过程

1.要分析C语言的函数调用过程,理解汇编指令push,pop是关键,

在汇编中,栈的增长方式是从高地址往低地址增长,栈底在高地址,栈顶在低地址。

push eax入栈指令相当于:

ESP=ESP-4,[SS:ESP]<--eax内容;   (32 bit)

pop eax出栈指令相当于:

eax<--[SS:ESP]内容,ESP=ESP+4

                       

 2.先看下在vs2013工程下的C语言示例源码,以__cdecl调用方式调用函数

 1 #include <stdio.h>
 2 
 3 int add(int a, int b, int c)
 4 {
 5     return (a+b+c);
 6 }
 7 
 8 int main(int argc, char *argv[])
 9 {
10     int sum = 0;
11     int a = 1;
12     int b = 2;
13     int c = 3;
14     sum = add(a,b,c);
15     return 0;
16 }

反汇编后的源码

 1 __RTC_Initialize:
 2 01091145  jmp         _RTC_Initialize (01092D40h)  
 3 __controlfp_s:
 4 0109114A  jmp         __controlfp_s (0109376Ch)  
 5 _GetSystemTimeAsFileTime@4:
 6 0109114F  jmp         _GetSystemTimeAsFileTime@4 (01093C22h)  
 7 add:
 8 01091154h  jmp         add (010913C0h)  
 9 _DecodePointer@4:
10 01091159  jmp         _DecodePointer@4 (01093C28h)  
11 __invoke_watson:
12 0109115E  jmp         __invoke_watson (01093766h)  
13 ___report_rangecheckfailure:
14 01091163  jmp         __report_rangecheckfailure (01093940h)  
15 _RTC_GetSrcLine:
16 01091168  jmp         _RTC_GetSrcLine (010933D0h)  
17 __wmakepath_s:
18 0109116D  jmp         __wmakepath_s (0109377Eh)  
19 __CRT_RTC_INITW:
20 01091172  jmp         __CRT_RTC_INITW (0109262Ch)  
21 
22 #include <stdio.h>
23 
24 //调用函数add的地址
25 int add(int a, int b, int c)
26 {
27 010913C0  push        ebp       ;ebp=0030FB10 esp=0030FA00
28 010913C1  mov         ebp,esp      ;ebp=0030FA00
29 010913C3  sub         esp,0C0h     ;esp=0030F940
30 010913C9  push        ebx       ;保护现场,esp=0030F93C
31 010913CA  push        esi       ;esp=0030F938
32 010913CB  push        edi      ;edi=0030FB10, esp=0030F934
33 010913CC  lea         edi,[ebp-0C0h]  ;edi=0030F940
34 010913D2  mov         ecx,30h       ;初始化
35 010913D7  mov         eax,0CCCCCCCCh
36 010913DC  rep stos    dword ptr es:[edi]  
37     return (a+b+c);
38 010913DE  mov         eax,dword ptr [a]   ;取参数值,并计算
39 010913E1  add         eax,dword ptr [b]  
40 010913E4  add         eax,dword ptr [c]  
41 }
42 010913E7  pop         edi     ;恢复现场 edi=0030FB10, esp=0030F938
43 010913E8  pop         esi    ;esp=0030F93C
44 010913E9  pop         ebx     ;esp=0030F940
45 }
46 010913EA  mov         esp,ebp  ;esp=0030FA00
47 010913EC  pop         ebp    ;ebp=0030FB10, esp=0030FA04
48 010913ED  ret         ;esp=0030FA08 【__cdecl】调用方式内部没有平衡栈,由调用者负责平栈(编译器自动处理),【__stdcall】调用方式指令“return 0Ch”内部平栈
49 
50 //主调函数
51 int main(int argc, char *argv[])
52 {
53 01091400  push        ebp       ;将ebp内容压栈  ebp=0030FB60  esp=0030FB14
54 01091401  mov         ebp,esp   ;esp传给ebp  ebp=0030FB10  esp=0030FB10
55 01091403  sub         esp,0F0h  ;改变栈顶值,腾出空间,esp=esp-0F0h  esp=0030FA20
56 01091409  push        ebx       ;压栈ebx,esi,edi,保护现场. ebp=0030FB10 esp=0030FA1C
57 0109140A  push        esi       ;esp=0030FA18
58 0109140B  push        edi     ;esp=0030FA14
59 0109140C  lea         edi,[ebp-0F0h]    ;将(ebp-0F0h)=0030FA20的值放入edi中,edi=0030FA20
60 01091412  mov         ecx,3Ch   ;ecx=3Ch,rep指令循环次数
61 01091417  mov         eax,0CCCCCCCCh  ;eax=CCCCCCCC
62 0109141C  rep stos    dword ptr es:[edi]  ;重复填充CCCCCCCC,(3Ch)次
63     int sum = 0;
64 0109141E  mov         dword ptr [sum],0   ;&sum=0030fb08, sum=0
65     int a = 1;
66 01091425  mov         dword ptr [a],1     ;&a=0030fafc, a=1
67     int b = 2;
68 0109142C  mov         dword ptr [b],2     ;&b=0030faf0, b=2
69     int c = 3;
70 01091433  mov         dword ptr [c],3     ;&c=0030fae4, c=3
71     sum = add(a,b,c);
72 0109143A  mov         eax,dword ptr [c]   ;参数按从右至左的顺序压栈, eax=3
73 0109143D  push        eax           ;esp=0030FA10
74 0109143E  mov         ecx,dword ptr [b]   ;ecx=2
75 01091441  push        ecx           ;esp=0030FA0C
76 01091442  mov         edx,dword ptr [a]   ;edx=1
77 01091445  push        edx            ;esp=0030FA08
78 01091446  call        add (01091154h)     ;调用函数add,此时会将返回函数的下一指令地址0109144B压栈,调用前esp=0030FA04,调用后esp=0030FA08
79 0109144B  add         esp,0Ch         ;esp=0030FA14   【__cdecl】调用方式调用返回后外部平栈,【__stdcall】调用方式没有这条指令
80 0109144E  mov         dword ptr [sum],eax  ;将值传给变量sum
81     return 0;
82 01091451  xor         eax,eax  
83 }
84 01091453  pop         edi    ;恢复现场
85 01091454  pop         esi  
86 }
87 01091455  pop         ebx     ;esp=0030FA20
88 01091456  add         esp,0F0h  ;esp=0030FB10
89 0109145C  cmp         ebp,esp  
90 0109145E  call        __RTC_CheckEsp (01091136h)  
91 01091463  mov         esp,ebp  
92 01091465  pop         ebp     ;ebp=0030FB60 esp=0030FB14
93 01091466  ret       ;esp=0030FB18

 3.大概的过程是调用函数add前,参数先从右至左放入栈中,同时把返回地址也放入栈中。在add函数中,取出栈中的参数,执行完后返回,继续执行。

posted @ 2019-05-26 13:46  pro_love  阅读(2284)  评论(0编辑  收藏  举报