59 多次 mmap 虚拟地址的关系

news2025/1/13 15:53:13

前言

这是来自于网友的一篇帖子 

然后 我们这里来探究一下这个问题

主要是 多次连续的 mmap 获取到的 虚拟地址区域 是否连续

以及 衍生出的一些其他的问题

从 mmap 的实现 我们可以知道, mmap 的空间是 自顶向下 分配的, 因此 两块空间应该是连续的, 第一块在上面, 第二块在下面 

 

 

测试用例

测试用例很简单, 就是多次 mmap 同一个文件, 然后 观察一下 其地址信息

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

#define LEN (10*4096)

int main(void) {
    int fd;
    char *vadr;

    if ((fd = open("./1.txt", O_RDWR)) < 0) {
        return 0;
    }
    vadr = mmap(0, LEN, PROT_READ, MAP_PRIVATE | MAP_LOCKED, fd, 0);
    printf("vaddr = 0x%x\n", vadr);
    printf(" ch = %c \n", vadr[10]);


    if ((fd = open("./1.txt", O_RDWR)) < 0) {
        return 0;
    }
    vadr = mmap(0, LEN, PROT_READ, MAP_PRIVATE | MAP_LOCKED, fd, 0);
    printf("vaddr = 0x%x\n", vadr);
    printf(" ch = %c \n", vadr[10]);

    return 0;
}

 

程序执行输出如下, 可以证实我们上面的猜想, 但是还有一些 细节我们需要去了解

root@ubuntu:~/Desktop/linux/HelloWorld# ./startGdbServer.sh
Test07MmapRead.c: In function ‘main’:
Test07MmapRead.c:19:12: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘char *’ [-Wformat=]
     printf("vaddr = 0x%x\n", vadr);
            ^
Test07MmapRead.c:27:12: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘char *’ [-Wformat=]
     printf("vaddr = 0x%x\n", vadr);
            ^
Process /root/Desktop/linux/HelloWorld/Test07MmapRead created; pid = 52114
Listening on port 1235
Remote debugging from host ::ffff:192.168.220.132, port 44444
vaddr = 0xf7fea000
 ch = f
vaddr = 0xf7fe0000
 ch = f

 

 

基于内核的调试多次 mmap 的调用

我们这里 先放出一部分调试结果信息作为参照

如下调试会分为两个部分, 一个是 内核的调试, 一个是 glibc的调试, 这两部分 完整的解释日志的信息

我们这里核心关注的是 1.txt 对应的两段空间, 以及其到 堆栈底部 的空间

所以 ld-2.23.so, libc-2.23.so 对应的空间应该是 mmap 映射了之后 进行了 munmap 因此才有如下奇怪的 mmap 空间的申请, 然后 我们这里需要 大致梳理清楚 如下日志的具体情况

2260992 - 0x228000 - 0x7ffff7dd7000 - 0x7ffff7fff000 - ld-2.23.so
16384 - 0x4000 - 0x7ffff7ff8000 - vdso_image
4096 - 0x1000 - 0x7ffff7ff7000 - system_dirs
4096 - 0x1000 - 0x7ffff7ff6000 - realname libc.so.6 
3973120 - 0x3ca000 - 0x7ffff7a00000 - libc-2.23.so
	0x7ffff7dcf000 - dl_main - openaux - dl_map_segments 
	0x7ffff7dd5000 - dl_main - openaux - dl_map_segments
4096 - 0x1000 - 0x7ffff7ff5000 - dl_main - init_tls - dl_allocate_tls_storage - libc_memalign 
4096 - 0x1000 - 0x7ffff7ff4000 - dl_main - init_tls - dl_allocate_tls_storage - allocate_dtv 
40960 - 0xa000 - 0x7ffff7fea000 - 1.txt
40960 - 0xa000 - 0x7ffff7fe0000 - 1.txt

 

第一个 mmap 调用如下, 主要是 加载 ld-2.23.so, 这个纯粹是在内核的调用, 所以 待会儿 glibc 的调试不会碰到它 

ld-2.23.so 文件大小接近 160kb 左右  

