这是在 gdb 中查看进程的虚拟内存的结果;我对此有一些疑问:
为什么虚拟内存的某些部分是重复的?比如我们的程序(stack6)和libc库重复4次;如果他们将它们分成不同的部分,那为什么呢?为什么不把它们放在一起呢?
最上面的路径(/opt/pro...)是我们虚拟内存的指令部分(文本部分)并且只包含指令吗?
为什么4个libc的大小不同?偏移量是怎么回事,如果我们已经有了大小和起始地址,那么偏移量是什么?
数据、bss、内核和堆部分在哪里?为什么上图中的某些部分没有关于它们的信息?gdb 中是否有更好的选项可以实际显示所有部分?
有没有比 gdb 更好的程序可以更好地显示我们进程的虚拟内存部分?我只想对实际的虚拟内存有一个很好的了解,哪个调试程序提供了最好的结果。
我提到的部分:
gdb
'输出中缺少一项重要信息:页面的权限。(它们显示在 Solaris 和 FreeBSD 上,但不在 Linux 上。)您可以通过查看/proc/<pid>/maps
; 您的 Protostar 示例的地图显示(Protostar 示例在一个易于破解的 VM 中运行,大概是为了使练习易于处理:没有 NX 保护,也没有 ASLR。)
您将在上面看到,看似重复的映射
gdb
实际上对应于具有不同权限的不同映射。文本段被映射为只读和可执行;数据段被映射为只读;BSS 和堆被映射为读写。理想情况下,数据段、BSS 和堆是不可执行的,但此示例缺少 NX 支持,因此它们是可执行的。每个共享库都有自己的文本段、数据段和 BSS 映射。第四个映射是不可读、不可写、不可执行的段,通常用于防止缓冲区溢出(尽管考虑到此处使用的内核和 C 库的年龄,这可能有所不同)。偏移量,当给出时,表示文件中数据的偏移量,它不一定与它在地址空间中的位置有很大关系。加载时,受对齐约束;例如,
libc-2.11.2.so
的程序头文件指定了两个“LOAD”头文件:(
readelf -l
用于查看此内容。)如果映射到段的部分具有不同的保护标志,则这些可能会导致具有不同虚拟地址的相同偏移量的多个映射。在
stack6
的情况下:(这也解释了
proc info mappings
for显示的小尺寸stack6
:每个标头请求小于 4KiB,对齐为 4KiB,因此它在不同地址获得两个具有相同偏移量的 4KiB 映射。)空白映射对应匿名映射;详情见
man 5 proc
。您需要闯入mmap
以gdb
确定它们对应的内容。您看不到内核映射(除了
vsyscall
某些架构上的遗留问题),因为从进程的角度来看它们并不重要(它们不可访问)。我不知道更好的
gdb
选择,我总是使用/proc/$$/maps
.有关内核读取的 ELF 格式的详细信息,以及它如何映射到内存分配,请参阅程序如何运行:ELF 二进制文件;它有指向更多参考资料的指针。