如何做好运行时绑定基于Linux上的CPU能力 [英] How to do runtime binding based on CPU capabilities on linux

查看:190
本文介绍了如何做好运行时绑定基于Linux上的CPU能力的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能有一个Linux库(例如libloader.so)装入另一个库,以解决任何外部符号?

Is it possible to have a linux library (e.g. "libloader.so") load another library to resolve any external symbols?

我已经得到了code的一大堆,获取有条件编译的SIMD水平得到支持(SSE2,AVX,AVX2)。这个工作正常,如果构建平台是一样的运行时平台。但它的重用阻碍在不同代处理器。

I've got a whole bunch of code that gets conditionally compiled for the SIMD level to be supported ( SSE2, AVX, AVX2 ). This works fine if the build platform is the same as the runtime platform. But it hinders reuse across different processor generations.

一个想法是让执行这就要求函数链接 libloader.so 不直接实施函数。相反,它解析(绑定?)从另一个加载库,例如符号 libimpl_sse2.so libimpl_avx2.so 左右就取决于cpuflags。

One thought is to have executable which calls function link to libloader.so that does not directly implement function. Rather, it resolves(binds?) that symbol from another loaded library e.g. libimpl_sse2.so, libimpl_avx2.so or so on depending on cpuflags.

有数百个函数需要以这种方式动态地束缚,因此改变了声明或调用code未实用。
节目联动是相当容易改变。运行时环境变量也可以改变,但我想preFER没有。

There are hundreds of functions that need to be dynamically bound in this way, so changing the declarations or calling code is not practical. The program linkage is fairly easy to change. The runtime environment variables could also be changed, but I'd prefer not to.

据制作该建立并通过了LD标志解析的外部符号(UES)将启动一个可执行文件我已经得到了 - 没有得到解决,符号=忽略,所有 。但IMPL LIB的后续装载不会从空的UES函数的值更改。

I've gotten as far as making an executable that builds and starts with unresolved external symbols (UES) via the ld flag --unresolved-symbols=ignore-all. But subsequent loading of the impl lib does not change the value of the UES function from NULL.

推荐答案

编辑:后来我发现在下面描述的技术将只在有限的情况下工作。具体来说,您的共享库必须只包含的功能,没有任何全局变量。如果有要分发到图书馆里面全局变量,那么你会最终有一个运行时动态链接程序错误。出现这种情况的<一个href=\"http://stackoverflow.com/questions/34027468/can-i-make-shared-library-constructors-execute-before-relocations\">because全局变量搬迁前的共享库的构造函数被调用。因此,链接器需要尽早解决这些引用,以前这里描述的调度方案有机会运行。

I found out later on that the technique described below will only work under limited circumstances. Specifically, your shared libraries must contain functions only, without any global variables. If there are globals inside the libraries that you want to dispatch to, then you will end up with a runtime dynamic linker error. This occurs because global variables are relocated before shared library constructors are invoked. Thus, the linker needs to resolve those references early, before the dispatching scheme described here has a chance to run.

完成你想要的是(AB)的一种方法使用 DT_SONAME 字段在共享库的ELF头。这可以用来改变文件的名称,该动态加载程序( LD-Linux的所以* ),以解决共享库的依赖负荷运行时。这最好用一个例子来解释。说我编写的共享库 libtest.so 使用以下命令行:

One way of accomplishing what you want is to (ab)use the DT_SONAME field in your shared library's ELF header. This can be used to alter the name of the file that the dynamic loader (ld-linux-so*) loads at runtime in order to resolve the shared library dependency. This is best explained with an example. Say I compile a shared library libtest.so with the following command line:

g++ test.cc -shared -o libtest.so -Wl,-soname,libtest_dispatch.so

这将创建的文件名以 libtest.so ,但其 DT_SONAME 字段设置为共享库 libtest_dispatch.so 。让我们看看,当我们反对它链接程序会发生什么:

This will create a shared library whose filename is libtest.so, but its DT_SONAME field is set to libtest_dispatch.so. Let's see what happens when we link a program against it:

