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

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

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

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

代码语言:javascript
代码运行次数:0
运行
复制
#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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
7fcc36ad6000-7fcc36ad7000 ---p 00000000 00:00 0 
7fcc36ad7000-7fcc372d7000 rw-p 00000000 00:00 0 

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

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

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

EN

回答 1

Stack Overflow用户

发布于 2018-11-25 03:38:06

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

的第一个问题是

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

在……里面

代码语言:javascript
代码运行次数: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

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

代码语言:javascript
代码运行次数:0
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档