【问题标题】:Wrong entries with /proc/pid/stat?/proc/pid/stat 输入错误?
【发布时间】:2015-04-21 18:49:54
【问题描述】:

我编写了一个简单的 C 程序,其中包含一些全局变量和静态变量。一些代码,输出如下所示。

示例源代码:

#include <stdio.h>

int g1, g2;

int main(){

     printf("g1:%p g2:%p\n", &g1, &g2);

     return 0;
}

输出:

g1:0x6061b0 g2:0x6061c0

此类变量属于数据段。它们可以在已初始化的小节中,也可以在未初始化的(bss)小节中。我打印它们的地址以检查它们在内存中的位置,然后将这些值与/proc/&lt;pid&gt;/stat 伪文件的start_dataend_data 条目的值进行比较。我的变量属于那个区域。

/proc/pid/stat 给我的限制:

start_data: 604e10
end_data:   605180

来自documentation

45) start_data %lu(Linux 3.3 起) 上面哪个程序初始化的地址和 放置未初始化 (BSS) 的数据。

(46) end_data %lu(Linux 3.3 起) 下面是程序初始化的地址和 放置未初始化 (BSS) 的数据。

我已经设法使用linker 生成的map file 获得data segment 的正确区域,但是通过使用proc 界面,它会更干净(更容易,更快,..)。

我使用链接器中的 mapfile 发现的正确限制:

start: 605168
end:   606290

我正在使用带有 Linux 3.13 的 Ubuntu Server x64。

stat 的完整输出:

29505 (myexec) R 29504 29504 1438 34822 29504 24640 52 0 0 0 0 0 0 0 20 0 1 0 55253161 4308992 24 18446744073709551615 4194304 4210644 140737488347232 140737488337560 140737348896784 0 0 0 0 0 0 0 17 0 0 0 0 0 0 6311440 6312320 6320128 140737488347816 140737488347831 140737488347831 140737488351209 0

ma​​p_files 的输出:

total 0
lr-------- 1 root root 64 Apr 21 22:32 400000-41a000 -> /bin/ls
lr-------- 1 root root 64 Apr 21 22:32 619000-61a000 -> /bin/ls
lr-------- 1 root root 64 Apr 21 22:32 61a000-61b000 -> /bin/ls
lr-------- 1 root root 64 Apr 21 22:32 7ffff649e000-7ffff64a9000 -> /lib/x86_64-linux-gnu/libnss_files-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff64a9000-7ffff66a8000 -> /lib/x86_64-linux-gnu/libnss_files-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff66a8000-7ffff66a9000 -> /lib/x86_64-linux-gnu/libnss_files-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff66a9000-7ffff66aa000 -> /lib/x86_64-linux-gnu/libnss_files-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff66aa000-7ffff66b5000 -> /lib/x86_64-linux-gnu/libnss_nis-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff66b5000-7ffff68b4000 -> /lib/x86_64-linux-gnu/libnss_nis-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff68b4000-7ffff68b5000 -> /lib/x86_64-linux-gnu/libnss_nis-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff68b5000-7ffff68b6000 -> /lib/x86_64-linux-gnu/libnss_nis-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff68b6000-7ffff68cd000 -> /lib/x86_64-linux-gnu/libnsl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff68cd000-7ffff6acc000 -> /lib/x86_64-linux-gnu/libnsl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6acc000-7ffff6acd000 -> /lib/x86_64-linux-gnu/libnsl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6acd000-7ffff6ace000 -> /lib/x86_64-linux-gnu/libnsl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6ad0000-7ffff6ad9000 -> /lib/x86_64-linux-gnu/libnss_compat-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6ad9000-7ffff6cd8000 -> /lib/x86_64-linux-gnu/libnss_compat-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6cd8000-7ffff6cd9000 -> /lib/x86_64-linux-gnu/libnss_compat-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6cd9000-7ffff6cda000 -> /lib/x86_64-linux-gnu/libnss_compat-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff6cda000-7ffff6fa3000 -> /usr/lib/locale/locale-archive
lr-------- 1 root root 64 Apr 21 22:32 7ffff6fa3000-7ffff6fa7000 -> /lib/x86_64-linux-gnu/libattr.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff6fa7000-7ffff71a6000 -> /lib/x86_64-linux-gnu/libattr.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff71a6000-7ffff71a7000 -> /lib/x86_64-linux-gnu/libattr.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff71a7000-7ffff71a8000 -> /lib/x86_64-linux-gnu/libattr.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff71a8000-7ffff71ab000 -> /lib/x86_64-linux-gnu/libdl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff71ab000-7ffff73aa000 -> /lib/x86_64-linux-gnu/libdl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff73aa000-7ffff73ab000 -> /lib/x86_64-linux-gnu/libdl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff73ab000-7ffff73ac000 -> /lib/x86_64-linux-gnu/libdl-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff73ac000-7ffff73e9000 -> /lib/x86_64-linux-gnu/libpcre.so.3.13.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff73e9000-7ffff75e8000 -> /lib/x86_64-linux-gnu/libpcre.so.3.13.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff75e8000-7ffff75e9000 -> /lib/x86_64-linux-gnu/libpcre.so.3.13.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff75e9000-7ffff75ea000 -> /lib/x86_64-linux-gnu/libpcre.so.3.13.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff75ea000-7ffff77a5000 -> /lib/x86_64-linux-gnu/libc-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff77a5000-7ffff79a4000 -> /lib/x86_64-linux-gnu/libc-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff79a4000-7ffff79a8000 -> /lib/x86_64-linux-gnu/libc-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff79a8000-7ffff79aa000 -> /lib/x86_64-linux-gnu/libc-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff79af000-7ffff79b6000 -> /lib/x86_64-linux-gnu/libacl.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff79b6000-7ffff7bb5000 -> /lib/x86_64-linux-gnu/libacl.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff7bb5000-7ffff7bb6000 -> /lib/x86_64-linux-gnu/libacl.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff7bb6000-7ffff7bb7000 -> /lib/x86_64-linux-gnu/libacl.so.1.1.0
lr-------- 1 root root 64 Apr 21 22:32 7ffff7bb7000-7ffff7bd7000 -> /lib/x86_64-linux-gnu/libselinux.so.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff7bd7000-7ffff7dd6000 -> /lib/x86_64-linux-gnu/libselinux.so.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff7dd6000-7ffff7dd7000 -> /lib/x86_64-linux-gnu/libselinux.so.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff7dd7000-7ffff7dd8000 -> /lib/x86_64-linux-gnu/libselinux.so.1
lr-------- 1 root root 64 Apr 21 22:32 7ffff7dda000-7ffff7dfd000 -> /lib/x86_64-linux-gnu/ld-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff7ffc000-7ffff7ffd000 -> /lib/x86_64-linux-gnu/ld-2.19.so
lr-------- 1 root root 64 Apr 21 22:32 7ffff7ffd000-7ffff7ffe000 -> /lib/x86_64-linux-gnu/ld-2.19.so

