ASM: Problem mit C-Call pthread
lima-city → Forum → Programmiersprachen → Sonstige Programmiersprachen
adresse
anzahl
argument
assembler
aufruf
befehl
code
elf
fehler
format
funktion
null
parameter
pop
problem
programm
rep
stapel
text
url
-
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:
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.fasm pthread.asm && gcc -pthread pthread.o
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... -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
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
vor Zeile 6 geschrieben, allerdings stimmt es dann immer noch nicht (und ich glaube das ist dann sogar noch zusätzlicher Fehler).PUSH DWORD 0
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. -
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
-
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
, falls euch das hilft...rep stosd
Beitrag zuletzt geändert: 15.2.2014 20:07:07 von toolz -
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:
an sich führt selbstverständlich zu keinem Fehler, da CALL ja keine Parameter auf den Stack schiebt.CALL fkt
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 -
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
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.REP STOSD
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 -
Ich will euch nicht die Lösung vorenthalten. Nachdem darkpandemic sich eingehender damit beschäftigt hatte, ist bei ihm dieses funktionierende Programm herausgekommen:
Und das Beste: Es funktioniert! Wirklich!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
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 -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage