微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 libtool/libltdl 的 dlpreopening/preloading?

如何解决如何使用 libtool/libltdl 的 dlpreopening/preloading?

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

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

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

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

即使查看了 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

解决方法

显然 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 后缀,无论它是 .a、.o、.c 还是任何其他文件。下一个结构体将是从它导出的所有您希望使用的符号,然后,如果您愿意,还有另一个文件名、它的符号等等。符号名称将使用 (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",{"chlorine_LTX_chemical_name",(void *) &chlorine_LTX_chemical_name},{"bromine.a",{"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.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。