指针与引用
int main() { 000000013FA01010 push rdi 000000013FA01012 sub rsp,50h 000000013FA01016 mov rdi,rsp 000000013FA01019 mov ecx,14h 000000013FA0101E mov eax,0CCCCCCCCh 000000013FA01023 rep stos dword ptr [rdi] int x=0x12345678; 000000013FA01025 mov dword ptr [x],12345678h //取地址到指针变量p中 int *p=&x; 000000013FA0102D lea rax,[x] 000000013FA01032 mov qword ptr [p],rax int y=*p; 000000013FA01037 mov rax,qword ptr [p] 000000013FA0103C mov eax,dword ptr [rax] 000000013FA0103E mov dword ptr [y],eax printf("%d",y); 000000013FA01042 mov edx,dword ptr [y] 000000013FA01046 lea rcx,[__xi_z+150h (013FA068C0h)] 000000013FA0104D call qword ptr [__imp_printf (013FA0B540h)] return 0; 000000013FA01053 xor eax,eax } 000000013FA01055 mov edi,eax 000000013FA01057 mov rcx,rsp 000000013FA0105A lea rdx,[__xi_z+1A0h (013FA06910h)] 000000013FA01061 call _RTC_CheckStackVars (013FA010D0h) 000000013FA01066 mov eax,edi 000000013FA01068 add rsp,50h 000000013FA0106C pop rdi 000000013FA0106D ret
解引用在汇编中要取两次“地址”。
指针p是一个指针变量,空间内存放x的地址。
下面看看引用:
可以看到,两者反汇编代码是相同的,不同的是解引用是由编译器操作的。
我们在定义时,定义为引用,编译器就知道这是一个需要编译器寻址的指针。例如printf时,不需要写成*p。
看下面的代码:
void _swap(int a,int b) { int temp; temp=a; a=b; b=temp; } void swap1(int *a,int *b) { int temp; temp=*a; *a=*b; *b=temp; } void swap2(int &a,int &b) { int temp=a; a=b; b=temp; } int main() { int x,y; x=10; y=20; _swap(x,y); printf("%d,%d\n",x,y); swap1(&x,&y); printf("%d,%d\n",x,y); swap2(x,y); printf("%d,%d\n",x,y); return 0; }
vc中的反汇编代码:
void _swap(int a,int b) { 000000013F1F1030 mov dword ptr [rsp+10h],edx 000000013F1F1034 mov dword ptr [rsp+8],ecx 000000013F1F1038 push rdi 000000013F1F1039 sub rsp,10h 000000013F1F103D mov rdi,rsp 000000013F1F1040 mov ecx,4 000000013F1F1045 mov eax,0CCCCCCCCh 000000013F1F104A rep stos dword ptr [rdi] 000000013F1F104C mov ecx,dword ptr [a] int temp; temp=a; 000000013F1F1050 mov eax,dword ptr [a] 000000013F1F1054 mov dword ptr [rsp],eax a=b; 000000013F1F1057 mov eax,dword ptr [b] 000000013F1F105B mov dword ptr [a],eax b=temp; 000000013F1F105F mov eax,dword ptr [rsp] 000000013F1F1062 mov dword ptr [b],eax } 000000013F1F1066 add rsp,10h 000000013F1F106A pop rdi 000000013F1F106B ret ///////////////////////////////// void swap1(int *a,int *b) { 000000013F1F1080 mov qword ptr [rsp+10h],rdx 000000013F1F1085 mov qword ptr [rsp+8],rcx 000000013F1F108A push rdi 000000013F1F108B sub rsp,10h 000000013F1F108F mov rdi,rsp 000000013F1F1092 mov ecx,4 000000013F1F1097 mov eax,0CCCCCCCCh 000000013F1F109C rep stos dword ptr [rdi] 000000013F1F109E mov rcx,qword ptr [a] int temp; temp=*a; 000000013F1F10A3 mov rax,qword ptr [a] 000000013F1F10A8 mov eax,dword ptr [rax] 000000013F1F10AA mov dword ptr [rsp],eax *a=*b; 000000013F1F10AD mov rax,qword ptr [a] 000000013F1F10B2 mov rcx,qword ptr [b] 000000013F1F10B7 mov ecx,dword ptr [rcx] 000000013F1F10B9 mov dword ptr [rax],ecx *b=temp; 000000013F1F10BB mov rax,qword ptr [b] 000000013F1F10C0 mov ecx,dword ptr [rsp] 000000013F1F10C3 mov dword ptr [rax],ecx } 000000013F1F10C5 add rsp,10h 000000013F1F10C9 pop rdi 000000013F1F10CA ret ////////////////////////////////// void swap2(int &a,int &b) { 000000013F1F10E0 mov qword ptr [rsp+10h],rdx 000000013F1F10E5 mov qword ptr [rsp+8],rcx 000000013F1F10EA push rdi 000000013F1F10EB sub rsp,10h 000000013F1F10EF mov rdi,rsp 000000013F1F10F2 mov ecx,4 000000013F1F10F7 mov eax,0CCCCCCCCh 000000013F1F10FC rep stos dword ptr [rdi] 000000013F1F10FE mov rcx,qword ptr [a] int temp=a; 000000013F1F1103 mov rax,qword ptr [a] 000000013F1F1108 mov eax,dword ptr [rax] 000000013F1F110A mov dword ptr [rsp],eax a=b; 000000013F1F110D mov rax,qword ptr [a] 000000013F1F1112 mov rcx,qword ptr [b] 000000013F1F1117 mov ecx,dword ptr [rcx] 000000013F1F1119 mov dword ptr [rax],ecx b=temp; 000000013F1F111B mov rax,qword ptr [b] 000000013F1F1120 mov ecx,dword ptr [rsp] 000000013F1F1123 mov dword ptr [rax],ecx } 000000013F1F1125 add rsp,10h 000000013F1F1129 pop rdi 000000013F1F112A ret ////////////////////////////////// int main() { 000000013F541140 push rdi 000000013F541142 sub rsp,60h 000000013F541146 mov rdi,rsp 000000013F541149 mov ecx,18h 000000013F54114E mov eax,0CCCCCCCCh 000000013F541153 rep stos dword ptr [rdi] int x,y; x=10; 000000013F541155 mov dword ptr [x],0Ah y=20; 000000013F54115D mov dword ptr [y],14h _swap(x,y); 000000013F541165 mov edx,dword ptr [y] 000000013F541169 mov ecx,dword ptr [x] 000000013F54116D call _swap (013F541005h) printf("%d,%d\n",x,y); 000000013F541172 mov r8d,dword ptr [y] 000000013F541177 mov edx,dword ptr [x] 000000013F54117B lea rcx,[__xi_z+150h (013F5468C0h)] 000000013F541182 call qword ptr [__imp_printf (013F54B540h)] swap1(&x,&y); 000000013F541188 lea rdx,[y] 000000013F54118D lea rcx,[x] 000000013F541192 call swap1 (013F54100Ah) printf("%d,%d\n",x,y); 000000013F541197 mov r8d,dword ptr [y] 000000013F54119C mov edx,dword ptr [x] 000000013F5411A0 lea rcx,[__xi_z+158h (013F5468C8h)] 000000013F5411A7 call qword ptr [__imp_printf (013F54B540h)] swap2(x,y); 000000013F5411AD lea rdx,[y] 000000013F5411B2 lea rcx,[x] 000000013F5411B7 call swap2 (013F54100Fh) printf("%d,%d\n",x,y); 000000013F5411BC mov r8d,dword ptr [y] 000000013F5411C1 mov edx,dword ptr [x] 000000013F5411C5 lea rcx,[__xi_z+160h (013F5468D0h)] 000000013F5411CC call qword ptr [__imp_printf (013F54B540h)] return 0; 000000013F5411D2 xor eax,eax } 000000013F5411D4 mov edi,eax 000000013F5411D6 mov rcx,rsp 000000013F5411D9 lea rdx,[__xi_z+1F0h (013F546960h)] 000000013F5411E0 call _RTC_CheckStackVars (013F541290h) 000000013F5411E5 mov eax,edi 000000013F5411E7 add rsp,60h } 000000013F5411EB pop rdi 000000013F5411EC ret
在这上面看不出什么有价值的东西,看看IDA:
; int __cdecl main() main proc near a= dword ptr -44h b= dword ptr -24h push rdi sub rsp, 60h mov rdi, rsp mov ecx, 18h mov eax, 0CCCCCCCCh rep stosd mov [rsp+68h+a], 0Ah mov [rsp+68h+b], 14h mov edx, [rsp+68h+b] ; b mov ecx, [rsp+68h+a] ; a call j_?_swap@@YAXHH@Z ; _swap(int,int) mov r8d, [rsp+68h+b] mov edx, [rsp+68h+a] lea rcx, aDD ; "%d,%d\n" call cs:__imp_printf lea rdx, [rsp+68h+b] ; b lea rcx, [rsp+68h+a] ; a call j_?swap1@@YAXPEAH0@Z ; swap1(int *,int *) mov r8d, [rsp+68h+b] mov edx, [rsp+68h+a] lea rcx, aDD_0 ; "%d,%d\n" call cs:__imp_printf lea rdx, [rsp+68h+b] ; b lea rcx, [rsp+68h+a] ; a call j_?swap2@@YAXAEAH0@Z ; swap2(int &,int &) mov r8d, [rsp+68h+b] mov edx, [rsp+68h+a] lea rcx, aDD_1 ; "%d,%d\n" call cs:__imp_printf xor eax, eax mov edi, eax mov rcx, rsp ; frame lea rdx, v ; v call _RTC_CheckStackVars mov eax, edi add rsp, 60h pop rdi retn main endp ; void __cdecl _swap(int a, int b) ?_swap@@YAXHH@Z proc near var_18= dword ptr -18h arg_0= dword ptr 8 arg_8= dword ptr 10h ;win x64不超过4个参数用寄存器传参 ;但是堆栈会保留并且会赋值 mov [rsp+arg_8], edx mov [rsp+arg_0], ecx push rdi sub rsp, 10h mov rdi, rsp mov ecx, 4 mov eax, 0CCCCCCCCh rep stosd mov ecx, [rsp+18h+arg_0] mov eax, [rsp+18h+arg_0] mov [rsp+18h+var_18], eax mov eax, [rsp+18h+arg_8] mov [rsp+18h+arg_0], eax mov eax, [rsp+18h+var_18] mov [rsp+18h+arg_8], eax add rsp, 10h pop rdi retn ?_swap@@YAXHH@Z endp ; void __cdecl swap1(int *a, int *b) ?swap1@@YAXPEAH0@Z proc near var_18= dword ptr -18h arg_0= qword ptr 8 arg_8= qword ptr 10h mov [rsp+arg_8], rdx mov [rsp+arg_0], rcx push rdi sub rsp, 10h mov rdi, rsp mov ecx, 4 mov eax, 0CCCCCCCCh rep stosd mov rcx, [rsp+18h+arg_0] mov rax, [rsp+18h+arg_0] mov eax, [rax] mov [rsp+18h+var_18], eax mov rax, [rsp+18h+arg_0] mov rcx, [rsp+18h+arg_8] mov ecx, [rcx] mov [rax], ecx mov rax, [rsp+18h+arg_8] mov ecx, [rsp+18h+var_18] mov [rax], ecx add rsp, 10h pop rdi retn ?swap1@@YAXPEAH0@Z endp ; void __cdecl swap2(int *a, int *b) ?swap2@@YAXAEAH0@Z proc near var_18= dword ptr -18h arg_0= qword ptr 8 arg_8= qword ptr 10h mov [rsp+arg_8], rdx mov [rsp+arg_0], rcx push rdi sub rsp, 10h mov rdi, rsp mov ecx, 4 mov eax, 0CCCCCCCCh rep stosd mov rcx, [rsp+18h+arg_0] mov rax, [rsp+18h+arg_0] mov eax, [rax] mov [rsp+18h+var_18], eax mov rax, [rsp+18h+arg_0] mov rcx, [rsp+18h+arg_8] mov ecx, [rcx] mov [rax], ecx mov rax, [rsp+18h+arg_8] mov ecx, [rsp+18h+var_18] mov [rax], ecx add rsp, 10h pop rdi retn ?swap2@@YAXAEAH0@Z endp
对比一下:
指针与引用对比。两者反汇编代码是一样的。
1.为何用非指针非引用传参函数无效?
因为是在栈上的参数交换的地址内的数,属于公用的,并不是去改变x,y地址内的数。输出x,y当然没有改变。
2.指针、引用为何能改变?
因为它们找到x,y地址,改变了地址内的内容。