【问题标题】:How can I make GCC compile the .text section as writable in an ELF binary?如何让 GCC 将 .text 部分编译为在 ELF 二进制文件中可写?
【发布时间】:2012-02-06 08:23:58
【问题描述】:

我希望能够在我正在使用的库中动态更改可执行代码。本质上,如果不需要某些功能,我想动态地删除它们。

但是,我正在使用的库的 .text 部分是不可写的(大多数程序都是如此)。我有该库的源代码,因此想使用 GCC 将其编译为可写。

有没有办法做到这一点?

【问题讨论】:

  • 这样做的实际原因是什么?

标签: c++ gcc elf


【解决方案1】:

可能最好的方法是使用系统特定的 API 来更改您希望修改的内存的可写性,修改它,然后再改回来。

在 unix 系列系统上,您需要查看 mprotect。请记住,它处理的块是系统页面大小的倍数。可能是 4096,因此可能需要四舍五入。

【讨论】:

  • 嗯,我正在使用 Genode 操作系统并尝试重新编写动态链接器的 map_object() 函数。 mprotect() 是否适用于程序加载阶段的早期?
【解决方案2】:

在编译的库上尝试objcopy --writable-text,根据文档它应该使 .text 可写。

【讨论】:

    【解决方案3】:

    在一般意义上,mprotectsys/mman.h(检查http://linux.die.net/man/2/mprotect)下的首选(在符合 POSIX 的系统上)。只需获取进程可执行部分的地址和系统页数,然后调用mprotect请求权限权限;写信给它;然后再次调用mprotect释放写权限。

    但是,如果这意味着在速度绝对重要的低级例程上(或mprotect 不可用),那么您将希望编译库,其.text 部分可写为调用@ 987654329@ 最有可能发出转换后备缓冲区 (TLB) 刷新(尤其是在多处理器环境中)可能并且将导致瓶颈。如果特定系统通过分页使用硬件保护(现在几乎所有),那么更改保护的唯一方法是执行 TLB 刷新,必须在每个引用的页面、引用的页表(页组)、引用页目录(页表组)和每个处理器。最重要的是,这必须在环 0 中执行,这需要一个系统调用,它只是将樱桃放在顶部以获得开销。

    在后一种情况下,最简单的解决方案是正常编译库,然后用--writable-text objcopy 编译它(如ggiroux 所述)。

    另一种解决方案是自己定义链接器映射文件linker.ld。然后,您可以明确指定任何部分的权限。它并不太复杂;如果依赖于系统。请参阅http://www.math.utah.edu/docs/info/ld_3.html 上的文档。您还可以查看系统提供的linker.ld 文件并从那里修改它。将-Wl,--verbose 传递给gcc 将指示链接器吐出所有相关文件(包括其默认的linker.ld),然后您可以在其中修改.text 部分的权限并使用新的linker.ld 重新编译库(永远)文件。

    总而言之,我的建议是按照最后一段所述进行,并使用稍微修改的链接器脚本编译您的库。

    【讨论】:

      【解决方案4】:

      我发现的最简单的方法(binutils 2.22)是用 -N 链接 这可以通过 gcc -XN 传递给 gcc

      【讨论】:

      • 这个选项的长格式是--omagic。是的,它使 .text 可读取 + 可写,就像 .data。
      猜你喜欢
      • 2015-11-07
      • 1970-01-01
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      • 2012-05-15
      • 2014-10-19
      相关资源
      最近更新 更多