访问内存时,您正在访问进程地址空间.
进程地址空间分为页面(x86上通常为4 KB).这些是虚拟页面:它们的内容保存在其他地方.内核管理从虚拟页面到其内容的映射.内容可由以下人员提供:
>物理页面,用于当前由物理RAM支持的页面.对这些的访问直接发生(通过内存管理硬件).
>已换出磁盘的页面.访问它将导致内核处理的页面错误.它需要使用磁盘内容填充物理页面,因此它找到一个空闲的物理页面(可能将该页面的内容交换到磁盘),从磁盘读取内容,并更新映射以声明“虚拟页面X”在物理页面Y“.
>文件(即内存映射文件).
>硬件设备(即硬件设备寄存器).这些通常不会影响我们的用户空间.
假设我们有一个4 GB的虚拟地址空间,分成4 KB的页面,给我们1048576个虚拟页面.其中一些将由内核映射;别人不会.当进程开始时(即调用main()时),虚拟地址空间将包含以下内容:
>程序代码.这些页面通常是可读和可执行的.
>程序数据(即初始化变量).这通常有一些只读页面和一些读写页面.
>程序所依赖的库中的代码和数据.
>堆栈的一些页面.
这些东西都映射为4 GB地址空间中的页面.您可以通过查看/ proc /(pid)/ maps查看映射的内容,正如其中一条评论所指出的那样.这些页面的精确内容和位置取决于(a)所讨论的程序,以及(b)地址空间布局随机化(ASLR),这使得事物的位置更难以猜测,从而使某些安全开发技术更加困难.
您可以通过定义指针并取消引用它来访问内存中的任何特定位置:
*(unsigned char *)0x12345678
如果这恰好指向映射页面,并且该页面是可读的,那么访问将成功并产生映射在该地址的任何内容.如果没有,那么你将从内核收到一个SIGSEGV.你可以处理它(这在某些情况下是有用的,比如JIT编译器),但通常你不会,并且该过程将被终止.如上所述,由于ASLR,如果您在程序中执行此操作并多次运行程序,那么您将获得某些地址的非确定性结果.