我如何使用 objdump 之类的东西来判断是不是使用 -fPIC 构建了目标文件?

Posted

技术标签:

【中文标题】我如何使用 objdump 之类的东西来判断是不是使用 -fPIC 构建了目标文件?【英文标题】:How can I tell, with something like objdump, if an object file has been built with -fPIC?我如何使用 objdump 之类的东西来判断是否使用 -fPIC 构建了目标文件? 【发布时间】:2010-11-23 08:20:58 【问题描述】:

我怎样才能通过objdump 之类的内容来判断是否使用-fPIC 构建了目标文件?

【问题讨论】:

相关unix.stackexchange.com/questions/89211/… 【参考方案1】:

答案取决于平台。在大多数平台上,如果输出来自

readelf --relocs foo.o | egrep '(GOT|PLT|JU?MP_SLOT)'

为空,则要么foo.o 没有使用-fPIC 编译,要么foo.o 不包含任何-fPIC 重要的代码。

【讨论】:

我测试了我的 PIC/no-PIC 对象,但这个测试不起作用。事实上 --reloc 什么也没列出。 @teambob 抱歉,objdump 不理解 --relocs 标志,readelf 可以。 这不是一个很有帮助的测试。如果它不为空,这并不能证明任何事情。考虑一个由 2 个目标文件组成的共享库。一个目标文件用-fPIC 编译,另一个不用-fPIC 编译。输出不会为空,但库与位置无关。 @Vanuan 该测试不适用于共享库,是的。但问题是关于目标文件,而不是共享库。 您介意解释一下为什么这个测试有意义,或者它背后的原因是什么?一个 grepping 是为了什么?为什么没有 -fPIC 就找不到这些东西?【参考方案2】:

我只需要在 PowerPC 目标上执行此操作即可找到在没有 -fPIC 的情况下正在构建的共享对象 (.so)。我所做的是运行 readelf -d libMyLib1.so 并寻找 TEXTREL。如果您看到 TEXTREL,则构成您的 .so 的一个或多个源文件不是使用 -fPIC 构建的。如有必要,您可以将 readelf 替换为 elfdump

例如,

[user@host lib]$ readelf -d libMyLib1.so | grep TEXT   # Bad, not -fPIC
 0x00000016 (TEXTREL)
[user@host lib]$ readelf -d libMyLib2.so | grep TEXT   # Good, -fPIC
[user@host lib]$

为了帮助人们寻找解决方案,我在运行可执行文件时遇到的错误是:

root@target:/# ./program: error while loading shared libraries: /usr/lib/libMyLi
b1.so:  R_PPC_REL24 relocation at 0x0fc5987c for symbol 'memcpy' out of range

我不知道此信息是否适用于所有架构。

来源:blogs.oracle.com/rie

【讨论】:

【参考方案3】:

我假设,您真正想知道的是共享库是否由使用 -fPIC 编译的目标文件组成。

如前所述,如果有 TEXTREL,则不使用 -fPIC。

有一个很棒的工具叫做 scanelf,它可以显示导致 .text 重定位的符号。

更多信息请访问HOWTO Locate and Fix .text Relocations TEXTRELs。

【讨论】:

【参考方案4】: readelf -a *.so | grep 标志 标志:0x50001007,noreorder,pic,cpic,o32,mips32

这应该在大部分时间都有效。

【讨论】:

这看起来很简单,但是我面前的库是可重定位的,它的 .rel.plt 表中有很多 R_386_JUMP_SLOT 条目,但标志为 0x0。也许它只适用于 mips32。【参考方案5】:

-fPIC 意味着代码将能够在与编译地址不同的地址中执行。

要做到这一点,disasambler 看起来像这样......

call get_offset_from_compilation_address
get_offset_from_compilation_address: pop ax
sub ax, ax , &get_offset_from_compilation_address

现在在 ax 中,我们有一个偏移量,我们需要添加到任何对内存的访问中。

load bx, [ax + var_address

【讨论】:

【参考方案6】:

另一个区分你的程序是否是用 -fPIC 选项生成的选项:

前提是您的代码在编译时启用了 -g3 -gdwarf-2 选项。

其他 gcc 调试格式也可能包含宏信息:

注意下面的 $'..' 语法是假定 bash

echo $' main()  printf("%d\\n", \n#ifdef __PIC__\n__PIC__\n#else\n0\n#endif\n); ' | gcc -fPIC -g3 
-gdwarf-2 -o test -x c -

readelf --debug-dump=macro ./test | grep __PIC__

这样的方法是有效的,因为 gcc 手册声明如果使用 -fpic,PIC 被定义为 1,并且 如果使用 -fPIC,PIC 为 2。

以上通过检查GOT的答案是更好的方法。因为 -g3 -gdwarf-2 的 prerequest 我猜很少被使用。

【讨论】:

以上是关于我如何使用 objdump 之类的东西来判断是不是使用 -fPIC 构建了目标文件?的主要内容,如果未能解决你的问题,请参考以下文章

如果没有文件、objdump 或 gdb,如何知道二进制文件是不是包含调试符号?

如何判断一个库是不是是用 -g 编译的?

让 objdump 在每个助记符上使用像 l 这样的操作数大小的后缀,即使它不是模棱两可的?

我是不是需要将 Alamofire 请求打包成 AFNetwork 之类的东西?

如何在 Swift 中判断变量的类型

使用 objdump 或 gcc -c 将汇编指令转换为二进制