Ich benutze eine Nios2-System mit einem Coprozessor-Modul. Dabei will ich jetzt bestimmte Funktionen, zb eine double-Multiplikation so verbiegen, dass nicht mehr die Software-Routinen aufgerufen werden, sondern eine von mir zu schreibende Funktion, die den Coprozessor verwendet. Das ganze soll für den Benutzer transparent sein, so dass im Code weiter c=a*b geschrieben werden kann. Leider habe ich dazu nirgends etwas gefunden. Ich wäre für einen Ansatzpunkt sehr dankbar! Gruss, Andreas p.s. Meine ursprüngliche Idee, einfach den * Operator zu überladen geht nicht, weil ich nur neue Funktionen hinzufügen darf aber vorhandene nicht neu definieren. Jedenfalls soweit ich das verstanden habe, kann mir das jemand bestätigen?
Die sauberste Variante wäre es natürlich, das dem GCC richtig zu sagen und einen eigenen Port davon anzufertigen. Je nachdem, wie viel davon in RTL implementiert ist und wie viel in Hilfsfunktionen, kannst du zumindest die Hilfsfunktionen einfach durch deine eigenen überladen (die werden sonst aus der libgcc.a gelinkt). Wenn aber Dinge wie die Grundrechenarten direkt in RTL implementiert sind, dann generiert der Compilerpass letzlich die dafür notwendigen Assembleranweisungen intern, da kannst du nichts mehr reinklinken.
Ein eigener Port von GCC kommt eigentlich nicht in Frage, da ich dann bei jedem Update seitens Altera die neue GCC-Version wieder anpassen muss. Daher sollte das möglichst unabhängig davon sein. Die Hardware hat keine FPU, und der Compiler weiss momentan nichts davon. Jegliche float und double Operationen werden somit aus der libgcc.a geholt. Was ich brauche ist irgend eine Methode, damit der Compiler automatisch aus c = a*b eine Funktion c = fmul(a,b) aufruft. Darin kümmere ich mich dann um die Multiplikation und gebe das Ergebnis zurück. Leider ist mir völlig unklar, wie ich diesen Schritt bewerkstelligen soll.
AG wrote: > Jegliche float und double Operationen werden somit aus der > libgcc.a geholt. Dann kannst du stattdessen deine eigenen in einer Bibliothek hinterlegen. Da deine Bibliothek vor der libgcc.a gelinkt wird, werden die darin enthaltenen Funktionen benutzt. Die Namen dieser Funktionen sind etwas kryptisch, aber die Bildungsregel sollte irgendwo in der GCC-Doku stehen.
Ok, hört sich sinnvoll an. Für die double Addition sollte die entsprechende Funktion aus der libgcc.a __adddf3 sein. Diese Funktion habe ich jetzt mit einer .h und .c Datei nue definiert. Nicht ganz unüberassched beschwert sich jetzt der Linker, dass die Funktion schon vorhanden ist:
1 | Linking hello_world_0.elf... |
2 | /cygdrive/c/altera/72/nios2eds/bin/nios2-gnutools/H-i686-pc-cygwin/bin/../lib/gcc/nios2-elf/3.4.1/ |
3 | mcustom-fpu-cfg=60-2//libgcc.a(_addsub_df.o)(.text+0x330): In function `__adddf3': |
4 | /build/nios2eds-gnutools-win32-7.2/bin/nios2-gnutools/src/gcc/gcc/config/nios2/nios2-dp-bit.c:731: |
5 | multiple definition of `__adddf3' |
6 | obj/dpfpu.o(.text+0x0):../dpfpu.c:15: first defined here |
7 | /cygdrive/c/altera/72/nios2eds/bin/nios2-gnutools/H-i686-pc-cygwin/bin/../lib/gcc/nios2-elf/3.4.1/ |
8 | ../../../../nios2-elf/bin/ld: Warning: size of symbol `__adddf3' changed from 84 in obj/dpfpu.o |
9 | to 108 in /cygdrive/c/altera/72/nios2eds/bin/nios2-gnutools/H-i686-pc-cygwin/bin/../lib/gcc/nios2-elf/3.4.1/ |
10 | mcustom-fpu-cfg=60-2//libgcc.a(_addsub_df.o) |
11 | collect2: ld returned 1 exit status |
Wie umgehe ich das Problem? Muss ich dazu eine .a Datei erzeugen und das dem Compiler mitteilen?
Der Modul, der aus der libgcc.a gelinkt wird, heißt _addsub_df.o. Das suggeriert, dass er noch weitere Symbole außer __adddf3 enthält. Offensichtlich wurde der Modul aus der libgcc.a reingezogen, da eins der weiteren Symbole noch nicht definiert war. Bei dieser Gelegenheit hat er aber die Doppeldefinition für __adddf3 mit eingeschleppt.
Heisst das, dass ich alle Funktionen, die in der _addsub_df.o drin sind in meine eigenen Library auch einbauen muss? nm -a _addsub_df.o liefert mir folgende Ausgabe:
1 | 00000000 b .bss |
2 | 00000000 n .comment |
3 | 00000000 d .data |
4 | 00000000 N .debug_abbrev |
5 | 00000000 N .debug_aranges |
6 | 00000000 N .debug_frame |
7 | 00000000 N .debug_info |
8 | 00000000 N .debug_line |
9 | 00000000 N .debug_pubnames |
10 | 00000000 N .debug_ranges |
11 | 00000000 N .debug_str |
12 | 00000000 t .text |
13 | 00000330 T __adddf3 |
14 | U __negdi2 |
15 | U __pack_d |
16 | 0000039c T __subdf3 |
17 | U __thenan_df |
18 | U __unpack_d |
19 | 00000000 t _fpadd_parts |
20 | 00000000 a nios2-dp-bit.c |
Langsam glaube ich, dass es doch einfacher wäre, die libgcc.a zu patchen und neu zu kompilieren. Nur konnte ich durch trotz langem Suchen bisher nicht herausfinden, welches die Quellen sind, aus denen diese Datei compiliert wird.
AG wrote: > Heisst das, dass ich alle Funktionen, die in der _addsub_df.o drin sind > in meine eigenen Library auch einbauen muss? Ja. > nm -a _addsub_df.o liefert mir folgende Ausgabe: > >
1 | > 00000000 b .bss |
2 | > 00000000 n .comment |
3 | > 00000000 d .data |
4 | > 00000000 N .debug_abbrev |
5 | > 00000000 N .debug_aranges |
6 | > 00000000 N .debug_frame |
7 | > 00000000 N .debug_info |
8 | > 00000000 N .debug_line |
9 | > 00000000 N .debug_pubnames |
10 | > 00000000 N .debug_ranges |
11 | > 00000000 N .debug_str |
12 | > 00000000 t .text |
13 | > 00000330 T __adddf3 |
14 | > U __negdi2 |
15 | > U __pack_d |
16 | > 0000039c T __subdf3 |
17 | > U __thenan_df |
18 | > U __unpack_d |
19 | > 00000000 t _fpadd_parts |
20 | > 00000000 a nios2-dp-bit.c |
21 | > |
Das macht dann (wie der Name des Moduls erwarten ließe) außer __adddf3 nur noch __subdf3, was du da mit reinpacken musst. _fpadd_parts ist eine interne (static) Funktion, die von den anderen beiden nur in der libgcc-Implementierung benutzt wird, und die Us sind global undefined, d. h. Referenzen auf andere Funktionen.
So, mittlerweile funktionierts genau so wie ich mir das gewünscht habe. Zuerst mal herzlichen Dank an Jörg für die kompetente Hilfe! Folgende Schritte waren nötig: .h und .c Datei mit den Funktionen erzeugen, die ersetzt werden sollen. Die dazugehörigen Namen sind in den GCC Internals (Datei gccint.info oder hier: http://stderr.org/doc/gcc-4.2-doc/gccint.html, 4.2 Routines for floating point emulation) zu finden. In meinem Fall sind dies:
1 | double __adddf3 (double, double); |
2 | double __subdf3 (double, double); |
3 | double __muldf3 (double, double); |
4 | double __divdf3 (double, double); |
Zu beachten ist hierbei, dass die Funktionen in der libgcc.a in mehreren .o Dateien verteilt sind. Es müssen immer alle Funktionen, die in einer bestimmten .o Datei drin sind, ersetzt werden. Dazu: - mit ar die .o Dateien aus der libgcc.a auspacken - mit nm (siehe oben) die Funktionen in der relevanten .o Datei anzeigen Infos hierzu sind auch in http://www.network-theory.co.uk/docs/gccintro/index.html zu finden. Beim ausprobieren ist noch darauf zu achten, dass die ersetzten Sachen auch von anderen (System-) Routinen aufgerufen werden, so gibt zum Beispiel printf nur Müll aus wenn man die double Addition zu a+b = a umdefiniert :-) Andreas
Hallo, könnte man so dem AVRGCC echtes double-Format (64 bit) beibringen ? Zusätzlich müsste man dem GCC noch sagen, dass double 64 bit lang ist. Wo kann man das machen ? Hintergrund meiner Frage ist, dass ich eine ASM-Bibliothek für 64 bit double auf dem AVR geschrieben habe, diese aber bisher nur in Assembler nutzen kann. Gruß, Martin
> könnte man so dem AVRGCC echtes double-Format (64 bit) beibringen ?
Ich vermute (ohne es zu wissen), dass der double auch beim AVRGCC 64 bit
hat, nur die Rechenoperationen in der Library nur 32bit rechnen.
Wenn das tatsächlich so ist, kannst du mit der Beschreibung oben die
entsprechenden Funktionen abfangen und durch deinen Assembler-Code
ersetzen. Ich würds einfach mal ausprobieren, du kannst in der Funktion
ja auch Ausgabe statt ner Addition implementieren und damit dann einfach
mal nachschauen ob 32 oder 64 bit ankommen.
Martin Cibulski wrote: > könnte man so dem AVRGCC echtes double-Format (64 bit) beibringen ? Nein, das braucht auch schon noch ein wenig RTL-Code. Das erklärt dann auch die Frage, wo man dem Compiler sagt, wie groß die Typen sind. Der größere Anteil an Code steckt aber ganz sicher in der libgcc, keine Frage. Außerdem braucht es schließlich noch jemanden, der dafür eine libm.a zimmert Aber nur zu! Wir suchen schon lange jemanden, der sich des Themas mal annimmt. Falls jemand ernsthaft die Absicht hat, würde ich ihm erstens raten, sich auf der avr-gcc-list einzutragen (dort lesen zumindest alle diejenigen noch mit, die in den letzten Jahren irgend- was am AVR-Teil des GCC gezimmert haben) und zweitens nicht zu spät damit zu beginnen, die Copyright-Übertragung an die FSF in die Wege zu leiten, da die FSF darauf besteht und das Ganze nur mit Sackpost erledigt werden kann. (Die ist für unserereinen ansonsten komplett gegenstandslos, da man als Deutscher das Copyright sowieso niemandem übertragen kann...) Wenn sich das jemand ernsthaft auf die Fahnen schreibt, würde ich übrigens für eine Lösung wie bei -mint8 plädieren: der Default sollte sizeof(double) = 8 werden (weil nur das konform mit dem C99-Standard geht), aber es sollte eine Option, nennen wir sie -mdouble32, geben, die dem Compiler mitteilt, den Code wie bisher zu generieren. Die ausgelieferten Makefile-Templates könnten diese Option dann standard- mäßig mit auswählen, damit sich gegenüber dem bisherigen Verhalten nichts ändert.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.