g++ testprog.cc -o test -ltest

让我们来看一看生成的应用程序二进制运行时库依赖测试

> ldd test
linux-vdso.so.1 =>  (0x00007fffcc5fe000)
libtest_dispatch.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd1e4a55000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd1e4e4f000)

请注意,而不是查找 libtest.so ,动态加载程序,而不是要载入 libtest_dispatch.so 代替。你可以利用这个来实现所需的调度功能。下面是我会怎么做:

Note that instead of looking for libtest.so, the dynamic loader instead wants to load libtest_dispatch.so instead. You can exploit this to implement the dispatching functionality that you want. Here's how I would do it:


  • 创建共享库的各种版本。我认为有,可以一直使用,在运行时适当使用其它优化版本的一些通用的版本。我会名称的通用版本的普通库的名称 libtest.so ,并将其命名为他人无论您选择(如 libtest_sse2.so libtest_avx.so ,等等)。

  • Create the various versions of your shared library. I assume that there is some "generic" version that can always be used, with other optimized versions utilized at runtime as appropriate. I would name the generic version with the "plain" library name libtest.so, and name the others however you choose (e.g. libtest_sse2.so, libtest_avx.so, etc.).

在链接库的通用版本,覆盖其 DT_SONAME 别的东西,像 libtest_dispatch.so

When linking the generic version of the library, override its DT_SONAME to something else, like libtest_dispatch.so.

创建一个名为调度员库 libtest_dispatch.so 。当调度员是在应用程序启动时加载,它负责加载相应的执行库。下面是伪code为实施 libtest_dispatch.so 可能看起来是这样的:

Create a dispatcher library called libtest_dispatch.so. When the dispatcher is loaded at application startup, it is responsible for loading the appropriate implementation of the library. Here's pseudocode for what the implementation of libtest_dispatch.so might look like:

#include <dlfcn.h>
#include <stdlib.h>

// the __attribute__ ensures that this function is called when the library is loaded
__attribute__((constructor)) void init()
{
    // manually load the appropriate shared library based upon what the CPU supports
    // at runtime
    if (avx_is_available) dlopen("libtest_avx.so", RTLD_NOW | RTLD_GLOBAL);
    else if (sse2_is_available) dlopen("libtest_sse2.so", RTLD_NOW | RTLD_GLOBAL);
    else dlopen("libtest.so", RTLD_NOW | RTLD_GLOBAL);
    // NOTE: this is just an example; you should check the return values from 
    // dlopen() above and handle errors accordingly
}


  • 在链接对你的库的应用程序,链接它反对香草 libtest.so ,有一个它的 DT_SONAME 改写为指向调度库。这使得调度基本上是透明的使用库中的任何应用程序的作者。

  • When linking an application against your library, link it against the "vanilla" libtest.so, the one that has its DT_SONAME overridden to point to the dispatcher library. This makes the dispatching essentially transparent to any application authors that use your library.

    本应在Linux上上述工作。在Mac OS,共享库有一个安装名,即类似于在 DT_SONAME 的ELF使用共享库,所以过程非常类似于上述,可以替代使用。我不知道是否类似的东西可以在Windows上使用。

    This should work as described above on Linux. On Mac OS, shared libraries have an "install name" that is analogous to the DT_SONAME used in ELF shared libraries, so a process very similar to the above could be used instead. I'm not sure about whether something similar could be used on Windows.

    注意:有一个在上面做了一个重要的假设:库的各种实现之间的兼容性ABI。也就是说,你的图书馆应该被设计成可以安全地对在链接时最通用的版本,链接,同时在系统运行时优化的版本(如 libtest_avx.so )。

    Note: There is one important assumption made in the above: ABI compatibility between the various implementations of the library. That is, your library should be designed such that it is safe to link against the most generic version at link time while using an optimized version (e.g. libtest_avx.so) at runtime.

    这篇关于如何做好运行时绑定基于Linux上的CPU能力的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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