【问题标题】:How does one use libtool/libltdl's dlpreopening / preloading?如何使用 libtool/libltdl 的 dlpreopening / preloading?
【发布时间】:2021-08-23 14:16:02
【问题描述】:

这是我想使用 libtool 的 libltdl dlpreopening 的代码类型的粗略示例:

https://github.com/EmmaJaneBonestell/dlopen-sample

我希望能够重写使用 libdl 函数(dlopen、dlsym 等)的各种项目,以使用 libtool 的 libltdl dlpreopening/preloading 机制。从 libtool 的文档中,它将改为在编译时链接对象,从而生成真正的静态可执行文件。它适用于不支持动态加载的系统。

如果您使用它来编译和链接这些对象,libtool 将运行它的一些脚本,并创建必要的数据结构,并且我相信执行重整和去重,以允许重复的符号名称。

即使在查看 libtool 源代码中的示例、阅读其整个文档并查看测试套件中的相关测试(例如测试 118 和 120)之后,我仍然无法这样做。

除了 libtool 本身,在我能找到的任何地方基本上都没有提到这个功能。我确实设法在 Graphviz 中看到它以一种对我来说过于复杂的方式使用,但也没有什么文档。

我真的不是一个程序员,更像是一个修补匠。使用 libltdl 作为标准 dlopen/dlsym 的包装器对我来说很容易。

我认为我的主要问题是弄清楚如何为预先打开的对象返回正确的句柄,尽管我可能做错了其他事情。

文档指出 lt_dlopen 可以在预加载的静态模块上工作,但它似乎不接受我能想象到的任何可能的引用。

我也宁愿不必调用 libtool,而是 c'est la vie。

我没有费心将我在代码方面尝试过的任何内容(在示例中)包括在内,因为我已经尝试了如此混乱的东西,我觉得展示它真的会让人感到困惑。

当前的 libtool 文档: https://www.gnu.org/software/libtool/manual/libtool.html

【问题讨论】:

    标签: c compilation linker static-linking libtool


    【解决方案1】:

    显然 libtool 要求 .la 文件存在并正确声明其 rpath,即使它不会用于这个真正静态的二进制文件中的任何内容。

    Libtool 的文档清楚地表明,您的“模块”文件应包含以下预处理器宏,以便导出所有符号。

    #define SYMBOL SOURCEFILENAME_LTX_SYMBOL
    

    在我的例子中,这导致 bromine.c 和chloro.c 分别具有以下内容。

    #define chemical_name bromine_LTX_chemical_name
    #define chemical_name chlorine_LTX_chemical_name
    

    仍然假设我的问题中的代码存储库,以下命令是如何使用 libtool 自动 dlpreopen 二进制文件的示例。

    libtool --mode=compile gcc -static -fPIC -fno-plt -c bromine.c
    
    libtool --mode=compile gcc -static -fPIC -fno-plt -c chlorine.c
    
    libtool --mode=link gcc -all-static -fPIC -fno-plt -o bromine.la -rpath $PWD -module -no-undefined -avoid-version bromine.lo
    
    libtool --mode=link gcc -all-static -fPIC -fno-plt -o chlorine.la -rpath $PWD -module -no-undefined -avoid-version chlorine.lo
    

    但是,对我来说,跳过每个 libtool 步骤并简单地在 main.c 本身中声明所需的结构数组要简单得多。将重新定义的函数/符号声明为 extern int,无论其类型如何,并创建一个名为 lt__PROGRAM__LTX_preloaded_symbols 的 lt_dlsymlist 数组。第一个元素是程序本身,最后一个元素是 {0, (void *) 0}。在这两者之间,一个结构行将声明 dlpreopened 对象/静态存档的基本名称,文件后缀为“.a”。

    无论它是 .a、.o、.c 还是任何其他文件,它都会有 .a 后缀。下一个结构将是您希望使用的从中导出的所有符号,然后,如果您愿意,还有另一个文件名、它的符号等等。符号名称将使用 (void *) &SYMBOL 而不是 (void *) 0 ,就像所有其他字段一样。

    extern int bromine_LTX_chemical_name();
    extern int chlorine_LTX_chemical_name();
    
    const lt_dlsymlist lt__PROGRAM__LTX_preloaded_symbols[] ={ 
      {"@PROGRAM@", (void *) 0},
      {"chlorine.a", (void *) 0},
      {"chlorine_LTX_chemical_name", (void *) &chlorine_LTX_chemical_name},
      {"bromine.a", (void *) 0},
      {"bromine_LTX_chemical_name", (void *) &bromine_LTX_chemical_name},
      {0, (void *) 0}
    };
    

    最后,lt_dlopen 不反映 lt_dlsymlist 声明——理想情况下,您将只调用文件的基本名称,而不调用它的扩展名。例如

    handle = lt_dlopen("chlorine");
    

    不是

    handle = lt_dlopen("chlorine.a")
    

    但是,我相信无论您提供什么扩展,它都会起作用,因为 lt_dlopen 函数会剥离扩展。

    按照上述规定的方式进行操作可以将您的编译减少到一行并完全避免使用 libtool。例如

    gcc -static -Wl,-static -fPIC -fno-plt -Wl,-z,now,--no-undefined -o main main.c bromine.c chlorine.c -lltdl -ldl
    

    我还验证了这会生成一个真正的静态二进制文件,方法是链接到 libltdl 的调试版本,其中包含所有内容,但预先打开(没有 libdl 等)。

    $./main HOBr HOCl
    
    loaders: lt_preopen
    try_dlopen (bromine, (null))
    tryall_dlopen (bromine.a, lt_preopen)
    Calling lt_preopen->module_open (bromine.a)
      Result: Success
    try_dlopen (chlorine, (null))
    tryall_dlopen (chlorine.a, lt_preopen)
    Calling lt_preopen->module_open (chlorine.a)
      Result: Success
    The IUPAC name of HOBr is hypobromous acid.
    The IUPAC name of HOCl is hypochlorous acid.
    

    【讨论】:

    • 哇,这个答案很及时。几天前我在谷歌上搜索,找不到任何好的参考资料。您能否使用建议的解决方案更新链接的存储库?我很想看看这一切是如何协同工作的。
    • 我尝试按照您的示例进行操作,但似乎 libltdl 没有看到 lt__PROGRAM__LTX_preloaded_symbols - 它没有成为 preloaded_symlists 的一部分。
    • 是的,我会相应地更新存储库,可能在子文件夹中。我不打算展示如何使用 libtool 来做——只是如何自己做 + 链接 libltdl。
    • 是的,现在我很高兴让它以任何方式工作。我通过 libtool 尝试了-dlpreopen,以及如上所示的手动方法,但每次都出现同样的问题 - 符号被链接,但它们没有出现在 preloaded_symlists 中,所以 libltdl 一直试图回退到 dlopen。
    • 其实...我想我看到了我在非 libtool 版本中遗漏的内容,我可能在此过程中调用LTDL_SET_PRELOADED_SYMBOLS 为时已晚。
    猜你喜欢
    • 2016-02-16
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多