首页 > 代码库 > 指针与引用(反汇编)
指针与引用(反汇编)
一、指针
由于指针保存的数据都是地址,所以无论什么类型的指针都占4字节内存空间。
①各类型指针访问同一地址
每种数据类型在内存中所占的内存空间不同,指针中只保存了存放数据的首地址,而没有指明在哪里结束。这时需要根据对应的类型来寻找解释数据的结束地址。
先看看C++代码
int main(){ int num=0x12345678; int *pn=# char *pc=(char *)# short *psn=(short *)# long long *pln=(long long *)# cout<<hex<<static_cast<int>(*pn)<<endl; cout<<hex<<static_cast<int>(*pc)<<endl; cout<<hex<<static_cast<short>(*psn)<<endl; cout<<hex<<static_cast<long long>(*pln)<<endl; system("pause"); return 0;}
运行结果:
再看反汇编
int num=0x12345678;011E13EE mov dword ptr [num],12345678h int *pn=#011E13F5 lea eax,[num] //取的都是num的地址011E13F8 mov dword ptr [pn],eax char *pc=(char *)#011E13FB lea eax,[num] 011E13FE mov dword ptr [pc],eax short *psn=(short *)#011E1401 lea eax,[num] 011E1404 mov dword ptr [psn],eax long long *pln=(long long *)#011E1407 lea eax,[num] 011E140A mov dword ptr [pln],eax cout<<hex<<static_cast<int>(*pn)<<endl;011E140D mov esi,esp 011E140F mov eax,dword ptr [__imp_std::endl (11E82B0h)] 011E1414 push eax 011E1415 mov edi,esp 011E1417 mov ecx,dword ptr [pn] //将指针pn中存放的变量num的地址放入ecx011E141A mov edx,dword ptr [ecx] //从变量num的地址中,以4字节方式读取数据,存入edx中011E141C push edx ......//输出省略 cout<<hex<<static_cast<int>(*pc)<<endl;011E1455 mov esi,esp 011E1457 mov eax,dword ptr [__imp_std::endl (11E82B0h)] 011E145C push eax 011E145D mov ecx,dword ptr [pc] 011E1460 movsx edx,byte ptr [ecx] //从变量num的地址中,以1字节方式读取数据(int的第一个字节),存入edx中011E1463 mov edi,esp 011E1465 push edx ......//输出省略 cout<<hex<<static_cast<short>(*psn)<<endl;011E149E mov esi,esp 011E14A0 mov eax,dword ptr [__imp_std::endl (11E82B0h)] 011E14A5 push eax 011E14A6 mov edi,esp 011E14A8 mov ecx,dword ptr [psn] 011E14AB movzx edx,word ptr [ecx] //从变量num的地址中,以2字节方式读取数据(int的低2字节),存入edx中011E14AE push edx ......//输出省略 cout<<hex<<static_cast<long long>(*pln)<<endl;011E14E7 mov esi,esp 011E14E9 mov eax,dword ptr [__imp_std::endl (11E82B0h)] 011E14EE push eax 011E14EF mov edi,esp 011E14F1 mov ecx,dword ptr [pln] //这里存放的尽管依然是num的地址,但是num被强制转换为long long型,所以后面读取的是8字节的数据,但寄存器只能存放4字节数据,
//所以分两次读取。int4字节扩展到long long8字节,高4字节中的值是未知的011E14F4 mov edx,dword ptr [ecx+4] //从num地址+4的地址中,以4字节方式读取数据(long long型的高4字节),放入edx中011E14F7 push edx 011E14F8 mov eax,dword ptr [ecx] //从num地址中,以4字节方式读取数据(long long型的低4字节),放入eax中011E14FA push eax ......//输出省略
②各类型指针的寻址方式
指针的取内容操作分为两个步骤:先取指针中保存的地址,然后针对这个地址进行取内容,也就是一个间接寻址的过程,这也是识别指针的重要依据。
C++中,所有指针类型只支持加减法,其他运算对于指针而言没有意义。
指针加减用于地址偏移。指针加减1后,指针内保存的地址值并不一定加减1,具体的值取决于指针类型。
两指针相加没有意义,相减是计算两个地址之间的元素个数,结果为有符号整数,进行减法操作的两个指针必须是同类型指针相减。
C++代码
int main(){ char num[8]={0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48}; int *pnum=(int *)num; short *psnum=(short *)num; char *pcnum=num; long long *plnum=(long long *)num; pnum+=1; psnum+=1; pcnum+=1; plnum+=1; cout<<hex<<static_cast<int>(*pnum)<<endl; cout<<hex<<static_cast<short>(*psnum)<<endl; cout<<hex<<static_cast<char>(*pcnum)<<endl; cout<<hex<<static_cast<long long>(*plnum)<<endl; system("pause"); return 0;}
运行结果: 高高低低原则的结果
反汇编:
char num[8]={0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48};004014D8 mov byte ptr [ebp-10h],41h //为数组元素赋初值。EBP-10H,即是数组首元素的地址,又是数组地址004014DC mov byte ptr [ebp-0Fh],42h 004014E0 mov byte ptr [ebp-0Eh],43h 004014E4 mov byte ptr [ebp-0Dh],44h 004014E8 mov byte ptr [ebp-0Ch],45h 004014EC mov byte ptr [ebp-0Bh],46h 004014F0 mov byte ptr [ebp-0Ah],47h 004014F4 mov byte ptr [ebp-9],48h int *pnum=(int *)num;004014F8 lea eax,[ebp-10h] //赋值都是数组首地址004014FB mov dword ptr [ebp-1Ch],eax short *psnum=(short *)num;004014FE lea eax,[ebp-10h] 00401501 mov dword ptr [ebp-28h],eax char *pcnum=num;00401504 lea eax,[ebp-10h] 00401507 mov dword ptr [ebp-34h],eax long long *plnum=(long long *)num;0040150A lea eax,[ebp-10h] 0040150D mov dword ptr [ebp-40h],eax pnum+=1;00401510 mov eax,dword ptr [ebp-1Ch] //将指针pnum内存放的地址放入eax(num的地址),然后num的地址+4(int),再放入pnum指针,此时指向索引为4的元素的地址00401513 add eax,4 00401516 mov dword ptr [ebp-1Ch],eax psnum+=1;00401519 mov eax,dword ptr [ebp-28h] //将指针psnum内存放的地址放入eax(num的地址),然后num的地址+2(short),再放入psnum指针,此时指向索引为2元素的地址0040151C add eax,2 0040151F mov dword ptr [ebp-28h],eax pcnum+=1;00401522 mov eax,dword ptr [ebp-34h] //将指针pcnum内存放的地址放入eax(num的地址),然后num的地址+1(char),再放入pcnum指针,此时指向索引为1的元素的地址00401525 add eax,1 00401528 mov dword ptr [ebp-34h],eax plnum+=1;0040152B mov eax,dword ptr [ebp-40h] //将指针plnum内存放的地址放入eax(num的地址),然后num的地址+8(long),再放入pcnum指针,此时指向最后一个元素的后面的地址0040152E add eax,8 00401531 mov dword ptr [ebp-40h],eax cout<<hex<<static_cast<int>(*pnum)<<endl;00401534 mov esi,esp 00401536 mov eax,dword ptr [__imp_std::endl (40A324h)] 0040153B push eax 0040153C mov edi,esp 0040153E mov ecx,dword ptr [ebp-1Ch] 00401541 mov edx,dword ptr [ecx] //读取的是第5个元素地址开始的4个字节00401543 push edx ......//省略输出 cout<<hex<<static_cast<short>(*psnum)<<endl;0040157C mov esi,esp 0040157E mov eax,dword ptr [__imp_std::endl (40A324h)] 00401583 push eax 00401584 mov edi,esp 00401586 mov ecx,dword ptr [ebp-28h] 00401589 movzx edx,word ptr [ecx] //读取的是第3个元素地址开始的2个字节0040158C push edx ......//省略输出 cout<<hex<<static_cast<char>(*pcnum)<<endl;004015C5 mov esi,esp 004015C7 mov eax,dword ptr [__imp_std::endl (40A324h)] 004015CC push eax 004015CD mov ecx,dword ptr [ebp-34h] 004015D0 movzx edx,byte ptr [ecx] //读取的是第2个元素地址开始的1个字节004015D3 push edx ......//省略输出 cout<<hex<<static_cast<long long>(*plnum)<<endl;00401606 mov esi,esp 00401608 mov eax,dword ptr [__imp_std::endl (40A324h)] 0040160D push eax 0040160E mov edi,esp 00401610 mov ecx,dword ptr [ebp-40h] 00401613 mov edx,dword ptr [ecx+4] //读取的是第8个元素后面的地址开始的8个字节,是未知的值。00401616 push edx 00401617 mov eax,dword ptr [ecx] 00401619 push eax ......//省略输出
......
二、引用
引用类型是变量的别名。C++为了简化指针操作,对指针操作进行了封装,产生了引用类型。实际上引用类型就是指针类型,只不过它用于存放地址的内存空间对使用者而言是隐藏的,通过编译器实现寻址,而指针需要手动寻址,其存储方式也是和指针一样,都是使用内存空间存放地址值。反汇编下,没有引用这种类型。
看一下引用类型作为函数参数,和指针完全一样。
C++代码
void add(int &b){ b++;}int main(){ int a=1; add(a); cout<<a<<endl; system("pause"); return 0;}
运行结果:2
反汇编
int a=1;00EF140E mov dword ptr [a],1 add(a);00EF1415 lea eax,[a] //将变量a的地址放入eax00EF1418 push eax //把a的地址放入堆栈,传递给add00EF1419 call add (0EF1154h) //调用add函数00EF141E add esp,4 ......省略输出
add函数
b++;00EF13CE mov eax,dword ptr [b] //这里的b实际上是指向堆栈中变量a的地址,将b中存放的地址也就是变量a的地址放入eax,debug下,为了调试直观,直接用b表示了。00EF13D1 mov ecx,dword ptr [eax] //将eax也就是变量a地址中的内容放入ecx,然后ecx+1,再放入变量a的地址中00EF13D3 add ecx,1 00EF13D6 mov edx,dword ptr [b] //将堆栈中变量a的地址放入edx00EF13D9 mov dword ptr [edx],ecx //将ecx++后的值放入变量a的地址中。
.............
指针与引用(反汇编)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。