64位进程隐藏不蓝屏_浅析Linux 64位系统虚拟地址和物理地址的映射及验证方法...

0524b9b689fc82719a0deb1465f750c2.png

前言

有好久没更新了,这段时间发生了挺多大喜事哈。但是也还是有挺久没更新了,不得不意识到自己是个小菜鸡,就算是小菜鸡也要做一只快乐小菜鸡。就算更新慢但是我依然会持续更新,因为更文使我快乐。

虚拟内存

先简单介绍一下操作系统中为什么会有虚拟地址和物理地址的区别。因为Linux中有进程的概念,那么每个进程都有自己的独立的地址空间。

现在的操作系统都是64bit的,也就是说如果在用户态的进程中创建一个64位的指针,那么在这个进程中,这个指针能够指向的范围是0~0xFFFFFFFFFFFFFFFF(总共有16个F,每个F是4个bit)。

每个进程“理论上”都有这样的地址范围(-,-这里的”理论“是指猜测一下,指针乱指向未定义的范围会引发段错误,下文中会写明64bit的用户空间的地址范围)。

我们看到了,Linux为了让每个进程空间的独立,创造了虚拟地址这个概念。但是计算机最终还是需要操作物理的内存的。e57d0796bd9fddc9ec3978ed7c4f5d60.png

那么虚拟地址和物理地址的映射关系是怎样的?也只能用映射表了。比如说:进程A虚拟空间中的第0x1234个字节,对应于物理内存中的第0x823ABC个字节。这个一个字节和一个字节对应,理论上是可以的,但是太消耗资源了,为了映射这“一个字节”,仅映射这“一个字节”的表项的大小也远超过了一个字节的大小(大约四十个字节左右)。这是不行的,这就像几十个产品和项目经理去管一个程序员工作,这是效率低下的。3fe1c07ed0447c2e36d629fe737bba78.png

所以页这个概念产生了,一个页一个页映射总还可以了吧,我们将页作为最小单位去映射就好了。大多数32位体系结构支持4KB的页,而64位体系结构一般会支持8KB的页。在linux使用命令获取当前系统的页大小:

getconf PAGE_SIZE

在我的ubuntu 16.04 x86_64上的系统得到的结果是 4096。目前大部分64位的系统的页大小都是4096个字节。4a15f282269d29e6be4983fc01a9fcf9.png

系统中每个物理页都会建立一个类似映射表的结构体,但是依然会有人觉得这有点浪费内存。我们来算一下,比如一个物理页的属性和映射表的内容占用40个字节(linux代码中是struct page)。假设如当前大部分Linux上的页为4KB大小,系统有4GB物理内存,那么就有1048576个页,这么多页的映射表消耗的内存是1048576 * 40byte = 40MB。用40MB去管理4GB,还是可以接受的。

64位系统的虚拟内存布局

在AArch64下,页大小为4KB时,页管理为四级架构时的Linux的进程中的虚拟内存布局如下:0cd94df723cec9d288b33d833da432c7.png

可以看到即使是虚拟地址,用户态下能用的地址也就只是0 ~ 0000ffffffffffff,不过也有256TB大小了。也就是说每个进程都有自己独立的0 ~ 0000ffffffffffff的地址空间。0x0000ffffffffffff是12个f,也就是48个bit。

每个进程都有自己的虚拟地址到物理地址的映射关系表。Linux内核会根据每个不同的进程去查找表:如进程A的虚拟空间地址K的物理地址是哪个。为了加快查找效率,虚拟内存的地址的不同段映射到了不同的entry上,页管理表有4级的也有3级的。最常用的4级页管理映射表如下:e788911526d2c6968c5b9bb89dfcd84c.png

可以看到[47:0]这48个bits的虚拟地址,被分成了五段,前四段的每一份长度都是9 bits,最后一段是12 bits。

每个9 bits的段都是2^9 = 512,也就是说每个分级段都有512个entry。

最后一段[11:0],大小是12 bits的即2^12 = 4096,4096就是一个页的大小,所以最后一段是页内偏移(因为映射是以页为单位,所以虚拟地址和物理地址的页内偏移都是一样的)。前四段合在一起就是虚拟页号

我们举一个48 bit 虚拟地址的例子,这个地址以八进制表示:

003 010 007 413 1056
8c39a2e27fb2692cd7ffee15e14af65c.png

