首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >理解linux中的进程内存映射

理解linux中的进程内存映射
EN

Stack Overflow用户
提问于 2018-11-23 22:03:42
回答 1查看 4.8K关注 0票数 4

我试图理解linux进程内存布局的基础,我得到了以下程序:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h> // standard io
#include <stdlib.h> // C standard library
#include <pthread.h> // threading
#include <unistd.h> // unix standard library
#include <sys/types.h> // system types for linux

// getchar basically is like "read"
// it prompts the user for input
// in this case, the input is thrown away
// which makes similar to a "pause" continuation primitive 
// but a pause that is resolved through user input, which we promptly throw away!
void * thread_func (void * arg) {

    printf("Before malloc in thread 1\n");
    getchar();
    char * addr = (char *) malloc(1000);
    printf("After malloc and before free in thread 1\n");
    getchar();
    free(addr);
    printf("After free in thread 1\n");
    getchar();

}

int main () {

    char * addr;
    printf("Welcome to per thread arena example::%d\n", getpid());
    printf("Before malloc in the main thread\n");
    getchar();
    addr = (char *) malloc(1000);
    printf("After malloc and before free in main thread\n");
    getchar();
    free(addr);
    printf("After free in main thread\n");
    getchar();

    // pointer to the thread 1
    pthread_t thread_1;
    // pthread_* functions return 0 upon succeeding, and other numbers upon failing
    int pthread_status;

    pthread_status = pthread_create(&thread_1, NULL, thread_func, NULL);

    if (pthread_status != 0) {
        printf("Thread creation error\n");
        return -1;
    }

    // returned status code from thread_1
    void * thread_1_status;

    pthread_status = pthread_join(thread_1, &thread_1_status);

    if (pthread_status != 0) {
        printf("Thread join error\n");
        return -1;
    }

    return 0;
}

当我启动程序时,/proc/<pid>/maps中的内容是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00400000-00401000 r-xp 00000000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
00600000-00601000 r--p 00000000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
00601000-00602000 rw-p 00001000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
7fcc372d7000-7fcc37491000 r-xp 00000000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37491000-7fcc37691000 ---p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37691000-7fcc37695000 r--p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37695000-7fcc37697000 rw-p 001be000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37697000-7fcc3769c000 rw-p 00000000 00:00 0 
7fcc3769c000-7fcc376b5000 r-xp 00000000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc376b5000-7fcc378b4000 ---p 00019000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b4000-7fcc378b5000 r--p 00018000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b5000-7fcc378b6000 rw-p 00019000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b6000-7fcc378ba000 rw-p 00000000 00:00 0 
7fcc378ba000-7fcc378dd000 r-xp 00000000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37abe000-7fcc37ac1000 rw-p 00000000 00:00 0 
7fcc37ad8000-7fcc37adc000 rw-p 00000000 00:00 0 
7fcc37adc000-7fcc37add000 r--p 00022000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37add000-7fcc37ade000 rw-p 00023000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37ade000-7fcc37adf000 rw-p 00000000 00:00 0 
7ffdc1cff000-7ffdc1d20000 rw-p 00000000 00:00 0                          [stack]
7ffdc1dd8000-7ffdc1ddb000 r--p 00000000 00:00 0                          [vvar]
7ffdc1ddb000-7ffdc1ddd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

这些记忆区域的用途是什么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc37491000-7fcc37691000 ---p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
...
7fcc37abe000-7fcc37ac1000 rw-p 00000000 00:00 0 
7fcc37ad8000-7fcc37adc000 rw-p 00000000 00:00 0 

