GNU gcc / ld – завершение вызова символа с вызывающим и вызываемым, определенным в том же объектном файле

для уточнения, мой вопрос относится к обертыванию / перехвату вызовов от одной функции / символа к другой функции / символу, когда вызывающий и вызываемый определяются в одном компиляторе с компилятором и компоновщиком GCC.

У меня есть ситуация, напоминающая следующее:

/* foo.c */ void foo(void) { /* ... some stuff */ bar(); } void bar(void) { /* ... some other stuff */ } 

Я хотел бы обернуть вызовы к этим функциям, и я могу сделать это (до точки) с --wrap опции --wrap (а затем я реализую __wrap_foo и __wrap_bar, которые, в свою очередь, вызывают __real_foo и __real_bar, как и ожидалось результатом ld‘s --wrap ).

 gcc -Wl,--wrap=foo -Wl,--wrap=bar ... 

Проблема, с которой я сталкиваюсь, заключается в том, что это вступает в силу только для ссылок на foo и bar из- за пределов этого блока компиляции (и разрешено во время связи). То есть, вызовы foo и bar из других функций внутри foo.c не обернуты.

вызовы из блока компиляции решаются до обертывания компоновщика

Я попытался использовать objcopy –redefine-sym , но это только переименовывает символы и их ссылки.

Я хотел бы заменить вызовы на foo и bar (внутри foo.o) на __wrap_foo и __wrap_bar (так же, как они разрешаются в других объектных файлах с --wrap опции --wrap компоновщика) ПЕРЕД Я --wrap * .o-файлы в компоновщик --wrap и без необходимости изменять исходный код --wrap

Таким образом, обертывание / перехват происходит для всех вызовов foo и bar , а не только тех, которые происходят за пределами foo.o.

Это возможно?

    Вы должны ослабить и глобализовать символ, используя objcopy.

     -W symbolname --weaken-symbol=symbolname Make symbol symbolname weak. This option may be given more than once. --globalize-symbol=symbolname Give symbol symbolname global scoping so that it is visible outside of the file in which it is defined. This option may be given more than once. 

    Это сработало для меня

    bar.c:

     #include  int foo(){ printf("Wrap-FU\n"); } 

    foo.c:

     #include  void foo(){ printf("foo\n"); } int main(){ printf("main\n"); foo(); } 

    Скомпилируйте его

     $ gcc -c foo.c bar.c 

    Ослабьте символ foo и сделайте его глобальным, поэтому он снова доступен для компоновщика.

     $ objcopy foo.o --globalize-symbol=foo --weaken-symbol=foo foo2.o 

    Теперь вы можете связать свой новый объект с оберткой с bar.c

     $ gcc -o nowrap foo.o #for reference $ gcc -o wrapme foo2.o bar.o 

    Контрольная работа

     $ ./nowrap main foo 

    И завернутый:

     $ ./wrapme main Wrap-FU 
     #include  #include  //gcc -ggdb -o test test.c -Wl,-wrap,malloc void* __real_malloc(size_t bytes); int main() { int *p = NULL; int i = 0; p = malloc(100*sizeof(int)); for (i=0; i < 100; i++) p[i] = i; free(p); return 0; } void* __wrap_malloc(size_t bytes) { return __real_malloc(bytes); } 

    А потом просто скомпилируйте этот код и отлаживайте. Когда вы вызываете reall malloc, вызываемая функция будет __wrap_malloc и __real_malloc вызовет malloc.

    Я думаю, что это способ перехвата вызовов.

    В основном это опция -wrap, предоставленная ld.

    Это, похоже, работает как задокументированное:

      --wrap=symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "__wrap_symbol". ... 

    Обратите внимание на не определенную выше. Когда компоновщик обрабатывает foo.o , bar() не является неопределенным, поэтому компоновщик не обертывает его. Я не уверен, почему это делается именно так, но, вероятно, это вариант использования, который требует этого.

    Вы можете достичь того, чего хотите, если используете --undefined с --wrap

      -u SYMBOL, --undefined SYMBOL Start with undefined reference to SYMBOL 

    Вы можете использовать __attribute__((weak)) до реализации вызываемого абонента, чтобы позволить кому-либо переопределить его без критического крика GCC о множественных определениях.

    Например, предположим, что вы хотите высмеять world функцию в следующем блоке кода hello.c . Вы можете добавить атрибут, чтобы его можно было переопределить.

     #include "hello.h" #include  __attribute__((weak)) void world(void) { printf("world from lib\n"); } void hello(void) { printf("hello\n"); world(); } 

    И вы можете переопределить его в другом файле. Очень полезно для модульного тестирования / издевательств:

     #include  #include "hello.h" /* overrides */ void world(void) { printf("world from main.c"\n); } void main(void) { hello(); return 0; } 
    Interesting Posts
    Давайте будем гением компьютера.