将对象从C ++存档(.a)包含到共享库中 [英] Including objects to a shared library from a C++ archive (.a)
问题描述
我正在尝试将一些对象文件包含在我正在构建的共享库中。采取以下命令(为简洁起见,省略了[ETC]中的内容):
/ usr / bin / c ++ -fPIC -std = c ++ 14 -pthread -Iinclude / ext / liveMedia -Iinclude / ext / groupsock [ETC] -g -shared -Wl,-oname,libValkka.so -o lib / libValkka.so CMakeFiles / Valkka.dir / src / avthread .cpp.o CMakeFiles / Valkka.dir / src / opengl.cpp.o [ETC] CMakeFiles / Valkka.dir / src / decoders.cpp.o -lX11 -lGLEW -lGLU -lGL -Wl, - 整体档案库/libavcodec.a -Wl, - no-whole-archive
所以基本上我只是创建一个共享库,其中大部分对象来自我自己的源代码(即CMakeFiles / Valkka.dir / src / *。o),但是它们中的一些来自位于lib / libavcodec.a的外部静态库。我收到以下错误:
/ usr / bin / ld:lib / libavcodec.a(h264_cabac.o):relocation R_X86_64_PC32 against symbol制作共享对象时不能使用'ff_h264_cabac_tables'重新编译-fPIC
/ usr / bin / ld:最终链接失败:错误值
collect2:错误:ld返回1退出状态
但那真是太不真实了!我可以提取libavcodec.a与
ar x libavcodec.a
/ pre>
之后,检查
readelf --relocs h264_cabac.o | egrep'(GOT | PLT | JU?MP_SLOT)'
确实给了一些**它: p>
00000000175d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001926 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
...
与
objdump -r h264_cabac.o | grep -irelocation
所以,确实,libavcodec.a中的对象文件已经被编译得到PIC(位置无关代码)。
为什么链接器相信否则!?
相关链接:
如果使用-fPIC构建了一个对象文件,我可以用objdump这样的东西来告诉我吗?
解决方案TL; DR
添加
-Wl,-Bsymbolic
到共享库的gcc链接选项。
为什么?
您正在测试
h264_cabac.o
的PICness:readelf --relocs h264_cabac.o | egrep'(GOT | PLT | JU?MP_SLOT)
并得出结论, code> -fPIC 如果您获得任何
命中。大概你可以从最喜欢的答案
得到这个测试如果使用-fPIC构建了一个对象文件,我如何知道像objdump这样的东西?
你有一些点击,我可以复制多种方式:
从源代码
$ git clone https://github.com/FFmpeg/FFmpeg.git
$ cd FFmpeg
$ ./configure --enable-shared
$ make
然后:
$ cd libavcodec
$ readelf --relocs h264_cabac.o | egrep的 '(GOT | PLT | JU MP_SLOT?)'
00000000175d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001926 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
00000000259f 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000002f0d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000003216 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000003460 00330000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_chroma422_dc_s - 4
000000003afc 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000003fb6 00360000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_i_mb_type_info - 4
000000004031 00370000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_mb_sizes - 4
00000000409a 003800000004 R_X86_64_PLT32 0000000000000000 ff_init_cabac_decoder - 4
000000004248 00390000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_b_mb_ TYPE_INFO - 4
000000004299 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
000000004a31 003b00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra4x4 - 4
000000004bd5 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000004f85 003c0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_p_mb_type_info - 4
0000000050fd 003d0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_b_sub_mb_type_ - 4
000000005233 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
00000000544a 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000005bef 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
000000006db5 003e00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4
000000006de9 003f0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_p_sub_mb_type_ - 4
000000007171 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000008b1b 003e00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4
00000000ad41 004000000009 R_X86_64_GOTPCREL 0000000000000000 ff_h264_chroma_dc_scan - 4
00000000ad84 004000000009 R_X86_64_GOTPCREL 0000000000000000 ff_h264_chroma_dc_scan - 4
00000000b758 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
从Ubuntu 16.04开发包
$ sudo apt-get install libavcodec-dev
$ dpkg -S libavcodec.a
libavcodec-dev:amd64:/ usr / lib / x86_64-linux-gnu /libavcodec.a
$ mkdir〜/ deleteme
$ cd〜/ deleteme
$ ar x /usr/lib/x86_64-linux-gnu/libavcodec.a h264_cabac.o
$ readelf --relocs h264_cabac.o | egrep的 '(GOT | PLT | JU MP_SLOT?)'
0000000000c7 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
0000000002fa 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
00000000179d 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001966 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001b09 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001d4a 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000001ee5 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
00000000265f 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000002fcd 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
0000000032f6 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000003305 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
0000 00003bdc 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000003cb5 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
000000004121 00320000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_mb_sizes - 4
000000004187 003300000004 R_X86_64_PLT32 0000000000000000 ff_init_cabac_decoder - 4
000000004381 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
000000004afe 003500000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra4x4 - 4
000000005556 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
00000000576a 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4
000000005acf 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4
000000006e31 000000000000004 00004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4
00000000b425 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4
00000000b5ab 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
结果并不完全相同,我以第一种方式获得26个搬迁,第二种方式是25。但是有很多PIC安全的迁移方式和
我很高兴相信,h264_cabac.o
的编译都有-fPIC
,无论他们有什么其他选择。
我会说明这一点:符号
ff_h264_cabac_tables
,您的链接
抱怨:重定位R_X86_64_PC32对符号'ff_h264_cabac_tables'在制作时无法使用一个共享对象
不在这些列表中。这意味着这个目标文件 - 来自两个来源 - 包含 PIC安全和PIC不安全的迁移。
GCC如何获得 错误,没有任何人注意到目前为止?如果是这样,那么我只是运行FFmpeg的共享库构建,并且成功地链接libavcodec.so
?
我们来看看PIC- 不安全的重定位:
$ readelf --relocs h264_cabac.o | egrep -v'(GOT | PLT | JU?MP_SLOT)'
那么我可以删除〜160行,但是它们都描述了PC相对类型
000000000017 002c00000002 R_X86_64_PC32 0000000000000000 ff_h264_cabac_tables - 4
...
...
R_X86_64_PC32
>
重新定位和唯一提到的符号,折扣部分名称和本地标签
是我们的朋友ff_h264_cabac_tables
,符号表所示: p>
$ readelf -s h264_cabac.o | grep ff_h264_cabac_tables
44:0000000000000000 0 NOTYPE GLOBAL DEFAULT UND ff_h264_cabac_tables
这是一个全局变量在此目标文件中定义。
GCC的
-fPIC
未损坏。但是,知道使用
-fPIC
编译的对象文件不能绝对保证它不包含PC相关类型
R_X86_64_PC32
引用未定义的全局符号的重定位。对于符号'ff_h264_cabac_tables'的重新定位R_X86_64_PC32是
这样的重定位。 $ code> R_X86_64_PC32 类型重定位采用32位PC相对寻址模式,
这是有效的,但在64位连接的设置中有一个关键的限制。
链接器不能保证引用符号不会动态解析
到在该寻址模式下无法表示的地址。它不会有,所以
它说:重定位R_X86_64_PC32对符号'ff_h264_cabac_tables'不能使用当共享对象
及其建议:
重新编译为-fPIC
em>假设,歹徒对象文件未编译为
-fPIC
。
这可能是,但必然是正确的假设,而不是关于
你的罪魁祸首libavcodec.a(h264_cabac.o)
使用
-fPIC
进行编译将保证PIC安全的迁移,前提是编译器
被允许进行所有的汇编和代码生成。但是不允许
与您的标本h264_cabac.o
或我的任何标本。所有这些标本
从FFmpeg源代码树中的FFmpeg / libavcodec / x86 / h264_cabac.c
编译。
查看该文件,您将看到它定义了引用extern
全局变量ff_h264_cabac_tables
并且是在线,手工制作的
程序集中实现的。可以告诉GCC编译这些函数-fPIC
,但是它不会获得
的机会。这些功能的位置独立性是汇编代码的作者
的责任。
我们可以显示GCC能够编译一个
h264_cabac.o
只有PIC安全
重新定位,如果允许的话。这将相互证明您的链接
的失败源自我们的文件标本的手工装配,并且还将显示
,您可以修复链接失败。 FFmpeg的./ configure
脚本有一个选项:- disable- asm禁用所有组合优化
其中包含导致
要从纯C源文件
FFmpeg / libavcodec / h264_cabac.c
编译
,而不是
内联汇编源码FFmpeg / libavcodec / x86 / h264_cabac.c
。所以我们来试试一下:$ cd FFmpeg
$ make clean
$ ./configure --enable -shared --disable-asm
$ make
$ cd libavcodec
$ readelf --relocs h264_cabac.o | grep的ff_h264_cabac_tables
00000000000a 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
0000000000ca 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
000000001eb5 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
0000000021c6 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
0000000026fe 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
000000002a17 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
000000002f13 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
00000000324c 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
000000003509 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
00000000362a 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
0000000037d7 00300000002a R_X86_64_REX_GOTP 0000 000000000000 ff_h264_cabac_tables - 4
00000000592b 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
现在,所有引用的重定位
ff_h264_cabac_tables
是PIC安全的。
我们也可以证明这个h264_cabac.o
可以在共享库中链接。我们知道
,ff_h264_cabac_tables
在h264_cabac.o
中未定义,所以我们还需要链接
定义了 的目标文件。它恰好是./ cabac.o
。$ gcc - 共享-o libfoo.so h264_cabac.o cabac.o
Voila:
$ file libfoo.so
libfoo.so:ELF 64位LSB共享对象,x86-64,版本1(SYSV),动态链接,BuildID [sha1] = ed63107b715b357853da94d4a031c0b06c30c5f2,没有剥离
然而,如果您仍然感到有些不满,您必须链接自己的
共享库与这个未优化的$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $这些感觉还为时过早。
请记住,我已经使用简单的香草($)配置了FFmpeg ./configure --enable-shared 。
我说链接器在您的失败链接中的异议是R_X86_64_PC32
重定位引用ff_h264_cabac_tables
如果ff_h264_cabac_tables
是动态解决的,则运行时可能不可行。对于类型R_X86_64_PC32
这样的重定位并不是一个异议。这是一个预防性的反对意见,基于无知如何ff_h264_cabac_tables
将最终解决。
但是我们知道
ff_h264_cabac_tables
实际上是在cabac.o
中定义的,而
我们将把它包括在与h264_cabac.o
相同的链接,就像$ code> libavcodec.so 。我们可以告诉链接器,链接中的任何全局
引用将被静态地解析为链接的
共享库中的定义,如果有的话,通过传递参数:-Bsymbolic
这将删除其任何
R_X86_64_PC32
重定位的预防性异议。
它知道它将能够在链接时间决定R_X86_64_PC32
重定位到ff_h264_cabac_tables
是可行的如果没有,它将给
一个不同的错误:重定位被截断以适合:..
。否则它会成功
没有评论。
不可避免地,这就是在库存FFmpeg构建中成功链接了
libavcodec.so
。
从顶部再次出现:$ cd FFmpeg
$ make clean
$。 / configure --enable-shared
$ make
然后强制重新链接
libavcodec.so
:$ rm libavcodec / h264_cabac.o
$ $ make libavcodec / libavcodec.so V = 1
gcc -I。 -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS = 64 -D_LARGEFILE_SOURCE \
-D_POSIX_C_SOURCE = 200112 -D_XOPEN_SOURCE = 600 -DPIC -DZLIB_CONST -DHAVE_AV_CONFIG_H \
-std = c11 -fomit-frame-pointer -fPIC -pthread -g -Wdeclaration-after-statement \
-Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings \
-Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes \
-Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign \
-O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror = format-security \
-Werror = implicit-function-declaration -Werror = missing-prototypes -Werror = return-type \
-Werror = vla -Wformat -fdiagnostics-color = auto -Wno-maybe-uninitialized \
-MMD -MF libavcodec / h264_cabac.d -MT libavcodec / h264_cabac.o -c \
-o libavcodec / h264_cabac.o libavcodec / h264_cabac.c
sed's / MAJOR / 57 /'libavcodec / libavcode c.v |猫> libavcodec / libavcodec.ver
gcc -shared -Wl,-soname,libavcodec.so.57 -Wl,-Bsymbolic ...等...
^^^^^^^^ ^^^^^^
所以没有汇编编码的缺陷。要在共享库中链接手动优化的
h264_cabac.o
,您只需添加-Wl,-Bsymbolic
到gcc链接选项。这是
优化的要求。
最低限度地证明:
$ cd libavcodec /
$ gcc -shared -o libfoo.so h264_cabac.o cabac.o
/ usr / bin / ld:h264_cabac.o:对于符号ff_h264_cabac_tables的重定位R_X86_64_PC32在创建共享对象时不能使用;重新编译-fPIC
/ usr / bin / ld:最终链接失败:错误值
collect2:错误:ld返回1退出状态
再次出现故障。和:
$ gcc -shared -Wl,-Bsymbolic -o libfoo.so h264_cabac.o cabac.o
$ file libfoo.so
libfoo.so:ELF 64位LSB共享对象,x86-64,版本1(SYSV),动态链接,BuildID [sha1] = 7dc86aeae353c4d92cdb5fa35d169bf019b47eb2,不剥离
成功。
I am trying to include some object files into a shared library I am building. Take the following command (things in [ETC] have been omitted for brevity):
/usr/bin/c++ -fPIC -std=c++14 -pthread -Iinclude/ext/liveMedia -Iinclude/ext/groupsock [ETC] -g -shared -Wl,-soname,libValkka.so -o lib/libValkka.so CMakeFiles/Valkka.dir/src/avthread.cpp.o CMakeFiles/Valkka.dir/src/opengl.cpp.o [ETC] CMakeFiles/Valkka.dir/src/decoders.cpp.o -lX11 -lGLEW -lGLU -lGL -Wl,--whole-archive lib/libavcodec.a -Wl,--no-whole-archive
So basically I am just creating a shared library where most of the objects come from my own source code (i.e. CMakeFiles/Valkka.dir/src/*.o), but some of them come from an external static library, located at "lib/libavcodec.a". I get the following error:
/usr/bin/ld: lib/libavcodec.a(h264_cabac.o): relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' 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
But that is so untrue! I can extract "libavcodec.a" with
ar x libavcodec.a
And after that check that
readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)'
does give some **it:
00000000175d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001926 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
...
As does
objdump -r h264_cabac.o | grep -i "relocation"
So, indeed, the object files in "libavcodec.a" have been compiled to get PIC (position independent code).
Why does the linker believe otherwise!?
Related links:
How to include all objects of an archive in a shared object?
Linking archives (.a) into shared object (.so)
Is there a way to determine that a .a or .so library has been compiled as position indepenent code?
How can I tell, with something like objdump, if an object file has been built with -fPIC?
解决方案TL;DR
Add
-Wl,-Bsymbolic
to the gcc linkage options for your shared library.Why?
You're testing the PICness of
h264_cabac.o
with:readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)
and concluding the the object file was compiled with
-fPIC
if you get any hits. Presumably you got this test from the favourite answer to How can I tell, with something like objdump, if an object file has been built with -fPIC?You got some hits, and I can reproduce that more than one way:
From the source code
$ git clone https://github.com/FFmpeg/FFmpeg.git $ cd FFmpeg $ ./configure --enable-shared $ make
Then:
$ cd libavcodec $ readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)' 00000000175d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001926 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 00000000259f 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000002f0d 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000003216 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000003460 00330000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_chroma422_dc_s - 4 000000003afc 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000003fb6 00360000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_i_mb_type_info - 4 000000004031 00370000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_mb_sizes - 4 00000000409a 003800000004 R_X86_64_PLT32 0000000000000000 ff_init_cabac_decoder - 4 000000004248 00390000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_b_mb_type_info - 4 000000004299 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 000000004a31 003b00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra4x4 - 4 000000004bd5 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000004f85 003c0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_p_mb_type_info - 4 0000000050fd 003d0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_b_sub_mb_type_ - 4 000000005233 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 00000000544a 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000005bef 003a00000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 000000006db5 003e00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4 000000006de9 003f0000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_p_sub_mb_type_ - 4 000000007171 003200000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000008b1b 003e00000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4 00000000ad41 004000000009 R_X86_64_GOTPCREL 0000000000000000 ff_h264_chroma_dc_scan - 4 00000000ad84 004000000009 R_X86_64_GOTPCREL 0000000000000000 ff_h264_chroma_dc_scan - 4 00000000b758 003100000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
From the Ubuntu 16.04 dev package
$ sudo apt-get install libavcodec-dev $ dpkg -S libavcodec.a libavcodec-dev:amd64: /usr/lib/x86_64-linux-gnu/libavcodec.a $ mkdir ~/deleteme $ cd ~/deleteme $ ar x /usr/lib/x86_64-linux-gnu/libavcodec.a h264_cabac.o $ readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)' 0000000000c7 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 0000000002fa 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 00000000179d 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001966 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001b09 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001d4a 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000001ee5 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 00000000265f 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000002fcd 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 0000000032f6 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000003305 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000003bdc 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000003cb5 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4 000000004121 00320000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_mb_sizes - 4 000000004187 003300000004 R_X86_64_PLT32 0000000000000000 ff_init_cabac_decoder - 4 000000004381 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 000000004afe 003500000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra4x4 - 4 000000005556 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 00000000576a 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000005acf 003400000004 R_X86_64_PLT32 0000000000000000 ff_h264_pred_direct_mo - 4 000000006e31 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4 000000006e58 003600000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4 000000009c20 003600000004 R_X86_64_PLT32 0000000000000000 ff_h264_check_intra_pr - 4 00000000b425 002f00000004 R_X86_64_PLT32 0000000000000000 av_log - 4 00000000b5ab 002e00000004 R_X86_64_PLT32 0000000000000000 __stack_chk_fail - 4
The results aren't identical, and I get 26 relocations the first way, 25 the second way. But there are plenty of PIC-safe relocations either way and I'm happy to believe both compilations of
h264_cabac.o
had-fPIC
, whatever other options they had.I'll state the obvious: The symbol
ff_h264_cabac_tables
, about which your linkage complains:relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
isn't in either of those lists. That means this object file - from both provenances - contains both PIC-safe and PIC-unsafe relocations. How could GCC get that wrong, without anybody noticing till now? And if it did, how did I just run the shared library build of FFmpeg and link
libavcodec.so
successfully?Let's have a look at the PIC-unsafe relocations:
$ readelf --relocs h264_cabac.o | egrep -v '(GOT|PLT|JU?MP_SLOT)' 000000000017 002c00000002 R_X86_64_PC32 0000000000000000 ff_h264_cabac_tables - 4 ... ...
Well I'll elide ~160 lines of that, but they all describe PC-relative type
R_X86_64_PC32
relocations and the only symbol mentioned, discounting section names and local labels, is our friendff_h264_cabac_tables
, about which the symbol table says:$ readelf -s h264_cabac.o | grep ff_h264_cabac_tables 44: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND ff_h264_cabac_tables
It's a global variable, not defined in this object file.
GCC's
-fPIC
isn't broken. However, knowing that an object file was compiled with-fPIC
can't absolutely guarantee that it contains no PC-relative typeR_X86_64_PC32
relocations that reference undefined global symbols.relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables'
is such a relocation. TheR_X86_64_PC32
type relocation employs a 32-bit PC-relative addressing mode, which is efficient but has a critical limitation in the setting of a 64-bit linkage. The linker can't guarantee the referenced symbol will not be dynamically resolved to an address that's unrepresentable in this addressing mode. It won't have that, so it says:relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
and its advice:
recompile with -fPIC
is based on the hypothesis that the culprit object file was not compiled with
-fPIC
. Which is probably, but necessarily, the right hypothesis and is not right about your culpritlibavcodec.a(h264_cabac.o)
Compiling with
-fPIC
will guarantee you PIC-safe relocations provided that the compiler is allowed to do all the assembly and code-generation. But it wasn't allowed to with your specimen ofh264_cabac.o
or either of my specimens. All those specimens were compiled fromFFmpeg/libavcodec/x86/h264_cabac.c
in the FFmpeg source tree. Look at that file and you'll see that it defines functions that refer to theextern
global variableff_h264_cabac_tables
and are implemented in inline, hand-crafted assembly. GCC can be told to compile these functions-fPIC
, but it doesn't get a chance. The position-independence of these functions is the responsibility of the author of the assembly code.We can show that GCC is able to compile a
h264_cabac.o
that has only PIC-safe relocations, if it's allowed to. That will collaterally prove that your linkage failure stems from the hand-assembly of our specimens of the file and will also show you one fix for the linkage failure. FFmpeg's./configure
script has the option:--disable-asm disable all assembly optimizations
which has the effect, among others, of causing
h264_cabac.o
to be compiled from the pure C source fileFFmpeg/libavcodec/h264_cabac.c
instead of the the inline assembly sourceFFmpeg/libavcodec/x86/h264_cabac.c
. So let's try that:$ cd FFmpeg $ make clean $ ./configure --enable-shared --disable-asm $ make $ cd libavcodec $ readelf --relocs h264_cabac.o | grep ff_h264_cabac_tables 00000000000a 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 0000000000ca 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 000000001eb5 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 0000000021c6 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 0000000026fe 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 000000002a17 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 000000002f13 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 00000000324c 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 000000003509 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 00000000362a 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 0000000037d7 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4 00000000592b 00300000002a R_X86_64_REX_GOTP 0000000000000000 ff_h264_cabac_tables - 4
Now, all the relocations referencing
ff_h264_cabac_tables
are PIC-safe. We might as well prove that thish264_cabac.o
can be linked in a shared library. We know thatff_h264_cabac_tables
is undefined inh264_cabac.o
, so we'll also need to link the object file in which it is defined. It happens to be./cabac.o
.$ gcc -shared -o libfoo.so h264_cabac.o cabac.o
Voila:
$ file libfoo.so libfoo.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=ed63107b715b357853da94d4a031c0b06c30c5f2, not stripped
You might still feel a little aggrieved, however, if you have to link your own shared library with this unoptimized
h264_cabac.o
and a little disappointed by the assembly coding flaw that obliges you to. These feelings would be premature.Remember, I've already built FFmpeg successfully with plain vanilla
./configure --enable-shared
. I said that linker's objection in your failing linkage is that theR_X86_64_PC32
relocation referencingff_h264_cabac_tables
might not be feasible at runtime, ifff_h264_cabac_tables
is dynamically resolved. It is not an objection to the typeR_X86_64_PC32
relocation as such. It is a precautionary objection, based on ignorance of howff_h264_cabac_tables
will ultimately be resolved.But we know that
ff_h264_cabac_tables
is in fact defined incabac.o
and that we'll include it the same linkage withh264_cabac.o
, just as they're both included in the linkage oflibavcodec.so
. And we can tell the linker that any global references in the linkage are to be statically resolved to definitions in the shared library being linked, if at all, by passing it the argument:-Bsymbolic
This will remove its precautionary objection to any
R_X86_64_PC32
relocation. It knows it will be able to decide at linktime whether theR_X86_64_PC32
relocation againstff_h264_cabac_tables
is feasible. If not, it will give a different error:relocation truncated to fit:..
. Otherwise it will succeed without comment.Inevitably, that's how
libavcodec.so
is successfully linked in the stock FFmpeg build. Once more from the top:$ cd FFmpeg $ make clean $ ./configure --enable-shared $ make
Then force a relink of
libavcodec.so
:$ rm libavcodec/h264_cabac.o $ $ make libavcodec/libavcodec.so V=1 gcc -I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -DZLIB_CONST -DHAVE_AV_CONFIG_H \ -std=c11 -fomit-frame-pointer -fPIC -pthread -g -Wdeclaration-after-statement \ -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings \ -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes \ -Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign \ -O3 -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=format-security \ -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type \ -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized \ -MMD -MF libavcodec/h264_cabac.d -MT libavcodec/h264_cabac.o -c \ -o libavcodec/h264_cabac.o libavcodec/h264_cabac.c sed 's/MAJOR/57/' libavcodec/libavcodec.v | cat > libavcodec/libavcodec.ver gcc -shared -Wl,-soname,libavcodec.so.57 -Wl,-Bsymbolic ... etc. etc. ... ^^^^^^^^^^^^^^
So there is no assembly coding flaw. To link the hand-optimized
h264_cabac.o
in a shared library you just need to add-Wl,-Bsymbolic
to the gcc linkage options. It's a requirement of the optimization.Let's prove that minimally:
$ cd libavcodec/ $ gcc -shared -o libfoo.so h264_cabac.o cabac.o /usr/bin/ld: h264_cabac.o: relocation R_X86_64_PC32 against symbol `ff_h264_cabac_tables' 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
There's your failure again. And:
$ gcc -shared -Wl,-Bsymbolic -o libfoo.so h264_cabac.o cabac.o $ file libfoo.so libfoo.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=7dc86aeae353c4d92cdb5fa35d169bf019b47eb2, not stripped
success.
这篇关于将对象从C ++存档(.a)包含到共享库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!