运行程序后,我按enter键几次。在打印“在线程1中的malloc之前”之后。内存布局如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00400000-00401000 r-xp 00000000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
00600000-00601000 r--p 00000000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
00601000-00602000 rw-p 00001000 08:01 1323314                            /home/oscp/xg/c/memory_layout/a.out
00632000-00653000 rw-p 00000000 00:00 0                                  [heap]
7fcc36ad6000-7fcc36ad7000 ---p 00000000 00:00 0 
7fcc36ad7000-7fcc372d7000 rw-p 00000000 00:00 0 
7fcc372d7000-7fcc37491000 r-xp 00000000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37491000-7fcc37691000 ---p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37691000-7fcc37695000 r--p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37695000-7fcc37697000 rw-p 001be000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37697000-7fcc3769c000 rw-p 00000000 00:00 0 
7fcc3769c000-7fcc376b5000 r-xp 00000000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc376b5000-7fcc378b4000 ---p 00019000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b4000-7fcc378b5000 r--p 00018000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b5000-7fcc378b6000 rw-p 00019000 08:01 1053877                    /lib/x86_64-linux-gnu/libpthread-2.19.so
7fcc378b6000-7fcc378ba000 rw-p 00000000 00:00 0 
7fcc378ba000-7fcc378dd000 r-xp 00000000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37abe000-7fcc37ac1000 rw-p 00000000 00:00 0 
7fcc37ad8000-7fcc37adc000 rw-p 00000000 00:00 0 
7fcc37adc000-7fcc37add000 r--p 00022000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37add000-7fcc37ade000 rw-p 00023000 08:01 1053733                    /lib/x86_64-linux-gnu/ld-2.19.so
7fcc37ade000-7fcc37adf000 rw-p 00000000 00:00 0 
7ffdc1cff000-7ffdc1d20000 rw-p 00000000 00:00 0                          [stack]
7ffdc1dd8000-7ffdc1ddb000 r--p 00000000 00:00 0                          [vvar]
7ffdc1ddb000-7ffdc1ddd000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

这两个地区的目的是什么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc36ad6000-7fcc36ad7000 ---p 00000000 00:00 0 
7fcc36ad7000-7fcc372d7000 rw-p 00000000 00:00 0 

在打印“malloc之后,在线程1中空闲之前”之后,它会在下面创建另外两个区域:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc30000000-7fcc30021000 rw-p 00000000 00:00 0 
7fcc30021000-7fcc34000000 ---p 00000000 00:00 0 

这两个地区的目的是什么?

EN

回答 1

Stack Overflow用户

发布于 2018-11-24 19:38:06

你的问题涵盖了许多完全不同的事情,所以答案会很长。

的第一个问题是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc37491000-7fcc37691000 ---p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so

在……里面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc372d7000-7fcc37491000 r-xp 00000000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37491000-7fcc37691000 ---p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37691000-7fcc37695000 r--p 001ba000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so
7fcc37695000-7fcc37697000 rw-p 001be000 08:01 1053757                    /lib/x86_64-linux-gnu/libc-2.19.so

这个不可访问的内存区域是库中相邻的ELF段之间的一个空白(它应该占用内存的连续块)。---p保护模式禁止在偶尔分配内存时使用此间隙。如果在进程加载库时对其进行strace(1),您可能会看到如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mmap(NULL, 1848896, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3</usr/lib/libc-2.28.so>, 0) = 0x7f9673d8f000
mprotect(0x7f9673db1000, 1671168, PROT_NONE) = 0
mmap(0x7f9673db1000, 1355776, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3</usr/lib/libc-2.28.so>, 0x22000) = 0x7f9673db1000
mmap(0x7f9673efc000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3</usr/lib/libc-2.28.so>, 0x16d000) = 0x7f9673efc000
mmap(0x7f9673f49000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3</usr/lib/libc-2.28.so>, 0x1b9000) = 0x7f9673f49000

第一个mmap()将第一个ELF段映射到内存中,但保留了整个库的空间。这样做是为了允许内核酌情选择库的位置。为了保护段之间的任何可能的空白,调用mprotect(..., PROT_NONE);然后使用mmap()将所有剩余的段映射到内存中--这也会将适当内存页的保护模式从---p更改为该段所需的任何模式。您可以通过查看它实际上是如何工作的来获得一些乐趣。如果要验证加载过程中如何形成---p间隙,还可以在库的二进制文件中使用readelf(1),并对段的位置和对齐进行十六进制运算,并将结果与strace的输出进行比较。

