如何使用gcc工具链强制二进制函数的顺序?

如何使用gcc工具链强制二进制函数的顺序?,gcc,linker,gnu,Gcc,Linker,Gnu,我正在用几个源文件和库构建一个静态二进制文件,我想控制函数放入结果二进制文件的顺序 背景是,我有一个外部代码,它与这个二进制文件中的偏移量相链接。现在如果我更改源代码,所有偏移量都会更改,因为gcc可能会决定以不同的顺序排列函数,所以我希望以固定的顺序将引用的函数放在开头,以便它们的偏移量保持不变 我查阅了ld的文档,但找不到任何关于函数顺序的信息 我发现的唯一一件事是-fno toplevel reorder,这对我没有帮助。确实没有干净可靠的方法来强制函数到特定的地址(除了entry函数),

我正在用几个源文件和库构建一个静态二进制文件,我想控制函数放入结果二进制文件的顺序

背景是,我有一个外部代码,它与这个二进制文件中的偏移量相链接。现在如果我更改源代码,所有偏移量都会更改,因为gcc可能会决定以不同的顺序排列函数,所以我希望以固定的顺序将引用的函数放在开头,以便它们的偏移量保持不变

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


我发现的唯一一件事是
-fno toplevel reorder
,这对我没有帮助。

确实没有干净可靠的方法来强制函数到特定的地址(除了entry函数),甚至强制函数具有特定的顺序(如果你能强制执行这个命令,那仍然不意味着当源代码改变时地址保持不变!)

我所看到的最大问题是,即使可以将一个函数固定到某个地址,也不可能将所有函数都精确地固定到现有外部程序所期望的地址(假设您无法修改此程序)。如果这真的起作用,那将是完全巧合和纯粹的运气

在另一个程序所期望的地址提供蹦床,并且具有这些地址所指向的实际函数(无论它们在哪里)可能是最容易的。这将要求您的代码使用不同的基址,因此实际的程序代码不会与蹦床冲突

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

  • 您可以使用
    \uuu属性((节(“某些名称”))
    将不允许移动的每个函数放置在其正确的节中。不幸的是,
    .text
    始终显示为第一节,因此如果
    .text
    中的任何内容发生更改,从而使大小超出512字节边界,则偏移量将更改。默认情况下(但请参见下文)在
    .text
    之前,您无法获得要开始的节
  • -falign functions=n
    命令行选项允许您将函数与边界对齐。通常情况下,这大约是16个字节。现在,您可以选择一个大值,例如1024。这将浪费大量空间,但它还将确保只要函数只发生适度变化,foll的地址函数将保持不变。显然,它仍然不能阻止编译器/链接器在感觉需要时对整个块进行重新排序(尽管
    -fno topplevel reorder
    至少可以部分防止这种情况)
  • 如果您愿意编写自定义,您可以为每个部分分配一个开始地址。这些是虚拟内存地址,不是可执行文件中的位置,但我假设硬链接也适用于VMA(基于默认映像库)。因此,这可能是一种工作,尽管有很多麻烦,也不是很好。
    在编写自己的链接器脚本时,还可以考虑将不能移动的函数放入自己的部分<强>和<>强>在可执行文件的开始处移动这些部分(在代码前面>文本< /代码>),因此<>代码>文本< /代码>的更改不会移动您的函数。
  • 更新: “gcc”标签表明您可能以*NIX为目标,因此这可能对您没有帮助,但是……如果您可以选择使用COFF,美元符号部分可能会起作用(无论如何,其他人可能会对该信息感兴趣)

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

    “$”字符(美元符号)在对象文件的节名称中有特殊解释。确定包含对象节内容的图像节时,链接器将丢弃“$”以及其后的所有字符。因此,名为.text$X的对象部分实际上是图像中的.text部分的组成部分。但是,“$”后面的字符确定图像节贡献的顺序。具有相同对象节名称的所有贡献在图像中连续分配,贡献块按对象节名称按词法顺序排序。因此,具有节名称.text$X的对象文件中的所有内容都在.text之后结束$W捐款和.text$Y捐款之前


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

    使用
    -fffunction部分构建代码
    ——这将把每个函数放入自己的部分

    如果您使用的是GNULD,那么链接器脚本将为您提供绝对控制权,但这是一个非常特定于平台的解决方案,而且有点痛苦


    一个更好的解决方案可能是使用on
    gold
    ,它可以精确地对您正在寻找的函数进行排序。

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

    在外部代码可以找到的代码中嵌入一些东西,一个包含一些ascii代码和函数地址的常量结构,然后不管编译器将函数放在哪里,都可以找到它们


    或者使用普通的.dll或.so机制,而不必弄乱它。

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


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

    最后,我选择实现一个(脚本生成的)跳转表,所以我不需要