上面所述的每个Entry的结构体如下:7b47cfa9a5a913a62789f4c9a2d87289.png

可以看到物理地址的页号是40 bits,也就是说最多有2^40个物理页,每个页是4096个字节,也就是最多4PB(4096TB)。

虚拟地址到物理地址的验证方法

说了这么多,如何验证上面说的这些是真的。就算推导出物理地址了,那又有啥用呢?

如果你知道共享库和静态库的区别的话,那么就会知道不同的进程如果用了同一个共享库,那么其实这两个不同的进程使用的共享库是指向同一个物理地址!如果能验证这一点,那么从虚拟地址推导到物理地址的方法大体是正确的,以上所述大体也是对的。

借助proc下的maps和pagemap

通过man命令

man proc

可以找到以下条目:f2c885a54da5e0b9f5679ec936b56555.png以上我们知道通过/proc/[pid]/maps就能够知道一个进程的虚拟地址。306a225837a37fa01b49da68d18595dc.png以上我们知道通过/proc/[pid]/pagemap就能够将一个进程的虚拟地址页转成物理地址页。

测试代码

下面上硬菜。小伙子你要讲武德,你不能闪!

代码如下:

#include 
#include 
#include 
#include 
#include 

size_t virtual_to_physical(pid_t pid, size_t addr){
    char str[20];
    sprintf(str, "/proc/%u/pagemap", pid);
    int fd = open(str, O_RDONLY);
    if(fd 0)
    {
        printf("open %s failed!\n", str);
        return 0;
    }
    size_t pagesize = getpagesize();
    size_t offset = (addr / pagesize) * sizeof(uint64_t);
    if(lseek(fd, offset, SEEK_SET) 0)
    {
        printf("lseek() failed!\n");
        close(fd);
        return 0;
    }
    uint64_t info;
    if(read(fd, &info, sizeof(uint64_t)) != sizeof(uint64_t))
    {
        printf("read() failed!\n");
        close(fd);
        return 0;
    }
    if((info & (((uint64_t)1) <63)) == 0)
    {
        printf("page is not present!\n");
        close(fd);
        return 0;
    }
    size_t frame = info & ((((uint64_t)1) <55) - 1);
    size_t phy = frame * pagesize + addr % pagesize;
    close(fd);
    printf("The phy frame is 0x%zx\n", frame);
    printf("The phy addr is 0x%zx\n", phy);
    return phy;
}

int main(void){
    while(1)
    {
        uint32_t pid;
        uint64_t virtual_addr;
        printf("Please input the pid in dec:");
 scanf("%u", &pid);
        printf("Please input the virtual address in hex:");
 scanf("%zx", &virtual_addr);
 printf("pid = %u and virtual addr = 0x%zx\n", pid, virtual_addr);
        virtual_to_physical(pid, virtual_addr);
    }
    return 0;
}

首先,我编译一下!

gcc test.c -o haha

然后,我拷贝一下!

cp haha hahatest1; cp haha hahatest2; cp haha hahamonitor

接着,我运行一下!

nohup  ./hahatest1 &
[1] 3943
nohup  ./hahatest2 &
[2] 3944
sudo ./hahamonitor 

这里你可能已经发现我的意图了,我是用进程hahamonitor查看进程hahatest1和进程hahatest2的内存地址。

但是你不能大意,运行hahamonitor 一定要加sudo或者root权限,不然读出来就都是0了。

先看看hahatest1和hahatest2进程的地址空间:

zbf@zbf:~$ cat /proc/3943/maps 
00400000-00401000 r-xp 00000000 08:06 11150436                           /home/zbf/physic_virtual_memory/hahatest1
00600000-00601000 r--p 00000000 08:06 11150436                           /home/zbf/physic_virtual_memory/hahatest1
00601000-00602000 rw-p 00001000 08:06 11150436                           /home/zbf/physic_virtual_memory/hahatest1
011ad000-011cf000 rw-p 00000000 00:00 0                                  [heap]
7ffbf1b64000-7ffbf1d24000 r-xp 00000000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffbf1d24000-7ffbf1f24000 ---p 001c0000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffbf1f24000-7ffbf1f28000 r--p 001c0000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffbf1f28000-7ffbf1f2a000 rw-p 001c4000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffbf1f2a000-7ffbf1f2e000 rw-p 00000000 00:00 0 
7ffbf1f2e000-7ffbf1f54000 r-xp 00000000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffbf2133000-7ffbf2136000 rw-p 00000000 00:00 0 
7ffbf2153000-7ffbf2154000 r--p 00025000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffbf2154000-7ffbf2155000 rw-p 00026000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffbf2155000-7ffbf2156000 rw-p 00000000 00:00 0 
7ffd2529f000-7ffd252c0000 rw-p 00000000 00:00 0                          [stack]
7ffd25302000-7ffd25305000 r--p 00000000 00:00 0                          [vvar]
7ffd25305000-7ffd25307000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

