Cours n°7 :
Assembleur

R1.03 - Intro. Archi
Victor Poupet

Compilation

Source : Laura Roudge

Langages de programmation trop complexes pour le CPU


Registres

Les registres sont des emplacements mémoire sur le CPU pouvant contenir une valeur numérique (en général 32 bits ou 64 bits)


Quelques registres courants (32 bits) :

Quelques registres courants (64 bits) :

Instructions

Les instructions assembleur correspondent aux opérations élémentaires du CPU

Instructions

Quelques instructions courantes :

Flags

Source : Wikipedia

La pile

  • Segment de mémoire pour les variables locales des fonctions
  • Très fréquemment utilisée (→ cache)
  • En général augmente dans le sens des adresses décroissantes
  • Opérations
    • Ajout en haut de pile (push)
    • Suppression en haut de pile (pop)
  • Séparée en blocs (stack frames) correspondant aux fonctions en cours d'exécution
  • Registre rsp (stack pointer) contient l'adresse du haut de pile
  • Registre rbp (base pointer) contient l'adresse du bas du bloc

Changement de frame :

push  %rbp
mov   %rsp, %rbp
...
pop   %rbp

Premier exemple

int main() {
  int x = 12;
  int y = x + 14;
  return 0;
}

 $ gcc -S -o prog.s prog.c
.globl  _main  ; visible pour linker
_main:  ; déclaration de fonction
  push  %rbp
  mov   %rsp, %rbp
  xor   %eax, %eax   ; valeur de retour
  mov   $0, -4(%rbp) ;  "
  mov   $12, -8(%rbp)   ; x
  mov   -8(%rbp), %ecx  ; addition
  add   $14, %ecx       ;  "
  mov   %ecx, -12(%rbp) ; y
  pop   %rbp
  ret

Exécution conditionnelle

int main() {
  int a = 12;
  if (a > 10) {
    return 1;
  } else {
    return 0;
  }
}
.globl _main
_main:
  push  %rbp
  mov   %rsp, %rbp
  mov   $0, -4(%rbp)
  mov   $12, -8(%rbp) ; a
  cmp   $10, -8(%rbp) ; test
  jle   LBB0_2        ; saut si a <= 10
  mov   $1, -4(%rbp)  ; val de retour
  jmp   LBB0_3
LBB0_2:
  mov   $0, -4(%rbp)  ; val de retour
LBB0_3:
  mov   -4(%rbp), %eax
  pop   %rbp
  ret

Appel de fonction

int f(int x, int y) {
  return x + y;
}

int main() {
  int a = 12;
  int b = f(a, 14);
  return 0;
}
call _f          push %rip
                 mov _f, %rip
  ...              ...
ret              pop %rip
.globl _f
_f:
  push  %rbp
  mov   %rsp, %rbp
  mov   %edi, -4(%rbp)  ; x
  mov   %esi, -8(%rbp)  ; y
  mov   -4(%rbp), %eax  ; addition
  add   -8(%rbp), %eax  ;  "
  pop   %rbp
  ret
.globl  _main
_main:
  push  %rbp
  mov   %rsp, %rbp
  sub   $16, %rsp      ; stack frame
  mov   $0, -4(%rbp)
  mov   $12, -8(%rbp)  ; a
  mov   -8(%rbp), %edi ; x
  mov   $14, %esi      ; y
  call  _f    ; appel de fonction
  xor   %ecx, %ecx
  mov   %eax, -12(%rbp); retour de f
  mov   %ecx, %eax
  add   $16, %rsp      ; stack frame
  pop   %rbp
  ret

Boucle

int main() {
  int t = 0;
  for (int i = 0; i < 10; i++) {
    t += i;
  }
  return t;
}
.globl _main
_main:
  push  %rbp
  mov   %rsp, %rbp
  mov   $0, -4(%rbp)
  mov   $0, -8(%rbp)  ; t
  mov   $0, -12(%rbp) ; i
LBB0_1:
  cmp   $10, -12(%rbp)  ; test
  jge   LBB0_4  ; saut si i >= 10
  mov   -12(%rbp), %eax ; addition
  add   -8(%rbp), %eax  ;  "
  mov   %eax, -8(%rbp)  ; -> t
  mov   -12(%rbp), %eax ; incrémentation
  add   $1, %eax        ;  "
  mov   %eax, -12(%rbp) ; -> i
  jmp   LBB0_1
LBB0_4:
  mov   -8(%rbp), %eax  ; val retour
  pop   %rbp
  ret