kostenloser Webspace werbefrei: lima-city


ASM: Problem mit C-Call pthread

lima-cityForumProgrammiersprachenSonstige Programmiersprachen

  1. Autor dieses Themas

    toolz

    Kostenloser Webspace von toolz

    toolz hat kostenlosen Webspace.

    Ich versuche mich gerade an pthread, allerdings in Assembler. In C ist mir ein vergleichbares Programm bereits gelungen. Die Syntax gehört zu Linux-FASM, es kompiliert ohne Fehler:
    fasm pthread.asm && gcc -pthread pthread.o
    Jedoch kommt beim Ausführen ein Speicherzugriffsfehler, der sich mir nicht erschließt. Durch Einfügen diverser Debugausgaben konnte ich feststellen, dass die main anscheinend insgesamt nicht durchlaufen wird, wenn ich darin einen Aufruf an pthread mache. Bei Auskommentieren von Aufruf und Extern-Anweisung läuft das Programm jedoch fehlerfrei durch.
    FORMAT elf
    PUBLIC main
    SECTION '.text' executable
    
    main:
        PUSH fkt
        PUSH null
        PUSH zgr
        CALL pthread_create
    
        CALL fkt
    
        PUSH null
        PUSH zgr
        CALL pthread_join
    
        PUSH [anz]
        PUSH msg
        CALL printf
    RET
    
    fkt:
        INC [anz]
    RET
    
    EXTRN printf
    EXTRN pthread_create
    EXTRN pthread_join
    SECTION '.data'
    anz DD 0
    null DD 0
    msg DB "Anzahl der Aufrufe: %i",10,0
    zgr DD ?
    Wo liegt hier mein Fehler? Ich konnte ihn jetzt nach sehr langer Suche immer noch nicht entdecken...
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Hallo toolz,

    laut meiner Man-Page erwartet pthread vier Argumente:
    int pthread_create(
            pthread_t *restrict, 
            const pthread_attr_t *restrict, 
            void *(*)(void *), 
            void *restrict);

    Du hast aber nur drei, weshalb der Rücksprung aus pthread_create() wohl zum Aufruf einer falschen Adresse führt.


  4. Autor dieses Themas

    toolz

    Kostenloser Webspace von toolz

    toolz hat kostenlosen Webspace.

    In der Tat, da hast du zwar Recht, aber da meine Funktion fkt ja keine Argumente abruft (das vierte Argument also niemals vom Stapel geholt werden würde) stecke ich es gleich gar nicht hinein. Versuchsweise habe ich jetzt aber doch mal ein
    PUSH DWORD 0
    vor Zeile 6 geschrieben, allerdings stimmt es dann immer noch nicht (und ich glaube das ist dann sogar noch zusätzlicher Fehler).
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    Also das letzte Argument von pthread_create sind doch nur die Argumente der aufzurufenden Funktion - auf Assemblerebene kann ich das auch einfach weglassen, wenn die Funktion keine Argumente erwartet. Ich habe vielmehr das Gefühl, dass ich die Funktionsadresse falsch übergebe... Aber selbst wenn ich die nocheinmal in eine Variable packe und dann die Adresse der Variablen auf den Stapel haue wird mir immernoch ein Fehler beim Ausführen angezeigt.
    Ich bin etwas ratlos.
  5. Hallo toolz,

    die Argumente kann man auf keinen Fall weglassen, da die pthread_create() Funktion ja nicht wissen kann, dass Du das Argument weglässt. Daher wird sie immer vier Argumente vom Stack holen.
    Mein Arch hat den FASM jetzt leider auch nicht im Repo, dass ich es schnell testen könnte und eine offensichtlichen Fehler erkenne ich jetzt auch nicht :-(
  6. Autor dieses Themas

    toolz

    Kostenloser Webspace von toolz

    toolz hat kostenlosen Webspace.

    Stimmt! Je nach Implementierung kann pthread_create tatsächlich versuchen, das Argument vom Stapel zu holen (was noch nicht das Problem ist) und es dann analysieren wollen (das wäre ein Problem)! Aber selbst wenn ich sicherheitshalber noch null übergebe klappt die Ausführung nicht.
    Mein Debugger funktioniert leider gerade nicht und ich finde den Fehler einfach nicht.
    Bist du mittlerweile weiter gekommen? Oder weiß jemand anderes etwas darüber?

    Edit: Jetzt habe ich den Debugger wieder zum Laufen gebracht (extra hierfür) und es stellt sich heraus, dass der Prozess in der Routine pthread_create stecken bleibt. Und zwar bei einer Anweisung
    rep stosd
    , falls euch das hilft...

    Beitrag zuletzt geändert: 15.2.2014 20:07:07 von toolz
  7. Vorweg: ich habe keine Asm-Erfahrung unter Linux, troztzdem muss ich hier mal meinen Senf dazu abgeben:

    pthread_create erwartet als 3.Parameter einen Zeiger auf eine Funktion, welche selbst einen Pointer als Parameter nimmt. Du übergibst eine Speicheradresse, welche durchaus ausführbaren COde enthält, aber vermutlich keine Funktion darstellt. Für eine solche gibt es ja irgendwelche Calling-Convetions, von denen ich gerade nicht weiß wie die hier konkret aussieht, aber normal gehört da ja auch dazu, dass du deine Parameter (auch deine 0) in gegebener Reihenfolge vom Stack abholst, sonst "verrutscht" der Stackpointer und nach dem return wird auf die falschen Daten zugegriffen.
    Daher vermute ich, dass hier bei fkt: mindestens ein entsprecehender pop-Aufruf fehlt.
    Um dir anzusehen, wie das aussehen müsste, kannst du schnell in C eine leere Funktion mit passender Deklaration (void* Parameter) schreiben und dir ansehen, wie der Compiler die übersetzt...
    Noch was: Erwartet wird von deiner Funktion auch noch ein void* als Rückgabewert, den musst du natürlich auch behandeln. Wenn der per Convention auch über den Stack läuft, könntes es sein, dass sich die beiden Fehler aufheben und hier noch irgendwas anderes faul ist. Aber für mich sieht das verdächtig aus.

    Anmerkung:
    CALL fkt
    an sich führt selbstverständlich zu keinem Fehler, da CALL ja keine Parameter auf den Stack schiebt.


    Edit: anmerkung zum call fkt und Return-Wert hinzugefügt
    Edit2: BB-Code gefixt


    Beitrag zuletzt geändert: 15.2.2014 21:02:06 von nomis
  8. Hallo alle miteinander,

    an der Sache mit der Calling-Convention ist was dran.
    Ich habe nochmal rumgesucht um herauszufinden, wie diese unter 32-Bit Linux ist. Vermutlich ist aber die aufrufende Funktion für das Aufräumen des Stacks zuständig (siehe hier), d.h. die Funktion fkt sollte so eigentlich funktionieren. Ich habe die Funktion jetzt mal mit dem üblichen Kopf und Fuß ausgestattet. Vielleicht geht es ja dann:
    FORMAT elf
    PUBLIC main
    SECTION '.text' executable
     
    main:
        PUSH EBP
        MOV  EBP, ESP
    
        PUSH null
        LEA  EAX, ftk
        PUSH EAX
        PUSH null
        LEA  EAX, zgr
        PUSH EAX
        CALL pthread_create
        POP  EAX
        POP  EAX
        POP  EAX
        POP  EAX
     
        CALL fkt
     
        PUSH null
        LEA  EAX, zgr
        PUSH EAX
        CALL pthread_join
        POP  EAX
        POP  EAX
     
        PUSH [anz]
        LEA  EAX, msg
        PUSH EAX
        CALL printf
        POP  EAX
        POP  EAX
    
        LEAVE
        RET
     
    fkt:
        ; save EBP
        PUSH EBP
        ; load stack pointer to EBP
        MOV EBP, ESP
    
        INC [anz]
    
        ; set return value to 0
        XOR EAX, EAX    
        LEAVE
        RET
     
    EXTRN printf
    EXTRN pthread_create
    EXTRN pthread_join
    SECTION '.data'
    anz DD 0
    null DD 0
    msg DB "Anzahl der Aufrufe: %i",10,0
    zgr DD ?

    Bei
    REP STOSD
    kannst Du ja mal schauen, was in EAX steht. REP STOSD kopiert ja Daten von der Adresse auf die EAX zeigt und zwar sooft bis ECX 0 ist.

    Edit:
    Ich habe jetzt noch LEA-Befehle eingefügt. Dieser Befehl berechnet aus einem Offset die echte Adresse im Arbeitsspeicher. Nachdem der Assembler zu dem Zeitpunkt, an dem das Programm assembliert wird nicht wissen kann, welche Adressen Deine Daten und Funktionen später haben werden kann er eigentlich nur Offsets anstelle der absoluten Adressen pushen. Damit kann pthread_create() dann natürlich nichts anfangen.
    Merkwürdig ist aber, dass die meisten FASM-Beispiele etwas anderes suggerieren.
    Aber vielleicht geht es jetzt.

    Beitrag zuletzt geändert: 16.2.2014 14:07:15 von darkpandemic
  9. Autor dieses Themas

    toolz

    Kostenloser Webspace von toolz

    toolz hat kostenlosen Webspace.

    Ich will euch nicht die Lösung vorenthalten. Nachdem darkpandemic sich eingehender damit beschäftigt hatte, ist bei ihm dieses funktionierende Programm herausgekommen:
    format elf
    public main
    
    extrn printf
    extrn pthread_create
    extrn pthread_join
        
            SECTION '.data'
        
    anz:    dd      0
    msg:    db      "Anzahl der Aufrufe: %ld", 10, 0
    thr:    dd      0
    
    
            SECTION '.text'
        
    main:
            push    ebp
            mov     ebp, esp
            
            push    DWORD 0
            push    fkt
            push    DWORD 0
            push    thr
            call    pthread_create
            add     esp, 16
            
            call    fkt
            
            push    DWORD 0
            push    DWORD [thr]
            call    pthread_join
            add    esp, 8
        
            push    DWORD [anz]
            push    msg
            call    printf
            add     esp, 8
        
            xor     eax, eax
            leave
            ret
            
    fkt:
            push    ebp
            mov     ebp, esp
            
            inc     DWORD [anz]
            
            leave
            ret
    Und das Beste: Es funktioniert! Wirklich!
    Vielen Dank an nomis und ganz besonders darkpandemic und an alle anderen, die sich an meinem Problem versucht haben, ohne hier einen Beitrag zu erstellen.

    Beitrag zuletzt geändert: 28.2.2014 18:47:11 von toolz
  10. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!