吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6510|回复: 15
收起左侧

[其他转载] [谬]C语言指针的底层汇编实现原理

[复制链接]
君子谬 发表于 2016-12-1 11:08
指针的赋值过程与指针类型的真相
int指针:
int gi;
int *p;
p = &gi;
00EF166E C7 05 3C 91 EF 00 38 91 EF 00  mov         dword ptr ds:[00EF913Ch],0EF9138h

*p = 12;
00EF1678 A1 3C 91 EF 00                           mov         eax,dword ptr ds:[00EF913Ch]
00EF167D C7 00 0C 00 00 00                      mov         dword ptr [eax],0Ch

注释:
p = &gi;
mov         dword ptr ds:[00EF913Ch],0EF9138h       将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存
*p = 12;
mov          eax,dword ptr ds:[00EF913Ch ]                 将00EF913Ch所存储的地址,也就是gi的地址0EF9138h放入eax中.
mov          dword ptr [eax],0Ch                                    将0ch放入eax所存储的地址中,也就是把0ch放在了gi所代表的地址中,dword也就代表了向eax中写入4字节数据


short型指针:
short gi;
short *p;
p = &gi;
0034166E C7 05 3C 91 34 00 38 91 34 00 mov         dword ptr ds:[0034913Ch],349138h
*p = 12;
00341678 B8 0C 00 00 00                                          mov         eax,0Ch
0034167D 8B 0D 3C 91 34 00                                   mov         ecx,dword ptr ds:[0034913Ch]
00341683 66 89 01                                                      mov         word ptr [ecx],ax
注释:
p = &gi;
mov         dword ptr ds:[0034913Ch],349138h         将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存
*p = 12;
mov         eax,0Ch                                                        将0Ch放入eax中,由于eax是4字节,所以0ch放到了eax的低2字节,ax中
mov         ecx,dword ptr ds:[0034913Ch]                    将p所存储的地址,也就是gi的地址放入ecx中.
mov         word ptr [ecx],ax                                          将ax所存储的内容写入到ecx所指向的地址,也就是gi的地址,.word说明将向gi的地址写入2字节数据

char型指针:
char gi;
char *p;
p = &gi;
00CC166E C7 05 3C 91 CC 00 38 91 CC 00 mov         dword ptr ds:[00CC913Ch],0CC9138h
*p = 12;
00CC1678 A1 3C 91 CC 00                                           mov         eax,dword ptr ds:[00CC913Ch]
00CC167D C6 00 0C                                                      mov         byte ptr [eax],0Ch

注释:
p = &gi;
mov         dword ptr ds:[00CC913Ch],0CC9138h        将gi的地址0EF9138h放入00EF913Ch所指向的地址中保存

*p = 12;
mov         eax,dword ptr ds:[00CC913Ch]                     00EF913Ch所存储的地址,也就是gi的地址0EF9138h放入eax中.      
mov         byte ptr [eax],0Ch                                           将0ch放入eax所存储的地址中,也就是把0ch放在了gi所代表的地址中,byte 也就代表了向eax所存储的地址中写入1字节数据

总结:
     C语言指针包含两方面信息,一个是地址,存放在指针变量中,另一个是类型信息,决定了读写的长度,没有存储在指针变量中,位于指针读写过程所使用的mov指令中,不同的指针类型对应着读写的字节数.
这也间接解释了指针为什么+-1不是+-1个字节,而是加减长度是指针类型的字节数,void类型的指针之所以无法加减,就是因为它没有类型信息,无法确定加减的长度,代表的仅仅是一块内存地址.

指针类型强制转换
/****************************************************************/
程序:
int i;
int * pi;
short * ps;
char * pc;
int main()
{
                pi = &i;
                ps = ( short *)&i;
                pc = ( char *)&i;
                *pi = 0x1234;
                *ps = 0x1234;
                *pc = 0x12;
}
/***************************************************************/
反汇编:
pi = &i;
00941A8E C7 05 E0 94 94 00 DC 94 94 00 mov           dword ptr ds:[009494E0h],9494DCh
ps = (short *)&i;
00941A98 C7 05 E4 94 94 00 DC 94 94 00 mov           dword ptr ds:[009494E4h],9494DCh
pc = (char *)&i;
00941AA2 C7 05 E8 94 94 00 DC 94 94 00 mov          dword ptr ds:[009494E8h],9494DCh
*pi = 0x1234;

注释:
在把i赋值其他指针变量的过程中,强制转换并没有生成任何指令,可见,强制转换并不是在这里产生效果的

00941AAC A1 E0 94 94 00                                            mov         eax,dword ptr ds:[009494E0h]
00941AB1 C7 00 34 12 00 00                                        mov         dword ptr [eax],1234h
*ps = 0x1234;
00941AB7 B8 34 12 00 00                                              mov         eax,1234h
00941ABC 8B 0D E4 94 94 00                                       mov         ecx,dword ptr ds:[009494E4h]
00941AC2 66 89 01                                                         mov         word ptr [ecx],ax
*pc = 0x12;
00941AC5 A1 E8 94 94 00                                             mov         eax,dword ptr ds:[009494E8h]
00941ACA C6 00 12                                                       mov         byte ptr [eax],12h

注释:
可以看出,在这里,写入的字节数发生了变化,所以,强制转换的效果不在转换过程中体现,而是体现在转换后去访问内存时的指令中

注释2:
如果转换后指针指向的数据类型大小小于原来的数据类型大小,那么用该转换后的指针访问就不会越过原数据的内存,是安全的,否则危险,要越界

/*****************************************************/
程序:
#include<stdio.h>

int main()
{
                int * pi;
                short si = 12;
                pi = ( int *)&si;
                printf( "%d,%x", *pi, *pi);
}
/*****************************************************/

注释:
正常情况下这段程序应该输入的是12,0c
但是实际上的运行结果是-859045876,cccc000c
这是由于将si的地址强制转换为int *类型,然后赋值给pi;那么pi会访问4字节,这时越界了,将si后的2字节纳入了范围,即是cc cc,他们和0c 00合在一起正好与结果吻合
这就是违反了强制转换的原则,越界了

免费评分

参与人数 7吾爱币 +1 热心值 +7 收起 理由
俊之霜 + 1 + 1 谢谢@Thanks!
牵手的幸福~ + 1 谢谢@Thanks!
学IT的小屁孩 + 1 用心讨论,共获提升!
JIESHAO??? + 1 我很赞同!
mingo + 1 我很赞同!
挥汗如雨 + 1 我很赞同!
小可爱~ + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

A学习的小菜鸟 发表于 2017-8-14 17:00
现在终于搞清楚从语言为什么是底层语言了,它与汇编有着很多的联系,这样可以更加清楚的理解底层的原理和认识,谢谢楼主的解答了啊
小可爱~ 发表于 2016-12-1 11:44
xiaodouble 发表于 2016-12-1 11:53
吾爱丨破解 发表于 2016-12-1 12:06 来自手机
????ケ??????
mingo 发表于 2016-12-1 12:36
还不错!
JIESHAO??? 发表于 2016-12-1 12:46
感谢分享
ytw6176 发表于 2016-12-1 12:48
晕针。。   
pcx127 发表于 2016-12-1 12:53
这个对c指针很有用。。
dongdon923 发表于 2016-12-1 13:23
感谢分享
牵手的幸福~ 发表于 2016-12-1 19:11
了解了!谢谢
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-30 11:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表