2010-05-16 3 views
1

En assembleur:assembleur gcc instruction illégale

.globl _test 

_test: 

pushl %ebp 
movl %esp, %ebp 
movl 8(%ebp), %eax 

pushl %eax 
call printf 

popl %ebp 
ret 

Appel de c

main() 
{ 
    _test("Hello"); 
} 

Compile:

gcc -m32 test.c test -o test.s

Cette le code me donne parfois des instructions illégales et des erreurs de segment d'autres fois. En gdc je reçois toujours des instructions illégales, c'est juste un test simple, j'ai eu un programme plus grand qui fonctionnait et soudainement après aucune raison apparente a cessé de fonctionner, maintenant je reçois toujours cette erreur même si je recommence comme ci-dessus.

Je l'ai réduit à pushl% eax & appel printf, si je commente sur ces lignes le code fonctionne très bien.

Des idées? (Je cours le programme au cluster linux de mon université, donc je n'ai pas changé les paramètres ..)

+0

Vous avez simplement oublié de supprimer l'argument 'printf()' de la pile après le retour de l'appel. Votre 'popl% ebp' enlève la mauvaise chose, et votre' ret' essaie de sauter au mauvais endroit - parce qu'il y a un mot de plus sur la pile que prévu. –

Répondre

3

Vos deux dernières instructions corrompent le pointeur de base de la pile. Tout code reposant sur ebp (le pointeur de base) pour pointer vers l'espace de pile réel échouera. En général, attendre que ebp pointe vers l'espace de pile est une hypothèse sûre, et vous ne devriez pas invalider cette hypothèse lors de l'interfaçage avec le code C.

Vous exécutez pushl %eax (ou tout autre registre), puis popl %ebp. Ces deux ensemble ont le même effet que de faire movl %eax, %ebp.

Je suppose que vous essayez de renvoyer la valeur stockée dans eax. Dans la convention d'appel C, eax est utilisé pour les valeurs de retour, il n'est donc pas nécessaire de le pousser ou de faire quoi que ce soit, il suffit de laisser la valeur et l'autre code le récupèrera. Si ce n'est pas ce que vous essayez de faire, je suis perplexe quant à la raison pour laquelle vous pousseriez% eax à la fin de cette fonction.

+0

Merci d'avoir signalé cela, j'ai mis à jour le post principal avec un échantillon plus sain, je reçois toujours l'erreur cependant. printf affiche le dernier élément de la pile, donc popl ebp devrait être correct maintenant. – Bernt

+1

@Bernt: vous vous trompez sur 'printf' qui sort de la pile pour vous. Sous Linux/x86, la pile est inchangée quand une fonction que vous appelez revient - tous les arguments que vous avez «poussés» avant sont toujours là. C'est le problème dans votre code, un mot où vous n'en attendez aucun. –

2

Remplacez l'instruction pop par leave. Ceci restaure le pointeur de pile et de base.