Linux中获取页表偏移的方法 (linux 获取页表偏移)

在Linux操作系统中,页表是一种非常重要的数据结构。它被用来管理内存的分配和释放,同时也避免了内存空间的重复使用。在许多情况下,我们需要获得页表的偏移量,以便进行一些内存管理操作。本文将会介绍如何在Linux中获取页表偏移量的方法。

1. 什么是页表

在介绍如何获取页表偏移量之前,首先需要了解什么是页表。现代电脑的内存是由一系列固定大小的页面组成的。而通常情况下,每个页面都被安装一个唯一的序列号,这个序列号被称为页帧号(PFN)。页表是一种数据结构,用来维护虚拟地址和物理地址之间的映射关系。虚拟地址为每个页面分配了一个唯一的索引,这个索引被称为虚拟页面号(VPN)。当应用程序尝试访问一个虚拟地址时,操作系统会通过页表将该虚拟页面号映射到一个物理页面号,然后再将该物理页映射到实际的物理内存地址。

2. 页表偏移量的定义

页表偏移量指的是一个页面开头距离页表头的距离。在Linux中,页表信息存储在内核空间的页表数组中。数组的基地址是一个结构体pt_head,它包含一个指向页表数组头部的指针。假设想要访问第n个页表项,那么我们需要找到其在页表数组中的偏移量,即:

offset = n * sizeof(struct page) – PAGE_OFFSET

其中PAGE_OFFSET是内核空间的起始地址,而struct page是一个包含关于虚拟内存页面的信息的结构体。我们可以将其定义在“include/linux/mm_types.h”文件中。

了解了页表偏移量的概念之后,我们接下来可以介绍如何在Linux中获取页表偏移量。

3. 使用pfn_to_page函数

在Linux中,我们可以使用pfn_to_page函数来获取虚拟页面号(VPN)在页表数组中的偏移量。该函数定义在“include/linux/mm_types.h”文件中。

pfn_to_page接收一个页面号作为参数,并返回一个指向该页面所在struct page结构体的指针。 也就是说,pfn_to_page函数提供了一个从虚拟地址(或者PFN)到页表数组索引的映射,因此它也是一个获取页表偏移量的重要函数。

下面给出一个示例程序,来说明如何使用pfn_to_page函数获取页表偏移量:

#include

int get_page_table_offset(unsigned long virt_addr) {

unsigned long pfn = virt_to_phys(virt_addr) >> PAGE_SHIFT;

struct page *page_ptr = pfn_to_page(pfn);

unsigned long offset = (unsigned long)page_ptr – (unsigned long)pt_head.page_table;

return offset / sizeof(struct page);

}

上述代码中,get_page_table_offset函数接收一个虚拟地址,并通过virt_to_phys函数将其转换为页帧号。然后,它使用pfn_to_page函数获取该页面的struct page结构体指针。它计算该页面在页表数组中的偏移量(以页表项数量计算),并将其返回。

4. 结论

相关问题拓展阅读:

linux内核参与分页吗

参与吧!(答案非常不准确,仅供参考)

页式管理用以将线性地址转化成物理地址,并对访问权限进行检查。每个页面都是一个大小为4KB的连续空间,并按4KB对齐。从80386开始,Intel处理器开始支持页式管理,CR0寄存器的PG标志位用来表示是否支持分页。

1、标准分页

i386采用二级分页,其线性地址的结构如下:

Dir

Page

Offset

其中,Dir有10位,表示页表目录项的下标,指向一个页表;Page有10位,表示一个具体页表中的目录项的下标,指向一个物理页面;Offset有12位,表示在物理页面中的偏移量(单位为字节)。

i386中,从线性地址到物理地址的映射过程为:

(1)从CR3寄存器中取得页目录(页目录中包含1024条记录,每个记录4字节,正好为4KB,占用一个页面)的基地址;

(2)以线性地址中的Dir为下标,从目录中取出相应页表的基地址;

(3)以线性地址中的Page为下标,从页表中取出相应的页面描述结构;

(4)将页面描述符中的基地址与线性地址中的Offset偏移量相加,获得实际的物理地址。

2、页描述表项

在i386中,页目录和页表的结构相同,页描述表项的结构如下:

Address

Avail

G

PS

D

A

PCD

PWT

U/S

R/W

P

其中,Address有20位,表示对应页表或页的物理地址的高20位(由于页总是按4KB对其,故低12位恒为0);Avail有3位,供系统程序员使用;G只有1位,在页目录项中表示该页是否为全局页,在页表项中忽略;PS只有1位,在页表目录项中为1表示为4MB的页,为0表示为4KB的页;D只有1位,在页表目录项中未使用,在页表项中表示该页是否氏盯让山已被更改;A只有1位,表示该页是否已被访问过;PCD只有一位,表示该项是否禁止被缓存;PWT只有一位,为1表示使用write-through缓存策略,0表示使用write-back缓存策略;U/S只有一位,为1表示访问该页是否可以在用户态下访问;R/W只有一位,表示该项是否可写;P只有1位,表示该项是否在内存中。

