Можно ли переопределить статические функции в объектном модуле (gcc, ld, x86, objcopy)?

Есть ли способ переопределить функции со статической областью действия в объектном модуле?

Если я начну с чего-то подобного, модуль с глобальным символом "foo" - это функция, которая вызывает локальный символ "bar", который вызывает локальный символ "baz".

[scameron@localhost ~]$ cat foo.c
#include <stdio.h>
static void baz(void)
{
    printf("baz\n");
}

static void bar(void)
{
    printf("bar\n");
    baz();
}

void foo(void)
{
    printf("foo\n");
    bar();
}

[scameron@localhost ~]$ gcc -g -c foo.c
[scameron@localhost ~]$ objdump -x foo.o | egrep 'foo|bar|baz'
foo.o:     file format elf32-i386
foo.o
00000000 l    df *ABS*  00000000 foo.c
00000000 l     F .text  00000014 baz
00000014 l     F .text  00000019 bar
0000002d g     F .text  00000019 foo

У этого есть один глобальный, "foo" и два местных "бара" и "база".

Предположим, я хочу написать несколько модульных тестов, которые используют bar и baz, я могу сделать:

[scameron@localhost ~]$ cat barbaz
bar
baz
[scameron@localhost ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o
[scameron@localhost ~]$ objdump -x foo2.o | egrep 'foo|bar|baz'
foo2.o:     file format elf32-i386
foo2.o
00000000 l    df *ABS*  00000000 foo.c
00000000 g     F .text  00000014 baz
00000014 g     F .text  00000019 bar
0000002d g     F .text  00000019 foo
[scameron@localhost ~]$ 

И теперь bar и baz являются глобальными символами и доступны извне модуля. Все идет нормально.

Но что, если я хочу вставить свою собственную функцию поверх "baz", и пусть "bar" вызывает мой вставленный "baz"?

Есть способ сделать это?

Опция --wrap, похоже, не делает этого...

[scameron@localhost ~]$ cat ibaz.c
#include <stdio.h>
extern void foo();
extern void bar();

void __wrap_baz()
{
    printf("wrapped baz\n");
}
int main(int argc, char *argv[])
{
    foo();
    baz();
}

[scameron@localhost ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz
[scameron@localhost ~]$ ./ibaz
foo
bar
baz
wrapped baz
[scameron@localhost ~]$

База, вызванная из main(), была упакована, но bar по-прежнему вызывает локальную базу, а не упакованную.

Есть ли способ заставить бар вызывать завернутый баз?

Даже если для этого требуется изменить объектный код, чтобы он соответствовал адресам вызовов функций, если это можно сделать в автоматическом режиме, этого может быть достаточно, но в этом случае он должен работать как минимум на i386 и x86_64.

- Стив

3 ответа

Поскольку static это обещание компилятору C, что функция или переменная являются локальными для файла, компилятор может удалить этот код, если он может получить тот же результат без него.

Это может быть встраивание вызова функции. Это может означать замену переменной константами. Если код находится внутри if утверждение, что всегда ложно, функция может даже не существовать в скомпилированном результате.

Все это означает, что вы не можете надежно перенаправить вызовы этой функции.

Если вы компилируете с новым -lto Варианты это еще хуже, потому что компилятор может свободно переупорядочивать, удалять или вставлять весь код во всем проекте.

Я получил электронное письмо от Иана Ланса Тейлора (автора gold, альтернативного линкера ld):

Есть ли способ переопределить функции со статической областью действия в объектном модуле? (Я на x86_64 и i386 Linux)

Нет, нет В частности, компилятор может встроить вызовы статических функций, а также может переписать функции для использования другого соглашения о вызовах (GCC выполняет обе эти оптимизации). Поэтому нет надежного способа переопределить статическую функцию после компиляции кода.

Я думаю, что с вложением можно справиться с помощью -fno-inline, но изменение соглашений о вызовах, вероятно, слишком много.

При этом ребята из DynamoRIO утверждают, что могут это сделать, но я не проверял это: https://groups.google.com/forum/?fromgroups

Если у вас все в порядке с изменением машинного кода, у вас не должно возникнуть проблем с изменением исходного кода.

Написание сценариев для механического создания источников модульных тестов из реальных источников. Perl делает это очень хорошо.

Другие вопросы по тегам