GNU GCC / ld-zawijanie wywołania do symbolu z wywołaniem i wywołaniem zdefiniowanym w tym samym pliku obiektowym
Dla wyjaśnienia, moje pytanie odnosi się do zawijania/przechwytywania połączeń z jednej funkcji/symbolu do innej funkcji/symbolu , gdy wywołujący i wywołujący są zdefiniowane w tej samej jednostce kompilacji za pomocą kompilatora GCC i linkera.
Mam sytuację przypominającą:
/* foo.c */
void foo(void)
{
/* ... some stuff */
bar();
}
void bar(void)
{
/* ... some other stuff */
}
Chciałbym zawijać wywołania tych funkcji i mogę to zrobić (do pewnego punktu) za pomocą LD ' s --wrap
option (a następnie implementuję _ _ wrap _ foo i_ _ wrap _ bar, które z kolei wywołanie _ _ real _ foo i _ _ real _ bar zgodnie z oczekiwaniami wynikającymi z opcji --wrap
ld).
gcc -Wl,--wrap=foo -Wl,--wrap=bar ...
Problem, który mam polega na tym, że to działa tylko dla odniesień do foo i bar z poza tą jednostką kompilacji (i rozwiązane w czasie łącza). Oznacza to, że wywołania foo i bar z innych funkcji w foo.c nie daj się zapakować.
Próbowałem użyć objcopy --redefine-sym , ale to tylko zmienia nazwy symboli i ich referencje.
Chciałbym zamienić wywołania na foo
i bar
(w Foo.o) do __wrap_foo
i __wrap_bar
(tak jak zostaną rozwiązane w innych plikach obiektowych przez opcję --wrap
linkera), zanim przekażę *.o pliki do opcji --wrap
linkera i bez konieczności modyfikowania foo.kod źródłowy C.
foo
i bar
, a nie tylko tych odbywających się poza foo.o.
Czy to możliwe? 5 answers
Musisz osłabić i globalizować symbol za pomocą 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.
To zadziałało dla mnie
Bar.c:
#include <stdio.h>
int foo(){
printf("Wrap-FU\n");
}
Foo.c:
#include <stdio.h>
void foo(){
printf("foo\n");
}
int main(){
printf("main\n");
foo();
}
Skompiluj to
$ gcc -c foo.c bar.c
Osłabić symbol foo i uczynić go globalnym, więc będzie znowu dostępny dla linkera.
$ objcopy foo.o --globalize-symbol=foo --weaken-symbol=foo foo2.o
Teraz możesz połączyć swój nowy obj z owijką z paska.c
$ gcc -o nowrap foo.o #for reference
$ gcc -o wrapme foo2.o bar.o
Test
$ ./nowrap
main
foo
I owinięty:
$ ./wrapme
main
Wrap-FU
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 19:28:19
#include <stdio.h>
#include <stdlib.h>
//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);
}
A następnie skompiluj ten kod i debuguj. Kiedy wywołasz reall malloc, funkcja o nazwie will _ _ wrap _ malloc i _ _ real _ malloc wywoła malloc.
Myślę, że to jest sposób na przechwycenie połączeń.W zasadzie jest to opcja --wrap dostarczana przez ld.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-27 22:23:07
Wygląda na to, że działa to zgodnie z dokumentacją:
--wrap=symbol
Use a wrapper function for symbol.
Any undefined reference to symbol will be resolved to "__wrap_symbol". ...
Zwróć uwagę na undefined powyżej. Gdy linker przetwarza foo.o
, bar()
jest Nie niezdefiniowany, więc linker go nie zawija. Nie jestem pewien dlaczego jest to zrobione w ten sposób, ale prawdopodobnie istnieje przypadek użycia, który tego wymaga.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-28 08:04:15
Możesz osiągnąć to, czego chcesz, jeśli używasz --undefined
z --wrap
-u SYMBOL, --undefined SYMBOL
Start with undefined reference to SYMBOL
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-18 03:12:01
Możesz użyć __attribute__((weak))
przed implementacją callee, aby ktoś mógł ją ponownie zaimplementować bez krzyczenia GCC o wielu definitonach.
Na przykład załóżmy, że chcesz wyśmiewać funkcję world
w następującej hello.C jednostka kodu. Możesz dodać atrybut, aby móc go zastąpić.
#include "hello.h"
#include <stdio.h>
__attribute__((weak))
void world(void)
{
printf("world from lib\n");
}
void hello(void)
{
printf("hello\n");
world();
}
I można go zastąpić w innym pliku jednostki. Bardzo przydatne do testów jednostkowych/wyśmiewania:
#include <stdio.h>
#include "hello.h"
/* overrides */
void world(void)
{
printf("world from main.c"\n);
}
void main(void)
{
hello();
return 0;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 12:05:49