C语言函数

Tutorial: C与汇编 Category: C语言 Published: 2026-04-07 13:58:26 Views: 20 Likes: 0 Comments: 0
1. 函数调用
  • 源码
int plus(int x, int y)
{
    return x + y;
}

void main()
{
    plus(1, 2);
    return;
}
  • 汇编
1:    int plus(int x, int y)
2:    {
00401020   push        ebp                   ; 保存调用者的基指针
00401021   mov         ebp, esp              ; 新的基指针现在是栈顶
00401023   sub         esp, 0x40             ; 在栈上分配64字节空间给局部变量
00401026   push        ebx                   ; 保存ebx寄存器的值
00401027   push        esi                   ; 保存esi寄存器的值
00401028   push        edi                   ; 保存edi寄存器的值
00401029   lea         edi, [ebp - 0x40]     ; 将局部变量的起始指针传给edi
0040102C   mov         ecx, 0x10             ; 将16(用于循环计数)传递给ecx
00401031   mov         eax, 0xCCCCCCCC       ; 调试目的的模式填充值放入eax
00401036   rep stos    dword ptr [edi]       ; 用0xCCCCCCCC填充局部变量区域
3:        return x + y;
00401038   mov         eax, dword ptr [ebp+8]   ; 将x的值加载到eax
0040103B   add         eax, dword ptr [ebp+0xC] ; 将y的值加到eax,得和
4:    }
0040103E   pop         edi                   ; 恢复edi寄存器原来的值
0040103F   pop         esi                   ; 恢复esi寄存器原来的值
00401040   pop         ebx                   ; 恢复ebx寄存器原来的值
00401041   mov         esp, ebp              ; 重置栈指针,丢弃局部变量
00401043   pop         ebp                   ; 恢复调用者的基指针
00401044   ret                               ; 返回到调用者,返回值在eax中

6:    void main()
7:    {
00401050   push        ebp                     ; 保存调用者的基指针
00401051   mov         ebp, esp                ; 新的基指针现在是栈顶
00401053   sub         esp, 0x40               ; 在栈上分配64字节空间给局部变量
00401056   push        ebx                     ; 保存ebx寄存器的值
00401057   push        esi                     ; 保存esi寄存器的值
00401058   push        edi                     ; 保存edi寄存器的值
00401059   lea         edi, [ebp - 0x40]       ; 将局部变量的起始指针传给edi
0040105C   mov         ecx, 0x10               ; 将16(用于循环计数)传递给ecx
00401061   mov         eax, 0xCCCCCCCC         ; 调试目的的模式填充值放入eax
00401066   rep stos    dword ptr [edi]         ; 用0xCCCCCCCC填充局部变量区域
8:        plus(1, 2);
00401068   push        2                       ; 将2作为函数参数压栈
0040106A   push        1                       ; 将1作为函数参数压栈
0040106C   call        @ILT+0(plus) (00401005) ; 调用plus函数
00401071   add         esp, 8                  ; 清理栈上的参数空间(两个int,每个占用4字节)
9:        return;
10:   }
00401074   pop         edi                     ; 恢复edi寄存器原来的值
00401075   pop         esi                     ; 恢复esi寄存器原来的值
00401076   pop         ebx                     ; 恢复ebx寄存器原来的值
00401077   add         esp, 0x40               ; 清理栈空间(加回先前分配的局部变量大小)
0040107A   cmp         ebp, esp                ; 检查栈指针和基指针是否一致(安全检查)
0040107C   call        __chkesp (004010a0)     ; 如果不一致,调用__chkesp处理潜在的栈问题
00401081   mov         esp, ebp                ; 恢复栈指针
00401083   pop         ebp                     ; 恢复调用者的基指针
00401084   ret                                 ; 返回到调用者,结束main函数
2. 分析
1. 原始
    esp = 0019FEE4
    ebp = 0019FF30
2. push 2
    esp = 0019FEE0 // int 4byte
    ebp = 0019FF30
3. push 1
    esp = 0019FEDC // int 4byte
    ebp = 0019FF30
4. call 00401005   // 函数调用
    esp = 0019FED8
    ebp = 0019FF30
5. 00401005   jmp         plus (00401020)
6. 00401020   push        ebp
    esp = 0019FED4
    ebp = 0019FF30
7. mov         ebp, esp // 设置小栈
    esp = 0019FED4
    ebp = 0019FED4