zbf@zbf:~$ cat /proc/3944/maps 
00400000-00401000 r-xp 00000000 08:06 11150444                           /home/zbf/physic_virtual_memory/hahatest2
00600000-00601000 r--p 00000000 08:06 11150444                           /home/zbf/physic_virtual_memory/hahatest2
00601000-00602000 rw-p 00001000 08:06 11150444                           /home/zbf/physic_virtual_memory/hahatest2
01e8b000-01ead000 rw-p 00000000 00:00 0                                  [heap]
7fe786964000-7fe786b24000 r-xp 00000000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7fe786b24000-7fe786d24000 ---p 001c0000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7fe786d24000-7fe786d28000 r--p 001c0000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7fe786d28000-7fe786d2a000 rw-p 001c4000 08:06 20714662                   /lib/x86_64-linux-gnu/libc-2.23.so
7fe786d2a000-7fe786d2e000 rw-p 00000000 00:00 0 
7fe786d2e000-7fe786d54000 r-xp 00000000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7fe786f33000-7fe786f36000 rw-p 00000000 00:00 0 
7fe786f53000-7fe786f54000 r--p 00025000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7fe786f54000-7fe786f55000 rw-p 00026000 08:06 20714659                   /lib/x86_64-linux-gnu/ld-2.23.so
7fe786f55000-7fe786f56000 rw-p 00000000 00:00 0 
7fffd3388000-7fffd33a9000 rw-p 00000000 00:00 0                          [stack]
7fffd33ce000-7fffd33d1000 r--p 00000000 00:00 0                          [vvar]
7fffd33d1000-7fffd33d3000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

可以看到这两个进程都链接了/lib/x86_64-linux-gnu/libc-2.23.so这个动态库,在进程3943(hahatest1)中的虚拟地址是:7ffbf1b64000,但在进程3944中的虚拟地址是:7fe786964000

我们用hahamonitor康康它们的最终的物理地址都是什么?

zbf@zbf:~/$ sudo ./hahamonitor 
Please input the pid in dec:3943
Please input the virtual address in hex:7ffbf1b64000
pid = 3943 and virtual addr = 0x7ffbf1b64000
The phy frame is 0x12ee58
The phy addr is 0x12ee58000

Please input the pid in dec:3944
Please input the virtual address in hex:7fe786964000
pid = 3944 and virtual addr = 0x7fe786964000
The phy frame is 0x12ee58
The phy addr is 0x12ee58000

可以看到物理地址是一样的,都是0x12ee58000。另外我也实验过这两个进程对应的堆栈的物理地址都是不一样的,这就对了!

有兴趣的朋友可以自行下载代码跑一下。

参考资料:

  1. https://www.kernel.org/doc/html/v4.19/admin-guide/mm/pagemap.html
  2. https://www.kernel.org/doc/Documentation/vm/pagemap.txt
  3. https://www.kernel.org/doc/html/latest/arm64/memory.html
  4. https://constantsmatter.com/posts/virtual-address/
  5. 程序喵大人:https://mp.weixin.qq.com/s?__biz=MzI3NjA1OTEzMg==&mid=2247484681&idx=1&sn=45b7d8f38402622718fcdc10ba77f443&chksm=eb7a039adc0d8a8cc6bb635fcb8a3f2f567e064f9c0ee863297c90f486394b788de5c3fe6dbd&mpshare=1&scene=1&srcid=1129bC44tMBu7lpXza2ki1k6&sharer_sharetime=1606655711296&sharer_shareid=741c39217c916aaf06bf9827e80dbff6&exportkey=AX19wECY41gfhbceNfjn7ws%3D&pass_ticket=Tv1TS4ibFzi6ZvNrbr2emqQu9boZCHYlwz5dSAFLvlJHUrIsSAibiRbzFP%2FmiurU&wx_header=0#rd
  6. https://zhou-yuxin.github.io/articles/2017/Linux%20%E8%8E%B7%E5%8F%96%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80%E5%AF%B9%E5%BA%94%E7%9A%84%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80/index.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/476129.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知识图谱论文阅读(十五)【arxiv】A Survey on Knowledge Graph-Based Recommender Systems

