Cours et travaux pratiques d’assembleur sur PC sous Linux, tutoriel & guide de travaux pratiques en pdf.
Structures de controle
Dans notre contexte, on appelle structure de contrˆole toute s´equence d’instructions qui permet de contrˆoler la succession des actions d’un programme. En ce qui concerne l’assem-bleur, il s’agit exclusivement de s´equence d’instructions de sauts conditionnels.
Organisation de la memoire : segments et offsets
Sur une architecture 32 bits, la m´emoire physique peut ˆetre consid´er´ee comme une suite
` 32 −1 ; ainsi, on peut adresser environ 4 d’octets. A chaque octet est associ´e un num´ero de 0 a` 2 gigaoctets de m´emoire.
Abstraction de la m´emoire. La segmentation permet au programmeur de voir un pro-cessus en m´emoire sous la forme de plusieurs espaces d’adressages : les segments. Ainsi, chaques composantes du programme (pile, code, tas, donn´ees, etc.) peut avoir son propre segment.
Par exemple, le code binaire du programme en cours d’ex´ecution — stock´e ou non en m´emoire physique — peut ˆetre accessible par un segment. Dans cette abstraction, le code est vue comme une suite d’octets indic´ee de 0 a` 232 − 1. En th´eorie, un segment peut donc recouvrir l’ensemble de la m´emoire mais on n’utilise pas la totalit´e de cette derni`ere (le processeur permet de limiter l’acc`es a` cet espace).
Mode d’adressage et notion de saut. Pour acc´eder a` un octet, le processeur propose 3 m´ecanismes d’adressages :
– l’adressage direct (un registre 32 bits contient une adresse) ;
– l’adressage semi-direct (que nous n’expliciterons pas) ;
– l’adressage logique. On utilise pour ce faire une adresse logique. Cette adresse est com-pos´ee du num´ero du segment — contenu dans un registre 16 bits — et d’un offset — contenu dans un registre 32 bits.
C’est ce dernier mode d’adressage que nous utiliserons. Citons comme exemple d’adresse logique, l’adresse de la prochaˆıne instruction a` ex´ecuter :
– le registre %eip (Instruction Pointer) contient l’offset de la prochaˆıne instruction a` ex´ecuter ;
– le registre %cs (Code Segment) contient le num´ero du segment m´emoire dans lequel sont stock´e les instructions assembleur du code a` ex´ecuter.
Effectuer un saut vers une instruction dans le flux d’instructions consiste a` remplacer le contenu du registre %eip par l’offset de cette instruction. Pour illustrer ce point, nous allons d´ecrire dans la section suivante une instruction effectuant cette op´eration.
Instruction de saut inconditionnelle jmp
Cette instruction provoque un saut `a une adresse pouvant ˆetre sp´ecifi´ee par diff´erents types d’op´erandes :
– une ´etiquette d´efinie dans le segment de code. Remarquez que vous pourriez utiliser une ´etiquette d´efinie dans un segment de donn´ees sans que le compilateur ne bronche : ce n’est qu’`a l’ex´ecution qu’une erreur surviendrait ;
– un registre g´en´eraliste. Si on utilise un registre 8 bits, le saut est qualifi´e de court puisqu’il ne peut modifier la valeur du registre %eip que d’au plus 127. L’usage est d’utiliser un registre de 16 bits : on obtient ainsi un saut proche. L’utilisation d’un registre de 32 bits correspond a` un saut lointain g´en´eralement vers un autre segment de code ;
– une constante (cette possibilit´e est tr`es fortement d´econseill´ee).
Nous n’utiliserons que la premi`ere possibilit´e dans ce fascicule. Ainsi, dans le bout de code suivant :
done:
movl $0,%ebx
movl $1,%eax
jmp fini /* effectue un saut */
movl $666,%ebx
movl $666,%eax
fini:
int $0x80
les instructions :
movl $666,%ebx
movl $666,%eax
ne seront jamais ex´ecut´ees du fait du saut inconditionnel jmp fini.
Exercice 2 — Saut inconditionnel.
V´erifiez cette assertion.
Instructions de saut conditionnelles
Ces instructions v´erifient l’´etat d’un ou plusieurs drapeaux du registre EFLAGS (cf. la description de ce registre dans la section A.1). Si ce registre est dans l’´etat sp´ecifi´ alors le saut d´efini par l’op´erande de l’instruction est effectu´. Sinon, l’instruction suivante est ex´ecut´ee. Consid´erons l’exemple suivant :
top: addl (%ecx), %ebx
addl $4, %ecx /* D\’eplace le << pointeur >> sur l’\’el\’ement
suivant */
decl %eax /* D\’ecr\’emente le compteur EAX */
jnz top /* Si le contenu de EAX est non nul alors
ex\’ecuter le code \‘a partir du label top */
done: movl %ebx, UnAutre /* sinon, le resultat est stock\’e */
L’instruction decl %eax modifie le drapeau ZF en lui assignant la valeur 1 si le contenu de %eax est nul (ce comportement est indiqu´e dans la description de cette instruction dans l’annexe C).
L’instruction jnz top provoque un saut si, et seulement si, le drapeau ZF est positionn´e a` 0. Cette instruction est appel´ee jump if non zero et en tire son nom. On obtient ainsi une structure it´erative permettant la sommation dans le code ci-dessus.
Le tableau suivant regroupe les instructions conditionnelles de saut ainsi que la valeur des drapeaux correspondantes.