Segmentation Fault in Assembly-Sprache
Ich bin learningn AT&T, x86 assembly language". Ich bin versucht, zu schreiben ein Assembler-Programm, das dauert eine ganze Zahl n, und dann wieder das Ergebnis (n/2+n/3+n/4). Hier ist, was ich getan habe:
.text
.global _start
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
mov $0, %esi
movl $4, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $3, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $2, %ebp
div %ebp
addl %eax, %esi
movl %esi, %eax
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
ret
Das problem ist, ich bin immer segmentation fault. Wo ist das problem?
Haben Sie versucht, schrittweise durch den code mit einem debugger, um zu sehen, was Los ist ?
AT&T verzweigt in die Prozessoren? (-:
tripleee: "AT&T-syntax" bezieht sich auf die assembler-syntax, die ursprünglich aus der SysV-Unix. Es setzt das operand-size auf die Anweisung, wie ein suffix verwendet ein "%" zu-tag-Namen registrieren, und setzt das Ziel-register am Ende der Liste. Es ist die syntax, unterstützt von den GNU-assembler unter linux. Es ist ganz anders als "Intel" - syntax verwendet, die häufiger in der PC-Industrie.
Wenn du gehst, um zu lernen, Intel assembly language verwenden Sie die Intel-syntax. In einer anständigen Welt, die Greuel, die Sie aufrufen AT&T-syntax würde nie existiert haben.
AT&T verzweigt in die Prozessoren? (-:
tripleee: "AT&T-syntax" bezieht sich auf die assembler-syntax, die ursprünglich aus der SysV-Unix. Es setzt das operand-size auf die Anweisung, wie ein suffix verwendet ein "%" zu-tag-Namen registrieren, und setzt das Ziel-register am Ende der Liste. Es ist die syntax, unterstützt von den GNU-assembler unter linux. Es ist ganz anders als "Intel" - syntax verwendet, die häufiger in der PC-Industrie.
Wenn du gehst, um zu lernen, Intel assembly language verwenden Sie die Intel-syntax. In einer anständigen Welt, die Greuel, die Sie aufrufen AT&T-syntax würde nie existiert haben.
InformationsquelleAutor user1700688 | 2012-09-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke, der code schlägt fehl, hier:
So, Sie
push $24
(4 bytes) und danncall profit
, die schiebteip
und springt zuprofit
. Dann knallen Sie den Wert voneip
inebx
und der Wert$24
ineax
.Dann, am Ende, wenn
jg end
Filialenend:
, dann ist der stack nicht im Besitz einer gültigen Absenderadresse und dieret
fehl. Sie müssen wahrscheinlichpushl %ebx
es auch.InformationsquelleAutor nrz
Sie scheinbar nicht tun Funktionsaufrufe korrekt. Sie müssen Lesen und verstehen die x86-ABI (32-bit, 64-bit) insbesondere die "calling convention" Abschnitten.
Dies ist auch nicht Ihre unmittelbare problem, aber: schreiben Sie nicht
_start
schreibenmain
als wäre dies ein C-Programm. Wenn Sie beginnen, tun etwas komplizierter, Sie wollen die C-Bibliothek verfügbar sein, und das bedeutet, Sie haben zu lassen, es initialisiert sich selbst. Relatedly, nicht stellen Sie Ihr eigenes system fordert; Aufruf der Wrapper der C-Bibliothek. Das isoliert Sie von der low-level-änderungen in der kernel-Schnittstelle sorgt dafür, dasserrno
verfügbar ist, und so weiter._start
durchaus gültig ist dies hier ein reines Assembler-Programm.InformationsquelleAutor zwol
ecx
ohne jemals explizit initialisieren (ich bin mir nicht sicher, ob Linux garantiert der Staatecx
wenn der Prozess beginnt - wie es aussieht ist0
in der Praxis, wenn nicht durch die Regel)jg end
springen in der Nähe des Ende des Verfahrens wird die return-Adresse nicht mehr auf dem Stapel, soret
transfer Steuerelement, um einige Müll-Adresse.InformationsquelleAutor Michael Burr
Sieht es für mich wie Sie haben eine einzelne pushl rufen Sie vor dem profit und dann die erste Sache, die Gewinn macht, ist ein zwei popl Anweisungen. Ich würde erwarten, dass diese pop wäre der Wert, den Sie auf dem Stapel als auch der return-code so, dass das ret nicht funktionieren würde.
push-und pop-sollte die gleiche Anzahl von Zeiten.
rufen Sie drückt die return-Adresse auf den stack.
InformationsquelleAutor Richard Chambers
Dein problem ist, dass Sie aus dem pop-return-Adresse vom stack und wenn Sie den Zweig zu Ende, die Sie nicht wiederherstellen. Eine schnelle Lösung ist das hinzufügen
push %ebx
auch dort.Was Sie tun sollten, ist zu ändern Sie Ihre Vorgehensweise, so verwendet er die Aufruf-Konvention korrekt. Unter Linux wird die caller-Funktion wird erwartet, dass sauber die Argumente vom Stapel, so dass Ihr Verfahren sollte, lassen Sie Sie, wo Sie sind.
Statt dies zu tun, um das argument und dann wiederherstellen Sie die Adresse zurück, die später
Sollten Sie dies tun, und lassen Sie die Absenderadresse und die Argumente, wo sind Sie
bekommen und entfernen Sie den code, der schiebt die Rücksprungadresse zurück auf den stack. Sie sollten dann fügen Sie
nach dem Aufruf der Prozedur entfernen Sie das argument vom stack. Es ist wichtig, um dieses übereinkommen ordnungsgemäß, wenn Sie wollen in der Lage sein zu rufen, Ihre Montage-Prozeduren aus anderen Sprachen.
InformationsquelleAutor Dirk Holsopple