如何让 GCC 将 .text 部分编译为可写在 ELF 二进制文件中?
我希望能够动态更改我正在使用的库中的可执行代码.本质上,如果不需要某些功能,我想动态 NOP.
I would like to be able to dynamically change the executable code within a library I am using. Essentially, I would like to dynamically NOP out certain functions if they are not needed.
但是,我使用的库的 .text 部分是不可写的(大多数程序都是这种情况).我有库的源代码,因此想使用 GCC 将其编译为可写的.
However, the .text section of the library I am using is not-writable (as is the case for most programs). I have the source code of the library and so would like to use GCC to compile it as writable.
有没有办法做到这一点?
Is there a way to do this?
推荐答案
在一般意义上,mprotect
是 sys/mman.h<下的首选选择(在符合 POSIX 的系统上)/code>(检查 http://linux.die.net/man/2/mprotect).只需获取进程可执行部分的地址和系统页数,然后调用
mprotect
请求权限;写信给它;然后,再次调用mprotect
释放写权限.
In the general sense, mprotect
is the perferred choice (on POSIX conforming systems) under sys/mman.h
(check http://linux.die.net/man/2/mprotect). Simply get the address and system page count of the executable section of your process and call mprotect
to request permission permissions; write to it; then, call mprotect
again to release write permission.
但是,如果这是在速度绝对重要的低级例程上(或 mprotect
不可用),那么您将需要使用其 编译库.text
部分可写为调用 mprotect
最有可能发出转换后备缓冲区 (TLB) 刷新(尤其是在多处理器环境中)会导致瓶颈.如果特定系统通过分页使用硬件保护(现在几乎所有都是这样),那么改变保护的唯一方法是执行 TLB 刷新,它必须在每个被引用的页面、被引用的页表(页面组)、被引用的页面上执行页目录(页表组)和每个处理器.最重要的是,这必须在环 0 中执行,这需要一个系统调用,它只是将樱桃放在最上面以增加开销.
However, if this is meant to be on low-level routines where speed is of absolute importance (or mprotect
is not available) then you'll want to compile the library with its .text
section writable as calling mprotect
most likely issues a Translation Lookaside Buffer (TLB) flush that (especially in a multi-processor environment) can and will cause a bottleneck. If the specific system is using hardware protection via paging (which nearly all are now) then the only way to change the protection is by doing a TLB flush which must be executed on every referenced page, referenced page table (group of pages), referenced page directory (group of page tables) and every processor. To top it off, this must be executed in ring 0 which requires a syscall which just puts the cherry on top for overhead.
在后一种情况下,最简单的解决方案是正常编译库,然后使用 --writable-text
(如 ggiroux 所述)objcopy
它.
In the latter case, the easiest solution would be to compile the library normally and then objcopy
it with --writable-text
(as mentioned by ggiroux).
另一种解决方案是自己定义链接器映射文件 linker.ld
.然后您可以明确指定任何部分的权限.它不是太复杂;如果依赖于系统.请参阅 http://www.math.utah.edu/docs/info 上的文档/ld_3.html.您还可以查看系统提供的 linker.ld
文件并从那里修改它.将 -Wl,--verbose
传递给 gcc 将指示链接器吐出所有相关文件(包括其默认的 linker.ld),然后您可以在其中修改 .text 部分的权限并重新编译库(永远)使用新的 linker.ld
文件.
Another solution would be to define the linker map file linker.ld
yourself. Then you may specify permissions of any section explicitly. Its not too complicated; if system-dependent. Refer to documentation at http://www.math.utah.edu/docs/info/ld_3.html. You could also look at your system provided linker.ld
file and modify it from there. Passing -Wl,--verbose
to gcc will instruct the linker to spit out all relevant files (including its default linker.ld) in which you could then modify the permissions of the .text section and recompile the library (forevermore) using the new linker.ld
file.
总而言之,我的建议是按照最后一段所述进行操作,并使用稍微修改的链接器脚本编译您的库.
To summarize, my recommendation would be to do as the last paragraph states and compile your library with a slightly modified linker script.
相关文章