c#编程指南(十四) 平台调用P-INVOKE完全掌握, 反汇编细解结构体作为返回值
2010-09-30 22:46:03 来源:WEB开发网这篇解决上篇那个结构体作为返回值的问题。我们结合反汇编来探索这里面的秘密。如何反汇编?
方法如下:在C++函数内下断点,调试到断点断下,右键菜单,选择"反汇编",反汇编是VS自带功能。
下面是几个简单的类:
1 struct Test1
2 {
3 int Count1;
4 };
5
6 struct Test2
7 {
8 int Count1;
9 int Count2;
10 };
11
12 struct Test3
13 {
14 int Count1;
15 int Count2;
16 int Count3;
17 };
分别用上面的方法来逐个分析汇编:汇编里有我详细的注释:
1
2 当返回Test1的时候:汇编如下:
3 函数内:
4 ;----------------------------GetTest函数内-------------------------------------------------
5 _test.Count = 3333;
6 00411B0E mov dword ptr [_test (4174C4h)],0D05h
7 return _test;
8 00411B18 mov eax,dword ptr [_test (4174C4h)] ; //把返回值放到EAX寄存器
9 ;---------------------------主函数调用GetTest----------------------------------------------
10 Test test = GetTest();
11 004135FE call GetTest (4110E1h)
12 00413603 mov dword ptr [ebp-0D4h],eax ;//将返回值存储在栈中分配的变量中。
13 ;---------------------------------------------------------------------------------------------------
14
15 看来虽然Test1是结构体,但是由于就占4个字节,所以通过EAX正常返回。
16
17
18 看下Test2的反汇编:
19 ;----------------------------GetTest函数内-------------------------------------------------
20 _test.Count = 3333;
21 00411B0E mov dword ptr [_test (4174C4h)],0D05h
22 _test.Count2 = 4444;
23 00411B18 mov dword ptr [_test+4 (4174C8h)],115Ch
24 return _test;
25 00411B22 mov eax,dword ptr [_test (4174C4h)] ;返回值通过EAX,EDX返回
26 00411B27 mov edx,dword ptr [_test+4 (4174C8h)]
27 ;---------------------------主函数调用GetTest----------------------------------------------
28 Test test = GetTest();
29 004135FE call GetTest (4110E1h)
30 00413603 mov dword ptr [ebp-0DCh],eax ;返回值存入栈中变量
31 00413609 mov dword ptr [ebp-0D8h],edx
32 ;---------------------------------------------------------------------------------------------------
33
34 虽然Test2占8个字节,但是编译器通过组合EAX,EDX可以正确返回。
35
36
37 看下Test3的反汇编:
38 ;----------------------------GetTest函数内-------------------------------------------------
39 00411470 push ebp
40 00411471 mov ebp,esp ;构建栈帧
41
42 00411473 sub esp,0C0h ;分配局部变量
43
44 00411479 push ebx
45 0041147A push esi
46 0041147B push edi ;保存寄存器环境
47
48 0041147C lea edi,[ebp-0C0h]
49 00411482 mov ecx,30h
50 00411487 mov eax,0CCCCCCCCh
51 0041148C rep stos dword ptr es:[edi] ;设置trap area.
52
53 _test.Count1 = 3333;
54 0041148E mov dword ptr [_test (417140h)],0D05h
55 _test.Count2 = 4444;
56 00411498 mov dword ptr [_test+4 (417144h)],115Ch
57 _test.Count3 = 5555;
58 004114A2 mov dword ptr [_test+8 (417148h)],15B3h
59
60
61 return _test;
62 004114AC mov eax,dword ptr [ebp+8] ;得到第一个参数,注意__stdcall从右向左压栈.
63
64 004114AF mov ecx,dword ptr [_test (417140h)]
65 004114B5 mov dword ptr [eax],ecx ;参数是一个指针,写入第一个成员;
66 004114B7 mov edx,dword ptr [_test+4 (417144h)]
67 004114BD mov dword ptr [eax+4],edx ;参数是一个指针,写入第二个成员;
68 004114C0 mov ecx,dword ptr [_test+8 (417148h)]
69 004114C6 mov dword ptr [eax+8],ecx ;参数是一个指针,写入第三个成员;
70 004114C9 mov eax,dword ptr [ebp+8]
71 ;---------------------------主函数调用GetTest----------------------------------------------
72 Test test = GetTest();
73 004113BE lea eax,[ebp-0E4h]
74 004113C4 push eax ;压栈参数
75 004113C5 call GetTest (4110E1h)
76 004113CA add esp,4 ;回收栈帧
77
78 004113CD mov ecx,dword ptr [eax] ;返回参数。
79
80 004113CF mov dword ptr [ebp-0F8h],ecx ; 写入局部变量test
81 004113D5 mov edx,dword ptr [eax+4]
82 004113D8 mov dword ptr [ebp-0F4h],edx
83 004113DE mov eax,dword ptr [eax+8]
84 004113E1 mov dword ptr [ebp-0F0h],eax
85 004113E7 mov ecx,dword ptr [ebp-0F8h]
86 004113ED mov dword ptr [test],ecx
87 004113F0 mov edx,dword ptr [ebp-0F4h]
88 004113F6 mov dword ptr [ebp-0Ch],edx
89 004113F9 mov eax,dword ptr [ebp-0F0h]
90 004113FF mov dword ptr [ebp-8],eax
91 return 0;
92 00411402 xor eax,eax
93 ;---------------------------------------------------------------------------------------------------
94
95 Test3占12字节,无法正常通EAX,EDX返回,所以编译器把函数编译成带输入参数的函数,
96 就好像Test test = GetTest(&test);一样。
更多精彩
赞助商链接