分析函数调用的汇编指令

同样一段c++代码生成的汇编指令可能会不一样。有多种原因,例如编译器、调用约定或者底层平台。

今天要分析的是cdecl在x86机器上用visual c++ 2005上的编译结果。

首先需要设置一下项目配置以得到从源代码生成的汇编代码。

项目属性->配置属性->c/c++->输出文件->汇编输出 = Assembly With Source Code (/FAs)。

要被编译的源文件是:


#include  " stdafx.h "

struct  Point3D
{
    
int  X;
    
int  Y;
    
int  Z;

    Point3D(
int  x,  int  y,  int  z):X(x),Y(y),Z(z)
    {}
};

Point3D AddPoint3D(Point3D p1, Point3D p2)
{
    Point3D p(p1);
    p.X 
+=  p2.X;
    p.Y 
+=  p2.Y;
    p.Z 
+=  p2.Z;

    
return  p;
}

void  main()
{
    Point3D p1(
1 , 2 , 3 );
    Point3D p2(
4 , 5 , 6 );
    Point3D p3 
=  AddPoint3D(p1,p2);
}

 

生成的汇编代码是:

 


;  Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.762 

    TITLE    
d: /project/CheckAsm/CheckAsm/CheckAsm.cpp
    .686P
    .XMM
    include listing.
inc
    .model    flat

INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES

PUBLIC    ?AddPoint3D@@YA?AUPoint3D@@U1@0@Z        
;  AddPoint3D
EXTRN     @_RTC_CheckStackVars@8: PROC
EXTRN    
__RTC_Shutdown: PROC
EXTRN    
__RTC_InitBase: PROC
;     COMDAT rtc$TMZ
;
 File d:/project/checkasm/checkasm/checkasm.cpp
rtc$TMZ    SEGMENT
__RTC_Shutdown.rtc$TMZ DD 
FLAT: __RTC_Shutdown
rtc$TMZ    ENDS
;     COMDAT rtc$IMZ
rtc$IMZ    SEGMENT
__RTC_InitBase.rtc$IMZ DD 
FLAT: __RTC_InitBase
;  Function compile flags: /Odtp /RTCsu /ZI
rtc$IMZ    ENDS
;     COMDAT ?AddPoint3D@@YA?AUPoint3D@@U1@0@Z
;
上面一堆先不管
_TEXT    SEGMENT ; 定义PE文件中的Text段
_p$ = - 16                          ;  size = 12;
___$ReturnUdt$ =  8                      ;  size = 4
_p1$ =  12                          ;  size = 12
_p2$ =  24                          ;  size = 12
;
上面4个符号是AddPoint3D这个方法中的局部变量、返回值和参数的偏移量(相对于ebp)
?AddPoint3D@@YA?AUPoint3D@@U1@0@Z PROC             ;  AddPoint3D, COMDAT AddPoint3D方法的定义开始,由于name mangling,名称变为了AddPoint3D@@YA?AUPoint3D@@U1@0@Z
;
 15   : {

    
push     ebp ; 保存caller的ebp到堆栈
     mov     ebp, esp ; 设置本方法的ebp。ebp在方法调用的开始阶段被设置,结束阶段被还原,调用过程中保持不变。ebp表示为本次调用所分配的堆栈桢的起始地址
     sub     esp,  212                  ;  000000d4H esp减少一定的数量,表示为本次调用在栈上分配了一定的空间。让我们把>ebp && <= 现在的esp 的这段内存称之为locals
     push     ebx ; 保存现场的3个push
     push     esi
    
push     edi
    
lea     edi, DWORD PTR [ebp- 212 ] ; 把edi设置成刚才sub esp后esp的值,也就是locals的最低地址
     mov     ecx,  53                      ;  00000035H 53 * 4 = 212, you see whats going on here?
     mov     eax, - 858993460                  ;  ccccccccH    设置eax=cccccccch
     rep   stosd   ; 这是一个串操作指令,其意义是
;
while(ecx)
;
{
;
    *(int*)edi = eax;
;
    edi += sizeof(int);//这里就是4
;
    ecx--;
;
}
;
本指令和它上面的三条指令完成了把locals这段内存初始化成一片ccccccccccccccccccccc .
;
当此指令执行完毕,edi == ebp
;
 16   :     Point3D p(p1);

    
mov     eax, DWORD PTR _p1$[ebp]
    
mov     DWORD PTR _p$[ebp], eax
    
mov     ecx, DWORD PTR _p1$[ebp+ 4 ]
    
mov     DWORD PTR _p$[ebp+ 4 ], ecx
    
mov     edx, DWORD PTR _p1$[ebp+ 8 ]
    
mov     DWORD PTR _p$[ebp+ 8 ], edx
; 复制构造局部变量p。_p1$[ebp]的意思就是[ebp + _p1$],_p1$是在前面定义过的一个偏移量
;
 17   :     p.X += p2.X;

    
mov     eax, DWORD PTR _p$[ebp]
    
add     eax, DWORD PTR _p2$[ebp]
    
mov     DWORD PTR _p$[ebp], eax

;  18   :     p.Y += p2.Y;

    
mov     eax, DWORD PTR _p$[ebp+ 4 ]
    
add     eax, DWORD PTR _p2$[ebp+ 4 ]
    
mov     DWORD PTR _p$[ebp+ 4 ], eax

;  19   :     p.Z += p2.Z;

    
mov     eax, DWORD PTR _p$[ebp+ 8 ]
    
add     eax, DWORD PTR _p2$[ebp+ 8 ]
    
mov     DWORD PTR _p$[ebp+ 8 ], eax
; 这些很好理解
;
 20   : 
;
 21   :     return p;

    
mov     eax, DWORD PTR ___$ReturnUdt$[ebp]
; ReturnUdt中的Udt表示user defined type
;
这条指令的意思是,调用方在从ebp开始偏移量是___$ReturnUdt$的dword中保存的返回值应当存放的地址,把这个地址加载到eax中
;
此时eax保存的是一个地址,这个地址实际上call中局部变量p3的地址
     mov     ecx, DWORD PTR _p$[ebp]
    
mov     DWORD PTR [eax], ecx
    
mov     edx, DWORD PTR _p$[ebp+ 4 ]
    
mov     DWORD PTR [eax+ 4 ], edx
    
mov     ecx, DWORD PTR _p$[ebp+ 8 ]
    
mov     DWORD PTR [eax+ 8 ], ecx
; 从局部变量p复制到call的局部变量p3中
     mov     eax, DWORD PTR ___$ReturnUdt$[ebp]
; 在eax中保存返回值的地址
;
 22   : }
;
这一段{
     push     edx
    
mov     ecx, ebp
    
push     eax
    
lea     edx, DWORD PTR $LN5@AddPoint3D
    
call     @_RTC_CheckStackVars@8
    
pop     eax
    
pop     edx
; 这一段}可以忽略掉,并不是我们程序逻辑的一部分
     pop     edi
    
pop     esi
    
pop     ebx
    
mov     esp, ebp
    
pop     ebp
    
ret      0 ; 函数返回,返回值的保存地址存放在eax中
    npad     2
$
LN5@AddPoint3D:
    DD    
1
    DD    $LN4@AddPoint3D
$
LN4@AddPoint3D:
    DD    -
16                      ;  fffffff0H
    DD     12                      ;  0000000cH
    DD    $LN3@AddPoint3D
$
LN3@AddPoint3D:
    DB    
112                      ;  00000070H
    DB     0
?AddPoint3D@@YA?AUPoint3D@@U1@0@Z ENDP            
;  AddPoint3D
_TEXT    ENDS
PUBLIC    ??0Point3D@@QAE@HHH@Z                
;  Point3D::Point3D
PUBLIC    _main
EXTRN    
__RTC_CheckEsp: PROC
;  Function compile flags: /Odtp /RTCsu /ZI
;
    COMDAT _main
_TEXT    SEGMENT
_p3$ = -
56                          ;  size = 12
_p2$ = - 36                          ;  size = 12
_p1$ = - 16                          ;  size = 12
_main    PROC                         ;  COMDAT

