我正在学习可执行二进制文件的布局。我的最终目标是分析特定的可执行文件,以减少编译后的输出大小。
我一直在使用https://www.embeddedrelated.com/showarticle/900.php和https://www.geeksforgeeks.org/memory-layout-of-c-program/作为初始学习的参考。
根据我所了解的,链接器脚本指定了放置编译二进制文件部分的地址。例如。
> ld --verbose | grep text
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
我认为这意味着编译后的二进制文件的text
段开始于内存地址0x400000
-真吗?
0x400000
**,表示的值是什么?**我可能没有正确地理解一些东西,但是肯定0x400000
并不代表物理内存位置,对吗?例如,如果我要并行运行已编译的a.out
可执行文件的两个实例,它们不能同时占用0x400000
的空间,对吗?
发布于 2019-03-21 20:02:30
从内存芯片的角度来看,0x4000000不是物理地址。从CPU的角度来看,这是一个虚拟地址。
程序的加载程序会将几页物理内存映射到VA 0x400000,并将text-segment
的内容复制到其中。是的,您的程序的另一个实例可以占用text-segment
相同的物理和虚拟内存块,因为文本(代码)是可读和可执行的,但是不能写。其他段(数据、bss、堆栈、堆)可能具有相同的VA,但每个片段都将映射到它们的私有保护的物理内存块。
发布于 2020-04-01 15:24:32
什么是0x400000
我认为这意味着编译的二进制文件的文本段从内存地址0x400000-true开始吗?
不,这在https://sourceware.org/binutils/docs/ld/Builtin-Functions.html的官方文档中有很好的解释。
SEGMENT_START(段,默认) 返回命名段的基地址。如果已经为此段提供了显式值(带有命令行‘-T’选项),则将返回该值,否则该值将是默认值。目前,‘-T’命令行选项只能用于设置“text”、“data”和“bss”部分的基地址,但您可以使用任何段名的SEGMENT_START。
因此,SEGMENT_START
不是在设置地址,而是返回地址,在您的情况下,如果文档中提到的某些CLI机制(例如,man ld
中提到的-Ttext=0x200
)没有决定性地设置该值,那么这个值就是默认的。
物理与虚拟
正如您已经说过的,使用物理地址进行操作在userland中是非常少见的,并且至少总是需要sudo
,就像断裂过程分离一样。下面是用户进行物理地址处理的示例,例如:如何从Linux中的用户空间访问物理地址?
因此,当内核系统时,所有地址都被解释为虚拟地址。
不过,请注意,这只是一个惯例问题。例如,当我给我的Linux内核ELF二进制代码,让QEMU加载到内存中开始模拟。或引导加载程序在实际系统中这样做时,ELF地址将被视为物理地址,因为此时没有可用的页面表。
https://stackoverflow.com/questions/55270381
复制相似问题