有什么想法吗? 干杯。

【问题讨论】:

  • procfs 内容跨内核版本变化。你用的是什么版本的内核?您确定您正在查看正确的字段并且您的内核 >=3.3(支持 start_data 和 end_data)吗?
  • @BlueMoon 两者都是!查看更新后的问题!
  • 它在我的 ubuntu 3.11、i686 上正确显示您的代码(即范围与地图匹配)。可以发一下statls -l ../map_files的具体内容吗?
  • 程序内部看到的地址是物理地址->内核的虚拟地址。您的程序报告虚拟地址。 proc 可能会向您展示内核看到的内容 - 实际的物理地址。内存的结束是动态的—— brk 系统调用会在程序运行时更改驻留工作集大小的结束内存地址。尝试查看跟踪以了解我的意思。
  • @BlueMoon 请查看更新后的问题!请记住,地址以十进制显示!

标签: c linux memory-management memory-mapping


【解决方案1】:

似乎是的(或不正确的文档)。

ELF 使用一个小技巧来指定 BSS(我去掉了前导零):

$ objdump -x ./a.out

LOAD off    0x00000e00 vaddr 0x00600e00 paddr 0x00600e00 align 2**21
     filesz 0x00000258 memsz 0x00000268 flags rw-

对于那个 PT_LOAD:

vaddr = 0x00600e00
vaddr + filesz = 0x00601058
vaddr + memsz = 0x00601068

所以字节 [0x00600e00;0x00601058) 从文件加载到内存中,而最后的 0x10 字节也应该存在于内存中,但不从 ELF 文件加载——它们被归零,因为它是 BSS。您也可以使用 objdump 进行检查:

25 .bss    00000010  00601058  00601058  00001058  2**2
           ^ size    ^ base address

但是,在 ELF 的 binfmt 加载器内部,只有 vaddr + filesz 被视为 end_data(参见 fs/binfmt_elf.c):

k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;

if (k > elf_bss)
    elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
    end_code = k;
if (end_data < k)
    end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if (k > elf_brk)
    elf_brk = k;

所以:

  • end_data 指向从文件加载的最后一个字节
  • elf_bss 指向 BSS 的第一个字节(未暴露,内部使用)
  • elf_brk 指向 BSS 的最后一个字节(未暴露,内部使用)

您可以检查/proc/PID/maps -- 它应该显示更可靠的结果。

附:看来,内核文档已被随机陌生人更改:https://lkml.org/lkml/2011/12/6/604

【讨论】:

  • 不错的答案。感谢您花时间解释它!但是,为什么start_data 也是错误的?至于您的最后建议,我希望 /proc/PID/maps 更可靠。看看我昨天的问题:stackoverflow.com/questions/29681712/…
  • @Paschalis,有不止您的数据 落入数据段。使用 objdump 检查是否可以找到 .got.jcr 等服务部分。
  • 根据您的建议,文档似乎不正确。
  • @myaut 我在mapfile 上找到了这些部分,我从linker 制作。虽然不知道他们是什么。我刚刚通过引入一个 initialised 变量验证了您所说的,它位于地址 605180!
  • 这意味着:该区域仅涵盖初始化数据,并且 BSS。 文档有误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多