3.4 结构作为参数和返回值(返回值长度小于等于8)
(1)源程序
#include <stdio.h> typedef struct T_test { char x; int y; }T_test; T_test add(T_test c , T_test d) { T_test e; e.x=c.x+d.x; e.y=c.y+d.y; return e; } void main() { T_test a = {1,2}; T_test b = {3,4}; T_test c; c=add(a,b); while (1) { } }
(2)汇编代码
1: #include <stdio.h> 2: typedef struct T_test 3: { 4: char x; 5: int y; 6: }T_test; 7: 8: T_test add(T_test c , T_test d) 9: { 0040B650 push ebp 0040B651 mov ebp,esp 0040B653 sub esp,48h 0040B656 push ebx 0040B657 push esi 0040B658 push edi 0040B659 lea edi,[ebp-48h] 0040B65C mov ecx,12h 0040B661 mov eax,0CCCCCCCCh 0040B666 rep stos dword ptr [edi] 10: T_test e; 11: e.x=c.x+d.x; 0040B668 movsx eax,byte ptr [ebp+8] // 取c.x 0040B66C movsx ecx,byte ptr [ebp+10h] // 取d.x 0040B670 add eax,ecx // c.x+d.x 0040B672 mov byte ptr [ebp-8],al // e.x=c.x+d.x 12: e.y=c.y+d.y; 0040B675 mov edx,dword ptr [ebp+0Ch] // 参见上面 0040B678 add edx,dword ptr [ebp+14h] 0040B67B mov dword ptr [ebp-4],edx 13: 14: return e; 0040B67E mov eax,dword ptr [ebp-8] // eax=e.x 0040B681 mov edx,dword ptr [ebp-4] // dx=e.y 返回值是8字节时, 返回值通过edx:eax返回 15: } 0040B684 pop edi 0040B685 pop esi 0040B686 pop ebx 0040B687 mov esp,ebp 0040B689 pop ebp 0040B68A ret 16: 17: 18: void main() 19: { 0040B530 push ebp 0040B531 mov ebp,esp 0040B533 sub esp,60h 0040B536 push ebx 0040B537 push esi 0040B538 push edi 0040B539 lea edi,[ebp-60h] 0040B53C mov ecx,18h 0040B541 mov eax,0CCCCCCCCh 0040B546 rep stos dword ptr [edi] 20: T_test a = {1,2}; 0040B548 mov byte ptr [ebp-8],1 // 栈中保存a.x,在低地址 0040B54C mov dword ptr [ebp-4],2 // 栈中保存a.y 21: T_test b = {3,4}; 0040B553 mov byte ptr [ebp-10h],3 // 栈中保存b.x 0040B557 mov dword ptr [ebp-0Ch],4 // 栈中保存b.y 22: 23: T_test c; 24: 25: c=add(a,b); 0040B55E mov eax,dword ptr [ebp-0Ch] 0040B561 push eax // b.y的值入栈 0040B562 mov ecx,dword ptr [ebp-10h] 0040B565 push ecx // b.x的值入栈, 即栈中有一个b结构的副本 0040B566 mov edx,dword ptr [ebp-4] 0040B569 push edx // a.x的值入栈 0040B56A mov eax,dword ptr [ebp-8] 0040B56D push eax // a.y的值入栈 0040B56E call @ILT+30(add) (00401023) // 调用add 0040B573 add esp,10h // 调整堆栈 0040B576 mov dword ptr [ebp-20h],eax // 从eax取返回值的低32位, 保存到一个临时的地方temp 0040B579 mov dword ptr [ebp-1Ch],edx // 从edx取返回值的高32位, 保存到一个临时的地方temp 0040B57C mov ecx,dword ptr [ebp-20h] 0040B57F mov dword ptr [ebp-18h],ecx 0040B582 mov edx,dword ptr [ebp-1Ch] 0040B585 mov dword ptr [ebp-14h],edx // c=temp 26: 27: while (1) 0040B588 mov eax,1 0040B58D test eax,eax 0040B58F je main+63h (0040b593) 28: { 29: } 0040B591 jmp main+58h (0040b588) 30: } 0040B593 pop edi 0040B594 pop esi 0040B595 pop ebx 0040B596 add esp,60h 0040B599 cmp ebp,esp 0040B59B call __chkesp (004010e0) 0040B5A0 mov esp,ebp 0040B5A2 pop ebp 0040B5A3 ret
说明:add()函数返回后,把edx:eax保存的返回值保存到堆栈的一个临时存放点[ebp-20h](相当于一个局部临时变量),这个地点的地址不是随便定的。
(3)小结
可以看出,add函数函数返回时是把返回值放到EDX:EAX, 但不是直接赋给变量c,而是先赋给一个栈中的临时变量空间,然后再把这个临时变量赋给c。如果直接写成add(a,b);而不处理返回值,也有这个拷贝到temp的过程。比较怪异吧,参见下一个例子的分析。
最新评论