GNU Assembler (AT&T-Syntax) unter Linux für 64 Bit-Plattform - Programm ohne Anweisung stirbt mit Segfault



  • Bei Aufruf des erstellten Programms erscheint die Fehlermeldung 'Speicherzugriffsfehler (Speicherabzug geschrieben)'. dmesg gibt lediglich die Zeile aus:

    [x.y] test[8080]: segfault at 1 ip 0000000000000001 sp 00007fff19712848 error 14 in test[400000+1000]
    

    Verwendete Linux-Distro: Debian
    Verwendeter Assembler: siehe oben.
    Verwendeter Linker: 'ld'
    Verwendete Plattform: 64 Bit Athlon

    Code der verwendeten Makefile:

    as --verbose --64 -o test.o test.asm
    ld --verbose -o test test.o
    

    Assembly-Code (Für 'as', der GNU Assembler):
    test.asm

    .section .text
    .global _start
    _start:
            ret
    

    Ich habe etliche Dokumentationen zu dem Thema angeschlagen, aber entweder wurde vom GAS abgeraten oder es wurde für x86 programmiert. Im Code tauchen keine besonderen Befehle auf, tatsächlich sorgt bereits das ret für den Segfault. as und ld geben keine Fehlermeldungen zurück, die Objektdatei wird korrekt erstellt und ld gibt 'attempt to open test.o succeeded' und die Datei 'test' aus. Es sind meine ersten Schritte mit Assembler, aber diesen Fehler kann ich nicht nachvollziehen. Die FAQ habe ich bereits konsultiert, dort wird aber nur direkt auf die Programmierung unter x86 verlinkt. Das Programm sollte sich eigentlich sofort beenden, aber egal, welchen Code ich dort einfüge, gibt es den gleichen Fehler. Er tritt nicht auf, wenn ich Assembler-Code in C-Code einbinde. Meine Bǘcher und Tutorials kennen diesen Fehler nicht.

    Ich habe auch versucht, gdb auf die Datei anzuwenden, allerdings mit dem gleichen für mich nichtssagenden Resultat:

    gdb test
    GNU gdb (xxx) yyy
    Copyright (C) 2012 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/xxx/assembler/test...(no debugging symbols found)...done.
    (gdb) run
    Starting program: /home/xxx/assembler/test 
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000000001 in ?? ()
    

    Mir fallen leider keine Möglichkeiten mehr ein, wie ich den Fehler begrenzen kann, und mehr habe ich bisher auch nicht finden können. Eventuell fällt es jemandem hier auf, ich sehe gerade den Wald vor Bäumen nicht.



  • Schon mal mit sys_exit versucht? Oder ein Rückgabewert setzen (xor eax,eax)?



  • Zu Rückgabewert setzen:
    Ja, habe ich schon (sowohl %eax als auch %rax für das 64-Bit-Register) - hat aber nichts gebracht, der Segfault taucht nach neuassemblierung immer noch auf, allerdings mit der Meldung:

    Program received signal SIGSEGV, Segmentation fault.
    0x000000000040007b in ?? ()
    

    Zu sys_exit:
    Habe ich gerade ausprobiert:

    _start:
            movl $1,%eax
            movl $0,%ebx
            int $0x80
    

    Funktioniert zwar, der Segfault wird nicht mehr angezeigt, allerdings erwähnt mein Buch nichts hiervon, den Code habe ich gerade so eingebaut. Streng genommen wird auch der Prozess beendet, bevor die Funktion zurückkehren und den Fehler verursachen kann, und mich würde schon interessieren, warum dies passiert.



  • Dr.Google: sys_exit ist die einzige Methode um Threads zu verlassen, da diese nicht mit Call aufgerufen werden und somit auch keine Rücksprungadresse auf dem Stack vorliegt.



  • Der aus dem Westen .. schrieb:

    Funktioniert zwar, der Segfault wird nicht mehr angezeigt, allerdings erwähnt mein Buch nichts hiervon, den Code habe ich gerade so eingebaut. Streng genommen wird auch der Prozess beendet, bevor die Funktion zurückkehren und den Fehler verursachen kann, und mich würde schon interessieren, warum dies passiert.

    Sicher, dass dein Buch nicht Programme beschreibt, die vom Startup-Code der Libc aufgerufen werden? Dann würde ret ja funktionieren. Ansonsten musst du in der Tat den entsprechenden Syscall aufrufen, um dein Programm zu beenden.

    In einem 64-Bit-Programm macht man das aber nicht mit int 0x80, sondern mit dem Syscall-Befehl.

    movl $60, %eax //Syscall-Nr für exit
    syscall
    

    Ein exit(2) zu übergebender Rückgabewert gehört in rdi.


Anmelden zum Antworten