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

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

我已经编写了C代码来parsingproc/self/maps中的信息,以读取映射的地址范围并计算其长度。 我通过从结束地址减去起始地址来计算长度,然后将起始地址和计算长度作为各自的parameter passing给munmap 。 问题是munmap失败与EINVAL(无效的参数)。

我已经检查了我的机器使用sysconf(_SC_PAGESIZE)的页面大小,它返回了4096,这是我计算的长度的值。 GNU手册指出,如果出现以下情况, munmap可能会失败并显示EINVAL:

给出的内存范围在用户mmap范围之外或者不是页面alignment的。

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

你选择的方法将不起作用,但不一定是你想的原因。 然而,有一种方法,所以阅读…

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

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

不能只是取消映射区域[ 不管方法]。 加载器已经完成了这些库的重定位和符号链接。 unmap删除了该区域,但是现在一切都中断了,因为链接器设置的各种指针现在指向空白空间。 装载机将不知道你做了什么。

那么,你将如何重新映射库的新版本[和内存中的位置]? 即使重新映射到相同的地址也不能保证,因为你无法调整加载器已经完成的事情。

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

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

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

而不是使用ld链接 (比如) libA ,离开ld命令行并让程序自己加载libA

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

您将不得不跟踪符号表,但更改为新版本很容易。 当你想要新版本的时候,简单地做dlclose然后dlopen 。 您将不得不重新调用dlsym来获取更新的地址,但这一切都相当简单和标准

问题是模块不能被卸载,而我的进程持有一个引用。

原因是ELF装载机做到了这一点。 随着dlopen et。 你没有同样的问题。

对的,这是可能的。 我仔细看了一下我的代码。 当把映射的开始地址传递给munmap时,有一些误解。 我最初读了一个无符号long long的开始地址,出于某种原因,我把这个值转换成了一个十六进制字符串,而不是在调用munmap时将其转换为void指针。 在本质上:

 /* 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);