访问内存过程小结

     本文总结一下,Linux下面几种访问内存的方式方法。相关资料转载自:Linux 内存与I/O访问

     X86体系结构下,内存空间分为I/O空间和内存空间,I/O空间通过特定的指令in、out来访问,内存空间采用mov等指令访问。

     arm体系结构下,内存空间和I/O空间统一划分,他们在一个地址空间内。

      在处理器和真实的内存空间之间,还有MMU这一神奇的部件存在,它辅助操作系统进行内存管理,提供虚拟地址和物理地址的映射关系转换、内存访问权限保护和cache缓存控制等硬件功能,操作系统借助MMU,实现虚拟地址空间的管理,使得上层应用程序不必考虑真实物理地址大小,面对一片“虚拟”的逻辑地址空间。

   

在Linux内核空间,kmalloc、__get_free_page,这两个函数申请的内存空间在物理地址上都是连续的,vmalloc申请的内存空间在物理地址上不是连续的。

方法1:

内核中,可以使用virt_to_phys()可以实现虚拟地址转换为物理地址,代码清单如下:

  #define _ _pa(x)  ((unsigned long)(x)-PAGE_OFFSET)
  extern inline unsigned long virt_to_phys(volatile void * address)
  {
    return _ _pa(address);
  }

   与之对应的函数是phys_to_virt(),用于将物理地址转化为虚拟地址。具体代码如下:

   #define  _ _pa(x)      ((unsigned long)(x)+PAGE_OFFSET)

extern inline unsigned long virt_to_phys(volatile void * address)

   {

return _ _pa (address);

   }

注意:上述方法仅适用于内核空间地址对于常规内存的访问,对于高端内存的访问,需要通过kmap和kunmap来动态映射访问。

 

方法2:

    通过ioremap函数将设备所处的物理地址空间映射到虚拟地址空间

     ioremap()原型:

           void *ioremap(unsigned long offset, unsigned long size);

     它返回一个特殊的虚拟地址,用来存取特定的物理地址页面,我们可以通过c指针来访问这些地址,

      iounmap()原型:

            void iounmap(void *addr);

      它用来释放通过ioremap映射的虚拟地址空间

  

方法3:

    通过mmap结合 /dev/mem 来直接映射物理内存空间,这种可以在应用程序态访问内核态的东西

    /dev/mem 是物理内存的全镜像,可以用来访问物理I/O设备。通常只有root用户对其有读写权限

[Note]:新内核版本限制了/dev/mem中的内存访问接口,

   /dev/kmem :kernel看到的虚拟内存全镜像,可以用来访问kernel的内容,查看kernel变量,用作rootkit等

    对于/dev/mem,我们可以把他当做一个字符设备,先open,再read或者write就行。 也可以直接通过命令来查看和修改物理内存内容,这个命令就是hexedit

   通过它,可以显示/dev/mem中的内容。执行 hexedit /dev/mem,显示结果如下:一行显示16个字节内容,从左到右分布是物理内存地址:4组十六进制内容,对应的ASCII内容。

    按tab键进入修改模式,修改内容以粗体显示,按F2保存内容,按ctrl+c退出。

   下面的函数需要 sys/mman.h 头文件支持。

1. void *mmap(void *stat,             //映射结果地址,通常设为NULL,表示系统自动选择映射成功后的地址

                    size_t length,           //映射大小,以字节为单位

                    int prot,                  // 映射区保护方式:可执行(PROT_EXEC),可读(PROT_READ),可写(PROT_WRITE)

                    int flag,                  // 特性选项:MAP_SHARED(对映射区域的写入写回到fd中) MAP_PRIVATE(对映射区域的写入不写回到fd)

                    int fd,                    // 指定映射的文件描述符(本例中,为由open以可读写的方式打开/dev/mem)

                    off_t offset             // 被映射的偏移量 ,表示从哪个文件开始映射,一般设置为0,表示从头开始映射。offset必须为页大小的倍数(4K)

                     )

   映射成功,返回对于的虚拟地址空间,映射失败,返回MAP_FAILED,同时errno错误变量被设置。

2. void munmap(void *addr,size_t length )  // 释放映射的虚拟内存空间 当调用进程终止时,该区域自动解除映射关系。关闭打开的文件描述符不会解除映射关系。

   解除映射成功,munmap返回0,失败返回-1,全局errno被设置。

3. int  msync(void *addr,           //回写映射开始地址

                  size_t  length,        // 回写长度

                  int flags                // MS_ASYNC: 异步调用,立即返回,回写操作由系统管理

                                             // MS_SYNC:同步调用,阻塞,直到回写完成后才返回

                  )

      msync将写入共享映射区的信息回写到磁盘上,不使用它,在munmap调用之前,无法确保写入映射区的内容真实写入磁盘中。

      回写成功,返回0,失败返回-1,同时设置全局错误变量errno 。

 

Technorati 标签: 内存访问

时间: 2024-10-02 10:53:41