论文题目&#xff1a; A Survey on Knowledge Graph-Based Recommender Systems 论文链接&#xff1a; 论文代码&#xff1a; 想法 出现Refine就是用某些方法更好的优化特征表示embed的意思就是变成低维向量&#xff01; 论文 摘要 难点&#xff1a; 当今推荐系统的难点 &…

LeetCode 921. 使括号有效的最少添加(栈)

1. 题目 给定一个由 ( 和 ) 括号组成的字符串 S&#xff0c;我们需要添加最少的括号&#xff08; ( 或是 )&#xff0c;可以在任何位置&#xff09;&#xff0c;以使得到的括号字符串有效。 从形式上讲&#xff0c;只有满足下面几点之一&#xff0c;括号字符串才是有效的&…

Shlwapi介绍

Windows中有一个Shlwapi.dll文件&#xff0c;包含了大量的Windows字符串处理方法&#xff0c;这些方法&#xff0c;在通常的程序应用中&#xff0c;经常会用到&#xff0c;有一部分处理方法&#xff0c;在CRuntime中也存在&#xff0c;但不方便使用。有一部分函数&#xff0c;也…

java权限框架_Java高级工程师必备技术栈-由浅入深掌握Shiro权限框架

权限系统在任何一个系统中都存在&#xff0c;随着分布式系统的大行其道&#xff0c;权限系统也趋向服务化&#xff0c;对于一个高级工程师来说&#xff0c;权限系统的设计是必不可少需要掌握的技术栈Apache Shiro™是一个功能强大且易于使用的Java安全框架&#xff0c;用于执行…

【RippleNet】(一)preprocessor.py【未完】

首先读入的文件有movie和book和news三种&#xff0c;肯定会选择一种进行解析&#xff01; 下面我们以movies作为样例分析&#xff1a; 本论文中使用的数据集是movie-1m ratings.dat&#xff1a; 分别是用户&#xff1a;&#xff1a;电影&#xff1a;&#xff1a;评分&#xff…

LeetCode 961. 重复 N 次的元素

1. 题目 在大小为 2N 的数组 A 中有 N1 个不同的元素&#xff0c;其中有一个元素重复了 N 次。 返回重复了 N 次的那个元素。 示例 1&#xff1a; 输入&#xff1a;[1,2,3,3] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;[2,1,2,5,3,2] 输出&#xff1a;2示例 3&a…

日照华软游戏开发价格_开发区将是未来刚需人群的首选!

开发区真的只是备胎吗?想必在日照人的心目中一定有一张区域排行榜&#xff0c;而排在榜首的一定是东城片区&#xff0c;这是无可厚非的&#xff0c;毕竟东城片区的各项资源是全市其他区域无法抗衡的&#xff0c;然后西城片区、山海天片区、石臼片区……紧随其后&#xff0c;而…

知识图谱论文阅读(十六)【WWW2019】Knowledge Graph Convolutional Networks for Recommender

题目&#xff1a; KGCN 论文链接&#xff1a; 代码链接&#xff1a;https://github.com/hwwang55/KGCN 想法 高阶的意思就是multi-hop的意思注意是从外向里聚合的&#xff0c;第h-1跳是外侧&#xff0c;第h跳是里侧&#xff01; 所以才有聚合邻居和本身之说 创新 摘要 为了…

LeetCode 925. 长按键入(双指针)

1. 题目 你的朋友正在使用键盘输入他的名字 name。 偶尔&#xff0c;在键入字符 c 时&#xff0c;按键可能会被长按&#xff0c;而字符可能被输入 1 次或多次。 你将会检查键盘输入的字符 typed。 如果它对应的可能是你的朋友的名字&#xff08;其中一些字符可能被长按&#…

java 拉取收件箱邮件源码_邮件提醒系统:新邮件识别

