我关注的是Linux;我猜我的大部分答案适用于每个POSIX系统;但在MacOSX上,dlopen
需要 .dylib
动态库 文件,而不是 .so
共享对象。
一个程序甚至可以在某个临时文件 /tmp/foo1234.c
中发出一些 C 代码,通过某个 gcc -O -shared -fPIC /tmp/foo1234.c -o /tmp/foo1234.so
命令将该 /tmp/foo1234.c
编译成共享库 /tmp/foo1234.so
并在程序运行时生成和执行,然后也许会删除 /tmp/foo1234.c
文件(因为它不再需要),并 dlopen
那个 /tmp/foo1234.so
(也许在 dlopen
后甚至会删除 /tmp/foo1234.so
),所有这些都在同一个进程中完成。我的 GCC MELT 插件和 Bigloo 都是这样做的,GCCJIT 库正在做类似的事情。
总的来说,你的任务是不可能的,甚至没有意义。
有没有一种可靠的方法可以获取这些信息而不会出现假阳性?
不,没有可靠的方法可以获取这样的信息而不会出现假阳性(你可以证明等同于停机问题,或者其他不可判定问题)。另请参见 Rice定理。
在实践中,大多数dlopen
发生在某些配置提供的插件上。在配置文件中可能没有确切地命名为这样(例如,一些Foo
程序可能有一个约定,即在某个foo.conf
配置文件中命名为bar
的插件由foo-bar.so
插件提供)。
然而,您可能会发现一些启发式的近似方法。大多数执行某些
dlopen
的程序在插件中有一些请求特定符号名称的插件约定。您可以搜索定义这些名称的共享对象。当然,您会得到假阳性。
例如,
zsh shell接受名为
zsh模块的插件。
example模块显示期望在zsh模块中使用
enables_
、
boot_
、
features_
等函数。您可以使用
nm -D
查找提供这些文件(因此找到可能由
zsh
加载的插件)。
我不认为这样的方法是值得的;实际上,你通常应该知道哪些插件适用于
你的系统,根据不同的应用程序进行选择。
顺便提一下,你可以在某个命令的执行过程中使用strace(1)来了解它所做的系统调用,以及它加载的插件。你也可以使用ltrace(1)或pmap(1)(对于某个特定的进程),或者简单地使用cat /proc/1234/maps
来了解它的虚拟地址空间,以及它已经加载的插件-对于一个进程 1234。请参见proc(5)。
注意,在 Linux 上存在
strace
、
ltrace
、
pmap
,但许多 POSIX 系统都有类似的程序。
此外,程序可以在运行时生成一些机器代码并执行它(
SBCL 在每个
REPL交互中都这样做!)。您的程序还可以使用一些
JIT 技术(例如
libjit,
llvm,
asmjit,
GCCJIT 或手写代码...)来实现类似的功能。因此,插件式行为可以在没有
dlopen
的情况下发生(您可以使用
mmap
调用和一些
ELF 重定位处理来模仿
dlopen
)。
补充:
如果你正在安装火狐浏览器的打包版本(例如Debian上的iceweasel
包),那么它的包很可能会处理依赖关系。
dlopen()
载入的库不一定会在ldd
的输出中出现,这并不影响它们被正确地加载和链接。 - mahfind / |xargs file |grep 'ELF .* shared object'
- nwellnhof