/proc/procid/maps 中具有相同偏移量和权限的段

问题描述 投票:0回答:1

我目前正在研究 ELF 二进制文件以及它们如何加载到 Linux 内核的内存中。我真的很困惑 PT_LOAD 段是如何加载到内存中的。我有一个名为 test.elf:

的 ELF 可执行文件
root@ubuntu-s-4vcpu-8gb-amd-sgp1-01:~/C# readelf -l test.elf

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x10c0
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000718 0x0000000000000718  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x0000000000000259 0x0000000000000259  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x0000000000000124 0x0000000000000124  R      0x1000
  LOAD           0x0000000000002da0 0x0000000000003da0 0x0000000000003da0
                 0x0000000000000274 0x0000000000000278  RW     0x1000
  DYNAMIC        0x0000000000002db0 0x0000000000003db0 0x0000000000003db0
                 0x00000000000001f0 0x00000000000001f0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000030 0x0000000000000030  R      0x8

从上面的输出中可以看到,该文件有四个 PT_LOAD 段。我希望它能以四个段的形式加载到内存中。但是,当我检查 /proc/pid/maps 时,它显示正在运行的进程有从可执行文件加载的五个段。

root@ubuntu-s-4vcpu-8gb-amd-sgp1-01:~/C# cat /proc/209183/maps
55acd5d31000-55acd5d32000 r--p 00000000 fc:01 517731                     /root/C/test.elf
55acd5d32000-55acd5d33000 r-xp 00001000 fc:01 517731                     /root/C/test.elf
55acd5d33000-55acd5d34000 r--p 00002000 fc:01 517731                     /root/C/test.elf
55acd5d34000-55acd5d35000 r--p 00002000 fc:01 517731                     /root/C/test.elf
55acd5d35000-55acd5d36000 rw-p 00003000 fc:01 517731                     /root/C/test.elf
55acd6e88000-55acd6ea9000 rw-p 00000000 00:00 0                          [heap]
7f85da4fe000-7f85da501000 rw-p 00000000 00:00 0
7f85da501000-7f85da529000 r--p 00000000 fc:01 31232                      /usr/lib/x86_64-linux-gnu/libc.so.6
7f85da529000-7f85da6be000 r-xp 00028000 fc:01 31232                      /usr/lib/x86_64-linux-gnu/libc.so.6
7f85da6be000-7f85da716000 r--p 001bd000 fc:01 31232                      /usr/lib/x86_64-linux-gnu/libc.so.6

我还注意到第三和第四段具有相同的偏移量和权限。经过大量搜索,我仍然不明白为什么。我还检查了段中驻留的部分,这些部分没有什么特别的。

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.got .plt.sec .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag
   09     .note.gnu.property
   10     .eh_frame_hdr
   11
   12     .init_array .fini_array .dynamic .got

谁能解释一下,我真的很想知道这种差异背后的原因!

我预计它只有四个部分

linux linux-kernel executable elf
1个回答
0
投票

这是我系统上

readelf -Wl /usr/bin/cat
的输出:

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x3990
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x0002d8 0x0002d8 R   0x8
  INTERP         0x000318 0x0000000000000318 0x0000000000000318 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x001600 0x001600 R   0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x004111 0x004111 R E 0x1000
  LOAD           0x007000 0x0000000000007000 0x0000000000007000 0x0011a0 0x0011a0 R   0x1000
  LOAD           0x008a90 0x0000000000009a90 0x0000000000009a90 0x0005d8 0x000730 RW  0x1000
  DYNAMIC        0x008c08 0x0000000000009c08 0x0000000000009c08 0x0001f0 0x0001f0 RW  0x8
  NOTE           0x000338 0x0000000000000338 0x0000000000000338 0x000050 0x000050 R   0x8
  NOTE           0x000388 0x0000000000000388 0x0000000000000388 0x0000d0 0x0000d0 R   0x4
  GNU_PROPERTY   0x000338 0x0000000000000338 0x0000000000000338 0x000050 0x000050 R   0x8
  GNU_EH_FRAME   0x007dc8 0x0000000000007dc8 0x0000000000007dc8 0x0000b4 0x0000b4 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x008a90 0x0000000000009a90 0x0000000000009a90 0x000570 0x000570 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.sec .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag .note.package
   09     .note.gnu.property
   10     .eh_frame_hdr
   11
   12     .init_array .fini_array .data.rel.ro .dynamic .got

这表示内核应该执行 4 个

mmap
来建立 4 个
LOAD
段。让我们看看是否如此。

