【发布时间】:2016-06-16 16:17:14
【问题描述】:
elf 可执行文件包含一个节表。当程序加载到内存中时,这些部分被映射到段。 我认为是编译器决定了内存中的段地址? 你认为操作系统可以在程序加载时改变段地址吗?
我说的是单个 elf 可执行文件。这不是图书馆。 事实上,我有一个二进制文件。我知道内存中的一个函数地址,我想从外部程序中挂钩这个函数。我只是想确保这个地址永远不会改变。我不会重新编译或更改目标程序中的任何内容。
【问题讨论】:
标签: elf
elf 可执行文件包含一个节表。当程序加载到内存中时,这些部分被映射到段。 我认为是编译器决定了内存中的段地址? 你认为操作系统可以在程序加载时改变段地址吗?
我说的是单个 elf 可执行文件。这不是图书馆。 事实上,我有一个二进制文件。我知道内存中的一个函数地址,我想从外部程序中挂钩这个函数。我只是想确保这个地址永远不会改变。我不会重新编译或更改目标程序中的任何内容。
【问题讨论】:
标签: elf
elf 可执行文件包含一个节表。
错误:从完全链接的ET_EXEC 或ET_DYN 二进制文件中剥离节表是完全有效的。
当程序加载到内存中时,这些部分被映射到段。
错误:节到段的映射发生在静态链接时,而不是在运行时。
我认为是编译器决定了内存中的段地址?
错误:它是为ET_EXEC 决定这个的静态链接器。对于ET_DYN,静态链接器和运行时加载器协同工作。
你认为操作系统可以在程序加载时改变段地址吗?
对于ET_EXEC,二进制文件总是加载到静态链接器链接该二进制文件的地址。将其加载到其他任何地方都会导致程序崩溃。
对于ET_DYN,也称为PIE 二进制文件,在随机地址加载是可能的和预期的。
我有一个二进制文件。我知道内存中的一个函数地址,我想从外部程序中挂钩这个函数。我只是想确保这个地址永远不会改变。
如果二进制文件的类型为ET_EXEC,则所有段总是加载到链接地址,所以是的。
更新:
在PIE 二进制文件中,一切 将通过相同的重定位一起移动(main、foo、_start 等)(重定位通常会因运行而异运行;但 GDB 禁用地址空间随机化,因此必须执行 (gdb) set disable-randomization off)。
要在 GDB 中查找重定位,您可以:
(gdb) p &main
(gdb) start
(gdb) p &main
进程开始前&main 的第一个值应与nm test | grep main 的输出相同。第二个值(进程启动后)应该是重定位值(main 在内存中的位置)。两者的区别在于(页面对齐)重定位。
要在运行时(从程序本身)找到这个重定位,需要使用dl_iterate_phdr() 和dlpi_addr。 Documentation.
【讨论】:
-pie 标志链接可执行文件,则该可执行文件将具有ET_DYN 类型,并且其行为类似于共享库。另请参阅stackoverflow.com/questions/1449987/…
PIE 二进制文件中,main 和 foo 都将被重新定位到相同的页面对齐但其他随机地址,是的。
PIE 二进制文件,-fPIC 是不够的。 readelf -h test 将为您的二进制文件显示 ET_EXEC,而不是 ET_DYN。试试gcc -fPIE -pie test.cc -o test。此外,GDB 默认禁用地址随机化。从 GDB 内部运行二进制文件时,您需要 set disable-randomization off 启用随机化。