如何使用类似objdump的工具判断一个目标文件是否使用了-fPIC参数进行编译?

75

我如何使用像 objdump 这样的工具来判断一个目标文件是否是用 -fPIC 编译的?


1
请测试Linux二进制文件是否编译为位置无关代码。 - Ciro Santilli OurBigBook.com
7个回答

81

答案取决于平台。在大多数平台上,如果从

readelf --relocs foo.o | egrep '(GOT|PLT|JU?MP_SLOT)'
如果空的话,则表示 foo.o 没有使用 -fPIC 编译或者 foo.o 中不存在 -fPIC 所需的代码。

2
我测试了我的PIC/非PIC对象,但这个测试没有成功。事实上,--reloc什么也没有列出来。 - teambob
1
现在你已经编辑过它,它可以正常工作并且是一个不错的简单测试。我为你投了赞成票。 - teambob
2
这不是一个非常有用的测试。如果它不为空,那么这并不能证明什么。考虑一个由2个目标文件组成的共享库。其中一个目标文件使用-fPIC编译,另一个则没有。输出不会为空,但该库不是位置无关的。 - Vanuan
3
@Vanuan 这个测试对于共享库确实无效,没错。但是问题是关于目标文件,而不是共享库。 - Employed Russian
2
你介意解释一下为什么这个测试有意义,或者背后的推理是什么吗?一个人在使用grep查找什么?为什么那些东西在没有-fPIC的情况下不会被找到? - ffledgling
显示剩余5条评论

18

我曾经需要在 PowerPC 目标环境下执行以下操作,找出哪个共享对象(.so)没有使用 -fPIC 标志进行构建。 我运行 readelf -d libMyLib1.so 命令,并查找 TEXTREL。 如果您看到 TEXTREL,则意味着一个或多个源文件未使用 -fPIC 构建成您的 .so。 如果需要,您可以使用 elfdump 命令代替 readelf

例如:

[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编译的目标文件组成。
如先前提到的,如果存在TEXTRELs,则未使用-fPIC。
有一个很棒的工具叫做scanelf,可以显示导致.text重定位的符号。
更多信息可在HOWTO Locate and Fix .text Relocations TEXTRELs中找到。

2

-fPIC的意思是代码能够在与编译地址不同的地址上执行。

为了实现这一点,反汇编器看起来会像这样....

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}

2
使用readelf -a *.so命令并grep Flags
  标志:                             0x50001007, noreorder, pic, cpic, o32, mips32

这通常可以起作用。


2
这看起来很简单,但是我面前的库是可重定位的,在它的.rel.plt表中有很多R_386_JUMP_SLOT条目,但标志位为0x0。也许它只适用于mips32。 - James
很遗憾,这似乎在aarch64上无法工作。 - leosh

0

来自Linux编程接口

On Linux/x86-32, it is possible to create a shared library using modules compiled without the –fPIC option. However, doing so loses some of the benefits of shared libraries, since pages of program text containing position-dependent memory references are not shared across processes. On some architectures, it is impossible to build shared libraries without the –fPIC option.

In order to determine whether an existing object file has been compiled with the –fPIC option, we can check for the presence of the name _GLOBAL_OFFSET_TABLE_ in the object file’s symbol table, using either of the following commands:

$ nm mod1.o | grep _GLOBAL_OFFSET_TABLE_
$ readelf -s mod1.o | grep _GLOBAL_OFFSET_TABLE_

Conversely, if either of the following equivalent commands yields any output, then the specified shared library includes at least one object module that was not compiled with –fPIC:

$ objdump --all-headers libfoo.so | grep TEXTREL
$ readelf -d libfoo.so | grep TEXTREL

然而,以上引用和这个问题的任何答案都不适用于x86_64。

我在我的x86_64 Ubuntu机器上观察到的是,无论是否指定-fPIC,它都会生成fPIC .o。也就是说

gcc -g -Wall -c -o my_so.o my_so.c // has _GLOBAL_OFFSET_TABLE_
gcc -g -Wall -fPIC -c -o my_so_fpic.o my_so.c // has _GLOBAL_OFFSET_TABLE_

readelf -s my_so.o > 1.txt && readelf -s my_so_fpic > 2.txt && diff 1.txt 2.txt

没有区别,my_so.omy_so_fpic.o都可以用来创建共享库。

为了生成非 fpic 对象文件,我在如何测试 Linux 二进制文件是否编译为位置无关代码?的第一条评论中找到了一个名为-fno-pic的 gcc 标志。

这很有效,

gcc -g —Wall -fno-pic -c -o my_so_fnopic.o my_so.c // no _GLOBAL_OFFSET_TABLE_ 

并且

gcc -g -Wall -shared -o libdemo.so my_so_fnopic.o 

出现错误:

/usr/bin/ld: my_so_fnopic.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
collect2: error: ld returned 1 exit status

无法使用非 PIC .o 创建共享库。

0

区分您的程序是否使用了 -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的先决条件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接