4

I have a (relatively big) static binary in which I'd like to replace a function with the other one. Given the function's complexity, I'd like to use C and gcc to compile spliced-in function and then just replace the code. For this to work, obviously, I need somehow to enforce functions and certain global variables I would access to be located at specific offsets. How do I do that using gcc and ld?

A very simple example - given a program like that:

int global = 42;
int get_global() { return global; }

int main() {
    return get_global();
}

Compiling and disassembling this function yields the following:

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   

Note that:

  • global variable has address 0x600918
  • get_global got 0x4004ad

Basically, the question is, how do I use gcc and ld to produce the code for a function that would:

  • reference global variable and/or function on exactly addresses mentioned
  • start at the address I'd like it to start (I'm particularly interested in starting at address 0x4004ad, so it could potentially be used to splice over existing get_global implementation)

I thought that it could be possible with either some pragmas or compiler-specific attributes specified for function prototypes and/or globals, and, indeed, gcc has some variables attributes that control packing and placement of functions/variables in certain sections, but it's impossible to specify fixed addresses.

I strongly suspect that it could be done with manually invoking ld and using some ld linker script magic, but a quick look at its documentation doesn't seem to ring any bells for me. Am I missing something?

Definitely related: Fixed address variable in C

Community
  • 1
  • 1
GreyCat
  • 16,622
  • 18
  • 74
  • 112

2 Answers2

1

I have seen that done before, using an ASM file for just pinning the variables to specific addresses. This was specifically used for global variable used in shared memory.

In any other source file, you will obviously need to declare the global variable extern

So write a short asm file with just your variables, and compile and link that with the rest of your code.

Soren
  • 14,402
  • 4
  • 41
  • 67
  • Sounds like a plan, gonna try it. Albeit this solves only part (1) of the task, i.e. referencing other symbols by fixed addresses, and does not allow (2) to generate functions that would start at pinpointed location. – GreyCat Aug 13 '14 at 04:36
1

GNU ld allows you to use a custom linker script that might do what you want. A lot of embedded projects do this to place constants at specific locations in ROM. If you put the variables in a separate section using __attribute__((section("foo"))) you can put the section anywhere you want and specify the address in the linker script.

For example (from one of my projects, this is a modified script from 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
}

So as you can see in this example, Everything that's put into the section '.devid*' and '.device*' gets merged into section '.text', in freeform. There are still only 3 sections in the resulting file: .text, .data, .bss, the sections you create in the C source code will get merged by this linker script.

If you want to do this with a hosted platform, extract the linker script (insert voodoo here), and modify that with your section merging.

chmeee
  • 3,608
  • 1
  • 21
  • 28
  • One-section-per-variable sounds like an overkill to me, plus, what's even more dubious, I can't think of virtually any object formats that allow non-page-aligned sections. Could you point me to any projects that use this technique? – GreyCat Aug 13 '14 at 04:34