Ich möchte Ihnen zeigen, wie Sie Ihr Problem durch die Verwendung GDB finden konnte:
- starten gdb und laden Sie Ihr Programm:
>> gdb write
Breakpoint
- Set direkt am Start:
(gdb) b _start
konnte .Sie einfach Lassen Sie das Programm bis segfault laufen, aber wenn der Stack durcheinander ist, sind die Chancen hoch, dass Sie nichts sehen werden.
- die Anzeige einrichten 5 Top-Werte auf dem Stack nach jedem Schritt automatisch zu zeigen:
(gdb) display/x {unsigned int[5]}$sp
- Um die nächste ausgeführten Zeile zu sehen:
(gdb) display/i $pc
- Jetzt laufen:
(gdb) run
Debugger trifft den Haltepunkt und sehen Sie den Stapel aufgebaut durch das System:
1: /x {unsigned int[5]}$sp = {0x1, 0xffffd284, 0x0, 0xffffd29d, 0xffffd2b2}
Alles Ok, so weit, wurde das Programm mit einem Argument gestartet (012.auf der Oberseite) - der Pfad zum Programm (Sie können es durch (gdb) print (char[10])*(0xffffd284)
sehen).
- machen Sie einen Schritt
(gdb) si
, jetzt sprangen wir auf das message
Symbol.
Mit (gdb) disas
kann man mehr von dem Code sehen:
(gdb) disas
Dump of assembler code for function message:
=> 0x08048083 <+0>: call 0x8048072 <main>
0x08048088 <+5>: dec %eax
0x08048089 <+6>: gs
0x0804808a <+7>: insb (%dx),%es:(%edi)
0x0804808b <+8>: insb (%dx),%es:(%edi)
0x0804808c <+9>: outsl %ds:(%esi),(%dx)
0x0804808d <+10>: and %ecx,(%edx)
End of assembler dump.
Wie Sie sehen können, Ihre "Hallo" -string als Operationen interpretiert wird, beginnend bei 0x08048088
- machen Sie einen weiteren Schritt:
(gdb) si
, gehen in die Funktion main
.
nun einen Blick auf den Stapel nehmen:
1: /x {unsigned int[5]}$sp = {0x8048088, 0x1, 0xffffd283, 0x0, 0xffffd29c}
Die call
-Befehl schob die Rücksprungadresse auf dem Stack - 0x08048088
- die Adresse Ihrer Zeichenfolge. Nizza Trick, hoffen wir, dass main
wird nie wieder zurückkehren ...
- Lassen Sie uns schnell nach vorn auf den Aufruf von
write
: (gdb) si 3
und gehen innerhalb (gdb) si
.
die auf dem Stapel Werfen wir einen Blick, wie erwartet, hinzugefügt call
die Rücksprungadresse auf den Stack:
1: /x {unsigned int[5]}$sp = {0x804807b, 0x8048088, 0x7, 0x1, 0xffffd283}
- Ihr Programm erwartet, dass der Zeiger auf den String und die Länge oben zu sein, aber das ist nicht der Fall.
- Ermöglicht schnellen Vorlauf zur Rückkehr der Funktion
write
: (gdb) si 7
.
Werfen Sie einen Blick auf den Stapel:
1: /x {unsigned int[5]}$sp = {0x7, 0x1, 0xffffd283, 0x0, 0xffffd29c}
die nächste Operation - ret
0x7
vom Stapel pop und versuchen, die Ausführung an der Adresse 0x7
, die in einem segfault führt zu übernehmen (wie rcd Verdacht).
Ihr Problem ist also, dass Ihre Funktionen den Stapel beschädigen. Normalerweise ist die Funktion, die den Stapel für einen Anruf aufbaut, auch dafür verantwortlich, ihn danach zu bereinigen.
ist nicht die Zeichenfolge Hallo! sollte mit 0 enden? da es eine Schnur ist? – rcd
@rcd Da dies ein Aufruf zum Schreiben ist und ich die Länge der Zeichenfolge angeben muss, nein, muss es nicht nullterminiert sein. – Fluffy
Was zeigt das Ausführen in einem Debugger? Wo denkst du, dass die 'ret'-Anweisung zurückkommen wird, seit du sie am Anfang von' write' vom Stapel genommen hast? Vielleicht hast du vergessen, dass mit einem 'call' die Rücksendeadresse auf den Stack geschoben wird? Ich vermute, dass, seit Sie die Rücksprungadresse plus das erste Argument, dass Ihr Code versucht, zu Speicheradresse 7, die an der Spitze des Stapels gewesen wäre, wenn Ihr Aufruf zum 'write' zurückgegeben wird zurückgegeben. –