web-dev-qa-db-fra.com

Symbole masqué dans les bibliothèques statiques construites avec Xcode

J'essaie de savoir si je peux créer une bibliothèque statique qui masque tous ses objets et fonctions internes, etc., à l'exception des interfaces que je souhaite exporter. J'expérimente avec Xcode (gcc 4.2).

J'ai utilisé l'attribut __attribute__((visibility("hidden"))) sur certaines classes C++ par cette documentation . J'ai également défini les petites fonctions d'aide C comme étant des fichiers locaux (statique), etc.

Cependant, lorsque j'exécute strings sur le fichier de bibliothèque résultant, même compilé dans la configuration de Release, je vois toujours les noms de mes classes apparemment cachées, avec leurs noms de méthodes et même les noms de fonctions locales aux fichiers éparpillés là aussi. 

J'ai ajouté le -fvisibility=hidden et même -fno-rtti aux drapeaux gcc. Bien que cela réduise certaines des chaînes, les noms de classe, les noms de méthodes et les noms de fonctions statiques sont toujours présents, sous une forme simple ou altérée, mais lisible. 

Existe-t-il un moyen fiable de faire en sorte que le compilateur construise ces éléments sans que les noms de chaînes de tous les éléments internes soient émis dans le binaire? Il ne devrait pas être nécessaire d’avoir des clients externes qui se connectent.

(Pour clarifier: je pose une question sur l'obscurcissement de la dénomination interne, par opposition aux besoins de liaison d'exportation littérale. Je suis déconcerté que tous les travaux internes soient visibles via la commande strings, que ces symboles soient officiellement exportés ou non.)

Merci.

41
Ben Zotto

Le masquage des noms internes nécessite quelques paramètres de construction Xcode simples et il n'est généralement pas nécessaire de modifier la source ni le type du produit généré.

  1. Éliminez tous les symboles internes requis entre les modules en effectuant une liaison préliminaire à un seul objet. Définissez le paramètre de construction Xcode nommé "Effectuer la liaison préliminaire à un seul objet" sur Oui (GENERATE_MASTER_OBJECT_FILE = YES). Cela provoque l'exécution de ld avec l'indicateur "-r".
  2. Assurez-vous que le paramètre "Style de bande" est défini sur "Symboles non globaux" (STRIP_STYLE = non global), cela transmet "-x" à ld.
  3. Le strip-tease n'est réellement exécuté sur les bibliothèques statiques que si le post-traitement est activé (et ce n'est pas la valeur par défaut). Définissez le paramètre de construction Xcode "Postprocessing de déploiement" sur yes. (DEPLOYMENT_POSTPROCESSING = YES). Assurez-vous également que "Utiliser une bande séparée" est défini sur Oui (pas toujours la valeur par défaut) (SEPARATE_STRIP = YES).
  4. Si, en plus des symboles locaux, vous devez supprimer certains des symboles globaux, vous pouvez fournir des options supplémentaires à la commande de bande, sous le paramètre de construction Xcode "Drapeaux de bande supplémentaires". Par exemple. J'utilise couramment l'option strip -R somefile pour fournir à un fichier une liste supplémentaire de symboles que je souhaite supprimer de la table des symboles globaux. 
46
bleater

La principale astuce pour masquer les symboles dans les bibliothèques statiques consiste à générer un fichier objet relocalisable (par opposition à une archive de bibliothèque statique qui consiste simplement en une collection de fichiers .o individuels). Pour créer un fichier objet déplaçable, vous devez choisir votre cible dans XCode en tant qu'ensemble (par opposition à "Bibliothèque statique de Cocoa Touch"). La cible Bundle apparaît sous les modèles OS X et vous pouvez définir sa cible sur iOS dans les paramètres de construction si vous créez pour iOS.

