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

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

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

[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."

Предположим, я хочу написать несколько юнит-тестов, которые используют 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 являются глобальными символами и доступны из вне модуля. Пока все хорошо.

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

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

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

[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 (), завернута, но Бар по-прежнему вызывает локальный баз, а не завернутый баз.

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

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

- Стив

Ответы [ 3 ]

4 голосов
/ 21 марта 2012

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

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

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

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

2 голосов
/ 22 марта 2012

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

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

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

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

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

0 голосов
/ 26 марта 2012

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

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

...