Faute de Segmentation en Langage d'Assemblage
Je suis à l'apprentissage de AT&T x86 langage d'assemblage. Je suis en train d'écrire un programme d'assemblée, qui prend un entier n, puis retourner le résultat (n/2+n/3+n/4). Voici ce que j'ai fait:
.text
.global _start
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
mov $0, %esi
movl $4, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $3, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $2, %ebp
div %ebp
addl %eax, %esi
movl %esi, %eax
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
ret
Le problème est que je suis faute de segmentation. Où est le problème?
- Ne vous essayez pas à pas dans le code avec un débogueur pour voir ce qui se passe ?
- AT&T ramifiée dans les processeurs? (-:
- tripleee: "AT&T syntaxe" se réfère à l'assembleur de syntaxe ci-dessus, utilisée à l'origine dans SysV Unix. Il met l'opérande de taille sur l'instruction comme un suffixe, utilise un "%" à la balise enregistrer des noms, et met le registre de destination à la fin de la liste. C'est la syntaxe prise en charge par l'assembleur GNU linux. Il est tout à fait différent de "Intel" syntaxe plus couramment utilisés dans l'industrie du PC.
- Si vous allez en apprendre de langage assembleur Intel, utilisez Intel syntaxe. Dans un décent monde, cette abomination que vous appelez AT&T syntaxe n'aurait jamais existé.
Vous devez vous connecter pour publier un commentaire.
Je pense que le code ne fonctionne pas ici:
Donc, vous
push $24
(4 octets), puiscall profit
, qui pousseeip
et les sauts deprofit
. Ensuite vous sautez à la valeur deeip
enebx
et la valeur$24
eneax
.Puis, en fin de compte, si
jg end
branches deend:
, puis la pile ne sera pas de la validité de l'adresse de retour etret
échouera. Vous avez probablement besoin depushl %ebx
là aussi.mov 4(%esp), %eax
. (Ou ce décalage est-il en si vous pousser à quelque chose d'autre en premier). Si vous faire un traditionnel frame de pile avec EBP, vous seriez en mesure d'accéder à la première arg comme8(%ebp)
indépendamment de l'autre pousse.Vous ne vous présentez pas à faire des appels de fonction correctement. Vous avez besoin de lire et de comprendre le x86 ABI ( 32-bit , 64-bit), en particulier la "convention d'appel" des sections.
Aussi, ce n'est pas votre problème immédiat, mais: Ne pas écrire
_start
, écriremain
comme s'il s'agissait d'un programme C. Quand vous commencez à faire quelque chose de plus compliqué, vous voulez la bibliothèque C pour être disponible, et cela signifie que vous devez le laisser s'initialiser. Par ailleurs, ne pas faire votre propre système d'appels; appelez les pâtes dans la bibliothèque C de. Que vous isole de faible niveau de changements dans le noyau de l'interface, assure queerrno
est disponible, et ainsi de suite._start
est parfaitement valide ici, c'est un pur montage du programme.ecx
sans jamais explicitement initialisation (je ne sais pas si Linux permettra de garantir l'état deecx
lorsque le processus démarre - on dirait qu'il est0
dans la pratique, si ce n'est pas la règle)jg end
sauter près de la fin de la procédure, l'adresse de retour n'est plus sur la pile, afin deret
permettra de transférer le contrôle à certaines des ordures adresse.Votre problème est que vous sautez à l'adresse de retour hors de la pile, et lorsque vous branche à la fin vous n'avez pas le restaurer. Une solution rapide est d'ajouter
push %ebx
il ainsi.Ce que vous devez faire est de modifier votre procédure de sorte qu'il utilise la convention d'appel correctement. Sous Linux, l'appelant la fonction est prévue pour nettoyer les arguments sur la pile, de sorte que votre procédure devrait les laisser là où ils sont.
Au lieu de faire cela pour obtenir de l'argument et de la restauration à l'adresse de retour plus tard
Vous devriez le faire et de laisser l'adresse de retour et des arguments où ils sont
et de se débarrasser du code qui pousse l'adresse de retour de retour sur la pile. Vous devez ensuite ajouter
après l'appel à la procédure pour supprimer l'argument de la pile. Il est important de suivre cette convention correctement si vous voulez être en mesure d'appeler vos procédures de montage à partir d'autres langues.
Il me semble que vous avez un seul pushl avant d'appeler le bénéfice et puis la première chose que le profit n'est à faire deux popl instructions. Je m'attends à ce que ce serait de la pop la valeur que vous avez poussé sur la pile ainsi que le code de retour de sorte que votre ret ne fonctionnerait pas.
push et pop devrait être le même nombre de fois.
appel pousse l'adresse de retour sur la pile.