将对象从C ++存档(.a)包含到共享库中 [英] Including objects to a shared library from a C++ archive (.a)

查看:264
本文介绍了将对象从C ++存档(.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(位置无关代码)。



为什么链接器相信否则!?



相关链接:



如何将存档的所有对象包含在共享对象中?



将归档(.a)链接到共享对象(.so)



有没有办法确定.a或.so库已编译为位置独立代码?



如果使用-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)'
000000000017 002c00000002 R_X86_64_PC32 0000000000000000 ff_h264_cabac_tables - 4
...
...
那么我可以删除〜160行,但是它们都描述了PC相对类型 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 friend ff_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 type R_X86_64_PC32 relocations that reference undefined global symbols. relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' is such a relocation. The R_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 culprit libavcodec.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 of h264_cabac.o or either of my specimens. All those specimens were compiled from FFmpeg/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 the extern global variable ff_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 file FFmpeg/libavcodec/h264_cabac.c instead of the the inline assembly source FFmpeg/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 this h264_cabac.o can be linked in a shared library. We know that ff_h264_cabac_tables is undefined in h264_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 the R_X86_64_PC32 relocation referencing ff_h264_cabac_tables might not be feasible at runtime, if ff_h264_cabac_tables is dynamically resolved. It is not an objection to the type R_X86_64_PC32 relocation as such. It is a precautionary objection, based on ignorance of how ff_h264_cabac_tables will ultimately be resolved.

But we know that ff_h264_cabac_tables is in fact defined in cabac.o and that we'll include it the same linkage with h264_cabac.o, just as they're both included in the linkage of libavcodec.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 the R_X86_64_PC32 relocation against ff_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