【问题标题】:How can I force the order of functions in a binary with the gcc toolchain?如何使用 gcc 工具链强制执行二进制文件中的函数顺序?
【发布时间】:2011-07-07 16:53:22
【问题描述】:

我正在从几个源文件和库中构建一个静态二进制文件,并且我想控制将函数放入生成的二进制文件的顺序。

背景是,我有与此二进制文件中的偏移量相关联的外部代码。现在如果我改变源,所有的偏移量都会改变,因为 gcc 可能会决定对函数进行不同的排序,所以我想把引用的函数以固定的顺序放在开头,这样它们的偏移量就保持不变......

我查看了 ld 的文档,但找不到任何关于函数顺序的信息。

我发现的唯一东西是-fno-toplevel-reorder,它并没有真正帮助我。

【问题讨论】:

  • 最后,我选择实现一个(脚本生成的)跳转表,这样我就不再关心移动函数了。这两个答案也可能会起作用。

标签: gcc linker gnu


【解决方案1】:

确实没有干净可靠的方法可以将函数强制到特定地址(入口函数除外),甚至强制具有特定顺序的函数(如果您可以强制执行 order仍然不意味着更改源时地址保持不变!)。

我看到的最大问题是,即使可以将一个函数修复到 some 地址,也绝对不可能将它们全部修复到已经存在的地址需要外部程序(假设您无法修改此程序)。如果这真的奏效了,那将是完全的巧合和纯粹的运气。

在其他程序期望的地址处提供蹦床几乎是最简单的,并且具有这些指向的实际功能(无论它们可能在哪里)。这将要求您的代码使用不同的基地址,因此实际的程序代码不会与蹦床发生冲突。

几乎可以通过三件事为函数提供固定地址:

  1. 您可以使用__attribute__ ((section ("some name"))) 将每个不允许移动的函数放在其适当的部分。不幸的是,.text 总是作为第一部分出现,所以如果.text 中的任何内容发生变化,导致大小超出 512 字节边界,您的偏移量就会发生变化。默认情况下(但见下文),您无法在 .text 之前开始某个部分。
  2. -falign-functions=n 命令行选项可让您将函数与边界对齐。通常这是大约 16 个字节。现在,您可以选择一个较大的值,例如 1024。这将浪费大量空间,但也可以确保只要函数只是适度更改,以下函数的地址将保持不变。显然,它仍然不能阻止编译器/链接器在需要时重新排序整个块(尽管-fno-toplevel-reorder 至少会部分阻止这种情况)。
  3. 如果您愿意编写自定义linker script,您可以为每个部分分配一个起始地址。这些是虚拟内存地址,而不是可执行文件中的位置,但我假设硬链接也适用于 VMA(基于默认映像库)。所以这可能有点工作,虽然有很多麻烦而且不是很漂亮。
    在编写自己的链接器脚本时,您还可以考虑将不能移动到它们自己的部分中的函数将这些部分移动到可执行文件的开头(.text 前面),因此更改在.text 中不会移动你的函数。

更新: “gcc”标签表明您可能以 *NIX 为目标,所以这可能对您没有帮助,但是...如果您可以选择使用 COFF,美元符号部分可能会起作用(该信息可能对其他人,无论如何)。

我今天偶然发现了这个(强调我的):

“$”字符(美元符号)在目标文件的部分名称中有特殊的解释。在确定将包含对象部分内容的图像部分时,链接器会丢弃“$”及其后面的所有字符。因此,名为 .text$X 的对象部分实际上有助于图像中的 .text 部分。但是,“$”后面的字符决定了对图像部分的贡献的顺序。具有相同对象部分名称的所有贡献在图像中连续分配,贡献块按对象部分名称按词汇顺序排序。 因此,在 .text$W 贡献之后和 .text$Y 贡献之前,目标文件中具有部分名称 .text$X 的所有内容最终都在一起

如果文档没有说谎(如果我没看错),这意味着您应该能够将所有想要位于前面的函数打包到一个部分 .text$A 中,并将其他所有内容打包到 @ 987654333@,它应该这样做。

【讨论】:

  • 您对偶然发现的文字有参考吗?谢谢!
  • 四年后?当然 :-) 这是来自 “Microsoft Portable Executable and Common Object File Format” 的引用。原件在 MS Word 中,许多网站上都提供了转换为 PDF 的更易读的版本,例如 zeros.googlecode.com/files/pecoff_v8.pdf
  • 优秀...我在 Linux 上进行开发,所以您的参考资料的第一个字为我节省了浪费的精力...谢谢!
  • .text$X 对我不起作用,它将函数设置在一个名为 .text$X 的新部分中。您必须检查链接描述文件如何创建最终的 .text 部分并在需要时对其进行更改。我找到了Here
【解决方案2】:

使用-ffunction-sections 构建您的代码——这会将每个函数放入自己的部分。

如果您使用的是 GNU-ld,则链接器脚本为您提供绝对控制权,但这是一个非常特定于平台且有些痛苦的解决方案。

更好的解决方案可能是在gold 上使用recent work,它可以完全按照您正在寻找的功能排序。

【讨论】:

    【解决方案3】:

    其中很多来自函数在文件中的顺序以及链接时文件在命令行上的顺序。

    在你的外部代码可以找到的代码中嵌入一些东西,一个带有一些 ascii 代码和函数地址的 const 结构,然后无论编译器将函数放在哪里,你都可以找到它们。

    或者使用正常的 .dll 或 .so 机制,而不必乱用它。

    【讨论】:

      【解决方案4】:

      根据我的经验,gcc -O0 将修复函数的二进制顺序以匹配源代码中的顺序。

      但是正如其他人所提到的,即使顺序是固定的,偏移量也会随着您修改源代码或升级工具链而改变。

      【讨论】:

        猜你喜欢
        • 2015-11-07
        • 1970-01-01
        • 2012-05-26
        • 2011-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-23
        • 1970-01-01
        相关资源
        最近更新 更多