83077a8059544ed5a28adf481c2d58bd.png

 

接着 munmap 了没有使用的空间, 现在的情况是 ld-2.23.so 占用的空间是 0x7ffff7dd7000 - 0x7ffff7dfd000

释放掉了空间 0x7ffff7dfd000 - 0x7ffff7fff000

276462568b51466c86fcb057b46981c3.png 

第二个 mmap 调用如下,映射的是 vdso 的镜像, 映射的区间是 0x7ffff7ff8000 - 0x7ffff7ffc000

f6e7edd503414a0f94d61b9afac1942e.png

 

第三个 mmap 调用如下, 映射的是 “/root/Desktop/linux/glibc-2.23/install/lib” 的字符串, 映射的区间是 0x7ffff7ff7000 - 0x7ffff7ff8000

9046882641c144f3a3d002a421dec579.png

 

第四个 mmap 调用如下, 映射的是 “libc.so.6” 对应的一个 linkmap 的一个结构体, 映射的区间是 0x7ffff7ff6000 - 0x7ffff7ff7000

0f66c4bbb66c4ac8a05b48e61d3b6ab0.png

 

第五个 mmap 调用如下,映射的是 “libc-2.23.so” 的动态库, 映射的区间是 0x7ffff7a0d000 - 0x7ffff7dd7000

空间之所以 在这里是因为 ld-2.23.so 的 mmap 映射区只有 2m, 这里需要 3m, 因此 继续向前寻找空间, 找到的 ld-2.23.so 前面的一块空间 

cf3c7714d06d4b9c98fbfa7b68458e48.png

 

第六个 mmap 调用如下, dl_main - init_tls - dl_allocate_tls_storage - libc_memalign 映射了 4k 的映射区, 映射的区间是 0x7ffff7ff5000 - 0x7ffff7ff6000

6310225c1fa345859860209bd7371455.png 

第七个 mmap 调用如下, dl_main - init_tls - dl_allocate_tls_storage - allocate_dtv 映射了 4k 的映射区, 映射的区间是 0x7ffff7ff4000 - 0x7ffff7ff5000

737a2b7830594dc4ac983dfe83808672.png 

 

接下来就是我们需要关心的业务 mmap 映射了 

目前 mmap 映射区已经使用的空间如下, 接着需要申请两个 40kb 的空间, 在 0x7ffff7dfd000 - 0x7ffff7ff4000 的空间是可以容纳这需求的 2 * 40kb 的 

0x7ffff7a0d000 - 0x7ffff7dd7000 = libc-2.23.so
0x7ffff7dd7000 - 0x7ffff7dfd000 = ld-2.23.so
0x7ffff7ff4000 - 0x7ffff7ff5000 = dl_main - init_tls - dl_allocate_tls_storage - allocate_dtv
0x7ffff7ff5000 - 0x7ffff7ff6000 = dl_main - init_tls - dl_allocate_tls_storage - libc_memalign
0x7ffff7ff6000 - 0x7ffff7ff7000 = system_dirs
0x7ffff7ff7000 - 0x7ffff7ff8000 = realname libc.so.6
0x7ffff7ff8000 - 0x7ffff7ffc000 = vdso_image

 

第八个 mmap 调用申请了 40kb, 申请的空间为 0x7ffff7fea000 - 0x7ffff7ff4000

16744318c95245e7849ba590c3a8d326.png

 

第九个 mmap 调用申请了 40kb, 申请的空间为 0x7ffff7fe0000 - 0x7ffff7fea000

4b42d959b5894999b726b2b3f5939d96.png 

 

最终整个 mmap 映射区使用空间如下  

0x7ffff7a0d000 - 0x7ffff7dd7000 = libc-2.23.so
0x7ffff7dd7000 - 0x7ffff7dfd000 = ld-2.23.so
0x7ffff7fe0000 - 0x7ffff7fea000 = mmap("1.txt")
0x7ffff7fea000 - 0x7ffff7ff4000 = mmap("1.txt")
0x7ffff7ff4000 - 0x7ffff7ff5000 = dl_main - init_tls - dl_allocate_tls_storage - allocate_dtv 
0x7ffff7ff5000 - 0x7ffff7ff6000 = dl_main - init_tls - dl_allocate_tls_storage - libc_memalign 
0x7ffff7ff6000 - 0x7ffff7ff7000 = system_dirs 
0x7ffff7ff7000 - 0x7ffff7ff8000 = realname libc.so.6 
0x7ffff7ff8000 - 0x7ffff7ffc000 = vdso_image

 

 

基于glibc的调试多次 mmap 的调用

这里主要是基于 glibc 进行调试, 这里的断点是上面的 内核调试断点的一部分

然后 上面各个 mmap 映射区的 大部分映射空间的逻辑意义 也可以在这里找到, 上面给出了各个 mmap 映射区的逻辑意义信息, 但是没有给为什么 

这里 基于 glibc 的调试就是 给出为什么 

 

第一个 mmap 调用如下, 映射的是 “/root/Desktop/linux/glibc-2.23/install/lib” 的字符串, 映射的区间是 0x7ffff7ff7000 - 0x7ffff7ff8000

4a825416b1914a9bb1191472087958d4.png

 

分配空间的大小参照, 以及具体使用如下, 注意这里的 malloc 不同于我们不同的应用程序的 malloc 调用

fae71955ff464bdd9291f3e6321215dc.png

 

第二个 mmap 调用如下,映射的是 “libc.so.6” 对应的一个 linkmap 的一个结构体, 映射的区间是 0x7ffff7ff6000 - 0x7ffff7ff7000

972885a97ec641dca07e4271fdcc8611.png

 

分配空间的大小参照, 以及具体使用如下, 主要是新建了一个 linkmap 结构体, 然后存储它的各个属性 

08e405dcb5684d3f844941b8f17d7f14.png  

第三个 mmap 调用如下,映射的是 “libc-2.23.so” 的动态库, 映射的区间是 0x7ffff7a38000 - 0x7ffff7dd7000

因为在宿主机 和 在 qemu 虚拟机中 libc-2.23.so 大小不太一样, 因此这里 libc-2.23.so 对应的 vma 区间不太一致 

50067e952d4440e7a18a0fde02314179.png

 

第四个 mmap 调用如下, 这里我们不太关心, 直接跳过 

内核中没有该断点, 因为这里是传入的地址, 内核的断点是在 申请空间的地方

a5c4eaad61444992b9ff5b96ea8e7e34.png

 

第五个 mmap 调用如下, 这里我们不太关心, 直接跳过 

内核中没有该断点, 因为这里是传入的地址, 内核的断点是在 申请空间的地方

7277b67bda764e74a7961e2ab7884a44.png

 

第六个 mmap 调用如下, dl_main - init_tls - dl_allocate_tls_storage - libc_memalign 映射了 4k 的映射区, 映射的区间是 0x7ffff7ff5000 - 0x7ffff7ff6000

ce72e0d0996147adbf844a368a229610.png

 

第七个 mmap 调用如下, dl_main - init_tls - dl_allocate_tls_storage - allocate_dtv 映射了 4k 的映射区, 映射的区间是 0x7ffff7ff4000 - 0x7ffff7ff5000

2786ddaca9e048e4b83aa79b25d53612.png

 

第八个 mmap 调用申请了 40kb, 申请的空间为 0x7ffff7fea000 - 0x7ffff7ff4000

从 rax 寄存器中可以看到 mmap 申请的空间的首地址, 从上层堆栈信息中可以看到当前执行的代码位置 

a1192f7d97de413e8676211ddbd98cc6.png

 

第九个 mmap 调用申请了 40kb, 申请的空间为 0x7ffff7fea000 - 0x7ffff7fe0000

从 rax 寄存器中可以看到 mmap 申请的空间的首地址, 从上层堆栈信息中可以看到当前执行的代码位置 

4fd5801c44fe4638836d44dcb2d29ba5.png

 

 

 main 中 第一个 mmap 和 第二个 mmap 调用如下, 你也可以对一下 上面 glibc 上层调用 mmap 的代码的地址信息 