第二个问题是以下匿名映射:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc36ad6000-7fcc36ad7000 ---p 00000000 00:00 0 
7fcc36ad7000-7fcc372d7000 rw-p 00000000 00:00 0 

这看起来像thread 1的线程堆栈。第二个映射是堆栈本身(372d7000 - 36ad7000 = 800000 =8 MiB,这是许多发行版中的默认堆栈大小限制,这反过来又是pthread的默认堆栈大小),第一个映射是堆栈保护页。这个具有模式---p的页面保护堆栈不溢出,并在溢出发生时触发分段错误(因为对此写保护的页面进行了写入)。

注意:在旧的Linux内核中,线程堆栈在[stack:TID]文件中使用maps名称进行注释,但是这个特性被删除了,所以我不能保证这个映射实际上是一个线程堆栈(尽管它看起来像)。但是,您可以使用straceclone() syscall的child_stack参数中找到确切的线程堆栈位置,并与此映射进行比较。

还在继续。第三个问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc30000000-7fcc30021000 rw-p 00000000 00:00 0 
7fcc30021000-7fcc34000000 ---p 00000000 00:00 0 

这就是malloc() in thread 1为分配所请求的内存所做的事情。简而言之,整个区域7fcc30000000-7fcc34000000是一个堆,从堆中进行分配。从这个堆中分配的rw-p间隔7fcc30000000-7fcc30021000将增长,因为您将使用malloc()请求越来越多的内存。当这个堆耗尽时,将使用mmap()请求新的堆。

正如您可能注意到的,对于您的问题中的下列映射,我没有一个解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
7fcc37abe000-7fcc37ac1000 rw-p 00000000 00:00 0 
7fcc37ad8000-7fcc37adc000 rw-p 00000000 00:00 0 

我不能很快认出那些家伙,也不确定这些是普通的分配。这可能需要单独调查,因为这个话题已经太长了。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53455603

