为什么链接器修改一个–defsym“绝对地址”

目标:使用可执行文件(不导出符号)的函数的共享库。

意思是: gcc -Wl,--defsym,function=0x432238

手册页指出:

 "--defsym symbol=expression" Create a global symbol in the output file, containing the absolute address given by expression. 

令我沮丧的是, dlopen()将共享库的基地址(这是64位代码) 0x7ffff676f000添加到导出的“绝对符号地址”中:

  executable shared library ---------- linker -------------- symbol: 0x432238 =====> 0x7ffff6ba1238 

objdump在库中显示正确的符号地址( 0x432238 ),但是一旦用dlopen()加载,符号的地址为0x7ffff6ba1238

如果,一旦加载,我手动修补库符号到正确的地址,然后一切正常(否则,库SEGFAULT)。

  • 为什么“绝对地址”被修改?
  • 如何避免它?

更新:

我反驳下面的答复的技术相关性,甚至更多的是“更新”:

让–defsym在PIC库/可执行文件中定义重定位的符号是没有意义的(除了污染没有任何可用function的二进制文件之外,它不起任何作用)。

因此,PIC共享库或PIC可执行文件中唯一相关的–defsym的用法是定义一个( 非重定位的 )“绝对地址”。

顺便说一下,如果你懒得阅读手册页,这就是–defsym的官方目的:

“在输出文件中创build一个全局符号,其中包含由expression式给出的absolute address 。”

至多,这是一个Linux链接器deffect这将是微不足道的修复。 对于那些不能等待拒绝人员来实现(并修复)他们的错误的人来说,解决的办法是在二进制映像被不良链接器加载之后修补重定位表。

然后,–defsym在PIC库/可执行文件中变得有用,在我看来这是一个值得欢迎的进展。

Solutions Collecting From Web of "为什么链接器修改一个–defsym“绝对地址”"

你似乎从根本上误解了--defsym功能。

 --defsym=symbol=expression Create a global symbol in the *output* file, ... 

也就是说,您正在创建图书馆中的新符号。 因此,该符号(自然地)被重新定位到图书馆。

我猜你想要这样的东西,而不是:

 // code in library int fn() { // exe_fn not exported from the executable, but we know where it is. int (*exe_fn)(void) = (int (*)(void)) 0x432238; return (*exe_fn)(); } 

如果您不想将0x432238硬编码到库中,而是在构建时在命令行上传递值,则只需使用-DEXE_FN=0x432238即可实现该功能。

更新:

目标:使用可执行文件中的函数的共享库

这个目标不能通过你选择的方法来实现。 你将不得不使用其他手段。

为什么“绝对地址”被修改?

事实并非如此。 当您要求链接器在绝对地址0x432238处定义function时,它确实如此。 你可以在objdumpnmreadelf -s输出中看到它。

但是因为符号是共享库中定义的所以对该符号的所有引用都被重新定位,即通过共享库加载地址(由动态加载器完成)进行调整。 对于动态加载程序来说没有任何意义

如何避免它?

你不能。 使用其他手段来实现你的目标。