8. sub         esp, 0x40             ; 在栈上分配64字节空间给局部变量
    esp = 0019FE94 // 局部变量的起始指针
    ebp = 0019FED4
9. 00401026   push        ebx                   ; 保存ebx寄存器的值
   00401027   push        esi                   ; 保存esi寄存器的值
   00401028   push        edi                   ; 保存edi寄存器的值
    esp = 0019FE88
    ebp = 0019FED4
10. 00401059   lea         edi, [ebp - 0x40]       ; 将局部变量的起始指针传给edi
    esp = 0019FE88
    ebp = 0019FED4
    edi = 0019FE94 //  19FE94 - 19FED4 小栈空间
11. 0040105C   mov         ecx, 0x10               ; 将16(用于循环计数)传递给ecx
12. 00401061   mov         eax, 0xCCCCCCCC         ; 调试目的的模式填充值放入eax
13. 00401066   rep stos    dword ptr [edi]         ; 用0xCCCCCCCC填充局部变量区域 16次,一次4字节(eax) = 64 字节
    esp = 0019FE88
    ebp = 0019FED4
    edi = 0019FED4
14. 00401038   mov         eax, dword ptr [ebp+8]   ; 将x的值加载到eax      19FED4 + 8 = 19FEDC = 1
15. 0040103B   add         eax, dword ptr [ebp+0xC] ; 将y的值加到eax,得和   19FED4 + C = 19FEDC = 19FEE0
// 0019FEDC  01 00 00 00  ....
// 0019FEE0  02 00 00 00  ....
// 0019FEE4  E0 10 40 00  ..@.
// 0019FEE8  E0 10 40 00  ..@.
// 0019FEEC  00 60 24 00  .`$.
// 0019FEF0  CC CC CC CC  烫烫
// 0019FEF4  CC CC CC CC  烫烫
// 0019FEF8  CC CC CC CC  烫烫
// 0019FEFC  CC CC CC CC  烫烫
// 0019FF00  CC CC CC CC  烫烫
// 0019FF04  CC CC CC CC  烫烫
// 0019FF08  CC CC CC CC  烫烫
// 0019FF0C  CC CC CC CC  烫烫
// 0019FF10  CC CC CC CC  烫烫
// 0019FF14  CC CC CC CC  烫烫
// 0019FF18  CC CC CC CC  烫烫
// 0019FF1C  CC CC CC CC  烫烫
// 0019FF20  CC CC CC CC  烫烫
// 0019FF24  CC CC CC CC  烫烫
// 0019FF28  CC CC CC CC  烫烫
// 0019FF2C  CC CC CC CC  烫烫
16. 0040103E   pop         edi                   ; 恢复edi寄存器原来的值
17. 0040103F   pop         esi                   ; 恢复esi寄存器原来的值
18. 00401040   pop         ebx                   ; 恢复ebx寄存器原来的值
    esp = 0019FE94
    ebp = 0019FED4
    edi = 0019FF30
19. 00401041   mov         esp, ebp              ; 重置栈指针,丢弃局部变量
    esp = 0019FED4
    ebp = 0019FED4
    edi = 0019FF30
20. 00401043   pop         ebp                   ; 恢复调用者的基指针
    esp = 0019FED8
    ebp = 0019FF30
    edi = 0019FF30
21. 00401044   ret                               ; 返回到调用者,返回值在eax中
    esp = 0019FEDC
    ebp = 0019FF30
    edi = 0019FF30
22. 00401077   add         esp,8
    esp = 0019FEE4
    ebp = 0019FF30
    edi = 0019FF30

// 额外main函数
00401074   pop         edi                     ; 恢复edi寄存器原来的值
00401075   pop         esi                     ; 恢复esi寄存器原来的值
00401076   pop         ebx                     ; 恢复ebx寄存器原来的值
00401077   add         esp, 0x40               ; 清理栈空间(加回先前分配的局部变量大小)
0040107A   cmp         ebp, esp                ; 检查栈指针和基指针是否一致(安全检查)
0040107C   call        __chkesp (004010a0)     ; 如果不一致,调用__chkesp处理潜在的栈问题
00401081   mov         esp, ebp                ; 恢复栈指针
00401083   pop         ebp                     ; 恢复调用者的基指针
00401084   ret                                 ; 返回到调用者,结束main函数