809febbf94624237bcdf9f5131da7821.png

84256796d7934c279d0ccb3ba2419550.png 

 

同一个文件, 两个虚拟地址空间怎么关联的?

虚拟地址空间映射物理页的时候是从 pagecache 中获取的 给定的文件对应的物理页

两个虚拟地址空间 对应的文件一样, 因此是映射到了相同的物理页 

b6deb44adfea42388c8667b6812d9a11.png

 

第一个 mmap 映射区的第一个物理页如下 

0ac3a169640e4e40898f0fc7ce32c367.png

 

第二个 mmap 映射区的第一个物理页如下, 可以发现 两个虚拟地址空间映射的物理页相同

f69c98d2ce064193acc9dd2a0dbfa5bc.png

 

 

 

 

 

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

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

相关文章

二百三十七、Hive——DWS层生成每个清洗字段的异常情况记录

一、目的 在Hive中对每种业务数据的清洗字段的异常数据进行记录 例如这张图&#xff0c;上面是原始数据&#xff0c;下面是每台雷达每天的异常字段的记录 二、实施步骤 &#xff08;一&#xff09;建表 create table if not exists dws_data_clean_record_queue(data_ty…

Go团队:Go是什么

2024年的Google I/O大会[1]如期而至。 这届大会的核心主旨毫无疑问是坚定不移的以AI为中心&#xff1a;Google先是发布了上下文长度将达到惊人的200万token的Gemini 1.5 Pro[2]&#xff0c;然后面对OpenAI GPT-4o的挑衅&#xff0c;谷歌在大会上直接甩出大杀器Project Astra[3]…

关于pytest中用例名称使用中文乱码的解决

场景&#xff1a;使用pytest.mark.parametrize装饰器为用例自定义名称时&#xff0c;运行显示乱码。如下图所示&#xff1a; 解决方案&#xff1a; 1.在根目录 pytest.ini中增加一行代码 [pytest] disable_test_id_escaping_and_forfeit_all_rights_to_community_supportTrue…

学习使用博客记录生活

学习使用博客记录生活 新的改变 今天新的开始&#xff0c;让我用图片开始记录吧 看这个背景图片怎么样

微信小程序实现容器图片流式布局功能,配合小程序原生框架使用。

小程序实现容器图片流式布局功能&#xff0c;因为目前论坛上也有很多博主出过类似的文章&#xff0c;这里我就以一个小白角度去讲一下如何实现的吧。给作者一点点鼓励&#xff0c;先点个赞赞吧&#x1f44d;&#xff0c;蟹蟹&#xff01;&#xff01; 目标 实现下方效果图 技术…

基金/证券项目如何进行非交易日数据补全(实战)

一些大数据开发的项目&#xff0c;特别是基金/证券公司的项目&#xff0c;都经常会涉及到交易日与非交易日的概念。 如果要让你对一张交易日跑批的主表&#xff0c;怎么去补全非交易日的数据呢&#xff1f; 在遇到这种情况的时候&#xff0c;我们要去怎么处理&#xff1f;来&…

模板编译之入口分析

Vue 是一个渐进式 JavaScript 框架&#xff0c;提供了简单易用的模板语法&#xff0c;帮助开发者以声明式的方式构建用户界面。Vue 的模板编译原理是其核心之一&#xff0c;它将模板字符串编译成渲染函数&#xff0c;并在运行时高效地更新 DOM。本文将深入探讨 Vue 模板编译的原…

图片分类模型训练及Web端可视化预测(下)——Web端实现可视化预测

Web端实现可视化预测 基于Flask搭建Web框架&#xff0c;实现HTML登录页面&#xff0c;编写图片上传并预测展示页面。后端实现上一篇文章所训练好的模型&#xff0c;进行前后端交互&#xff0c;选择一张图片&#xff0c;并将预测结果展示到页面上。 文章目录 Web端实现可视化预测…

前端基于word模板导出word文档

