Ich analysiere die Demontage des folgenden (sehr einfachen) C-Programms in GDB auf X86_64.Die Adressierung von Stack-Variablen
int main()
{
int a = 5;
int b = a + 6;
return 0;
}
Ich verstehe, dass in X86_64 der Stapel wächst nach unten. Das heißt, der obere Teil des Stapels hat eine niedrigere Adresse als der untere Teil des Stapels. Der Assembler aus dem obigen Programm ist wie folgt:
Dump of assembler code for function main:
0x0000000000400474 <+0>: push %rbp
0x0000000000400475 <+1>: mov %rsp,%rbp
0x0000000000400478 <+4>: movl $0x5,-0x8(%rbp)
0x000000000040047f <+11>: mov -0x8(%rbp),%eax
0x0000000000400482 <+14>: add $0x6,%eax
0x0000000000400485 <+17>: mov %eax,-0x4(%rbp)
0x0000000000400488 <+20>: mov $0x0,%eax
0x000000000040048d <+25>: leaveq
0x000000000040048e <+26>: retq
End of assembler dump.
ich verstehen:
- Wir schieben den Basiszeiger auf den Stapel.
- Wir kopieren dann den Wert des Stapelzeigers zum Basiszeiger.
- Wir kopieren dann den Wert 5 in die Adresse
-0x8(%rbp)
. Da in einem int ist 4 Bytes sollte dies nicht an der nächsten Adresse im Stapel sein, die-0x4(%rbp)
statt-0x8(%rbp)
ist?. - Wir kopieren dann den Wert an der Variablen
a
in%eax
, fügen 6 hinzu und kopieren dann den Wert in die Adresse-0x4(%rbp)
.
die diese Grafik als Referenz verwenden:
http://eli.thegreenplace.net/images/2011/08/x64_frame_nonleaf.png
es wie der Stapel sieht hat folgenden Inhalt:
|--------------|
| rbp | <-- %rbp
| 11 | <-- -0x4(%rbp)
| 5 | <-- -0x8(%rbp)
, als ich das erwartet hatte:
|--------------|
| rbp | <-- %rbp
| 5 | <-- -0x4(%rbp)
| 11 | <-- -0x8(%rbp)
whi ch scheint der Fall in 7-understanding-c-by-learning-assembly zu sein, wo sie die Montage zeigen:
(gdb) disassemble
Dump of assembler code for function main:
0x0000000100000f50 <main+0>: push %rbp
0x0000000100000f51 <main+1>: mov %rsp,%rbp
0x0000000100000f54 <main+4>: mov $0x0,%eax
0x0000000100000f59 <main+9>: movl $0x0,-0x4(%rbp)
0x0000000100000f60 <main+16>: movl $0x5,-0x8(%rbp)
0x0000000100000f67 <main+23>: mov -0x8(%rbp),%ecx
0x0000000100000f6a <main+26>: add $0x6,%ecx
0x0000000100000f70 <main+32>: mov %ecx,-0xc(%rbp)
0x0000000100000f73 <main+35>: pop %rbp
0x0000000100000f74 <main+36>: retq
End of assembler dump.
Warum wird der Wert von b
in eine höhere Speicheradresse als a
in den Stapel gelegt wird, wenn a
eindeutig deklariert und zunächst initialisiert?
Der Compiler kann die Variablen für die automatische Dauer auf einmal auf dem Stapel zuweisen, wenn es sich so anfühlt. Nur der naivste Compiler würde den Code durchlaufen und bei jeder Deklaration und jedem Exit des Bereichs den Stapelzeiger ändern, und verschiedene Compiler und Versionen davon könnten anderen Code ausspucken. Der C-Standard selbst hat nichts über die relativen Adressen zweier automatischer Variablen zu sagen. –