Bonjour,

Première question, je me demandais où pointait $eip lorsqu'on arrive à la fin de la fonction main (ret).


Il y a quelque chose qui me chagrine avec gcc, je ne comprend pas pourquoi lorsque je compile une simple source ( int main(){} ) avec gcc sous une debiane j'obtiens :

version gcc 4.0.4 20060507 (Debian 4.0.3-3)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
 
;prologue
push   %ebp
mov    %esp,%ebp
 
;épilogue
pop    %ebp
ret
alors que sous fedora core, j'obtiens pour le même code un truc plus compliqué avec des instructions vraiment inutiles mais qui au final revient à exactement à la même chose :

gcc 4.1.1 20060525 (Red Hat 4.1.1-1)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
;prologue

0x08048354 <main+0>:    lea    0x4(%esp),%ecx 
;on sauvegarder l'addresse de la pile + 4 (correspond à l'adresse de retour theoriquement)

0x08048358 <main+4>:    and    $0xfffffff0,%esp 

;on reserve un espace (entre 0 et 16 octets) dans la pile
;alignement de la pile ?

0x0804835b <main+7>:    pushl  0xfffffffc(%ecx) 
; on empile ecx - 4 soit l'adresse la pile a la base
; cette valeur n'est même pas dépilé dans l'epilogue

0x0804835e <main+10>:   push   %ebp             
 ;sauvegarde du pointeur de frame

0x0804835f <main+11>:   mov    %esp,%ebp      
;nouveau pointeur de pile

0x08048361 <main+13>:   push   %ecx              
;on empile ecx (contient donc ancien adresse esp + 4)


[le corp de la fonction]

;épilogue

0x08048362 <main+14>:   pop    %ecx               
; (qui contient ancienne adresse esp + 4)              

0x08048363 <main+15>:   pop    %ebp
; on réstaure le pointeur de frame

0x08048364 <main+16>:   lea    0xfffffffc(%ecx),%esp
; esp <- ecx-4 soit la l'ancienne valeur de esp
; 
; là je me demande alors l'utilité de l'instruction du prologue : 0x0804835b <main+7>:    pushl  0xfffffffc(%ecx) 
; => équivalent de leave

0x08048367 <main+19>:   ret
; eip restauré
Pourquoi faire :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
0x08048354 <main+0>:    lea    0x4(%esp),%ecx
0x08048358 <main+4>:    and    $0xfffffff0,%esp
0x0804835b <main+7>:    pushl  0xfffffffc(%ecx)
alors qu'on peut aussi simplement faire(ou alors peut etre que je ne comprend pas du tout la syntaxe AT&T, mais je crois bien que c'est équivalent) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
0x08048354 <main+0>:    mov    %esp,%ecx
0x08048358 <main+4>:    and    $0xfffffff0,%esp
0x0804835b <main+7>:    pushl  %ecx