RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1373841
Accepted
Грузчик
Грузчик
Asked:2022-06-22 01:07:33 +0000 UTC2022-06-22 01:07:33 +0000 UTC 2022-06-22 01:07:33 +0000 UTC

Linux中的进程虚拟内存结构

  • 772

定义堆栈区、动态数据区、静态数据区和程序模块指令区边界的指针是如何分布的以及在哪些处理器寄存器上?

linux
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    eanmos
    2022-06-22T15:45:17Z2022-06-22T15:45:17Z

    这个问题与 C 语言或 GCC 编译器无关,而与程序运行的操作系统有关。具体来说,您对进程的虚拟内存映射感兴趣- 是她确定可执行文件的堆栈、堆和段(那些.bss,.text等等.data)位于什么地址。以下是具有 Linux 内核和 x86 系列架构的操作系统的答案。


    Linux内核将一个进程的整个虚拟地址空间分为两部分:用户空间内存和内核内存。具体划分不同,至少有三种选择:

    1. 在 i386 架构上,通常整个虚拟地址空间为 4 GiB,内核将底部 3 GiB 分配给用户空间,将顶部 1 GiB 分配给内核本身*。
    2. 在具有 4 级页表的 x86_64 架构上,虚拟地址空间为 48 位。用户空间内存占用 128 TB,以 address 开头,以 address0x0000000000000000结尾0x00007fffffffffff。内核内存也占用 128 TB,从地址开始到地址†0xffff800000000000结束。0xffffffffffffffff
    3. 在具有 5 级页表的 x86_64 架构上,虚拟地址空间为 56 位,其分区方案类似于 (2) †。

    内核内存是相同的,并且由所有程序共享,所以我们将对用户空间内存感兴趣。

    奇怪的是,在 Linux 中找到有关进程地址空间分区的具体信息并不容易。我设法找到了一篇相当详细的文章“Understanding the Memory Layout of Linux Executables”,经过相当长的调查,结果大约是以下进程内存分配:

    0
    Nothing here, because it was just an arbitrary choice by the linker
    ELF and Program and Section Headers - 0x400000 on 64 bit
    Program Text (.text) - Entry Point as Reported by readelf
    Nothing Here either
    Some unknown assembly and data - 0x600000
    Initialised Data (.data) - 0x601068
    Uninitialised Data (.bss) - 0x601078
    Heap
        |
        v
    Memory Mapped Region for Shared Libraries or Anything Else
        ^
        |
    User Stack
    

    因此,我们看到堆栈(eng.stack )位于地址空间的最末端并“向下”增长‡,即朝向较低地址(朝向零)。反过来,堆(eng. heap)会“向上”增长,并立即位于 section 之后.bss。

    默认堆栈大小为 8 MiB。最初,为堆栈分配了 4 KiB 的第一个内存页。如果用户代码超出这 4 KiB,则会发生页面错误,从而捕获内核。然后内核检查堆栈是否超出范围 8 MiB。如果没有退出,它会为堆栈分配一个新页面(堆栈增长),如果退出,它会杀死进程。

    堆栈大小可以使用程序从用户空间更改ulimit。

    还值得注意的是,由于ASLR(地址空间层随机化),每次运行时特定的堆和堆栈地址总是不同的。随机化它们的函数在linux/mm/util.c. 具体来说,这些是函数randomize_stack_top和arch_randomize_brk.

    一种计算进程内存结构的实用方法

    在 Linux 中找出进程内存布局的另一种方法是使用文件/proc/<PID>/maps,它实际上包含有关进程地址空间的信息。如果你写最简单的 hello world,你会看到这样的东西:

    $ cat /proc/$(pidof hello)/maps
    558c1ca6f000-558c1ca70000 r--p 00000000 00:20 638                        /tmp/hello
    558c1ca70000-558c1ca71000 r-xp 00001000 00:20 638                        /tmp/hello
    558c1ca71000-558c1ca72000 r--p 00002000 00:20 638                        /tmp/hello
    558c1ca72000-558c1ca73000 r--p 00002000 00:20 638                        /tmp/hello
    558c1ca73000-558c1ca74000 rw-p 00003000 00:20 638                        /tmp/hello
    558c1e82c000-558c1e84d000 rw-p 00000000 00:00 0                          [heap]
    7ff9a4a01000-7ff9a4a03000 rw-p 00000000 00:00 0
    7ff9a4a03000-7ff9a4a29000 r--p 00000000 103:04 789879                    /usr/lib/libc-2.33.so
    7ff9a4a29000-7ff9a4b74000 r-xp 00026000 103:04 789879                    /usr/lib/libc-2.33.so
    7ff9a4b74000-7ff9a4bc0000 r--p 00171000 103:04 789879                    /usr/lib/libc-2.33.so
    7ff9a4bc0000-7ff9a4bc3000 r--p 001bc000 103:04 789879                    /usr/lib/libc-2.33.so
    7ff9a4bc3000-7ff9a4bc6000 rw-p 001bf000 103:04 789879                    /usr/lib/libc-2.33.so
    7ff9a4bc6000-7ff9a4bd1000 rw-p 00000000 00:00 0
    7ff9a4be3000-7ff9a4be4000 r--p 00000000 103:04 789868                    /usr/lib/ld-2.33.so
    7ff9a4be4000-7ff9a4c08000 r-xp 00001000 103:04 789868                    /usr/lib/ld-2.33.so
    7ff9a4c08000-7ff9a4c11000 r--p 00025000 103:04 789868                    /usr/lib/ld-2.33.so
    7ff9a4c11000-7ff9a4c13000 r--p 0002d000 103:04 789868                    /usr/lib/ld-2.33.so
    7ff9a4c13000-7ff9a4c15000 rw-p 0002f000 103:04 789868                    /usr/lib/ld-2.33.so
    7ffecbeaf000-7ffecbed0000 rw-p 00000000 00:00 0                          [stack]
    7ffecbf31000-7ffecbf35000 r--p 00000000 00:00 0                          [vvar]
    7ffecbf35000-7ffecbf37000 r-xp 00000000 00:00 0                          [vdso]
    ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
    

    在这里您可以看到文件的前五行表示可执行文件的部分/tmp/hello。具体名称不详,但从权限集中可以猜出部分部分的含义。

    您还可以使用前端程序pmap:

    $ pmap $(pidof hello)
    35111:   ./hello
    000055eef0906000      4K r---- hello
    000055eef0907000      4K r-x-- hello
    000055eef0908000      4K r---- hello
    000055eef0909000      4K r---- hello
    000055eef090a000      4K rw--- hello
    000055eef116b000    132K rw---   [ anon ]
    00007f2b7a11f000      8K rw---   [ anon ]
    00007f2b7a121000    152K r---- libc-2.33.so
    00007f2b7a147000   1324K r-x-- libc-2.33.so
    00007f2b7a292000    304K r---- libc-2.33.so
    00007f2b7a2de000     12K r---- libc-2.33.so
    00007f2b7a2e1000     12K rw--- libc-2.33.so
    00007f2b7a2e4000     44K rw---   [ anon ]
    00007f2b7a301000      4K r---- ld-2.33.so
    00007f2b7a302000    144K r-x-- ld-2.33.so
    00007f2b7a326000     36K r---- ld-2.33.so
    00007f2b7a32f000      8K r---- ld-2.33.so
    00007f2b7a331000      8K rw--- ld-2.33.so
    00007ffd6e1a9000    132K rw---   [ stack ]
    00007ffd6e1cb000     16K r----   [ anon ]
    00007ffd6e1cf000      8K r-x--   [ anon ]
    ffffffffff600000      4K --x--   [ anon ]
     total             2368K
    

    * 在Unix SE 的一个问题下的评论中,一位名为 @phuclv 的用户声称这不是完全正确的信息。根据评论,“根据内核版本,分区率可能会有所不同。旧版本可能使用 1/3、2/2 或 3/1 分割,如 ; 所示CONFIG_VMSPLIT_。从 2007 年开始,可以选择像 5/16 和 15/32 这样的小数分区。如果手动改一些#define-s,就可以实现任意分区。今天,受 Meltdown 漏洞影响的系统通常使用 4/4 拆分,即内核和用户模式的地址空间完全分开。”

    † x86_64 的虚拟内存映射的详细描述可以在内核文档中找到。

    ‡ 堆栈增长方向实际上取决于平台。请参阅 enSO 上的相关问题。

    • 4

相关问题

  • 如果 fuser -k number/tcp 没有帮助,如何在 Debian 中释放端口?

  • Ubuntu。startx 不起作用。黑屏

  • --syn 在 iptables 中有什么作用?

  • 为什么需要iso格式?

  • C程序中没有密码的sudo

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5