Analyse d'un processus de saut simple
- Code source
#include <stdio.h>
int difference(int x, int y) {
return x - y;
}
int total(int val1, int val2) {
int resultat = difference(100, 9);
return val1 + val2 + resultat;
}
int principal(void) {
int premiere = 12;
int seconde = 98;
int total_resultat = total(premiere, seconde);
return 0;
}
- Code assembleur après compilation
0x555555555129 <difference> endbr64
0x55555555512d <difference+4> push %rbp
0x55555555512e <difference+5> mov %rsp,%rbp
0x555555555131 <difference+8> mov %edi,-0x4(%rbp)
0x555555555134 <difference+11> mov %esi,-0x8(%rbp)
0x555555555137 <difference+14> mov -0x4(%rbp),%eax
0x55555555513a <difference+17> sub -0x8(%rbp),%eax
0x55555555513d <difference+20> pop %rbp
0x55555555513e <difference+21> retq
0x55555555513f <total> endbr64
0x555555555143 <total+4> push %rbp
0x555555555144 <total+5> mov %rsp,%rbp
0x555555555147 <total+8> sub $0x18,%rsp
0x55555555514b <total+12> mov %edi,-0x14(%rbp)
0x55555555514e <total+15> mov %esi,-0x18(%rbp)
0x555555555151 <total+18> mov $0x9,%esi
0x555555555156 <total+23> mov $0x64,%edi
0x55555555515b <total+28> callq 0x555555555129 <difference>
0x555555555160 <total+33> mov %eax,-0x4(%rbp)
0x555555555163 <total+36> mov -0x14(%rbp),%edx
0x555555555166 <total+39> mov -0x18(%rbp),%eax
0x555555555169 <total+42> add %eax,%edx
0x55555555516b <total+44> mov -0x4(%rbp),%eax
0x55555555516e <total+47> add %edx,%eax
0x555555555170 <total+49> leaveq
0x555555555171 <total+50> retq
0x555555555172 <principal> endbr64
0x555555555176 <principal+4> push %rbp
0x555555555177 <principal+5> mov %rsp,%rbp
0x55555555517a <principal+8> sub $0x10,%rsp
0x55555555517e <principal+12> movl $0xc,-0xc(%rbp)
0x555555555185 <principal+19> movl $0x62,-0x8(%rbp)
0x55555555518c <principal+26> mov -0x8(%rbp),%edx
0x55555555518f <principal+29> mov -0xc(%rbp),%eax
0x555555555192 <principal+32> mov %edx,%esi
0x555555555194 <principal+34> mov %eax,%edi
0x555555555196 <principal+36> callq 0x55555555513f <total>
0x55555555519b <principal+41> mov %eax,-0x4(%rbp)
0x55555555519e <principal+44> mov $0x0,%eax
0x5555555551a3 <principal+49> leaveq
0x5555555551a4 <principal+50> retq
- Description des registres
%rsp: Pointeur de pile, pointant vers le sommet de la trame de pile de la fonction actuelle (position la plus basse)rip: Pointe vers l'instruction actuellement en cours d'exécution%eax: La valeur de retour doit être stockée dans%eax(convention)
- Description des instructions
endbr64: Peut être ignoré, cette instruction ne modifie aucune donnéepush %rbp: Diminue[%rsp], puis stocke la valeur dans[%rsp]
[%rsp] = [%rsp] - 8
[%rsp] = [%rbp]
Note : %rsp stocke une adresse de pile, donc ici nous ne stockons pas la valeur dans le registre, mais dans l'adresse de pile pointée par %rsp
mov src dest:[dest] = [src]movl $0xc,-0xc(%rbp): Stocke un immédiat dans la pilecallq total: Saut, stocke l'adrsese de l'instruction suivante sur la pile, puis saute pour continuer l'exécution
[%rsp] = [%rsp] - 8
[%rsp] = adresse de la prochaine instruction, ici 0x55555555519b
[%rip] = 0x55555555513f (adresse de la fonction total, saut vers total)
pop %rbp:
[%rbp] = [%rsp]
[%rsp] = [%rsp] + 8
retq:
popq %rip:
[%rip] = [%rsp]
[%rsp] = [%rsp] + 8
leaveq:
mov %rbp, %rsp
popq %rbp
- Analyse du code
Supposons que rsp = X au départ
principal()
- Stocke la base de la trame de pile de la fonction appelant principal dans la pile
push %rbp:
%rsp = %rsp-8 = X-8
[%rsp] = [%rbp]
- Définit l'adresse de base de la trame de pile actuelle pour rbp
mov %rsp,%rbp
- Crée la trame de pile pour la fonction actuelle,
rsppointant vers le sommet de la trame
sub $0x10,%rsp
rsp = rsp - 16 # Crée une trame de pile de 16B
- Les quatre lignes suivnates créent les variables, car on ne peut pas placer directement des nombres dans les registres, il faut utilsier la pile
- Les deux lignes suivantes placent les variables dans les registres de passage de paramètres spécifiés
- Stocke l'adresse de retour d'exécution dans la pile, fait pointer rip vers total, et effectue le saut
callq 0x55555555513f <total>
[rsp] = [rsp] - 8
[rsp] = adresse de la prochaine instruction, ici 0x5555,5555,519b
[rip] = adresse de la fonction total, saut vers total
Trame de pile actuelle
total()
Similaire à la fonction principale précédemment, stocke la base de la trame de pile de la fonction précédente, crée une trame de pile, extrait les paramètres passés par la fonction précédente, les place dans la pile, exécute, puis saute à la fonction difference
Trame de pile actuelle
difference()
Similaire auparavant, commençons l'explication à partir de pop %rbp
Trame de pile actuelle comme suit
pop %rbp
[%rbp] = [%rsp]
[%rsp] = [%rsp] + 8
À ce stade, %rbp pointe vers rbp_total, %rsp pointe vers l'adresse de retour de total 2. retq
[%rip] = [%rsp]
[%rsp] = [%rsp] + 8
À ce stade, rip pointe vers adresse de retour de total, rsp pointe vers le sommet de la pile de la fonction difference
Saut de retour vers total()
total()
Comme difference n'a pas créé de trame de pile, le retour est plus simple. Lorsqu'une trame de pile est créée, l'instruction leaveq est nécessaire pour effectuer le retour
leaveq
1.mov %rbp, %rsp:
%rsp = %rbp
2.popq %rbp:
[%rbp] = [%rsp]
[%rsp] = [%rsp] + 8
À ce stade, %rbp pointe vers rbp_principal, rsp pointe vers l'adresse de retour de principal2. retq
[%rip] = [%rsp]
[%rsp] = [%rsp] + 8
À ce stade, rip pointe vers adresse de retour de principal, rsp pointe vers le sommet de la pile de la fonction total
Saut de retour vers principal()
Note:
Vous pouvez compiler et exécuter manuellement pour observer
Manuel d'utilisation simple de gdb