;  25   : {
;
主函数的调用过程
;
参见上面的注释{
     push     ebp
    
mov     ebp, esp
    
sub     esp,  252                  ;  000000fcH
     push     ebx
    
push     esi
    
push     edi
    
lea     edi, DWORD PTR [ebp- 252 ]
    
mov     ecx,  63                      ;  0000003fH
     mov     eax, - 858993460                  ;  ccccccccH
     rep   stosd
; 参见上面的注释}
;
 26   :     Point3D p1(1,2,3);

    
push      3
    
push      2
    
push      1
    
lea     ecx, DWORD PTR _p1$[ebp] ; ecx传递this指针,thiscall
     call     ??0Point3D@@QAE@HHH@Z             ;  Point3D::Point3D

;  27   :     Point3D p2(4,5,6);

    
push      6
    
push      5
    
push      4
    
lea     ecx, DWORD PTR _p2$[ebp]
    
call     ??0Point3D@@QAE@HHH@Z             ;  Point3D::Point3D

;  28   :     Point3D p3 = AddPoint3D(p1,p2);

    
sub     esp,  12                      ;  0000000cH 分配实参p1的空间并按值传递
     mov     eax, esp
    
mov     ecx, DWORD PTR _p2$[ebp]
    
mov     DWORD PTR [eax], ecx
    
mov     edx, DWORD PTR _p2$[ebp+ 4 ]
    
mov     DWORD PTR [eax+ 4 ], edx
    
mov     ecx, DWORD PTR _p2$[ebp+ 8 ]
    
mov     DWORD PTR [eax+ 8 ], ecx
    
sub     esp,  12                      ;  0000000cH 分配实参p2的空间并按值传递
     mov     edx, esp
    
mov     eax, DWORD PTR _p1$[ebp]
    
mov     DWORD PTR [edx], eax
    
mov     ecx, DWORD PTR _p1$[ebp+ 4 ]
    
mov     DWORD PTR [edx+ 4 ], ecx
    
mov     eax, DWORD PTR _p1$[ebp+ 8 ]
    
mov     DWORD PTR [edx+ 8 ], eax
    
lea     ecx, DWORD PTR _p3$[ebp]
    
push     ecx     ; 注意这个地方,p3的地址被保存在这里,也就是返回值的地址
     call     ?AddPoint3D@@YA?AUPoint3D@@U1@0@Z     ;  AddPoint3D
     add     esp,  28                      ;  0000001cH 调用方清理参数堆栈28=12+12+4

;  29   : }

    
xor     eax, eax
    
push     edx
    
mov     ecx, ebp
    
push     eax
    
lea     edx, DWORD PTR $LN7@main
    
call     @_RTC_CheckStackVars@8
    
pop     eax
    
pop     edx
    
pop     edi
    
pop     esi
    
pop     ebx
    
add     esp,  252                  ;  000000fcH
     cmp     ebp, esp
    
call     __RTC_CheckEsp
    
mov     esp, ebp
    
pop     ebp
    
ret      0
    npad    
3
$
LN7@main:
    DD    
3
    DD    $LN6@main
$
LN6@main:
    DD    -
16                      ;  fffffff0H
    DD     12                      ;  0000000cH
    DD    $LN3@main
    DD    -
36                      ;  ffffffdcH
    DD     12                      ;  0000000cH
    DD    $LN4@main
    DD    -
56                      ;  ffffffc8H
    DD     12                      ;  0000000cH
    DD    $LN5@main
$
LN5@main:
    DB    
112                      ;  00000070H
    DB     51                      ;  00000033H
    DB     0
$
LN4@main:
    DB    
112                      ;  00000070H
    DB     50                      ;  00000032H
    DB     0
$
LN3@main:
    DB    
112                      ;  00000070H
    DB     49                      ;  00000031H
    DB     0
_main    ENDP
;  Function compile flags: /Odtp /RTCsu /ZI
_TEXT    ENDS
;     COMDAT ??0Point3D@@QAE@HHH@Z
_TEXT    SEGMENT
_this$ = -
8                          ;  size = 4
_x$ =  8                              ;  size = 4
_y$ =  12                          ;  size = 4
_z$ =  16                          ;  size = 4
??0Point3D@@QAE@HHH@Z PROC                 ;  Point3D::Point3D, COMDAT
;
 _this$ = ecx

;  11   :     {}

    
push     ebp
    
mov     ebp, esp
    
sub     esp,  204                  ;  000000ccH
     push     ebx
    
push     esi
    
push     edi
    
push     ecx
    
lea     edi, DWORD PTR [ebp- 204 ]
    
mov     ecx,  51                      ;  00000033H
     mov     eax, - 858993460                  ;  ccccccccH
     rep   stosd
    
pop     ecx
    
mov     DWORD PTR _this$[ebp], ecx
    
mov     eax, DWORD PTR _this$[ebp]
    
mov     ecx, DWORD PTR _x$[ebp]
    
mov     DWORD PTR [eax], ecx
    
mov     eax, DWORD PTR _this$[ebp]
    
mov     ecx, DWORD PTR _y$[ebp]
    
mov     DWORD PTR [eax+ 4 ], ecx
    
mov     eax, DWORD PTR _this$[ebp]
    
mov     ecx, DWORD PTR _z$[ebp]
    
mov     DWORD PTR [eax+ 8 ], ecx
    
mov     eax, DWORD PTR _this$[ebp]
    
pop     edi
    
pop     esi
    
pop     ebx
    
mov     esp, ebp
    
pop     ebp
    
ret      12                      ;  0000000cH
??0Point3D@@QAE@HHH@Z ENDP                 ;  Point3D::Point3D
_TEXT    ENDS
END
摘自:http://www.cnblogs.com/zhy2002/archive/2008/12/10/1351796.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值