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 neara= dword ptr -44hb= dword ptr -24hpush rdisub rsp, 60hmov rdi, rspmov ecx, 18hmov eax, 0CCCCCCCChrep stosdmov [rsp+68h+a], 0Ahmov [rsp+68h+b], 14hmov edx, [rsp+68h+b] ; bmov ecx, [rsp+68h+a] ; acall 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_printflea rdx, [rsp+68h+b] ; blea rcx, [rsp+68h+a] ; acall 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_printflea rdx, [rsp+68h+b] ; blea rcx, [rsp+68h+a] ; acall 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_printfxor eax, eaxmov edi, eaxmov rcx, rsp ; framelea rdx, v ; vcall _RTC_CheckStackVarsmov eax, ediadd rsp, 60hpop rdiretnmain endp; void __cdecl _swap(int a, int b)?_swap@@YAXHH@Z proc nearvar_18= dword ptr -18harg_0= dword ptr 8arg_8= dword ptr 10h;win x64不超过4个参数用寄存器传参;但是堆栈会保留并且会赋值mov [rsp+arg_8], edxmov [rsp+arg_0], ecxpush rdisub rsp, 10hmov rdi, rspmov ecx, 4mov eax, 0CCCCCCCChrep stosdmov ecx, [rsp+18h+arg_0]mov eax, [rsp+18h+arg_0]mov [rsp+18h+var_18], eaxmov eax, [rsp+18h+arg_8]mov [rsp+18h+arg_0], eaxmov eax, [rsp+18h+var_18]mov [rsp+18h+arg_8], eaxadd rsp, 10hpop rdiretn?_swap@@YAXHH@Z endp; void __cdecl swap1(int *a, int *b)?swap1@@YAXPEAH0@Z proc nearvar_18= dword ptr -18harg_0= qword ptr 8arg_8= qword ptr 10hmov [rsp+arg_8], rdxmov [rsp+arg_0], rcxpush rdisub rsp, 10hmov rdi, rspmov ecx, 4mov eax, 0CCCCCCCChrep stosdmov rcx, [rsp+18h+arg_0]mov rax, [rsp+18h+arg_0]mov eax, [rax]mov [rsp+18h+var_18], eaxmov rax, [rsp+18h+arg_0]mov rcx, [rsp+18h+arg_8]mov ecx, [rcx]mov [rax], ecxmov rax, [rsp+18h+arg_8]mov ecx, [rsp+18h+var_18]mov [rax], ecxadd rsp, 10hpop rdiretn?swap1@@YAXPEAH0@Z endp; void __cdecl swap2(int *a, int *b)?swap2@@YAXAEAH0@Z proc nearvar_18= dword ptr -18harg_0= qword ptr 8arg_8= qword ptr 10hmov [rsp+arg_8], rdxmov [rsp+arg_0], rcxpush rdisub rsp, 10hmov rdi, rspmov ecx, 4mov eax, 0CCCCCCCChrep stosdmov rcx, [rsp+18h+arg_0]mov rax, [rsp+18h+arg_0]mov eax, [rax]mov [rsp+18h+var_18], eaxmov rax, [rsp+18h+arg_0]mov rcx, [rsp+18h+arg_8]mov ecx, [rcx]mov [rax], ecxmov rax, [rsp+18h+arg_8]mov ecx, [rsp+18h+var_18]mov [rax], ecxadd rsp, 10hpop rdiretn?swap2@@YAXAEAH0@Z endp
对比一下:
指针与引用对比。两者反汇编代码是一样的。
1.为何用非指针非引用传参函数无效?
因为是在栈上的参数交换的地址内的数,属于公用的,并不是去改变x,y地址内的数。输出x,y当然没有改变。
2.指针、引用为何能改变?
因为它们找到x,y地址,改变了地址内的内容。