我希望能够动态更改我正在使用的库中的可执行代码.从本质上讲,如果不需要,我想动态地删除某些功能.
但是,我使用的库的.text部分是不可写的(大多数程序都是如此).我有库的源代码,因此希望使用GCC将其编译为可写.
有没有办法做到这一点?
在一般意义上,mprotect
是尤佳的选择(对符合POSIX系统)下sys/mman.h
(检查http://linux.die.net/man/2/mprotect).只需获取进程可执行部分的地址和系统页数,然后调用mprotect
请求权限权限; 写信给它; 然后,mprotect
再次调用以释放写入权限.
但是,如果这意味着在速度极为重要(或mprotect
不可用)的低级例程中,那么您将需要编译其.text
可写部分的库,因为调用mprotect
最有可能发出转换后备缓冲区(TLB)刷新(特别是在多处理器环境中)可以并且将导致瓶颈.如果特定系统通过分页使用硬件保护(几乎所有都是现在),则更改保护的唯一方法是执行TLB刷新,必须在每个引用的页面上执行,引用的页面表(页面组),引用页面目录(页表组)和每个处理器.最重要的是,这必须在环0中执行,这需要一个系统调用,它只是将樱桃放在顶部以便开销.
在后一种情况下,最简单的解决方案是正常编译库,然后objcopy
使用--writable-text
(如ggiroux所述).
另一种解决方案是自己定义链接器映射文件linker.ld
.然后,您可以明确指定任何部分的权限.它不太复杂; 如果系统依赖.请参阅http://www.math.utah.edu/docs/info/ld_3.html上的文档.您还可以查看系统提供的linker.ld
文件并从那里进行修改.传递-Wl,--verbose
给gcc将指示链接器吐出所有相关文件(包括其默认的linker.ld),然后您可以在其中修改.text部分的权限并使用新linker.ld
文件重新编译库(永远).
总而言之,我的建议是在最后一段中指出并使用略微修改的链接描述文件编译您的库.
也许最好的方法是使用系统特定的 API 来更改您想要修改的内存的可写性,修改它,然后将其改回来。
在 Unix 系列系统上,您需要查看mprotect
. 请记住,它处理的块是系统页面大小的倍数。可能是 4096,因此可能需要四舍五入。