Forum: Compiler & IDEs GCC Funktionen "umbiegen"


von AG (Gast)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von AG (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von AG (Gast)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von AG (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von AG (Gast)


Lesenswert?

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

von Martin Cibulski (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

nm kann übrigens auch direkt auf .a-Archiven arbeiten.

von AG (Gast)


Lesenswert?

> 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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.