1

(虽然英特尔的论坛是一个更自然地提出这个问题的地方,但我在这里发布它是希望比英特尔完全缺乏的活动更多 - 到目前为止)

我无法创建使用 Intel Media SDK(linux 服务器)来操作 h264 视频的动态链接库,并注意到 MFX 库的设计存在问题。据我了解,程序应该链接到静态库,例如:

$ g++ .... -L/opt/intel/mediasdk/lib/lin_x64 -lmfx

但是,此libmfx.a库似乎将所有调用委托给dlopened动态/opt/intel/mediasdk/lib64/libmfxhw64.so。值得注意的是,静态库和动态库公开的函数名(和签名)是​​相同的,这有点令人困惑和危险。

虽然我不理解这种设计背后的基本原理,但它本身不应该是一个问题,当(静态)libmfx.a包含在共享对象中时,库中的一些静态/全局初始化显然不会造成严重破坏。IE。:

    +------+     +-----------+
    | main | <-- | mylib.so  |
    +------+     |           |          +---------------+
                 | libmfx.a  | (dlopen) | libmfxhw64.so |
                 |          <-------------              |
                 |+---------+|          |+-------------+|
                 ||MFXInit()||          ||  MFXInit()  ||
                 ||...      ||          ||  ...        ||
                 ||         ||          ||             ||
                 +===========+          +===============+

上面的库可以这样组装:

$ g++ -shared -o mylib.so my1.o my2.o -lmfx

然后(动态)链接到main.o这样:

$ g++ -o main main.o mylib.so -ldl

(请注意,附加libdl是必要的,以允许libmfx.adlopen() libmfxhw64.so

不幸的是,在第一次MFXInit()调用时,程序会导致分段错误(访问地址 0x0000400)。GDB 回溯:

#0  0x0000000000000400 in ?? ()
#1  0x00007ffff61fb4cd in MFXInit () from /opt/intel/mediasdk/lib64/libmfxhw64-p.so.1.13
#2  0x00007ffff7bd3a1f in MFX_DISP_HANDLE::LoadSelectedDLL(char const*, eMfxImplType, int, int) () from ./lib-a.so
#3  0x00007ffff7bd12b1 in MFXInit () from ./lib-a.so
#4  0x00007ffff7bd09c8 in test_mfx () at lib.c:12
#5  0x0000000000400744 in main (argc=1, argv=0x7fffffffe0d8) at main.c:8

(注意MFXInit()at stackframe#3是 inlibmfx.a而 at#1是 in libmfxhw64.so。)

请注意,创建为静态库时不会崩溃。使用断点和反汇编程序,我设法制作了以下回溯快照,在这两种情况下都是 at ,但它们似乎遇到了不同版本的(由于重定位,绝对地址毫无意义):mylib#1MFXInit+424MFXQueryVersion

#0  0x00007ffff6411980 in MFXQueryVersion () from /opt/intel/mediasdk/lib64/libmfxhw64-p.so.1.13
#1  0x00007ffff640c4cd in MFXInit () from /opt/intel/mediasdk/lib64/libmfxhw64-p.so.1.13
#2  0x000000000040484f in MFX_DISP_HANDLE::LoadSelectedDLL(char const*, eMfxImplType, int, int) ()
#3  0x00000000004020e1 in MFXInit ()
#4  0x0000000000401800 in test_mfx () at lib.c:12
#5  0x0000000000401794 in main (argc=1, argv=0x7fffffffe0e8) at main.c:8

因为静态和共享的英特尔库都公开了相同的 API 函数,所以我可以直接链接到libmfxhw64.so胆量,但我认为绕过静态“调度程序”是没有保证的(?)

有人可以解释英特尔在上述设计背后的想法吗?规范,为什么要提供一个仅委托给.so具有相同接口的静态库?

此外,SEGV 似乎是由libmfx.a或中的静态/全局数据引起的libmfxhw64.so。有没有办法在动态加载的静态/全局部分上强制执行特定的执行顺序?调试此类问题的最佳方法是什么?


在 Intel Haswell i7-4790 @3.6Ghz 上使用 Intel Media SDK R2 (ubuntu 12) 和 Intel Media SDK 2015R3-R5 (Centos 7, 1.13/1.15) 进行测试

如果您有一个有效的英特尔 MSDK 设置,请编译我的示例代码以确认问题。

4

2 回答 2

3

在最近发布的调度程序源代码中,文件“readme-dispatcher-linux.pdf”的最后是这样的:

从可执行模块或共享对象使用 Dispatcher 库之间存在细微差别。为了减轻 Linux* 上自身与 SDK 共享对象之间的符号冲突,应用程序应:1) 链接到 libdispatch_shared.a 而不是 libmfx.a 2) 在任何 SDK 包含之前定义 MFX_DISPATCHER_EXPOSED_PREFIX

我已经使用了它,它可以解决您描述的符号冲突问题。

如果您安装“Intel Media Server Studio Professional 2016”,您可以找到此文件。有一个免费的社区版。源文件和 PDF 位于 /opt/intel/mediasdk/opensource/

于 2016-07-31T20:07:49.453 回答
0

(好吧,由于似乎没有人急于求成,我会做一件不雅的事情,并发布我自己问题的答案)。

经过大量研究试图打破无意的循环链接,我发现该ld选项--exclude-libs提供了安慰。本质上,我一直在寻找一种在创建 DLL 时libmfx.a使用它们来解决依赖关系后强制删除任何符号的方法。lib.o这可以通过创建这样的来完成so

g++ -shared -o lib-a.so lib.o -L/opt/intel/mediasdk/lib/lin_x64 -lmfx -Wl,--exclude-libs=libmfx

一旦像这样创建库,Bob 就是你的叔叔:

g++ -o main-so-a main.o lib-a.so -ldl

(请注意,libdl仍然需要,因为英特尔的 MFX(现在在里面lib-a.so)仍然用于dlopen发现libmfxhw64.so

ld手册页:

   --exclude-libs lib,lib,...
       Specifies a list of archive libraries from which symbols should not be
       automatically exported.  The library names may be delimited by commas or
       colons.  Specifying "--exclude-libs ALL" excludes symbols in all archive
       libraries from automatic export.  This option is available only for the
       i386 PE targeted port of the linker and for ELF targeted ports.  For i386
       PE, symbols explicitly listed in a .def file are still exported,
       regardless of this option.  For ELF targeted ports, symbols affected
       by this option will be treated as hidden.

因此,本质上,诀窍是不确保相关的 ELF 符号被标记为hidden。通常这将由#pragma库开发人员(即英特尔)通过 s 处理,但由于他们的疏忽,在这种情况下需要对其进行改造。

我想同样可以用--version-script地图文件完成,但结果可能更脆弱,因为我们libmfx.a无论如何都想完全封装。

于 2015-07-21T07:59:29.600 回答