分析简单的c语言函数编译得到的X86汇编代码(VS2013)

查看源代码生成的汇编代码:单步调试->调试->窗口->反汇编

总结:

①、函数被调用时,实参值赋值给函数栈中的形参,使用以下步骤:

       I、call函数前实参值压栈   

       II、函数中分配局部变量的代码执行完   

       III、使用原始栈顶值 ebp 的正偏移量(实参),和负偏移量(形参),配合mov指令来实现值传递,如:

                mov [ebp,ebp-3] [ebp+16,ebp+13]         //计算时不可遗漏了栈中 push pc 和 push ebp带来的esp变化

②、vc编译c源代码时,给函数中的临时变量在栈中分配的存储区域,不是根据临时变量的多少制定的,而是一个固定值 204B

③、vc在栈中给函数中临时变量分配存储单元后,会执行一系列汇编代码,给这些存储单元赋上初始值,本例中每个字节都是十六进制 0xcc ;   执行完赋初始值操作后,才开始进行实参形参值传递

④、vc函数中的临时变量包括以下种类: ①、函数形参  ②、函数体内定义的临时变量   ③、函数返回值

⑤、本例子中 sum 函数的返回值使用 寄存器eax来传递;  一般化的适用于所有情况的函数返回值要使用栈来传递给调用本函数的代码吧。

c源代码:

int sum(int a, int b)
{
    int c = a + b;
    return c;
}

int main()
{
    int a = 2, b = 3;
    int c = 0;
    c=sum(a, b);
    return 1;
}

汇编代码:

int sum(int a, int b)
{
00E813C0  push        ebp                 ;ebp值入栈保存
00E813C1  mov         ebp,esp          ;将当前栈顶值esp赋值给ebp
00E813C3  sub         esp,0CCh        ;esp=esp-204,空出204B的栈空间用于本函数的临时变量(这里为何是204B不理解,本函数不优化的情况下临时变量只需要4*4=16B)

                                                          ;继续解释上行代码,本汇编语言采用递减栈,即push dword值语句等价于下面①②

                                                           ①、mov dword ptr [esp],dword值   ②、mov esp esp-4  
00E813C9  push        ebx                  ;ebx值入栈保存
00E813CA  push        esi                   ;esi值入栈保存  
00E813CB  push        edi                   ;edi值入栈保存 
00E813CC  lea         edi,[ebp-0CCh]  ;给edi=当前段中ebp的地址-204(即00E813C3行执行完后的esp值)
00E813D2  mov         ecx,33h            ;给ecx赋值33h (十进制数51,由204/4计算得出,204是栈中存储临时变量的字节数)
00E813D7  mov         eax,0CCCCCCCCh   ;给eax赋值 0CCCCCCCCh ,本值作为栈中临时变量区每个dword元素的初始值
00E813DC  rep stos    dword ptr es:[edi]  ;给栈中204B的临时变量区字节赋初始值。本语句由以下①②指令复合而来

                                                            ①、rep 指令 :重复执行指令ecx次(每执行完一次ecx=ecx-1,然后判断是否继续执行)

                                                            ②、stos  dword ptr es:[edi] : I、move dword ptr es:[edi] eax  II、mov edi edi+4
    int c = 0;
00E813DE  mov         dword ptr [c],0  ; 这里应该是 mov dword ptr [ebp-8,ebp-11],0 

                                                   插入以下本编译器UI中未生成的但实际执行了的语句(此时内存中数据排布见下面分析):

                                                                 mov [ebp,ebp-3] [ebp+16,ebp+13]          ; sum函数形参b=sum函数实参b

                                                                 mov [ebp-4,ebp-7] [ebp+12,ebp+9]         ; sum函数形参a=sum函数实参a

                                                                 
    c = a + b;
00E813E5  mov         eax,dword ptr [a]  
00E813E8  add         eax,dword ptr [b]  
00E813EB  mov         dword ptr [c],eax  
    return c;
00E813EE  mov         eax,dword ptr [c]  

                                                                 上面几行代码中a、b、c所占的存储器空间应该是:(占据栈中临时变量区起始单元)

                                                                    b(实参):[ebp+16,ebp+13]   (这里的ebp是esp给栈中临时变量分配空间前的值)

                                                                    a(实参):[ebp+12,ebp+9]

                                                                    push pc  (call sum产生,占4字节)

                                                                    push ebp(sum函数开始部分的操作,占4字节)

                                                                    b(形参):[ebp,ebp-3]

                                                                    a(形参):[ebp-4,ebp-7]

                                                                    c:[ebp-8,ebp-11]

                                                                 从main函数 call sum 开始(包括本行),共执行了以下汇编代码

                                                                 main函数中调用sum函数的操作包括:

                                                                 mov         eax,dword ptr [b]   ;  这里的 a b 是main函数栈内的临时变量a b
                                                                 push        eax   ;实参入栈
                                                                 mov         ecx,dword ptr [a]  
                                                                 push        ecx    ;实参入栈 
                                                                 call        sum (0E8105Fh)   ; 本行等价于①、 push pc  ②、move pc sum地址             

}
00E813F1  pop         edi  
00E813F2  pop         esi  
00E813F3  pop         ebx  
00E813F4  mov         esp,ebp  
00E813F6  pop         ebp  
00E813F7  ret           ; pop pc
--- 无源文件 -----------------------------------------------------------------------
00E813F8  int         3  
00E813F9  int         3  
00E813FA  int         3  
00E813FB  int         3  
00E813FC  int         3  
00E813FD  int         3  
00E813FE  int         3  
00E813FF  int         3  
--- c:\user_data\11project\practise_project\cpp\testasm\testasm\main.cpp -------

int main()
{
00E81400  push        ebp  
00E81401  mov         ebp,esp  
00E81403  sub         esp,0E4h  
00E81409  push        ebx  
00E8140A  push        esi  
00E8140B  push        edi  
00E8140C  lea         edi,[ebp-0E4h]  
00E81412  mov         ecx,39h  
00E81417  mov         eax,0CCCCCCCCh  
00E8141C  rep stos    dword ptr es:[edi]  
    int a = 2, b = 3;
00E8141E  mov         dword ptr [a],2  
00E81425  mov         dword ptr [b],3  
    int c = 0;
00E8142C  mov         dword ptr [c],0  
    c=sum(a, b);
00E81433  mov         eax,dword ptr [b]  
00E81436  push        eax  
00E81437  mov         ecx,dword ptr [a]  
00E8143A  push        ecx  
00E8143B  call        sum (0E8105Fh)  
00E81440  add         esp,8  
00E81443  mov         dword ptr [c],eax  
    return 1;
00E81446  mov         eax,1  
}
00E8144B  pop         edi  
00E8144C  pop         esi  
00E8144D  pop         ebx  
00E8144E  add         esp,0E4h  
00E81454  cmp         ebp,esp  
00E81456  call        __RTC_CheckEsp (0E8113Bh)  
00E8145B  mov         esp,ebp  
00E8145D  pop         ebp  
00E8145E  ret  

猜你喜欢

转载自blog.csdn.net/hemeinvyiqiluoben/article/details/84970729
今日推荐