Programmation Assembleur/x86/Les branchements
Programmation Assembleur/x86 |
Modifier ce modèle |
Par défaut, les instructions sont exécutées les unes à la suite des autres, en séquence.
Les instructions de branchement ou de saut permettent de passer à une autre instruction que la suivante, pour diverses raisons :
- Effectuer une boucle, dans ce cas, le saut revient à une instruction antérieure,
- Sauter les instructions conditionnelles quand la condition est fausse,
- Appeler un sous-programme.
Saut inconditionnel
[modifier | modifier le wikicode]Le saut réalisé par l'instruction JMP
est effectué sans test de condition.
Le seul paramètre de cette instruction est l'adresse où l'exécution doit se poursuivre.
Cette adresse peut être une constante, ou contenue dans un emplacement mémoire (un pointeur).
JMP adresse
Exemples :
JMP 20E5 ; Offset (near pointer : adresse proche)
JMP FFFF:0000 ; Segment:offset (far pointer : adresse lointaine)
JMP [BX] ; Offset contenu dans le mot de 16 bits pointé par DS:BX
es:
JMP [BX] ; Offset contenu dans le mot de 16 bits pointé par ES:BX
JMP far ptr [BX] ; Segment:offset contenu dans les deux mots de 16 bits pointés par BX (BX pour l'offset, BX+2 pour le segment)
Saut conditionnel
[modifier | modifier le wikicode]Les instructions de saut conditionnel n'effectue le saut que si la condition correspondante est réalisée.
Comme pour l'instruction JMP
, le seul paramètre est une adresse.
Toutefois, sur les anciens processeurs, l'adresse ne peut aller au delà de 128 octets en arrière ou 127 octets en avant, car l'adresse n'est codée que sur un octet signé.
Dans ce cas, l'astuce est de sauter à une instruction JMP
qui utilise une adresse codée sur plus d'octets.
Comparaison puis saut(s)
[modifier | modifier le wikicode]En assembleur, les conditions if sont décomposées en deux instructions :
- Une opération de comparaison des opérandes réalisant une soustraction ne stockant pas le résultat mais effectue la mise à jour des indicateurs du registre FLAGS,
- Un saut conditionnel basé sur l'état des indicateurs du registre FLAGS.
Cette décomposition permet d'optimiser certains cas :
- Quand les mêmes opérandes sont comparés une seule comparaison est faite, suivie de plusieurs sauts conditionnels ;
cmp ax, bx ; Comparaison : indicateurs mis à jour selon AX-BX
jl quand_plus_petit ; saut si AX < BX (non signé)
jg quand_plus_grand ; saut si AX > BX (non signé)
:quand_egaux
- L'opération de comparaison peut être remplacée par une ou des instructions mettant à jour les indicateurs, ce qui peut éviter une comparaison après une opération arithmétique. Les appels aux fonctions systèmes retournent souvent un état erreur ou OK dans un indicateur du registre FLAGS pouvant être traité par un saut conditionnel dans l'application au retour de l'appel de la fonction.
call sys_open ; Appel à open(...)
jb open_failure ; saut si erreur
Sauts conditionnels
[modifier | modifier le wikicode]La table ci-dessous résume les instructions de saut conditionnel, une case contenant tous les alias de la même instruction :
Instruction et synonymes | Signification (en anglais) | Condition nécessaire |
---|---|---|
JCXZ | Jump if CX is Zero | Registre CX (16 bits) égal à 0 |
JECXZ | Jump if ECX is Zero | Registre CX (32 bits) égal à 0 |
JRCXZ | Jump if RCX is Zero | Registre CX (64 bits) égal à 0 |
JZ
JE |
Jump if Zero flag is set
Jump if both operand were Equals |
Indicateur Zéro à 1
ou quand les deux opérandes A et B sont égaux (A-B = 0) |
JNZ
JNE |
Jump if No Zero flag is set
Jump if both operand were Not Equals |
Indicateur Zéro à 0
ou quand les deux opérandes A et B ne sont pas égaux (A-B != 0) |
JS | Jump if Sign flag is set | Indicateur de signe à 1 (résultat négatif) |
JNS | Jump if No Sign flag is set | Indicateur de signe à 0 (résultat positif) |
JO | Jump if Overflow flag is set | Indicateur de débordement à 1 |
JNO | Jump if No Overflow flag is set | Indicateur de débordement à 0 |
JC
JB JNAE |
Jump if Carry flag is set
Jump if Borrow flag is set / Jump if Below Jump if Not Above or Equal |
Indicateur de retenue à 1 (A < B, c'est à dire A-B < 0, retenue) |
JNC
JNB JAE |
Jump if No Carry flag is set
Jump if No Borrow flag is set / Jump if Not Below Jump if Above or Equal |
Indicateur de retenue à 0 (A >= B, c'est à dire A-B >= 0, pas de retenue) |
JBE
JNA |
Jump if Jump if Below or Equal
Jump if Not Above |
Indicateur de retenue à 1 ou indicateur Zéro à 1 (A < B ou A = B, c'est à dire A-B <= 0) |
JNBE
JA |
Jump if Jump if Not Below or Equal
Jump if Above |
Indicateur de retenue à 0 et indicateur Zéro à 0 (A >= B et A != B, c'est à dire A > B, A-B > 0) |
JL
JNGE |
Jump if Lower
Jump if Not Greater or Equal |
Indicateur de débordement différent de l'indicateur de signe (A < B) |
JNL
JGE |
Jump if Not Lower
Jump if Greater or Equal |
Indicateur de débordement et indicateur de signe égaux (A >= B) |
JLE
JNG |
Jump if Lower or Equal
Jump if Not Greater |
Indicateur de débordement différent de l'indicateur de signe ou indicateur zéro à 1 (A <= B) |
JNLE
JG |
Jump if Not Lower or Equal
Jump if Greater |
Indicateur de débordement et indicateur de signe égaux et indicateur zéro à 0 (A > B) |
JP
JPE |
Jump if Parity flag is set
Jump if Parity Even |
Indicateur de parité à 1 (les 8 bits de poids faible du résultat de A-B comportent un nombre pair de bits à 1) |
JNP
JPO |
Jump if No Parity flag is set
Jump if Parity Odd |
Indicateur de parité à 0 (les 8 bits de poids faible du résultat de A-B comportent un nombre impair de bits à 1) |
Les deux dernières instructions de saut conditionnel JPE
et JPO
permettent de déterminer un bit de parité pour un octet.
Elles sont notamment utilisées lors de la communication par port série.
Sauts conditionnels pour comparaison numérique
[modifier | modifier le wikicode]Les sauts conditionnels utilisables après la comparaison de deux nombres entiers varient selon que les nombres sont signés ou non-signés. L'interprétation diffère quand le bit de poids fort des deux nombres diffèrent.
Valeur (hex) | Interprétation en entiers non-signés | Interprétation en entiers signés |
---|---|---|
AX = 8800 | 34816 | -30720 |
BX = 45A0 | 17824 | +17824 |
Comparaison | AX > BX | AX < BX |
Le tableau suivant montre les sauts conditionnels à utiliser selon l'interprétation des nombres comparés en non-signés ou signés.
Comparaison | Entiers non signés | Entiers signés |
---|---|---|
JB |
JL
| |
JA |
JG
| |
JBE |
JLE
| |
JAE |
JGE
| |
JE
| ||
JNE
|
Appel à un sous-programme
[modifier | modifier le wikicode]L'instruction CALL
permet d'appeler un sous-programme.
Le seul paramètre de cette instruction est l'adresse du sous-programme à appeler.
Cette adresse peut être une constante, ou contenue dans un emplacement mémoire (un pointeur).
CALL adresse
Exemples :
CALL 20E5 ; Offset (near pointer : adresse proche)
CALL 2AE1:0200 ; Segment:offset (far pointer : adresse lointaine)
CALL [BX] ; Offset contenu dans le mot de 16 bits pointé par DS:BX
es:
CALL [BX] ; Offset contenu dans le mot de 16 bits pointé par ES:BX
CALL far ptr [BX] ; Segment:offset contenu dans les deux mots de 16 bits pointés par BX (BX pour l'offset, BX+2 pour le segment)
L'instruction CALL
est similaire à JMP
excepté qu'avant d'effectuer le saut à l'adresse indiquée, l'adresse de retour est enregistrée dans la pile :
- Pour un appel d'adresse proche, seul l'offset est sauvegardé.
- Pour un appel d'adresse lointaine, le segment et l'offset sont sauvegardés.
L'adresse de retour sauvegardée dans la pile est celle du premier octet de l'instruction qui suit l'instruction CALL
.
Le sous-programme doit se terminer par une instruction de retour pour restituer l'adresse sauvegardée dans les registres CS:IP :
- L'instruction
RET
(Return) restitue l'offset (sous-programme appelé avec adresse proche) ; - L'instruction
RETF
(Return Far) restitue l'offset et le segment (sous-programme appelé avec adresse lointaine).
Il existe aussi une instruction IRET
(Interruption Return) qui en plus restitue les indicateurs mais elle est utilisée plutôt en fin de routine de traitement des interruptions.