如果要使用4MB的扩展分页,则要求CR4寄存器中的PSE标志被置1。此时,系统仅采用一级分页策略,线性地址前10位为页表项,后22位为偏移量,且页按4MB对齐,页描述表项中Address仅有高10位有效。

3、物理地址扩展(PAE)分页机制

从Pentium Pro开始,Intel处理器的地址总线宽度增加到了36位,共支持访问64GB的内存。同时,Intel提供了PAE和页大小扩展(PSE-36)两种机制用以将32位的线性地址转化成36位的物理地址。其中,后者从Pentium III开始提供,且未在Linux内核中使用。

要启用PAE机制必须将CR4寄存器中的PAE标志置位。PAE启用后,处理器会对分页机制做如下更改:

(1)将64GB的内存空间划分成2^24个不同页面,页表项的体积扩展为64位,物理地址域扩展为24位;

(2)引入新的更高一级页表,称为页目录指针表(PDPT),其中包含4个64位的项;

(3)CR3寄存器中包含27位的PDPT的高位地址(其低5位地址为0);

(4)当将线性地址映射到4KB的页面时,CR3由高位到低位依次为2位PDPT索引,Array位页目录索引,Array位页表索引,12位页内偏移;当将线性地址映射到4KB的页面时,CR3由高位到低位依次为2位PDPT索引,Array位页目录索引,21位页内偏移。

但是,PAE机制并未增大单个进程能够访问的地址空间,仅仅将内核能够访问的地址空间增加到了64GB。

4、Linux内核中的分页

Linux内核对分页机制的依赖性很强,其使用一种适合32位和64位结构的通用分页模型,该模型使用四级分页,即页全局目录、页上层目录、页中层目录和页表。

对于不同的体系结构,Linux采用的四级页表目录的大小有所不同:对于i386而言,仅采用二级页表,即页上层目录和页中层目录长度为0;对于启用PAE的i386,采用了三级页表,即页上层目录长度为0;对于64位体系结构,可以采用三级或四级页表,具体选择由硬件决歼滑和定。

linux内核中没有分页内存吗?是的,没有,那么windows的内核为何就有呢?毕竟不是一个家族不好做全方位的评判,我的结论就是linux上的任何的程序只将内核作为一个平台而不依赖内核。这个事实的结果就是在linux内核中不能分配过大的内存,linux内核中唯一可以分配大内存的地方就是vmalloc区域,仅仅放松了对物理内存连续的限制,在vmalloc中分配内存只要求虚拟内存连续,并且事实上最多只能分配128M的内存,这是linux内核中最宽松的限制了。

在linux中,一切功能都可以由用户空间应用程序来解决,就连杀毒程序也不例外,这是因为linux有强大的安全机制,单点验证机制,只要linux保证任何用户不能随意su到root权限就可以了,这事实上就是一个消除一切漏洞的行为,只要操作系统安全机制没有漏洞,只要内核没有漏洞,那么一切恶意程序的得逞完全归结于该恶意程序所利用的用户空间应用程序设计的不足,而且这件事在linux看来,内核完全没有必要过问,正如一个国家的机关只认百姓的请求以及该请求的代理权限,只要认证通过就给与服务而不再对别的情况加以过问,linux只是一个服务者罢了,它不喜欢任何额外的机制要靠内核来完成,也就是说任何用户都不要随意动不动就用内核实现一个机制,只要在用户空间实现就好了。

看看windows下的杀毒程序这一简单的使用内核来完成的程序,正是由于windows不能保证复杂但是薄弱的用户空间机制都是安全的,才会动用内核来实现更高级别的安全管理,它没有linux的那种简单但是可以信赖的单点验证机制。正如微软建议的那样,在没有别的办法的时候请实现一个驱动程序,在DriverEntry中完成一切。既然微软会建议程序员编写内核驱动,那么微软的操作系统当然也把内核空间的开发开放给了程序员,于是DDK成了很大一部分人最后的救命稻草,既然将内核驱动的开发开放给了程序员,那么如何使用内存就不应该有任何限制,再者windows希望用一种简单一致的机制管理所有的不管是用户空间还是内核空间的内存,于是内核空间的内存管理和用户空间的内存管理大体上没有区别,都可以使用分页内存,说一句可能让windows的粉丝不愿意听的话:我们windows实现的不是很安全,所以你们可以用内核这个更高级别的执行绪以权势压人。反观linux,开源的linux难道没有将内核开放给程序员吗?不,绝对的开放,看看lkml的热闹程度吧!但是不同的是,linux下开发内核是完全为了内核本身的机制扩展而不涉及任何用户策略,linux的内核和用户应用分得比较开,不信你去内核邮件列表去问一个应用的问题,看看有没有人骂。

关于linux 获取页表偏移的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux中获取页表偏移的方法 (linux 获取页表偏移)