Empêcher le link de certaines fonctions dans un .so
Le
sthanizlas

Bonjour,
Je me demandais s'il était possible d'empêcher le link de fonctions dan=
s un .so. Je m'explique:
j'ai un fichier test.c qui contient ceci:
int f1 (int a)
{
return a;
}
un fichier test2.c qui contient ceci:
int f1 (int);
int f2 (int a, int b)
{
return f1 (a + b);
}
Je compile les 2 avec -fPIC et avec les objets, je produis 2 libraires, une=
static, et une dynamique.
ar cr libtest.a test.o test2.o
ranlib libtest.a
gcc -fPIC -shared -o libtest.so test.o test2.o
Je fais un fichier principal main.c qui utilise cette librairie:
#include <stdio.h>
int f1 (int);
int f2 (int, int);
int main (int argc, char *argv)
{
printf ("f1: %d", f1 (3));
printf ("f2: %d", f2 (3, 4));
return 0;
}
Tout va bien, que je fasse du link static ou dynamique, le programme m'affi=
che bien
f1: 3
f2: 7
Maintenant, sans modifier le code existant, j'ai envie de wrapper la foncti=
on f1 dans une fonction à moi qui exécuterait également le code de f1=
. Je cherche un peu sur le net, je trouve, je fais un fichier wrapped.c com=
me ceci:
int __real_f1 (int);
int __wrap_f1 (int a)
{
a = a + 42;
return __real_f1 (a);
}
et je link mon main.c avec wrapped.c, la libtest, et l'option -Wl,-wrap,f1
au link static, j'obtiens
f1: 45
f2: 49
au link dynamique, j'obtiens
f1: 45
f2: 7
Que s'est-il passé ? Tout simplement, dans la lib static libtest.a on n'a=
pas effectué d'édition de lien du tout (c'est juste une collection de =
.o). Tout se fait à la fin et la fonction f1 est wrappée partout. Lors =
de la création de la lib dynamique, une édition partielle de lien a é=
té effectuée, en particulier, l'appel à f1 dans la fonction f2 a ét=
é mappé au code de f1 contenu dans la librairie libtest.so, ce qui expl=
ique le résultat.
Question:
Est-il possible d'empêcher ce comportement ? (au moins pour les fonctions=
exportées)
J'ai essayé diverses options de linker en vain. J'ai parcouru le web en v=
ain aussi.
J'espère que ça éveillera votre curiosité :)
Je me demandais s'il était possible d'empêcher le link de fonctions dan=
s un .so. Je m'explique:
j'ai un fichier test.c qui contient ceci:
int f1 (int a)
{
return a;
}
un fichier test2.c qui contient ceci:
int f1 (int);
int f2 (int a, int b)
{
return f1 (a + b);
}
Je compile les 2 avec -fPIC et avec les objets, je produis 2 libraires, une=
static, et une dynamique.
ar cr libtest.a test.o test2.o
ranlib libtest.a
gcc -fPIC -shared -o libtest.so test.o test2.o
Je fais un fichier principal main.c qui utilise cette librairie:
#include <stdio.h>
int f1 (int);
int f2 (int, int);
int main (int argc, char *argv)
{
printf ("f1: %d", f1 (3));
printf ("f2: %d", f2 (3, 4));
return 0;
}
Tout va bien, que je fasse du link static ou dynamique, le programme m'affi=
che bien
f1: 3
f2: 7
Maintenant, sans modifier le code existant, j'ai envie de wrapper la foncti=
on f1 dans une fonction à moi qui exécuterait également le code de f1=
. Je cherche un peu sur le net, je trouve, je fais un fichier wrapped.c com=
me ceci:
int __real_f1 (int);
int __wrap_f1 (int a)
{
a = a + 42;
return __real_f1 (a);
}
et je link mon main.c avec wrapped.c, la libtest, et l'option -Wl,-wrap,f1
au link static, j'obtiens
f1: 45
f2: 49
au link dynamique, j'obtiens
f1: 45
f2: 7
Que s'est-il passé ? Tout simplement, dans la lib static libtest.a on n'a=
pas effectué d'édition de lien du tout (c'est juste une collection de =
.o). Tout se fait à la fin et la fonction f1 est wrappée partout. Lors =
de la création de la lib dynamique, une édition partielle de lien a é=
té effectuée, en particulier, l'appel à f1 dans la fonction f2 a ét=
é mappé au code de f1 contenu dans la librairie libtest.so, ce qui expl=
ique le résultat.
Question:
Est-il possible d'empêcher ce comportement ? (au moins pour les fonctions=
exportées)
J'ai essayé diverses options de linker en vain. J'ai parcouru le web en v=
ain aussi.
J'espère que ça éveillera votre curiosité :)
Manque des gros bouts d'explication.
Faudrait au moins dire de quel OS tu parles, et de quelles versions de
linker (bon, ca ressemble fort a du binutils recent sur linux ceci-dit).
Bon, deux points:
1/ on parle de bibliotheques en francais. "library" est un faux ami.
2/ plus important: le terme de "bibliotheque partagee" est abusif. En
elf, on parle de "shared object". Ca veut dire que ce ne sont pas des
bibliotheques, mais des trucs plus simples (en particulier, on s'attend
a ce que tu charges tout d'un coup).
Oui, c'est normal. ton ld est cense te pondre un objet complet.
Bof. Pas trop de curiosite. Mais histoire que tu aies quelques reponses,
faut vraiment que tu apprennes a poser plus precisement tes problemes.
C'est ta methodologie qui pose souci. Ce que tu decris ici n'a rien
de portable... donc au minimum, voir dans quel cadre tu vas en avoir
besoin... et si ce souci de portabilite en est un pour toi.
le fait de preciser le besoin devrait aussi t'amener a revoir les endroits
ou poser ta question... t'auras plus de chance dans les groupes systeme
que dans fr.comp.lang.c.
Enfin, je soupconne que ce que tu veux n'est pas possible tel quel, mais
possible en rusant (la-encore ca sera fortement dependant de l'OS, mais
on n'en est plus a ca pres, hein): tu n'arriveras pas a tes fins avec
un seul shared object. Par contre, tu dois pouvoir garder tes deux fichiers
objets separes (sous forme d'un test1.so et d'un test2.so) et utiliser un
linker-script pour fabriquer une libtest.so qui ne sera PAS un shared object,
mais bien un truc qui charge test1.so et test2.so (si tu es comme je le
soupconne sous linux, tu peux regarder a quoi ressemble reellement ta libc.
Il y a de fortes chances que le fichier qui s'appelle "libc.so" ne soit pas
un binaire, mais bien une composition de plusieurs sous-machins).
Ou alors, alternativement, avoir libtest.so qui soit un seul de test1/test2,
et qui depende de l'autre bibliotheque. Caveat: dans tous les cas, ca va
etre un peu folklorique cote gestion du path si tu veux que ca soit
transparent.
J'avais déjà la solution d'utiliser 2 .so séparées, mais je voulais n'en garder qu'une seule. Par contre, je ne connaissais pas le coup du lin ker-script, je pense que c'est la solution vers laquelle je vais me tourner .
Non. Tout au plus avec le système d'objets partagés habituellement
utilisé avec *nix, on peut masquer des fonctions en interposant un autre
.so devant celui qui contient la fonction que tu veux empêcher: l'effet
sur le code exécuté est le même, mais pas la méthode, et donc le
résultat n'est pas identique car le simple fait de charger ou pas un .so
a un effet non-nul.
Et tout ceci ne fonctionne pas dans la logique Windows, et en ce qui
concerne Mac OSX je ne sais pas.
Techniquement c'est le contraire... Quand tu utilises des bibliothèques
dynamiques, la compilation ne réalise pas totalement l'édition des
liens, celle-ci est terminée au moment du chargement juste avant
l'exécution du programme.
Antoine