
Continuons cette série sur les codes fantastiques avec deux drapeaux qui interagissent avec l’interposition de symboles.
Certains d’entre vous connaissent la fonctionnalité d’interposition du standard ELF à travers la variable d’environnement LD_PRELOAD, qui permet de remplacer un symbole par un autre à l’exécution, sans modifier le code du binaire.
Cette fonctionnalité a un impact sur le code généré ; pour le code suivant :
l’appel à foo se fait à travers la Procedure Linkage Table (PLT), ce qui permet à la magie de LD_PRELOAD d’opérer. Par conséquent, le compilateur ne doit pas avoir l’autorisation d’inliner foo dans pain, car cela casserait le remplacement de la fonction par LD_PRELOAD !
Ce comportement est activé par -fsymbolic-interposition, et ce n’est… pas le comportement par défaut de Clang, qui active -fno-semantic-interposition par défaut, l’autre approche impactant de manière significative les performances. GCC est quant à lui plus respectueux du standard, comme le montre la sortie de gcc -shared a.c -fPIC -o liba.so -O2 && objdump -S liba.so, où l’appel indirect est bien visible.
Et avec -fno-semantic-interposition, l’appel à foo est bien inliné :
Une approche qui ne met en œuvre que l’éditeur de liens consiste à laisser le compilateur optimiser les appels de fonction sans passer par la PLT ; -Wl,-Bsymbolic-functions permet de faire ça, par exemple gcc -shared a.c -fPIC -o liba.so -O2 && objdump -S liba.so qui combine l’optimisation au niveau compilateur et au niveau éditeur de liens :
Cela laisse beaucoup de choix d’optimisation entre les mains du développeur !