我有一个工作程序,用dlopen
加载插件。
新的要求:在代码的某一点,我给了一个指针,我需要testing这个指针是指向代码还是插件的静态数据。
bool is_pointer_into_plugin(void *p, void *handle);
等价地,我需要检索指针指向的插件(如果有的话)。 我还需要知道指针是指向主程序的代码还是静态数据(最好是区分只读区域和读写区域)。
void *handle plugin_containing_pointer(void *p);
等同地,我需要能够检索插件映射的范围(地址和大小)。 我也需要这个主要程序的信息。
我如何实现is_pointer_into_plugin
,或者plugin_containing_pointer
,或者其他什么东西?
如果需要的话,我可以改变对dlopen
的调用。 查找应该尽可能快,加载时间代码不需要很快。 在单独的进程中运行插件并通过共享内存进行通信不是一种select。
我的程序运行在Linux(和Windows,但这是另一个问题 )。 未来的其他Unix系统(至less到OSX)的便携性将是一个加号。
一种方式(完全特定于Linux)是解析/proc/self/maps
(另请参阅了解Linux / proc / id / maps ),它描述了进程的内存映射。 每个动态加载的库都有一个或多个条目(通常为3),它提供了其地址范围,访问权限和文件名。 下面是一个显示C库映射的例子:
f7622000-f7775000 r-xp 00000000 08:06 6950542 /lib/tls/i686/cmov/libc-2.11.1.so f7775000-f7777000 r--p 00153000 08:06 6950542 /lib/tls/i686/cmov/libc-2.11.1.so f7777000-f7778000 rw-p 00155000 08:06 6950542 /lib/tls/i686/cmov/libc-2.11.1.so
第一列给出地址范围,第二列给出权限,第三列给出库(或主要可执行文件)的完整路径。 最后一列或最后一列不是文件名的条目对应于非文件支持的区域(堆栈,堆等)。 权限r-xp
表示代码, r--p
是只读数据, rw-p
是可变数据。
如果插件文件被重命名或删除,这将反映在/proc/self/maps
。 如果发生这种情况,为避免出现问题,请在调用( dlopen
)后尽快阅读信息; 注意到有一个不可避免的竞争条件。 插件文件可以通过设备和inode进行跟踪:打开文件,在/dev/fd/NUM
上调用dlopen
,读取/proc/self/maps
,比较第4列和第5列与fstat
获得的值。
一种方法是,如果你足够的控制插件 – 玩连接器脚本应该做的伎俩 – 将是确保在开始和结束指定的符号 – 即类似于__executable_start
, _etext
, _edata
, _end
,然后使用dlsym得到他们的地址。 您可能可以在所有带有动态库的系统上获得相同的效果,从而将大部分系统依赖关系推向构建方面。