Une fois que vous avez correctement configuré votre cible, procédez comme suit pour que le masquage de symbole soit correct:

  1. Définissez l'option "Symboles masqués par défaut" sur Oui dans les paramètres de construction. Cela garantit que tous les symboles compilés dans les fichiers sont marqués comme privés.

  2. Comme il s’agit d’une bibliothèque, vous devez garder certains symboles publics. Vous devez placer le code des fonctions que vous souhaitez garder publiquement visibles dans des fichiers distincts et compiler ces fichiers avec l'indicateur -fvisibility=default (vous pouvez définir cet indicateur pour des fichiers individuels "Phases de construction> Compiler les sources> - Indicateurs du compilateur" dans Xcode). Alternativement, vous pouvez préfixer le nom de la fonction/classe que vous souhaitez voir visible avec la directive __attribute__((visibility("default"))).

  3. Sous les paramètres de liaison dans le projet X-code, définissez le type Mach-O sur "Fichier objet relogeable". Cela signifie que tous les fichiers .o seront liés à nouveau pour générer un seul fichier objet. C’est cette étape qui permet de marquer tous les symboles comme privés lorsque les fichiers .o sont liés ensemble en un seul fichier. Si vous construisez une bibliothèque statique (c'est-à-dire un fichier .a), cette étape de reconnexion ne se produit pas et les symboles ne sont jamais masqués. Il est donc essentiel de choisir un fichier objet relocalisable comme cible.

  4. Même après avoir marqué les symboles comme privés, ils apparaissent toujours dans le fichier .o. Vous devez activer la suppression pour vous débarrasser des symboles privés. Cela peut être fait en définissant le paramètre "Produit lié Stripped" sur Oui dans les paramètres de construction. La définition de cette option exécute la commande strip -x sur le fichier objet qui supprime les symboles privés du fichier objet.

  5. Vérifiez deux fois que tous les symboles internes ont disparu en exécutant la commande nm sur le fichier objet déplaçable final généré par le processus de construction.

Les étapes ci-dessus vous aideront à vous débarrasser des noms de symbole de la commande nm. Vous verrez toujours certains noms de fonction et noms de fichier si vous exécutez la commande strings sur votre fichier objet (en raison de la compilation de certaines chaînes et de certains noms d'objet via des exceptions). Un de mes collègues a un script qui renomme certains de ces symboles en consultant les sections binaires et en renommant ces chaînes. Je l'ai posté ici pour que vous puissiez l'utiliser: https://Gist.github.com/varungulshan/6198167 . Vous pouvez ajouter ce script en tant qu'étape de construction supplémentaire dans Xcode.

15
Varun Gulshan

Il est un peu difficile pour moi de savoir comment masquer les symboles dans les bibliothèques statiques de l'environnement de ligne de commande linux sur la base des réponses précédentes. Je vais donc poster ici ma solution ici pour la postérité (étant donné que c'est l'un des meilleurs résultats sur Google pour cela. question).

Disons que vous avez ces deux fichiers .c:

// f1.c
const char *get_english_greeting(void)
{
  return "hello";
}

__attribute__((visibility("default")))
const char *get_greeting(void)
{
  return get_english_greeting();
}

et

// f2.c
#include <stdio.h>
const char *get_english_greeting(void);

__attribute__((visibility("default")))
void print_greeting(void)
{
  puts(get_english_greeting());
}

Vous souhaitez convertir ces deux fichiers en une bibliothèque statique exportant à la fois get_greeting et print_greeting, mais pas get_english_greeting, que vous ne souhaitez pas rendre statique car vous voudriez l'utiliser dans toute votre bibliothèque.

Voici les étapes pour y parvenir:

gcc -fvisibility=hidden -c f1.c f2.c
ld -r f1.o f2.o -o libf.o
objcopy --localize-hidden libf.o
ar rcs libf.a libf.o

Maintenant cela fonctionne:

// gcc -L. main.c -lf
void get_greeting(void);
void print_greeting(void);
int main(void)
{
  get_greeting();
  print_greeting();
  return 0;
}

Et cela ne veut pas:

// gcc -L. main.c -lf
const char *get_english_greeting(void);
int main(void)
{
  get_english_greeting();
  return 0;
}

Pour ce dernier, vous obtenez cette erreur:

/tmp/ccmfg54F.o: In function `main':
main.c:(.text+0x8): undefined reference to `get_english_greeting'
collect2: error: ld returned 1 exit status

C'est ce que nous voulons.

Notez que les noms de symbole masqués sont toujours visibles dans la bibliothèque statique, mais l'éditeur de liens refusera de créer un lien avec eux en dehors de ladite bibliothèque statique. Pour supprimer complètement les noms de symboles, vous devez supprimer et masquer.

0
ypsu