复制
相关文章
java——调用方法交换两个数的值
而利用Java的调用方法来交换两个数字的值,没有那么直接,我们需要用到数组这个引用类型,才能在方法中实现两个数字的交换。
小雨的分享社区
2022/10/26
8210
java——调用方法交换两个数的值
交换两个数的值的方法(三种)
采用中间变量C,来承接a的值,再将a的值设置为b,最后将中间变脸c的值设置到b中。
ha_lydms
2023/08/09
1740
Python判断两个单词的相似度
本文要点在于算法的设计:如果两个单词中不相同的字母足够少,并且随机选择几个字母在两个单词中具有相同的前后顺序,则认为两个单词是等价的。 目前存在的问题:可能会有误判。 from random import sample, randint def oneInAnother(one, another): '''用来测试单词one中有多少字母不属于单词another''' return sum((1 for ch in one if ch not in another)) def testPositions(
Python小屋屋主
2018/04/16
1.6K0
jQuery.html()方法ie下不能设置html代码的问题
jQuery一般来说还是很好用的,但有时候它也会有些问题的,比如jQuery的html()方法设置html代码,在一种情况下,ie6、ie7、ie8 下是不能设置html代码的。本文说的问题只针对ie8(包括ie8)以下的浏览器。   1.什么情况下IE6、IE7、IE8 jQuery.html("xxx")方法会设置不上html代码?   答:当被加载的的html代码里面出现以下情况,ie8(包括ie8)以下是设置不上html代码的:     a) 被设置的html代码中包含引用其他js的,如:<scr
磊哥
2018/05/08
1.9K0
多种方法快速交换两个变量的值
# 使用多种方法快速交换两个变量的值 1、利用元组的快速交换变量值 2、引入新的变量来交换 3、使用加减法交换变量值 4、利用元组从一个函数中返回两个不同的值 # 代码 # 1. 利用元组的快速交换变量值 a = 5 b = 8 a, b = b, a print(a, b) # 2. 引入新的变量来交换 c = b b = a a = c print(a, b) # 3. 使用加减法交换变量值 a = a + b b = a - b a = a - b print(a, b) # 4. 利用元组
benym
2022/07/14
5620
Java List的get方法
List的get方法是Java的集合框架中常用的一个方法,用于获取List集合中指定位置的元素。
很酷的站长
2023/10/20
6050
Java List的get方法
php 中file_get_contents超时问题的解决方法
最近开发遇到一个file_get_contents超时的问题,主要是因为访问腾讯服务器导致php脚本超时,下面我来总结file_get_contents超时问题的解决方法总结 1.创建一个可以控制的资源句柄,通过控制资源句柄超时来控制file_get_contents超时时间 $context = stream_context_create( array( 'http' => array( 'timeout' => 3000 //超时时间,单位为秒
joshua317
2018/04/16
2.7K0
【html】referrer值的设置小记
当html页面中引入跨域的资源时(image,js,css等),可在html的header中加上
一朵灼灼华
2022/08/05
5.8K0
找出两个文件中相同的单词(java实现)
第二种比较单词的方法:将string【】数组转换成集合,通过集合的retainAll()方法 两个集合取交集
崔笑颜
2020/08/24
1.7K0
Visual Studio 中两个窗体(WinForm)之间相互传值的方法
编写WinowsForm应用程序时,实现两个窗体之间相互传递值的方法其实很简单。以下用一个例子说明:在名为FormMain主窗体运行过程中利用名为FormInfo窗体,获取用户输入信息,并将这些信息返回给FormMain
zls365
2021/04/23
2.3K0
Visual Studio 中两个窗体(WinForm)之间相互传值的方法
问题 1505: [蓝桥杯][算法提高VIP]单词个数统计
题目描述 编写一个程序,输入一个字符串(长度不超过80),然后统计出该字符串当中包含有多少个单词。例如:字符串“this is a book”当中包含有4个单词。
且陶陶
2023/04/12
4750
16.动态路由传值和get传值
1.动态路由传值  1.在components目录下新建vContent.vue组件 <template> <div> <h2>{{msg}}</h2> </div> </template> <script> export default { data () { return { msg:'详情组件', } }, methods:{ }, mounted(){ console.log(this
玩蛇的胖纸
2019/10/21
1.6K0
go get超时的网络问题
可以肯定是网络的问题,但是排查网络ping都是ok的,也能越“墙”;go env的设置也是ok的:
DifficultWork
2021/02/19
1.8K0
Visual Studio 中两个窗体(WinForm)之间相互传值的方法
编写WinowsForm应用程序时,实现两个窗体之间相互传递值的方法其实很简单。以下用一个例子说明:在名为FormMain主窗体运行过程中利用名为FormInfo窗体,获取用户输入信息,并将这些信息返回给FormMain
用户9127601
2021/11/01
1.8K0
get和post方法的区别
在form表单提交数据的过程中,method属性提供了两个值:get,post,默认为get方式[参1]
Hongten
2018/09/13
1.6K0
GET、POST编码问题
GET请求、POST经常会出现中文乱码的问题,最好约定前后端的编码,一般为UTF-8。但是这里面也是有坑的。 后端设置编码为UTF-8的推荐方式: SpringMVC配置过滤器: <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <ini
欠扁的小篮子
2018/07/04
6840
英文单词排序方法
List<String> words = new ArrayList<String>(); words.add("China"); words.add("Americal"); words.add("lafei"); words.add("lundom"); Collections.sort(words,new Comparator<String>() { public int compare(String o1, String o2) {
斯文的程序
2019/11/07
9550
点击加载更多

相似问题

获取用ajax AsyncFileUpload保存的文件的新文件名?

21

文件上传控件和Ajax AsyncFileUpload控件

20

Ajax控制工具包AsyncFileUpload文件上传控制

32

Ajax AsyncFileUpload.FileBytes返回null

35

本地化AsyncFileUpload(Ajax ControlToolkit)

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文