访问内存过程小结的相关文章

java类实例化内存过程与面向对象特征

在谈到类实例化的内存过程时先说说几个概念: 对象:内存上来说是分配在堆上面的一块内存区域 类:把一类具体事物相同特征,功能/行为抽象为属性与方法过程. 类是对象的模板,对象是类的具体表现. 构造函数:与类名同名的函数,用来实例化对象并初始化成员变量. 注意:构造器.构造函数不能称为构造方法. 类的结构: 静态块:当对应的class文件被首次加载到虚拟机时执行. 代码块 构造函数 静态属性与变量首先加载.其次时静态块,之后是代码块,最后是构造函数. 具体过程: 当一个类被创建(A a=new A(

Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试

摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就提出了一种把通过FILE*来访问内存的需求,下文是针对这个需求的几个方面的尝试及其结论. 以下尝试的前提是:Win7 + VS2010. 在vc中,FILE其实就是_iobuf,定义如下: struct _iobuf { char *_ptr; //文件输入的下一个位置 int _cnt; //当前

Java访问权限控制小结

进行访问权限控制的两个原因 第一,可以控制类成员的可见性,使客户程序员只看到应该看到的内容 第二,可以使类的创建者随意改变类内部的工作方式,而不必担心会对客户端程序产生重大影响 四种访问权限 pulic 默认(包权限) protected private 用于域和方法 public表示所有人对本成员都可以访问 默认访问权限表示同一包下的类可以对本成员进行访问,其他包中的则不可以(!默认包) protected用于类的继承中,protected提供包访问权限,同时,子类也对protected成员具

64位 SQL Server2008链接访问Oracle 过程汇总解决方法记录

64位 SQL Server2008链接访问Oracle 过程汇总解决方法记录 经过几天不停的网上找资料,实验,终于联通了. 环境:系统:win 2008 ,SqlServer2008 R2, 连接Oracle10g 在SqlServer2008 R2机器上需要安装Oracle客户端32位和64位两个,然后配置连接别名.设置注册表.详细情况见下面 1.错误1 ------------------------------------------------ 64位机器上建立OLE_DB链接报错 报

php中禁止单个ip与ip段访问的代码小结

1.禁止单个IP <?php //IP访问限制 if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { $userip = getenv('HTTP_CLIENT_IP'); } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown

探索数字迷塔问题及遇到指针无法访问内存的错误

Problem : 探索数字迷塔 Time Limit: 1 Sec  Memory Limit: 64 MB Description 晶晶最近迷上了数字迷宫游戏,整天沉浸在一串串看似简单的数字中自得其乐.数字迷宫游戏的魅力体现在变化中隐含着不变的规律,归纳是探究数字迷宫的法宝之一.图10.1-1就是一个由线连接起来的数字小方格组成的数字迷塔. 这个迷塔共n层,它由n×(n+1)/2个小方格组成.每个小方格中都有一个数字,并且连着下一层的两个小方格.现从塔顶走到塔底,每一步只能走到相邻的方格中,

访问内存的有效时间

从进程发出指定逻辑地址的访问请求,经过地址变换,到在内存中找到对应的实际物理地址单元并取出数据,所需花费的总时间,称为内存的有效访问时间(Effective Access Time, ETA) 在 基本分页存储管理 方式中: 有效访问时间分为第一次访问内存时间(即查找页表对应的页表项所消耗的时间t)与第二次访问内存时间(即将页表项中的物理块号与页内地址拼接成实际物理地址所耗费的时间t)之和: ETA = t + t = 2t 在 引入快表的分页存储管理 方式中: 通过查询快表可直接得到逻辑页所对

JVM内存模型小结

JVM运行时的数据区域划分图如下,该图是JVM内存模型最主要的内容. 从图中可以看出来,JVM将内存主要划分为五个部分:程序计数器.Java虚拟机栈.本地方法栈.Java堆和方法区.这些被划分为用途不一的数据区域有着各自的特点,它们都有自己创建和销毁的时间,有的区域随着进程的启动而存在,有的是伴随着用户线程的启动而建立.随着线程的结束而销毁. (一) 程序计数器(Program Counter Register) 1> 内存空间较小; 2> 当前线程所执行的字节码行号指示器: 功能:a.在JV

javascript 变量,作用域,内存管理小结

js的变量保存两种类型的数据——基本数据类型与引用类型.具有以下几点特征:   变量: 1)基本类型值在内存中占固定大小的空间,因此被保存在栈内存中; 2) 把保存基本类型值得变量赋给另一个变量,会创建这个值的副本; 3) 引用类型的值是对象,存在堆内存中; 4) 变量不会保存对象,只是创建了新的指针指向该对象,对象始终在堆内存中; 5) 指向对象的变量复制给一个新的变量,只是复制了指向对象的指针,最后两个变量都指向该对象; 6)  查看变量属于哪种基本类型得用typeof操作符,查看变量是哪种