2009-06-03 11 views
10

J'ai écrit un programme "dangereux" en C++ qui saute d'une pile à l'autre. L'objectif est de passer du niveau le plus bas d'une pile d'appels à un appelant, de faire quelque chose, puis de redescendre à chaque fois en sautant tous les appels entre les deux. Je le fais en changeant manuellement l'adresse de base de la pile (réglage %ebp) et en sautant à une adresse d'étiquette. Cela fonctionne totalement, avec gcc et icc à la fois, sans aucune corruption de pile du tout. Le jour où cela a fonctionné était une journée fraîche.Que fait le registre PIC (% ebx)?

Maintenant, je prends le même programme et le réécrit en C, et cela ne fonctionne pas. Plus précisément, il ne fonctionne pas avec gcc v4.0.1 (Mac OS). Une fois que je suis passé au nouveau cadre de pile (avec le pointeur de base de la pile correctement défini), les instructions suivantes s'exécutent, juste avant un appel à fprintf. La dernière instruction ci-tombe en panne ici, déréférencement NULL:

lea 0x18b8(%ebx), %eax 
mov (%eax), %eax 
mov (%eax), %eax 

Je l'ai fait un peu de débogage, et je l'ai compris que le registre en mettant %ebx manuellement lorsque je passe des cadres de pile (en utilisant une valeur j'ai observé avant de partir la fonction en premier lieu), je répare le bug. J'ai lu que ce registre traite du "code indépendant de la position" dans gcc.

Qu'est-ce qu'un code indépendant de la position? Comment fonctionne le code indépendant de la position? À quoi ce registre pointe-t-il? PIC est le code qui est déplacé dynamiquement lorsqu'il est chargé.

+0

Vous pouvez considérer setjmp/longjmp pour obtenir cette fonctionnalité sans avoir à utiliser directement% ebx. –

+2

En général, oui, vous avez raison. Dans ce cas, je dois pouvoir passer à un appelant, exécuter une autre fonction, puis revenir à l'appelé. Avec setjmp/longjmp, la pile de l'appelé serait écrasée par l'autre fonction. –

Répondre

6

PIC est un code qui est déplacé dynamiquement lorsqu'il est chargé. Le code qui n'est pas PIC a des adresses de saut et d'appel définies au moment de la liaison. PIC a une table qui référence tous les endroits où de telles valeurs existent, un peu comme un .dll. Lorsque l'image est chargée, le chargeur mettra à jour dynamiquement ces valeurs.

D'autres schémas font référence à une valeur de données qui définit une "base" et l'adresse cible est décidée en effectuant des calculs sur la base. La base est généralement définie par le chargeur à nouveau. Enfin, d'autres schémas utilisent divers trampolines qui appellent des décalages relatifs connus. Les décalages relatifs contiennent du code et/ou des données mises à jour par un chargeur.

Il existe différentes raisons pour lesquelles différents schémas sont choisis. Certains sont rapides lors de l'exécution, mais plus lents à charger. Certains sont rapides à charger, mais ont moins de performances d'exécution.

13

EBX indique la table de décalage global. Voir this reference about PIC on i386. Le lien explique quel PIC est un EBX utilisé.

+0

GOT - Table de décalage global. –

+0

C'était une bonne ressource; Ça vaut vraiment le coup d'être lu. –