2009-02-26 18 views
1

J'écris un petit chargeur de programme pour ma langue parce que j'ai renoncé à la compréhension du format ELF (et en faisant cela, je pourrais éventuellement mieux le comprendre). Je mmap les fichiers sur la mémoire et tux réjouit quoi que ce soit ..Comment puis-je transmettre au mieux une table de décalage global (GOT) pour ma langue sur x86?

Je ne veux pas entraver le partage du programme en faisant des changements sur elle. Par conséquent, je finis par faire la même chose que C et Elf: table de compensation globale.

Le problème est: comment puis-je passer le GOT pour mon programme?

La première chose qui vient à l'esprit est de le donner dans un registre ou un argument de pile. Dans un registre ce serait génial, mais x86 est retardé par son compte de registre. Cela pourrait signifier que je vais perdre ebx ou ebp ou une telle. Dans une architecture sensée, ce serait un compromis équitable. En x86, il se sent un peu d'échec.

Le désassemblage d'une bibliothèque partagée me montre que gcc le fait en tant qu'adressage relatif IP. Si je le faisais, ce serait:

call 0 
here: 
    pop eax 
    ; do something with [eax + (got - here) + index*4] 

Bien que cela soit partiellement compliqué. Je n'aime pas faire ça.

D'autres idées, quelqu'un?

Edit: Lors de l'obtention de gérer cela avec plusieurs bibliothèques, j'ai réalisé ceci: je vais avoir plusieurs GOT par l'application et l'utilisation de certains GOT dépend du morceau de code que je suis en accord Par conséquent GOT dans un document distinct. Le registre va nécessiter quelques astuces supplémentaires dont je ne suis pas conscient. Je voudrais savoir comment ils résolvent ce problème en gardant GOT dans les registres.

Répondre

1

Vous pouvez utiliser l'un des registres de segments (ou la base de ceux-ci) pour la base de votre image binaire. Donc, vous vous référez à vos données globales, par exemple. comme FS: xxx.

Ces registres sont des restes du modèle de mémoire dit segmenté. Fondamentalement, les segments sont des "fenêtres" dans l'espace d'adressage linéaire avec la base (et la limite) spécifiée, et si vous les utilisez pour l'adressage (par exemple si 0010: 00000001) l'adresse résultante est la base du segment avec le sélecteur 0010) +00000001. La base (ainsi que d'autres paramètres) du segment sont stockés dans la table des descripteurs (il y en a plus), qui est une zone spéciale en mémoire. Ceux-ci ne peuvent être modifiés qu'en mode noyau, il y a des appels système dans Linux qui le font (modify_ldt, arch_prctl). En mode 64 bits, la situation est un peu plus compliquée.

Pour référence, voir AMD64 architecture manual, en particulier Volume 2: Programmation système.

+0

J'ai besoin de lire à propos de ces registres de segments. Jusqu'à présent, je les ai ignorés comme un héritage. – Cheery

+0

En fait, vous pouvez utiliser GS et FS en mode 64 bits. Ils sont les exceptions au mode d'adressage plat. –