先上例子:
#include <stdio.h>
void func_reference(int & p)
{
int l1 = 1;
int l2 = 2;
p = 3;
printf("func_reference end\n");
}
void func_ptr(int * p)
{
int l1 = 1;
int l2 = 2;
*p = 3;
printf("func_ptr end\n");
}
void func_value(int p)
{
int l1 = 1;
int l2 = 2;
p = 3;
printf("func_value end\n");
}
void func_value2(int p)
{
int l1 = 1;
int l2 = 2;
p++;
printf("func_value2 end\n");
}
int main(void)
{
int a = 5;
int &b = a;
int c = 6;
int d = 7;
int e = 8;
func_reference(b);
func_value(c);
func_value2(d);
func_ptr(&e);
printf("a[%d], b[%d], c[%d], d[%d], e[%d]\n", a, b, c, d, e);
return 0;
}
编译后运行:
func_reference end
func_value end
func_value2 end
func_ptr end
a[3], b[3], c[6], d[7], e[3]
===========================================================
汇编代码
===========================================================
0000000000400640 <_Z14func_referenceRi>:
400640: 55 push %rbp
400641: 48 89 e5 mov %rsp,%rbp
400644: 48 83 ec 20 sub $0x20,%rsp
400648: 48 89 7d e8 mov %rdi,-0x18(%rbp)
40064c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
400653: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
40065a: 48 8b 45 e8 mov -0x18(%rbp),%rax
40065e: c7 00 03 00 00 00 movl $0x3,(%rax)
400664: bf 70 08 40 00 mov $0x400870,%edi
400669: e8 4a fe ff ff callq 4004b8 <puts@plt>
40066e: c9 leaveq
40066f: c3 retq
0000000000400670 <_Z8func_ptrPi>:
400670: 55 push %rbp
400671: 48 89 e5 mov %rsp,%rbp
400674: 48 83 ec 20 sub $0x20,%rsp
400678: 48 89 7d e8 mov %rdi,-0x18(%rbp)
40067c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
400683: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
40068a: 48 8b 45 e8 mov -0x18(%rbp),%rax
40068e: c7 00 03 00 00 00 movl $0x3,(%rax)
400694: bf 83 08 40 00 mov $0x400883,%edi
400699: e8 1a fe ff ff callq 4004b8 <puts@plt>
40069e: c9 leaveq
40069f: c3 retq
00000000004006a0 <_Z10func_valuei>:
4006a0: 55 push %rbp
4006a1: 48 89 e5 mov %rsp,%rbp
4006a4: 48 83 ec 20 sub $0x20,%rsp
4006a8: 89 7d ec mov %edi,-0x14(%rbp)
4006ab: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
4006b2: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
4006b9: c7 45 f4 03 00 00 00 movl $0x3,-0xc(%rbp)
4006c0: bf 90 08 40 00 mov $0x400890,%edi
4006c5: e8 ee fd ff ff callq 4004b8 <puts@plt>
4006ca: c9 leaveq
4006cb: c3 retq
00000000004006cc <_Z11func_value2i>:
4006cc: 55 push %rbp
4006cd: 48 89 e5 mov %rsp,%rbp
4006d0: 48 83 ec 20 sub $0x20,%rsp
4006d4: 89 7d ec mov %edi,-0x14(%rbp)
4006d7: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
4006de: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
4006e5: 83 45 ec 01 addl $0x1,-0x14(%rbp)
4006e9: bf 9f 08 40 00 mov $0x40089f,%edi
4006ee: e8 c5 fd ff ff callq 4004b8 <puts@plt>
4006f3: c9 leaveq
4006f4: c3 retq
00000000004006f5 <main>:
4006f5: 55 push %rbp
4006f6: 48 89 e5 mov %rsp,%rbp
4006f9: 48 83 ec 20 sub $0x20,%rsp
4006fd: c7 45 ec 05 00 00 00 movl $0x5,-0x14(%rbp)
400704: 48 8d 45 ec lea -0x14(%rbp),%rax
400708: 48 89 45 f8 mov %rax,-0x8(%rbp)
40070c: c7 45 f4 06 00 00 00 movl $0x6,-0xc(%rbp)
400713: c7 45 f0 07 00 00 00 movl $0x7,-0x10(%rbp)
40071a: c7 45 e8 08 00 00 00 movl $0x8,-0x18(%rbp)
400721: 48 8b 45 f8 mov -0x8(%rbp),%rax
400725: 48 89 c7 mov %rax,%rdi
400728: e8 13 ff ff ff callq 400640 <_Z14func_referenceRi>
40072d: 8b 45 f4 mov -0xc(%rbp),%eax
400730: 89 c7 mov %eax,%edi
400732: e8 69 ff ff ff callq 4006a0 <_Z10func_valuei>
400737: 8b 45 f0 mov -0x10(%rbp),%eax
40073a: 89 c7 mov %eax,%edi
40073c: e8 8b ff ff ff callq 4006cc <_Z11func_value2i>
400741: 48 8d 45 e8 lea -0x18(%rbp),%rax
400745: 48 89 c7 mov %rax,%rdi
400748: e8 23 ff ff ff callq 400670 <_Z8func_ptrPi>
40074d: 8b 7d e8 mov -0x18(%rbp),%edi
400750: 48 8b 45 f8 mov -0x8(%rbp),%rax
400754: 8b 10 mov (%rax),%edx
400756: 8b 45 ec mov -0x14(%rbp),%eax
400759: 8b 75 f0 mov -0x10(%rbp),%esi
40075c: 8b 4d f4 mov -0xc(%rbp),%ecx
40075f: 41 89 f9 mov %edi,%r9d
400762: 41 89 f0 mov %esi,%r8d
400765: 89 c6 mov %eax,%esi
400767: bf b0 08 40 00 mov $0x4008b0,%edi
40076c: b8 00 00 00 00 mov $0x0,%eax
400771: e8 32 fd ff ff callq 4004a8 <printf@plt>
400776: b8 00 00 00 00 mov $0x0,%eax
40077b: c9 leaveq
40077c: c3 retq
40077d: 90 nop
40077e: 90 nop
40077f: 90 nop
===========================================================
传引用之汇编分析
===========================================================
调用callq 400640 <_Z14func_referenceRi>之前的参数传递:
X64是寄存器传参,第一个参数是用rdi/edi传递,而传递给func_reference的参数为汇编指令
lea -0x14(%rbp),%rax 获取的地址,而-0x14(%rbp)中存放的是立即数5:
movl $0x5,-0x14(%rbp)
也就是说实际汇编传递给func_reference的是存放0x5的内存地址。
再来看func_reference的汇编指令:
0000000000400640 <_Z14func_referenceRi>:
400640: 55 push %rbp
400641: 48 89 e5 mov %rsp,%rbp
400644: 48 83 ec 20 sub $0x20,%rsp
400648: 48 89 7d e8 mov %rdi,-0x18(%rbp)
40064c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
400653: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
40065a: 48 8b 45 e8 mov -0x18(%rbp),%rax
40065e: c7 00 03 00 00 00 movl $0x3,(%rax)
400664: bf 70 08 40 00 mov $0x400870,%edi
400669: e8 4a fe ff ff callq 4004b8 <puts@plt>
40066e: c9 leaveq
40066f: c3 retq
rdi中的参数最终赋给了rax, 即rax中现在存放的是传递进来的存放5的内存地址,最终:
movl $0x3,(%rax)
把3放到rax指向的内存,也就是原来放5的内存,现在写进了3,所以最终结果是3.
===========================================================
传指针之汇编分析
===========================================================
调用callq 400670 <_Z8func_ptrPi> 之前的参数传递:
40071a: c7 45 e8 08 00 00 00 movl $0x8,-0x18(%rbp)
... ...
400741: 48 8d 45 e8 lea -0x18(%rbp),%rax
400745: 48 89 c7 mov %rax,%rdi
也就是说参数寄存器存放的是立即数8的内存地址。
再来看func_ptr的汇编代码:
0000000000400670 <_Z8func_ptrPi>:
400670: 55 push %rbp
400671: 48 89 e5 mov %rsp,%rbp
400674: 48 83 ec 20 sub $0x20,%rsp
400678: 48 89 7d e8 mov %rdi,-0x18(%rbp)
40067c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
400683: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
40068a: 48 8b 45 e8 mov -0x18(%rbp),%rax
40068e: c7 00 03 00 00 00 movl $0x3,(%rax)
400694: bf 83 08 40 00 mov $0x400883,%edi
400699: e8 1a fe ff ff callq 4004b8 <puts@plt>
40069e: c9 leaveq
40069f: c3 retq
最终rdi中的内存地址赋值给了rax, 最后:
movl $0x3,(%rax)
因此,内存内容被写成3
===========================================================
传值之汇编分析
===========================================================
调用func_value之前的参数传递:
40070c: c7 45 f4 06 00 00 00 movl $0x6,-0xc(%rbp)
... ...
40072d: 8b 45 f4 mov -0xc(%rbp),%eax
400730: 89 c7 mov %eax,%edi
因此,edi中存放的就是0x6。
再来看看func_value的汇编指令:
00000000004006a0 <_Z10func_valuei>:
4006a0: 55 push %rbp
4006a1: 48 89 e5 mov %rsp,%rbp
4006a4: 48 83 ec 20 sub $0x20,%rsp
4006a8: 89 7d ec mov %edi,-0x14(%rbp)
4006ab: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
4006b2: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
4006b9: c7 45 f4 03 00 00 00 movl $0x3,-0xc(%rbp)
4006c0: bf 90 08 40 00 mov $0x400890,%edi
4006c5: e8 ee fd ff ff callq 4004b8 <puts@plt>
4006ca: c9 leaveq
4006cb: c3 retq
可以看到edi放到了-0x14(%rbp),但是0x3放进了 -0xc(%rbp)
再来看func_value2的汇编:
00000000004006cc <_Z11func_value2i>:
4006cc: 55 push %rbp
4006cd: 48 89 e5 mov %rsp,%rbp
4006d0: 48 83 ec 20 sub $0x20,%rsp
4006d4: 89 7d ec mov %edi,-0x14(%rbp)
4006d7: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
4006de: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
4006e5: 83 45 ec 01 addl $0x1,-0x14(%rbp)
4006e9: bf 9f 08 40 00 mov $0x40089f,%edi
4006ee: e8 c5 fd ff ff callq 4004b8 <puts@plt>
4006f3: c9 leaveq
4006f4: c3 retq
由于func_value2执行的是p++,改变的是参数本身:
4006d4: 89 7d ec mov %edi,-0x14(%rbp)
... ...
4006e5: 83 45 ec 01 addl $0x1,-0x14(%rbp)