同样一段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