elf可执行文件包含一个section表。当程序加载到内存中时,此部分将映射到段。 我认为是编译器决定内存中的段地址? 您是否认为在加载程序时操作系统可以更改段地址。
我说的是单个精灵可执行文件。这不是一个图书馆。 事实上,我有一个二进制文件。我知道内存中的函数地址,我想从外部程序挂钩这个函数。我只是想确保这个地址永远不会改变。我不会在目标程序中重新编译或更改任何内容。
答案 0 :(得分:3)
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