使用gcc和GNU ld链接器,生成一个强制使用固定地址/偏移量的静态链接代码。

4
我有一个(相对较大的)静态二进制文件,我想用另一个函数替换其中一个函数。鉴于函数的复杂性,我想使用C和gcc编译剪接函数,然后只需替换代码即可。为了使其有效运行,我需要以某种方式强制执行函数和我将访问的某些全局变量位于特定偏移量处。如何使用gcc和ld完成这项工作?
一个非常简单的示例-给出这样的程序:
int global = 42;
int get_global() { return global; }

int main() {
    return get_global();
}

编译和反汇编此函数产生以下结果:
00000000004004ad <get_global>:
  4004ad:       55                      push   %rbp
  4004ae:       48 89 e5                mov    %rsp,%rbp
  4004b1:       8b 05 61 04 20 00       mov    0x200461(%rip),%eax        # 600918 <global>
  4004b7:       5d                      pop    %rbp
  4004b8:       c3                      retq   

请注意:
- 全局变量的地址为0x600918 - get_global函数的地址为0x4004ad
基本上,问题是:如何使用gcc和ld为一个函数生成代码,使其能够:
- 引用全局变量和/或函数确切地在上述地址处 - 从我想要它开始(我特别感兴趣的是从地址0x4004ad开始,这样它就可以潜在地用于覆盖现有的get_global实现)
我认为可能可以通过一些指定给函数原型和/或全局变量的编译器特定属性或编译指示来实现,实际上,gcc有一些变量属性控制函数/变量在某些部分的打包和放置, 但无法指定固定的地址。
我强烈怀疑可以通过手动调用ld并使用一些ld链接器脚本魔法来完成,但是快速查看其文档对我来说似乎没有任何提示。我有什么遗漏吗?
肯定相关:C中的固定地址变量
2个回答

1

我曾经见过这样的做法,使用ASM文件将变量固定到特定地址。这主要用于共享内存中使用的全局变量。

在任何其他源文件中,你显然需要声明全局变量extern

因此,编写一个只包含变量的短ASM文件,并将其与其余代码一起编译和链接。


听起来不错,我要试一试。虽然这只解决了任务的一部分(1),即通过固定地址引用其他符号,但不允许(2)生成从特定位置开始的函数。 - GreyCat

1
GNU ld允许您使用自定义链接器脚本,可能可以实现您想要的功能。许多嵌入式项目都会这样做,将常量放置在ROM中的特定位置。如果您使用__attribute__((section("foo")))将变量放置在单独的部分中,您可以将该部分放置在任何位置,并在链接器脚本中指定地址。
例如(来自我的一个项目,这是TI的修改脚本):
MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}

SECTIONS
{
    .text :
    {
        _text = .;
        KEEP(*(.isr_vector))
        *(.text*)
        _devid_start = ALIGN(4);
        KEEP(*(.devid*))
        sys_devices = .;
        KEEP(*(.device*))
        sys_devices_end = .;
        sys_threads = .;
        KEEP(*(.threads*))
        sys_threads_end = .;
        *(.rodata*)
        _etext = .;
    } > FLASH

    .data : AT(ADDR(.text) + SIZEOF(.text))
    {
        _data = .;
        *(vtable)
        *(.data*)
        _edata = .;
    } > SRAM

    .bss :
    {
        _bss = .;
        *(.bss*)
        *(COMMON)
        _ebss = .;
    } > SRAM
}

所以,正如您在此示例中看到的那样,放入“ .devid *”和“ .device *”部分的所有内容都会自由地合并到“ .text”部分中。结果文件仍然只有3个部分:.text、.data、.bss,您在C源代码中创建的部分将通过此链接器脚本进行合并。如果您想使用托管平台执行此操作,请提取链接器脚本(插入巫术),并使用您的部分合并进行修改。

每个变量一个部分对我来说听起来有点过度,而且更加可疑的是,我几乎想不到任何允许非页面对齐部分的对象格式。你能指导我一些使用这种技术的项目吗? - GreyCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接