将 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,-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
所以基本上我只是创建一个共享库,其中大部分对象来自我自己的源代码(即 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' 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
但事实并非如此!我可以用
提取 "libavcodec.a"
ar x libavcodec.a
然后检查
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
...
和
一样
objdump -r h264_cabac.o | grep -i "relocation"
所以,确实,"libavcodec.a"中的目标文件已经编译得到PIC(位置无关代码)。
为什么链接器不这么认为!?
相关链接:
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
将 -Wl,-Bsymbolic
添加到共享库的 gcc linkage 选项。
为什么?
您正在测试 h264_cabac.o
的 PICness:
readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)
并得出结论,目标文件是用 -fPIC
编译的,如果你得到任何
点击。大概你从 the favourite answer 得到了这个测试
至 How can I tell, with something like objdump, if an object file has been built with -fPIC?
你得到了一些点击,我可以通过不止一种方式重现:
来自源代码
$ 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
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
结果不一样,第一种方式我得到了 26 个重定位,第二种方式得到了 25 个。但是无论哪种方式,都有很多 PIC 安全的重定位,并且
我很高兴地相信 h264_cabac.o
的两个汇编都有 -fPIC
,无论他们有什么其他选择。
我会陈述显而易见的:符号 ff_h264_cabac_tables
,关于它你的 link年龄
抱怨:
relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
不在这两个列表中。这意味着这个目标文件 - 来自两个来源 - 包含 both PIC 安全和 PIC 不安全的重定位。
GCC 怎么会弄错 that,直到现在还没有人注意到?如果确实如此,如何
我刚刚 运行 FFmpeg 的共享库构建和 link 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
,符号 table 表示:
$ 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
引用未定义全局符号的重定位。 relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables'
是
这样的搬迁。 R_X86_64_PC32
类型重定位采用32位PC相对寻址方式,
这很有效,但在 64 位 linkage 的设置中有一个关键限制。
linker 不能保证引用的符号不会被动态解析
到在此寻址模式下不代表 table 的地址。它不会有那个,所以
它说:
relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
及其建议:
recompile with -fPIC
基于 假设 罪魁祸首目标文件未使用 -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 安全的
搬迁,如果允许的话。这将附带证明您的 link年龄
失败源于我们对文件样本的手工组装,并且还将显示
您可以修复 linkage 故障。 FFmpeg 的 ./configure
脚本有选项:
--disable-asm disable all assembly optimizations
具有导致编译 h264_cabac.o
等效果
来自纯 C 源文件 FFmpeg/libavcodec/h264_cabac.c
而不是 the
内联汇编源 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 0000000000000000 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
可以在共享库中 linked。我们知道
ff_h264_cabac_tables
在 h264_cabac.o
中未定义,因此我们还需要 link
定义的对象文件。正好是./cabac.o
.
$ gcc -shared -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]=ed63107b715b357853da94d4a031c0b06c30c5f2, not stripped
你可能还是觉得有点委屈,但是,如果你不得不link自己
与这个未优化的共享库 h264_cabac.o
有点失望
汇编代码缺陷迫使您这样做。这些感觉还为时过早。
记住,我已经用普通香草成功构建了 FFmpeg ./configure --enable-shared
。
我说 linker 反对你失败的 linkage 是 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
相同的 linkage 中,就像它们都包含在内一样
linklibavcodec.so
岁。我们可以告诉 linker 任何全球
linkage 中的引用将被静态解析为
共享库被 linked,如果有的话,通过给它传递参数:
-Bsymbolic
这将取消其对任何 R_X86_64_PC32
搬迁的预防性反对。
它知道它将能够在 link 时间决定 R_X86_64_PC32
针对 ff_h264_cabac_tables
的搬迁是可行的。如果没有,它会给
一个不同的错误:relocation truncated to fit:..
。否则会成功
无评论。
不可避免地,这就是 libavcodec.so
如何成功地 linked 在股票 FFmpeg 构建中。
再一次从顶部开始:
$ cd FFmpeg
$ make clean
$ ./configure --enable-shared
$ make
然后强制重新link 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. ...
^^^^^^^^^^^^^^
所以没有汇编代码缺陷。到link手优化h264_cabac.o
在共享库中,您只需将 -Wl,-Bsymbolic
添加到 gcc linkage 选项。它是
优化要求。
让我们证明一下:
$ 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
又是你的失败。并且:
$ 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
成功。
我正在尝试将一些目标文件包含到我正在构建的共享库中。执行以下命令(为简洁起见,省略了 [ETC] 中的内容):
/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
所以基本上我只是创建一个共享库,其中大部分对象来自我自己的源代码(即 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' 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
但事实并非如此!我可以用
提取 "libavcodec.a"ar x libavcodec.a
然后检查
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
...
和
一样objdump -r h264_cabac.o | grep -i "relocation"
所以,确实,"libavcodec.a"中的目标文件已经编译得到PIC(位置无关代码)。
为什么链接器不这么认为!?
相关链接:
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
将 -Wl,-Bsymbolic
添加到共享库的 gcc linkage 选项。
为什么?
您正在测试 h264_cabac.o
的 PICness:
readelf --relocs h264_cabac.o | egrep '(GOT|PLT|JU?MP_SLOT)
并得出结论,目标文件是用 -fPIC
编译的,如果你得到任何
点击。大概你从 the favourite answer 得到了这个测试
至 How can I tell, with something like objdump, if an object file has been built with -fPIC?
你得到了一些点击,我可以通过不止一种方式重现:
来自源代码
$ 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
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
结果不一样,第一种方式我得到了 26 个重定位,第二种方式得到了 25 个。但是无论哪种方式,都有很多 PIC 安全的重定位,并且
我很高兴地相信 h264_cabac.o
的两个汇编都有 -fPIC
,无论他们有什么其他选择。
我会陈述显而易见的:符号 ff_h264_cabac_tables
,关于它你的 link年龄
抱怨:
relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
不在这两个列表中。这意味着这个目标文件 - 来自两个来源 - 包含 both PIC 安全和 PIC 不安全的重定位。
GCC 怎么会弄错 that,直到现在还没有人注意到?如果确实如此,如何
我刚刚 运行 FFmpeg 的共享库构建和 link 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
,符号 table 表示:
$ 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
引用未定义全局符号的重定位。 relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables'
是
这样的搬迁。 R_X86_64_PC32
类型重定位采用32位PC相对寻址方式,
这很有效,但在 64 位 linkage 的设置中有一个关键限制。
linker 不能保证引用的符号不会被动态解析
到在此寻址模式下不代表 table 的地址。它不会有那个,所以
它说:
relocation R_X86_64_PC32 against symbol 'ff_h264_cabac_tables' can not be used when making a shared object
及其建议:
recompile with -fPIC
基于 假设 罪魁祸首目标文件未使用 -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 安全的
搬迁,如果允许的话。这将附带证明您的 link年龄
失败源于我们对文件样本的手工组装,并且还将显示
您可以修复 linkage 故障。 FFmpeg 的 ./configure
脚本有选项:
--disable-asm disable all assembly optimizations
具有导致编译 h264_cabac.o
等效果
来自纯 C 源文件 FFmpeg/libavcodec/h264_cabac.c
而不是 the
内联汇编源 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 0000000000000000 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
可以在共享库中 linked。我们知道
ff_h264_cabac_tables
在 h264_cabac.o
中未定义,因此我们还需要 link
定义的对象文件。正好是./cabac.o
.
$ gcc -shared -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]=ed63107b715b357853da94d4a031c0b06c30c5f2, not stripped
你可能还是觉得有点委屈,但是,如果你不得不link自己
与这个未优化的共享库 h264_cabac.o
有点失望
汇编代码缺陷迫使您这样做。这些感觉还为时过早。
记住,我已经用普通香草成功构建了 FFmpeg ./configure --enable-shared
。
我说 linker 反对你失败的 linkage 是 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
相同的 linkage 中,就像它们都包含在内一样
linklibavcodec.so
岁。我们可以告诉 linker 任何全球
linkage 中的引用将被静态解析为
共享库被 linked,如果有的话,通过给它传递参数:
-Bsymbolic
这将取消其对任何 R_X86_64_PC32
搬迁的预防性反对。
它知道它将能够在 link 时间决定 R_X86_64_PC32
针对 ff_h264_cabac_tables
的搬迁是可行的。如果没有,它会给
一个不同的错误:relocation truncated to fit:..
。否则会成功
无评论。
不可避免地,这就是 libavcodec.so
如何成功地 linked 在股票 FFmpeg 构建中。
再一次从顶部开始:
$ cd FFmpeg
$ make clean
$ ./configure --enable-shared
$ make
然后强制重新link 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. ...
^^^^^^^^^^^^^^
所以没有汇编代码缺陷。到link手优化h264_cabac.o
在共享库中,您只需将 -Wl,-Bsymbolic
添加到 gcc linkage 选项。它是
优化要求。
让我们证明一下:
$ 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
又是你的失败。并且:
$ 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
成功。