在gcc目标机器上,当想要编译共享库时,需要指定-fpic或-fPIC来使事情正常工作.这是因为默认使用绝对寻址,它适用于完全控制自己的地址空间的可执行文件,但不适用于可以在可执行文件的地址空间中的任何位置加载的共享库.
然而,现代内核现在正在实现地址空间随机化,并且许多现代架构支持PC相对寻址.这似乎使绝对寻址不可用(地址空间随机化)或不需要(PC相对寻址).
我还注意到clang没有-fPIC选项,这使我不再需要它.
那么-fpic现在是多余的,还是需要生成单独的.o文件,一个用于静态库,一个用于共享库?
您仍然需要使用-fPIC进行编译.pc相对寻址无法解决该问题.问题是如何解析外部符号.在动态链接的程序中,分辨率遵循不同的规则,尤其是在地址空间随机化时,它在链接时间内无法解析.
并且clang确实像gcc一样拥有-fPIC标志.
$ cat > foo.c
void foo(void);
void bar(void) { foo(); }
$ gcc -S foo.c && grep call.*foo foo.s
call foo
$ gcc -fPIC -S foo.c && grep call.*foo foo.s
call foo@PLT
$ clang -S foo.c && grep call.*foo foo.s
callq foo
$ clang -fPIC -S foo.c && grep call.*foo foo.s
callq foo@PLT
$
Run Code Online (Sandbox Code Playgroud)
您永远不需要生成单独的.o
文件。始终指定编译器选项来生成可移植代码(通常-fPIC
)。
在某些系统上,编译器可能会配置为强制启用此选项,或默认设置它。但无论如何指定它也没有什么坏处。
注意:人们希望在支持 PC 相对寻址并且性能良好的情况下,-fPIC
使用该模式而不是专用额外的寄存器。