appel de sous-routines conditionnellement à l'assemblée
Je suis en train d'apprendre x86 assemblée. Je me demandais comment vous effectuez un appel de sous-programme conditionnellement.
Comme je le comprends, le saut à l'étiquette ne fonctionne pas parce que l'adresse de retour n'est pas stocké et donc il ne sait pas où revenir.
cmp bx, 0
jz zero ; how do I do this correctly ?
; do something else and exit
zero:
; do something
ret
- Je n'ai pas écrite à l'assemblée en temps, mais je pense que je me souviens de pousser les adresses sur la pile ou dans un registre et le saut à la valeur à la fin de la sous-routine.
Vous devez vous connecter pour publier un commentaire.
Cela fonctionne bien si vous n'avez pas besoin de retourner à cette adresse. La plupart du temps vous pouvez structurer votre code tel que c'est le cas.
Sinon vous aurez à faire de la ramification avec
Jxx
instructions de saut autour du site d'appel ou, en d'autres façons de structurer votre code de contourner cette limitation. Dans ce cas, l'inversion de l'essai doit travailler:MODIFIER 2016-04-25: Comme @Peter Cordes mentionne dans les commentaires, le code ci-dessous sera probablement effectuer terriblement. Voir, par exemple, cet article pour une explication de pourquoi.
@Manny Ds suggestion dans les commentaires m'a inspiré pour écrire ce qui suit. Il pourrait ne pas être le produit de nettoyage ou mieux, mais c'est une autre façon de le structurer:
Explicitement pousse l'adresse de retour sur la pile de sorte que le
zero
fonction peut renvoyer ou pop la valeur (add esp, 4
) à partir de la pile si nous ne faisons pas appel de la fonction (pour se réadapter à la pile). Notez que vous avez besoin de faire quelques ajustements si vous voulez que cela fonctionne en 16 ou 64-bit de mode.if-else
situation donc je ne pense pas que je puisse restructurer comme ça. Je peux probablement avoir ce bout de code dans un autre sous-routine juste pour ce cas particulier, mais il semble un peu hacky. J'espérais qu'il y a un moyen propre à le faire.push back_from_zero
truc si la performance est importante à tous. Les Processeurs modernes garder une adresse de retour de prédiction de la pile, et un mal appariéscall
/ret
des pauses d'une pile, conduisant à une branche-mispredict sur chaqueret
peut-être pour la prochaine 15 niveaux de rendement. Pour éviter cela, avoir la fonction appelée main (sansret
): par exemple, la pop, le retour addr etjmp edx
. Ou en 64 bits ABI avec une zone rouge, vous pouvez également ajuster la pile puis de faire un mémoire indirectejmp [rsp - 8]
. Qui indirects jmp ne sera probablement pas avoir une BTB entrée, mais ne les détruisent pas la performance pour un autre code après.zero
se termine avecpop edx
/jmp edx
ou quelque chose. Mais qui ne fonctionne que si la fonction n'est jamais appelée sanscall
insn. Si il n'y a qu'un site d'appel, Rudy répondre de façon appropriée de la structure des branches pour exécuter conditionnellement quelque chose est une bien meilleure approche.Le propre façon de faire est tout simplement:
Je ne connais rien de mieux pour un si autre situation. Ok, si les deux branches doivent retourner directement après, vous pouvez le faire:
Si le traitement doit avoir lieu avant le ret (par exemple, popping valeurs précédemment poussé), vous devez utiliser la première approche.
ret
dans la fonction, de sorte que le fast-path n'a pas besoin de sauter sur elle. Ainsi, le fast-path a une non-prise de la branche, et le lent chemin a deux prises branches. (Il saute en arrière à l'endroit où vous le souhaitez.) gcc rend le code comme ça tout le temps: des blocs de code avec un ou plusieurs insns et puis unjmp
retour en haut dans la partie principale de la fonction. Bon point que la condition de la queue-les appels sont possibles. gcc n'est pas le cas, mais pourraitJe crois que la bonne façon de le faire est avec la
call
instruction. C'est équivalent à un appel de fonction dans une plus le langage de programmation. Le PC est stocké sur la pile, et donc laret
à la fin de votrezero:
sous-routine est ce qu'il est censé.call
instruction, mais je ne connais pas la syntaxe pour appeler sur la base d'un état.