我有一个 gdb 实用程序,它检查虚拟地址的 PFN(通过
/proc/<pid>/pagemap
)并检查所述 PFN 的标志(通过 /proc/kpagecount
和 /proc/kpageflags
)。
我编写并编译了一个小型 64 位 ELF,带有 2 个 PT_LOAD 程序头:
> readelf -l ./bin/a.out
Elf file type is EXEC (Executable file)
Entry point 0x401000
There are 2 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0000b0 0x0000b0 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x00005c 0x00005c R E 0x1000
Section to Segment mapping:
Segment Sections...
00
01 .text
查看 gdb 中的映射时:
(gdb) info proc mappings
process 8495
Mapped address spaces:
Start Addr End Addr Size Offset Perms objfile
0x400000 0x401000 0x1000 0x0 r--p <path-to-bin>
0x401000 0x402000 0x1000 0x1000 r-xp <path-to-bin>
0x7ffff7ff9000 0x7ffff7ffd000 0x4000 0x0 r--p [vvar]
0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x0 r-xp [vdso]
0x7ffffffdd000 0x7ffffffff000 0x22000 0x0 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall]
查看
0x400000
的PFN时,/proc/<pid>/pagemap
和/proc/kpageflags
上报的flags如下:
(gdb) pfn 0x400000
BigEndian? 0
VADDR: 0x400000, PageSize: 4096, EntrySize: 8
Reading /proc/8495/pagemap at 0x2000
[0]0xba [1]0x5 [2]0x22 [3]0x0 [4]0x0 [5]0x0 [6]0x80 [7]0xa1
file-mapped: true, exclusively-mapped: true, soft-dirty: true, swapped: false, uffd-wp write-protected: false
Result: 0xa1800000002205ba
PFN: 0x2205ba
(gef) kpage 0x2205ba
PFN: 0x2205ba
/proc/kpagecount: 1
Flags:
REFERENCED
UPTODATE
LRU
MMAP
据报道该页面是文件映射的,这是我所期望的,因为它是我的可执行文件的 ELF 文件头。但是,在带有
.text
部分的段上执行此过程会产生不同的结果:
(gdb) pfn 0x401000
BigEndian? 0
VADDR: 0x401000, PageSize: 4096, EntrySize: 8
Reading /proc/8495/pagemap at 0x2008
[0]0xbe [1]0xb0 [2]0x27 [3]0x0 [4]0x0 [5]0x0 [6]0x80 [7]0x81
file-mapped: false, exclusively-mapped: true, soft-dirty: true, swapped: false, uffd-wp write-protected: false
Result: 0x818000000027b0be
PFN: 0x27b0be
(gdb) kpage 0x27b0be
PFN: 0x27b0be
/proc/kpagecount: 1
Flags:
REFERENCED
UPTODATE
DIRTY
LRU
MMAP
ANON
SWAPBACKED
我本以为映射的
.text
部分是我的ELF文件的一部分并且是要加载的段也被标记为文件映射,就像ELF文件头一样。为什么不是?