000
13.04.2008, 16:35 Uhr
Olli
|
Hallo,
gleich vorneweg - es ist ein recht langer Text, ich hoffe jedoch jemand liest ihn trozdem....
Ich versuche gerade K5JB (eine userland TCP/IP Loesung) unter WEGA zu compilieren.
Den Samstag habe ich damit verbracht den Fehler zu suchen der im C-Compiler lcc steckt(e) variable Funktionen aufzurufen (CALLR) die den C-Datentyp void und nicht z.B. int zurueckliefern. Das habe ich dann heute morgen so gegen 1 Uhr gefixt gehabt. Nun stehe ich vor einem etwas schwierigerem Problem wo ich Eure Hilfe brauche, da dies sehr ASM-lastig ist.
Es gibt unter WEGA eine C-Funktion namens fcntl. Diese Funktion wird im Kernel bereitgestellt. Die Funktion im Kernel wird ueber einen sogenannten syscall aufgerufen. Die Funktion welche in der C-Funktionsibliothek "libc" zur Verfuegung steht, reicht die Argumente quasi ueber den syscall direkt an den Kernel durch, und dort wird dann die eigentliche fcntl Funktion ausgefuehrt.
Fcntl erwartet 3 Argumente. Als erstes Argument wird ein Dateizeiger uebergeben, dann wird das Kommando uebergeben welches die Aktion beschreibt die fcntl mit dem Dateizeiger durchfuehren soll. Das dritte Argument spezifiziert die Aktion naeher.
Ein kurzes Beispiel. Moechte ich ermitteln, ob eine geoeffnete Datei fuer "non blocking I/O" aufgerufen wurde, rufe ich z.B. folgendes auf file_flags = fcntl(fd, F_GETFL, 0) dann stehen in file_flags welche aktuell fuer diese Datei gueltig sind (wurde sie lesen, schreiben oder schreib/lesend geoffnet, wurde sie so geoeffnet, das ein schreiben nur am ende angehangen wird, oder wurde sie fuer non-blocking-I/O geoeffnet).
Ich habe hier als Beispiel einen kurzen C-Quellcode ohne Fehlerhandling (damit das ASM Listing kuerzer wird):
Quellcode: | #include <stdio.h> #include <fcntl.h>
main() { char cul[90]; int fd=0,fd2;
strcpy(cul,"/tmp/test"); fd = open(cul, O_EXCL | O_RDWR | O_NDELAY); fd2 = fcntl(fd, F_DUPFD,0 ); printf("%d -> %d\n",fd,fd2); }
|
Dieses Programm oeffnet dann die Datei /tmp/test und erzeugt mir dann mit fcntl() ein Duplikat des Dateizeigers. Compiliert und ausgefuehrt mit dem segmentierenden Systemcompiler scc sieht das dann so aus:
Quellcode: | #182 scc -o fcntl_test fcntl_test.c #183 ./fcntl_test 3 -> 4 #184
|
Man sieht also, das der Dateizeiger mit der ID 3 dupliziert wurde, und ich nun mit fd2 einen Dateizeiger mit der ID 4 habe.
Mit scc funktioniert also alles wie es soll. Mit dem lcc (den ich fuer das TCP/IP Programm verwenden muss aufgrund der Sprachkomplexitaet) sieht es aber so aus:
Quellcode: | #187 lcc -o fcntl_test fcntl_test.c #188 ./fcntl_test 3 -> -1 #189
|
Hier kommt also -1 zurueck, und -1 bedeutet das fcntl nicht erfolgreich ausgefuehrt werden konnte. Als Fehler selbst kommt
[EBADF] Fildes ist kein gueltiger offener Dateidescriptor.
zurueck.
Nun frage ich mich - warum klappt das mit scc, und warum mit lcc nicht. Lcc benutzt eine andere - eigene - libc als scc. Ich nam also an, vielleicht ist der Fehler in der C-Bibliothek selbst zu suchen. Wenn ich mir aber das Objekt welches den fcntl syscall an den Kernel durchschleift aus der scc libc herausloese, und es in die lcc libc einfuege komme ich zum gleichen Fehler. Neme ich das fcntl-Objekt aus der libc des lcc und fuege dies in die libc des scc ein, bekomme ich mit scc den gleichen Fehler. Das verwundert mich:
- Compiler scc, fcntl-Objekt von scc: funktioniert - Compiler scc, fcntl-Objekt von lcc: funktioniert nicht - Compiler lcc, fcntl-Objekt von lcc: funktioniert nicht - Compiler lcc, fcntl-Objekt von scc: funktioniert nicht
Ich haette etwas anderes erwartet....
Nun kann es also sowohl an der libc-Implementation der fcntl Funktion des lcc liegen, als auch an dem lcc Compiler selbst (erzeugt fehlerhaften ASM Code).
Ich habe hier mal den Sourcecode der libc-Implementation der fcntl Funktion des lcc:
Quellcode: | . .seg
sp := r15 SP := rr14
.psec .code _fcntl:: { ldm r0,|_stkseg+3|(sp),#4 xor r4,r4 sc #38 // switch ld r2,r4 ret nc jp cerror }
|
Der hexdump des daraus entstandenen Objektes sieht so aus:
Quellcode: | 0000000 e607 0000 0014 0000 0000 0010 002a 0000 0000010 0000 0000 0000 0000 0000 0000 0014 0000 0000020 0000 0001 0000 0000 5cf1 0003 0003 8944 0000030 7f26 a142 9e0f 5e08 8000 0000 0000 0000 0000040 001a 0000 0000 0000 0000 0000 0029 0028 0000050 0000 0000 2200 5f66 636e 746c 0000 0000 0000060 0000 2000 5f73 746b 7365 6700 0000 0000 0000070 2000 6365 7272 6f72 0000
|
Adresse 30-31 ist der Syscall auf #28.
Von der libc-Implementation der fcntl Funktion des scc habe ich leider keinen ASM source, kann hier also nur mit dem Hexdump dienen wo ich sehe das er unterschiedlich ist, ich das aber nicht zurueck in Mnemonik "geparsed" kriege im Kopf um den Unterschied zu erkennen:
Quellcode: | 0000000 e607 0000 0014 0000 0000 0020 0038 0000 0000010 0000 0000 0000 0000 0000 0000 0014 0000 0000020 0000 0001 0000 0000 0100 0000 0000 0000 0000030 0000 0002 0000 0000 a170 a161 a152 8344 0000040 7f26 a142 9e0f 5e08 8000 0000 0000 0000 0000050 0000 0000 0000 0000 0000 0000 0039 0038 0000060 0000 0000 1e00 6663 6e74 6c5f 7000 0100 0000070 0000 1e01 6663 6e74 6c5f 6400 0000 0000 0000080 6200 5f66 636e 746c 0000 0000 0000 6000 0000090 6365 7272 6f72 0000 0000098
|
Dort ist der Syscall auf die gleiche Adresse bei 40/41 zu finden. Also wird schonmal der gleiche Syscall ausgefuehrt, nur vorher und nachher passiert bei der scc Implementation ein bischen was anderes....
Wenn ich mir nun das ASM Listing, welches der lcc aus meiner C-Datei erzeugt anschaue: (nur der Ausschnitt mit dem fcntl Aufruf):
Quellcode: | . .seg fp := r13 FP := rr12 sp := r15 SP := rr14 [...] callr _open inc sp,#%6 ld FP(#~L1+%5a),r2 xor r2,r2 push @SP,r2 xor r2,r2 push @SP,r2 push @SP,_stkseg+~L1+%5a(fp) callr _fcntl inc sp,#%6
|
und mir jetzt den Code den der scc Compiler erzeugt anschaue:
Quellcode: | . .seg .psec data .data
fp := r15; sp := rr14; [...] callr _open ld |_stkseg+~L1+90|(fp),r2 ld r7,|_stkseg+~L1+90|(fp) sub r6,r6 sub r5,r5 callr _fcntl ld |_stkseg+~L1+92|(fp),r2
|
sieht man da schon Unterschiede - und hier hoerts nun auf. Ich weiss nicht wie ich mit dem ASM Code weiterverfahren soll, da mein ASM Wissen nun leider auch noch recht limitiert ist.
Eine moegliche Implementation von einem SYSIII der Funktion fcntl im Kernel ist hier: http://pofo.de/P8000/misc/fcntl.c Wie gesagt, das muss nicht die Funktion sein, so wie sie im WEGA-Kernel implementiert ist. Sie wird aber sehr aenlich sein.
Kann jemand aus dem Hexdump der fcntl-Implementation des scc ein ASM-Listing "rueckwaerts" erzeugen? Hat jemand eine Idee was mein lcc da falsch macht? -- P8000 adventures: http://pofo.de/blog/?/categories/1-P8000 Dieser Beitrag wurde am 13.04.2008 um 16:43 Uhr von Olli editiert. |