c-是否可以根据/proc/self/maps中的信息执行munmap



我需要能够取消映射通过我链接的一些库打开的文件。需要这样做的原因是,这些库所做的映射包含对模块的引用,这些模块可能需要在程序执行时重新加载(可能是长时间执行)。问题是,当我的进程持有引用时,无法卸载模块。

我已经编写了C代码来解析proc/self/maps中的信息,以便读取映射的地址范围并计算其长度。我通过从结束地址减去开始地址来计算长度,然后将开始地址和计算的长度作为相应的参数传递给munmap。问题是munmap因EINVAL(无效参数)而失败。

我已经用sysconf(_SC_PAGESIZE)检查了我的机器使用的页面的大小,它返回4096,这是我计算的长度值。GNU手册说munmap可能会与EINVAL一起失败,如果:

给定的内存范围超出用户mmap范围或不是页面对齐。

我是错过了什么,还是根本不可能?我的最后手段是仔细梳理系统调用,并通过strace检查每个mmap,但我希望这是最后手段,谢谢。

您选择的方法不起作用,但不一定是因为您认为的原因。然而,有一种方法,所以请继续阅读。。。

我需要能够取消映射通过我链接的一些库打开的文件。

一旦让ELF加载程序(例如ld.linux.so)为您加载库,您就失去了控制。

您可以而不是只是取消映射区域[,而不考虑方法的]。加载器已经为这些库进行了重新定位和符号链接。取消映射会删除该区域,但现在所有内容都会中断,因为链接器设置的各种指针现在指向空白。装载机将不知道你做了什么。

那么,你将如何重新映射库的新版本[以及在内存中的位置]?即使将其重新映射到同一地址也不能保证,因为您无法调整加载程序已经完成的操作。

需要这样做的原因是,这些库所做的映射包含对模块的引用,这些模块可能需要在程序执行时重新加载(可能是长时间执行)。

大多数需要更新到新版本库的程序只需重新执行它们自己。如果需要保留数据,可以制定一个转储/恢复机制。

但是,如果您确实想卸载/加载较新的库版本,可以使用动态链接来完成此操作。

不要使用ld链接与(例如)libA,请离开ld命令行,让程序自己加载libA

您可以使用dlopen/dlsym/dlclose打开/加载您控制下的库。

您必须跟踪符号表,但更改为新版本很容易。当您想要新版本时,只需执行dlclose,然后执行dlopen。您必须重新进行dlsym调用才能获得更新的地址,但所有这些都相当简单且标准的

问题是,当我的进程持有引用时,无法卸载模块。

原因是ELF加载程序做到了这一点。使用dlopen等,您不会遇到同样的问题。

是的,这是可能的。我仔细查看了我的代码;在传递映射到CCD_ 18的起始地址时,我有一些误解。最初,我将起始地址读取为一个无符号的long-long,出于某种原因,在调用munmap时,我将该值转换为十六进制字符串,而不是仅转换为空指针。本质上:

/* Values assigned here are really read from /proc/self/maps */
unsigned long long vm_start = 140013986873344;
unsigned long long vm_end   = 140013986877440;
unsigned long long length = vm_end - vm_start;
munmap((void *)vm_start, length);

最新更新