项目环境 vue2 js vue-cli等 依赖包都可以在npm官网找到对应文档 npm官网(英文) 1、依赖 安装依赖 docxtemplater npm i docxtemplaterfile-saver npm i file-saverjszip-utils npm i jszip-utilsjszip npm i jszip在对应页面或模块中引入依赖 import Docxtemplater …

探索AI写作工具:五款推荐

在现实生活中&#xff0c;除了专业的文字工作者&#xff0c;各行各业都避免不了需要写一些东西&#xff0c;比如策划案、论文、公文、讲话稿、总结计划……等等。而随着科技的进步&#xff0c;数字化时代的深入发展&#xff0c;AI已经成为日常工作中必不可少的工具了&#xff0…

智慧之选:开源与闭源大模型的未来探索

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

有一个3x4的矩阵,要求编写程序求出其中值最大的那个元素,以及其所在的行号和列号

解题思路&#xff1a; 先考虑解此问题的思路。从若干数中求最大数的方法很多&#xff0c;现在采用"打擂台"的算法。如果有若干人比武&#xff0c;先有一人站在台上&#xff0c;再上去一人与其交手&#xff0c;败者下台&#xff0c;胜者留在台上。第3个人再上…

selenium安装出错

selenium安装步骤&#xff08;法1&#xff09;&#xff1a; 安装失败法1 第一次实验&#xff0c;失败 又试了一次&#xff0c;失败 安装法2-失败&#xff1a; ERROR: Could not install packages due to an EnvironmentError: [WinError 5] 拒绝访问。: c:\\programdata\\a…

【C++题解】1697. 请输出n~1之间所有的整数

问题:1697. 请输出n~1之间所有的整数 类型&#xff1a;循环 题目描述&#xff1a; 从键盘读入一个整数 n &#xff0c;请输出 n∼1 之间所有的整数&#xff0c;每行输出 1 个。 比如&#xff0c;假设读入 n5 &#xff0c;输出结果如下&#xff1a; 5 4 3 2 1 输入&#xff1…

UE5 像素流与web 交互

总结下虚幻与网页的交互&#xff0c;这里将ue5 与js 交互传递参数记录下&#xff0c;其它的博主写的就是缺胳膊少腿的要么就是封闭收费&#xff0c;这个是在官方可以查询到。这里记录下&#xff1a; 点个关注不迷路&#xff1a; 具体的使用如下&#xff1a; 在你的游戏玩家类…

推荐几款新手学习编程的网站

免费在线开发平台 介绍一款编程平台&#xff0c;专为学生和开发者量身打造&#xff01;平台拥有近4000道编程题目&#xff0c;支持多种编程语言&#xff08;包括C、C、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3和C#&#xff09;&#xff0c;为您提供全面的学…

【Oracle篇】rman标准化全库备份策略:完整备份or增量备份(第三篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

YoloV8改进策略:蒸馏改进|CWDLoss|使用蒸馏模型实现YoloV8无损涨点|特征蒸馏

摘要 在本文中&#xff0c;我们成功应用蒸馏策略以实现YoloV8小模型的无损性能提升。我们采用了CWDLoss作为蒸馏方法的核心&#xff0c;通过对比在线和离线两种蒸馏方式&#xff0c;我们发现离线蒸馏在效果上更为出色。因此&#xff0c;为了方便广大读者和研究者应用&#xff…

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法

Kubernetes Service 之原理与 ClusterIP 和 NodePort 用法 Service 定义 在 Kubernetes 中&#xff0c;由于Pod 是有生命周期的&#xff0c;如果 Pod 重启它的 IP 可能会发生变化以及升级的时候会重建 Pod&#xff0c;我们需要 Service 服务去动态的关联这些 Pod 的 IP 和端口…

六个免费的AI制图网站的介绍

六个免费的AI制图网站的介绍 以下是六个免费的AI制图网站的介绍&#xff0c;包括官网、特点、缺点以及使用时的注意事项&#xff1a; 海鲸AI 官网&#xff1a;AI绘画创作平台 - 海鲸AI | 智能艺术生成器特点&#xff1a;支持PC和移动端&#xff0c;集成了Midjourney AI模型&am…