- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一个有趣的编译问题。首先,请看要编译的代码。
$ ls
Makefile main.c sub.c sub.h
$ gcc -v
...
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
## Makefile
%.o: CFLAGS+=-fPIE #[2]
main.so: main.o sub.o
$(CC) -shared -fPIC -o $@ $^
//main.c
#include "sub.h"
int main_func(void){
sub_func();
subsub_func();
return 0;
}
//sub.h
#pragma once
void subsub_func(void);
void sub_func(void);
//sub.c
#include "sub.h"
#include <stdio.h>
void subsub_func(void){
printf("%s\n", __func__);
}
void sub_func(void){
subsub_func();//[1]
printf("%s\n", __func__);
}
然后我编译它并得到如下错误
$ LANG=en make
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
/usr/bin/ld: sub.o: relocation R_X86_64_PC32 against symbol `subsub_func' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [main.so] Error 1
在此之后,我修改了代码(删除了一行 [1]/使用 -fPIC 而不是 -PIE[2]),然后成功编译了这些代码。
$ make #[1]
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
$ make #[2]
cc -fPIC -c -o main.o main.c
cc -fPIC -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
为什么会出现这种现象?
我听说在使用-fPIC 编译时通过PLT 调用对象内的函数,但在使用-fPIE 编译时通过直接跳转到该函数来完成。我猜是带有-fPIE的函数调用机制避免了重定位。但我想知道对此的准确解释。
你愿意帮我吗?
谢谢大家
最佳答案
-fPIC
之间的唯一 代码生成差异和 -fPIE
因为显示的代码在来自 sub_func
的调用中至 subsub_func
.与 -fPIC
, 该调用通过 PLT;与 -fPIE
, 是直接调用。在程序集转储 (cc -S
) 中,它看起来像这样:
--- sub.s.pic 2017-12-07 08:10:00.308149431 -0500
+++ sub.s.pie 2017-12-07 08:10:08.408068650 -0500
@@ -34,7 +34,7 @@ sub_func:
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
- call subsub_func@PLT
+ call subsub_func
leaq __func__.2258(%rip), %rsi
leaq .LC0(%rip), %rdi
movl $0, %eax
在未链接的目标文件中,这是重定位类型的改变:
--- sub.o.dump.pic 2017-12-07 08:13:54.197775840 -0500
+++ sub.o.dump.pie 2017-12-07 08:13:54.197775840 -0500
@@ -22,7 +22,7 @@
1f: 55 push %rbp
20: 48 89 e5 mov %rsp,%rbp
23: e8 00 00 00 00 callq 28 <sub_func+0x9>
- 24: R_X86_64_PLT32 subsub_func-0x4
+ 24: R_X86_64_PC32 subsub_func-0x4
28: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 2f <sub_func+0x10>
2b: R_X86_64_PC32 .rodata+0x14
2f: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 36 <sub_func+0x17>
并且,在此架构上,当您使用 cc -shared
链接共享库时, 链接器不允许输入目标文件包含 R_X86_64_PC32
以全局符号为目标的重定位,因此您在使用 -fPIE
时观察到的错误而不是 -fPIC
.
现在,您可能想知道为什么不允许在共享库中直接调用。事实上,它们是允许的,但前提是被调用者不是全局的。例如,如果您声明 subsub_func
与 static
, 然后调用目标将由汇编器解析并且目标文件中根本没有重定位,如果你用 __attribute__((visibility("hidden")))
声明它那么你会得到一个 R_X86_64_PC32
重定位,但链接器会允许它,因为被调用者不再从库中导出。但在这两种情况下subsub_func
将无法再从库外调用。
现在您可能想知道全局符号是什么意思,这意味着您必须通过共享库中的 PLT 调用它们。这与您可能会感到惊讶的 ELF 符号解析规则的一个方面有关:共享库中的任何全局符号都可以被可执行文件或链接顺序中较早的库覆盖。具体来说,如果我们离开你的 sub.h
和 sub.c
孤独却使main.c
像这样阅读:
//main.c
#include "sub.h"
#include <stdio.h>
void subsub_func(void) {
printf("%s (main)\n", __func__);
}
int main(void){
sub_func();
subsub_func();
return 0;
}
所以它现在有一个官方的可执行入口点,还有一个 subsub_func
的第二个定义。 ,我们编译sub.c
进入共享库和main.c
进入一个调用它的可执行文件,然后运行整个过程,就像这样
$ cc -fPIC -c sub.c -o sub.o
$ cc -c main.c -o main.o
$ cc -shared -Wl,-soname,libsub.so.1 sub.o -o libsub.so.1
$ ln -s libsub.so.1 libsub.so
$ cc main.o -o main -L. -lsub
$ LD_LIBRARY_PATH=. ./main
输出将是
subsub_func (main)
sub_func
subsub_func (main)
也就是说,两个来自main
的电话至 subsub_func
,以及来自 sub_func
的电话, 在图书馆内,到 subsub_func
, 被解析为可执行文件中的定义。为了实现这一点,来自 sub_func
的电话必须通过PLT。
您可以使用额外的链接器开关来更改此行为, -Bsymbolic
.
$ cc -shared -Wl,-soname,libsub.so.1 -Wl,-Bsymbolic sub.o -o libsub.so.1
$ LD_LIBRARY_PATH=. ./main
subsub_func
sub_func
subsub_func (main)
现在来自 sub_func
的电话解析为库中的定义。在这种情况下,使用 -Bsymbolic
允许 sub.c
用 -fPIE
编译而不是 -fPIC
,但我不建议你这样做。使用 -fPIE
还有其他效果而不是 -fPIC
,例如更改访问 thread-local storage 的方式需要完成,这些不能用 -Bsymbolic
解决.
关于c - 为什么我不能用 -fPIE 编译但可以用 -fPIC 编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47695390/
使用 Qt 时,CMake 会自动将 -fPIC 标志添加到编译选项。我想使用 -fpic,所以我检查了所有 Cmake 变量并将 -fPIC 替换为 -fpic。 cmake_minimum_req
环境:Ubuntu 16.04 在我的实验中,我运行了以下命令: gcc -c 1.c gcc -c -fPIC 2.c gcc -shared 1.o 2.o -o libmyxxx.so 我需要公
我已经阅读了 gcc 手册页,但我仍然无法理解 -fpic 和 -fPIC 之间的区别。有人可以用非常简单明了的方式解释一下吗? 相关问题: What does -fPIC mean when bui
海湾合作委员会错误: relocation R_X86_64_32S against `ebx' can not be used when making a shared object; recomp
我已经下载了一些我想从源代码编译的 C++。从命令行运行 cmake ../src 和 make 后,在构建目录中,出现以下错误: /usr/bin/ld: /usr/local/lib/libBul
我在 Google 上找不到直接的答案,而且由于我已经很长时间没有在 Linux 上做过任何事情,所以希望能在这里找到帮助。构建共享对象时,我在 Ubuntu 上遇到链接错误。链接器告诉我应该使用 -
我目前正在 cmake 环境中构建共享库 (lib1.so)。lib1.so 依赖于外部静态库 libLASlib.a(如有必要,我可以重新编译)。到目前为止,一切都在 Windows 上运行良好,但
我的应用程序需要在运行时加载一个或多个算法,为此我使用 .so。问题是这些库除了我的应用程序之外没有被任何其他进程使用,所以不需要与其他人共享 .text 部分。 .so 的某些部分来 self 预先
我正在尝试使用 luarocks 安装 numlua: luarocks make numlua-0.3-1.rockspec 但出现以下错误: /usr/bin/ld: numlua.o: relo
即使我可能不打算将生成的可重定位目标文件链接到共享库中,始终使用 -fPIC 进行编译是否有任何危害? 最佳答案 好吧,总是使用 -fPIC 进行编译会产生更臃肿和更慢的代码。 差异在 x64 目标上
我想检查共享库是否使用 -fPIC 标志编译。有哪些可能的方法(在 Linux 上,x86_64)检查这个? -fPIC 是否隐含(从而使检查变得多余?) 最佳答案 是的,GCC 不允许您在没有 -f
我知道 -fPIC 是共享库所必需的,并且知道为什么。 但是,我对这个问题不是很清楚: -fPIC 不应在构建可执行文件或静态库期间使用吗? 最佳答案 Should -fPIC never be us
我有 MPICH 3.0.4安装在我的机器上(Ubuntu 12.04)。我正在尝试安装一个名为 Qthreads 的库我之前使用过并成功安装过它(除了安装了 MPICH2 包)。配置工作正常: ./
我正在构建一个共享库。我只需要一个函数就可以公开。 共享库由几个目标文件和几个静态库构建而成。链接器提示一切都应该用 -fPIC 构建.所有目标文件和大多数静态库都是在没有这个选项的情况下构建的。 这
-fpic 标志有什么作用? 我想安装一个库( OpenSFM ),据说它需要使用 -fPIC 编译标志构建和安装 Ceres Solver。 问题是我已经安装了没有 -fPIC 标志的 Ceres
我想将目标文件和静态库组合成一个共享库,但是静态库不能暴露,它只在进入共享库的目标文件中引用。我认为在这种情况下,我不需要使用 -fPIC 编译静态库,但我不知道如何告诉链接器我不会使用静态库中的符号
今天,当尝试使用 mongodb c++ 客户端构建我的 so lib 项目时,出现错误: /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.8/../../.
我正在为一个类编写一些 C 代码,但我遇到了需要在 make 文件中完成的编译器问题,当它运行时它总是给出错误 usr/bin/ld: main.o: 重定位 R_X86_64_32S 对符号“被积函
在centos中./configure asterisk后我输入make命令但是出现了以下错误 /usr/bin/ld:/usr/local/lib/liblua.a(lapi.o): 创建共享对象时
我正在尝试在 linux 中创建一个共享库,但在尝试编译时出现以下错误: relocation R_X86_64_32S against `.rodata' can not be used when
我是一名优秀的程序员,十分优秀!