如何使用 gcc 工具链强制执行二进制文件中的函数顺序? [英] How can I force the order of functions in a binary with the gcc toolchain?

查看:12
本文介绍了如何使用 gcc 工具链强制执行二进制文件中的函数顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building a static binary out of several source files and libraries, and I want to control the order in which the functions are put into the resulting binary.

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

The background is, I have external code which is linked against offsets in this binary. Now if I change the source, all the offsets change because gcc may decide to order the functions differently, so I want to put the referenced functions at the beginning in a fixed order so their offsets stay unchanged...

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

I looked through ld's documentation but couldn't find anything about order of functions.

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

The only thing i found was -fno-toplevel-reorder which doesn't really help me.

推荐答案

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

There is really no clean and reliable way of forcing a function to a particular address (except for the entry function) or even forcing functions having a particular order (and if you could enforce the order that would still not mean that the addresses stay the same when the source is changed!).

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

The biggest problem that I see is that even if it may be possible to fix a function to some address, it will be sheer impossible to fix all of them to exactly the addresses that the already existing external program expects (assuming you cannot modify this program). If that actually worked, it would be total coincidence and sheer luck.

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

It might be almost easiest to provide trampolines at the addresses that the other program expects, and having the real functions (whereever they may be) pointed to by these. That would require your code to use a different base address, so the actual program code doesn't collide with the trampolines.

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

There are three things that almost work for giving functions fixed addresses:

  1. 您可以使用 __attribute__ ((section ("some name"))) 将每个不允许移动的函数放在相应的部分中.不幸的是,.text 总是作为第一部分出现,所以如果 .text 中的任何内容发生变化,导致大小超出 512 字节边界,您的偏移量就会发生变化.默认情况下(但见下文),您无法在 .text 之前开始某个部分.
  2. -falign-functions=n 命令行选项可让您将函数与边界对齐.通常这是大约 16 个字节.现在,您可以选择一个较大的值,例如 1024.这将浪费大量空间,但也可以确保只要函数只是适度更改,以下函数的地址将保持不变.显然,它仍然不能阻止编译器/链接器重新排序整个块(尽管 -fno-toplevel-reorder 将至少部分阻止这种情况).
  3. 如果您愿意编写自定义 链接器脚本,您可以为每个部分分配一个起始地址.这些是虚拟内存地址,而不是可执行文件中的位置,但我假设硬链接也适用于 VMA(基于默认映像库).所以这可能有点工作,虽然有很多麻烦而且不是很漂亮.
    在编写自己的链接器脚本时,您还可以考虑将不能移动到自己的部分中的函数将这些部分移动到可执行文件的开头(在 .text),因此 .text 中的更改不会移动您的函数.
  1. You can place each function that isn't allowed to move in its proper section using __attribute__ ((section ("some name"))). Unluckily, .text always appears as the first section, so if anything in .text changes so the size is bumped over the 512 byte boundary, your offsets will change. By default (but see below) you can't get a section to start before .text.
  2. The -falign-functions=n commandline option lets you align functions to a boundary. Normally this is something around 16 bytes. Now, you could choose a large value like for example 1024. That will waste an immense amount of space, but it will also make sure that as long as functions only change moderately, the addresses of the following functions will remain the same. Obviously it still does not prevent the compiler/linker from reordering entire blocks when it feels like it (though -fno-toplevel-reorder will prevent this at least partially).
  3. If you are willing to write a custom linker script, you can assign a start address for each section. These are virtual memory addresses, not positions in the executable, but I assume the hard linking works with VMAs (based on the default image base) too. So that could kind of work, although with much trouble and not in a pretty way.
    When writing your own linker script, you could also consider putting the functions that must not move into their own sections and moving these sections at the beginning of the executable (in front of .text), so changes in .text won't move your functions around.

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

Update: The "gcc" tag suggests that you probably target *NIX, so again this is probably not going to help you, but... if you have the option to use COFF, dollar-sign sections might work (the info might be interesting for others, in any case).

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

I just stumbled across this today (emphasis mine):

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

The "$" character (dollar sign) has a special interpretation in section names in object files. When determining the image section that will contain the contents of an object section, the linker discards the "$" and all characters that follow it. Thus, an object section named .text$X actually contributes to the .text section in the image. However, the characters following the "$" determine the ordering of the contributions to the image section. All contributions with the same object-section name are allocated contiguously in the image, and the blocks of contributions are sorted in lexical order by object-section name. Therefore, everything in object files with section name .text$X ends up together, after the .text$W contributions and before the .text$Y contributions.

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

If the documentation does not lie (and if I'm not reading wrong), this means you should be able to pack all the functions that you want located in the front into one section .text$A, and everything else into .text$B, and it should do just that.

这篇关于如何使用 gcc 工具链强制执行二进制文件中的函数顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