gdb -q /usr/bin/cat
(gdb) starti < /dev/null
Starting program: /usr/bin/cat < /dev/null
Downloading separate debug info for system-supplied DSO at 0x7ffff7fc7000

Program stopped.
0x00007ffff7fe4bc0 in _start () from /lib64/ld-linux-x86-64.so.2

(gdb) info prog
Last stopped for thread 1 (process 1304).
        Using the running image of child process 1304.
Program stopped at 0x7ffff7fe4bc0.
Type "info stack" or "info registers" for more information.

(gdb) shell cat /proc/1304/maps
555555554000-555555556000 r--p 00000000 08:20 92665                      /usr/bin/cat
555555556000-55555555b000 r-xp 00002000 08:20 92665                      /usr/bin/cat
55555555b000-55555555d000 r--p 00007000 08:20 92665                      /usr/bin/cat
55555555d000-55555555f000 rw-p 00008000 08:20 92665                      /usr/bin/cat
7ffff7fc3000-7ffff7fc7000 r--p 00000000 00:00 0                          [vvar]
7ffff7fc7000-7ffff7fc9000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fc9000-7ffff7fca000 r--p 00000000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7fca000-7ffff7ff1000 r-xp 00001000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7ff1000-7ffff7ffb000 r--p 00028000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7ffb000-7ffff7fff000 rw-p 00031000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]

事实上,只有 4 个映射。现在让我们运行直到

main
:

(gdb) b main
Downloading source file /usr/src/debug/coreutils-9.3-5.fc39.x86_64/separate/../src/cat.c
Breakpoint 1 at 0x5555555566c0: file ../src/cat.c, line 540.
(gdb) c
Continuing.

Breakpoint 1, main (argc=1, argv=0x7fffffffde48) at ../src/cat.c:540
540     {
(gdb) shell cat /proc/1304/maps
555555554000-555555556000 r--p 00000000 08:20 92665                      /usr/bin/cat
555555556000-55555555b000 r-xp 00002000 08:20 92665                      /usr/bin/cat
55555555b000-55555555d000 r--p 00007000 08:20 92665                      /usr/bin/cat
55555555d000-55555555e000 r--p 00008000 08:20 92665                      /usr/bin/cat
55555555e000-55555555f000 rw-p 00009000 08:20 92665                      /usr/bin/cat
7ffff7dd4000-7ffff7dd7000 rw-p 00000000 00:00 0
7ffff7dd7000-7ffff7dfd000 r--p 00000000 08:20 117079                     /usr/lib64/libc.so.6
7ffff7dfd000-7ffff7f5d000 r-xp 00026000 08:20 117079                     /usr/lib64/libc.so.6
7ffff7f5d000-7ffff7fab000 r--p 00186000 08:20 117079                     /usr/lib64/libc.so.6
7ffff7fab000-7ffff7faf000 r--p 001d3000 08:20 117079                     /usr/lib64/libc.so.6
7ffff7faf000-7ffff7fb1000 rw-p 001d7000 08:20 117079                     /usr/lib64/libc.so.6
7ffff7fb1000-7ffff7fbb000 rw-p 00000000 00:00 0
7ffff7fc3000-7ffff7fc7000 r--p 00000000 00:00 0                          [vvar]
7ffff7fc7000-7ffff7fc9000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fc9000-7ffff7fca000 r--p 00000000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7fca000-7ffff7ff1000 r-xp 00001000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7ff1000-7ffff7ffb000 r--p 00028000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7ffb000-7ffff7ffd000 r--p 00031000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffff7ffd000-7ffff7fff000 rw-p 00033000 08:20 117069                     /usr/lib64/ld-linux-x86-64.so.2
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]

发生什么事了?为什么会出现第5个映射?

这是之前的状态:

55555555d000-55555555f000 rw-p 00008000 08:20 92665                      /usr/bin/cat

这是之后的状态:

55555555d000-55555555e000 r--p 00008000 08:20 92665                      /usr/bin/cat
55555555e000-55555555f000 rw-p 00009000 08:20 92665                      /usr/bin/cat

注意映射的第一页如何变成只读的吗?

但这正是

GNU_RELRO
告诉加载程序要做的事情:加载程序完成更新重定位后,它应该对它们进行写保护。更准确地说,它应该对第四个映射的一部分进行写保护,该部分覆盖从
[0x8a90, 0x8a90+0x570)
开始偏移
/usr/bin/cat
处的字节。

© www.soinside.com 2019 - 2024. All rights reserved.