最近在做邮件提醒抄送企业微信消息系统&#xff0c;就目前而言&#xff0c;无论是pop3还是imap都没有一个好的方法只接收新邮件&#xff0c;基本只能依靠收件箱列表message自行判断&#xff0c;下面给出几种思路并作对比。//收件箱 folder store.getFolder("INBOX")…

Jquery 操作select总结

//遍历option和添加、移除optionfunction changeShipMethod(shipping){var len $("select[nameISHIPTYPE] option").lengthif(shipping.value ! "CA"){$("select[nameISHIPTYPE] option").each(function(){if($(this).val() 111){$(this).remo…

知识图谱论文阅读(十七)【WWW2021】DGCN: Diversified Recommendation with Graph Convolutional Networks

本论文是很明显是基于KGCN的&#xff01; 如果不懂KGCN&#xff0c;可以看我上一篇博文 论文题目&#xff1a; DGCN: Diversified Recommendation with Graph Convolutional Networks 论文链接&#xff1a; 论文代码&#xff1a; https://github.com/tsinghua-fib-lab/DGCN 想…

PKU-3624

代码 //0-1背包问题 如果不使用循环数组&#xff0c;空间越界。#include <stdio.h>intmain(){ intn, v, i, j; intw[3403], p[3403]; intf[12881]; scanf("%d %d", &n, &v); for(i 1; i <n; i) scanf("%d %d", &a…

LeetCode 1309. 解码字母到整数映射

1. 题目 给你一个字符串 s&#xff0c;它由数字&#xff08;‘0’ - ‘9’&#xff09;和 ‘#’ 组成。 我们希望按下述规则将 s 映射为一些小写英文字符&#xff1a; 字符&#xff08;a - i&#xff09;分别用&#xff08;1 - 9&#xff09;表示。 字符&#xff08;j - z&am…

redis如何设置定时过期_redis补充6之Redis 设置过期时间

一般情况下&#xff0c;我们设置保存的缓存数据的时候都会设置一个过期时间。Redis 中有个设置时间过期的功能&#xff0c;即对存储在 Redis 数据库中的值可以设置一个过期时间。作为一个缓存数据库&#xff0c;这是非常实用的。如我们一般项目中的 token 或者一些登录信息&…

知识图谱论文阅读(十八)【KDD2019】AKUPM: Attention-Enhanced Knowledge-Aware User Preference Model for Recommend

论文题目&#xff1a; AKUPM: Attention-Enhanced Knowledge-Aware User Preference Model for Recommendation 论文代码&#xff1a; 论文链接&#xff1a; 想法 什么叫折射到关系空间&#xff1f; &#xff08;添加了一个关系矩阵&#xff0c;但是关系矩阵为啥要加&#xf…

LeetCode 1304. 和为零的N个唯一整数

1. 题目 给你一个整数 n&#xff0c;请你返回 任意 一个由 n 个 各不相同 的整数组成的数组&#xff0c;并且这 n 个数相加和为 0 。 示例 1&#xff1a; 输入&#xff1a;n 5 输出&#xff1a;[-7,-1,1,3,4] 解释&#xff1a;这些数组也是正确的 [-5,-1,1,2,3]&#xff0c;…

vue做混合式app_Vue+原生App混合开发手记#1

项目的大致需求就是做一个App&#xff0c;里面集成各种功能供用户使用&#xff0c;其中涉及到很多Vue的使用方法&#xff0c;单独总结太麻烦&#xff0c;所以通过这几篇笔记来梳理一下。原型图如下&#xff1a;路由配置主界面会用到一些原生App方法&#xff0c;比如验证用户身份…

Android入门第八篇之GridView(九宫图)

GridView跟ListView都是比较常用的多控件布局&#xff0c;而GridView更是实现九宫图的首选!本文就是介绍如何使用GridView实现九宫图。GridView的用法很多&#xff0c;网上介绍最多的方法就是自己实现一个ImageAdapter继承BaseAdapter&#xff0c;再供GridView使用&#xff0c;…

(十九)【AAAI2021】Knowledge-Enhanced Hierarchical Graph Transformer Network for Multi-Behavior Recommend

题目&#xff1a; Knowledge-Enhanced Hierarchical Graph Transformer Network for Multi-Behavior Recommendation 论文链接&#xff1a; 代码链接&#xff1a;https://github.com/akaxlh/KHGT 论文 时间戳放入到关系中&#xff0c;可以参考这篇《Heterogeneous graph trans…