MyException - 我的异常网
当前位置:我的异常网» 软件设计 » 指针与引述(反汇编)

指针与引述(反汇编)

www.myexceptions.net  网友分享于:2015-02-01  浏览:0次
指针与引用(反汇编)

一、指针

由于指针保存的数据都是地址,所以无论什么类型的指针都占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=&num;
011E13F5  lea         eax,[num]  //取的都是num的地址
011E13F8  mov         dword ptr [pn],eax  
    char *pc=(char *)&num;
011E13FB  lea         eax,[num]  
011E13FE  mov         dword ptr [pc],eax  
    short *psn=(short *)&num;
011E1401  lea         eax,[num]  
011E1404  mov         dword ptr [psn],eax  
    long long *pln=(long long *)&num;
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的地址放入ecx
011E141A  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的地址放入eax
00EF1418  push        eax  //把a的地址放入堆栈,传递给add
00EF1419  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的地址放入edx
00EF13D9  mov         dword ptr [edx],ecx  //将ecx++后的值放入变量a的地址中。

.............

 

文章评论

程序员都该阅读的书
程序员都该阅读的书
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
老程序员的下场
老程序员的下场
每天工作4小时的程序员
每天工作4小时的程序员
一个程序员的时间管理
一个程序员的时间管理
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
那些争议最大的编程观点
那些争议最大的编程观点
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
程序员应该关注的一些事儿
程序员应该关注的一些事儿
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序员和编码员之间的区别
程序员和编码员之间的区别
我是如何打败拖延症的
我是如何打败拖延症的
漫画:程序员的工作
漫画:程序员的工作
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
如何成为一名黑客
如何成为一名黑客
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
总结2014中国互联网十大段子
总结2014中国互联网十大段子
 程序员的样子
程序员的样子
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
代码女神横空出世
代码女神横空出世
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
10个调试和排错的小建议
10个调试和排错的小建议
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
我的丈夫是个程序员
我的丈夫是个程序员
程序员必看的十大电影
程序员必看的十大电影
鲜为人知的编程真相
鲜为人知的编程真相
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有