Forum: Compiler & IDEs WinAVR Bug: Crash wegen Codegrösse


von Chris (Gast)


Lesenswert?

Hallo Zusammen,
Hallo GCC-Compiler-Experten,

Ich habe wohl einen Bug am avr-gcc entdeckt:
Ich arbeite an einem grösseren System (Atmega 2560 / WinAVR 20071221). 
Die Codegrösse (binär) liegt bei ca 135kB. Bisher lief über ein Jahr 
alles normal. Aber plötzlich crasht das System, sobald ich eine weitere 
Komponente hinzufüge. Egal was, ob eine weitere Funktion oder z.B. die 
scanf_float library.

Der Crash wird nicht durch die hinzugefügte Funktion verursacht.
Die Ursache ist wohl die sprintf und sprintf_P-Funktion, die oft 
verwendet wird. Ich habe mir mal das Map-File angesehen.

Anscheindend läuft die Funktion oder nicht, je nachdem, wohin sie 
gelinkt wird. Wird sie unterhalb 128kB gelinkt, läuft sie, wird sie 
oberhalb 128kB gelinkt, führt sie zum Absturz.

Wie kann das sein? Ich sitze seit einem Monat an diesem Fehler, und das 
behindert das ganze Projekt, das seit gut einem Jahr entwickelt wird. 
Ich bin am Verzeweifeln. Wenn ich keine Lösung finde, muss ich wohl den 
Compiler wechseln mitsamt der ganzen Toolchain.

Ich wäre seeehr froh, wenn jemand einen Rat wüsste. Danke.
Chris

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Teste, ob das Problem nur bei deinem alten WinAVR auftritt oder auch in 
neueren WinAVR Versionen.

Wenn neuere Versionen ebenfalls betroffen sind, dann stelle einen 
Sourcecode bereit, mit dem das Problem für Dritte reproduzierbar ist.

Es wäre optimal, wenn es möglich ist, das Problem zu identifizieren, 
ohne einen Atmega 2560 zu haben und geht/geht nicht anhand eines 
Runtime-Crashs zu entscheiden. Kannst du hierzu was sagen?

von Andreas K. (a-k)


Lesenswert?

Müsste dann im Simulator auch auftreten.

von Chris (Gast)


Lesenswert?

Das bisherige Programm konnte ich so nicht im Simulator laufen lassen, 
da doch an zu vielen Stellen auf weitere Peripherie zugegriffen wird. 
Andere mögliche Ursachen wie Stack Overflow oder Interruptroutinen habe 
ich auch geprüft, das ist es wohl nicht.

Ok, ich werde bis morgen mal einen entsprechenden Code zusammenstellen.

Bis denn...

von P. S. (Gast)


Lesenswert?

Ich bin ueberrascht, dass du so lange keine Probleme hattest - ich habe 
noch irgendwo im Hinterkopf, dass der AVR-gcc Probleme mit mehr als 64k 
Codegroesse hat? Ich kann aber keine Aussage dazu machen, wie 
zuverlaessig diese Information ist und meine eigene Arbeit ist noch ein 
gutes Stueck davon entfernt.

von Dirk B. (sharandac)


Lesenswert?

Peter Stegemann wrote:
> Ich bin ueberrascht, dass du so lange keine Probleme hattest - ich habe
> noch irgendwo im Hinterkopf, dass der AVR-gcc Probleme mit mehr als 64k
> Codegroesse hat? Ich kann aber keine Aussage dazu machen, wie
> zuverlaessig diese Information ist und meine eigene Arbeit ist noch ein
> gutes Stueck davon entfernt.

Die 64k beziehen sich auf mehrere Sachen mit unterschiedlicher 
Bedeutung. Beim Code sind es 64k-words (128kbyte) ab welcher segmentiert 
werden muss und es aufwending wird. Bei RAM bestehen die normalen 64K 
Grenzen. Wenn Daten im Flash abgelegt werden die per Programm ausgelesen 
werden gibt es wieder 64Kbyte Probleme und es muss Segmentiert werden. 
Also die üblichen Probleme :-).

CA Dirk

von Andreas K. (a-k)


Lesenswert?

Der Unterschied liegt in der Return-Adresse. Die ist bei AVRs mit mehr 
als 64KW Flash nicht mehr 2 Byte sondern 3 Byte gross. Das muss der 
Compiler berücksichtigen und wenn Assembler-Code beteiligt ist evtl. 
auch dieser. Es kann folglich nicht der gleiche Binärcode der Library 
für AVRs bis 64KW und für solche darüber verwendet werden.

Soweit ich weiss wird aber jenseits 64KW nichts segmentiert, sondern es 
wird mit eingefügten Sprungbefehlen dafür gesorgt, dass alle Funktionen 
mit einer Einsprungadresse in den ersten 64KW erreicht werden können. 
Dadurch wird vermieden, sämtliche Adressen auf 24 Bit erweitern zu 
müssen.

von Dirk B. (sharandac)


Lesenswert?

Jup ... das meinte ich damit eigentlich.

von P. S. (Gast)


Lesenswert?

Nun, dann habe ich ja noch etwas Platz, bis ich an die Grenze stosse - 
bei Chris scheint es mir aber auf das Problem zu passen?

von Dirk B. (sharandac)


Lesenswert?

Sieht danach aus. Da das springen mit diesen Jumptables nicht ganz 
trivial ist gibt es immer wieder Probleme damit. Ich habe auch 
Festgestellt das es auch von Version zu Version des AVR-GCC anders ist 
:-), ja nach dem wie gepatcht wurde. Bosonders ärgerlich ist dieses 
Problem wenn man viele "Daten" im Flash hat die mehr als 64Kbyte 
belegen, da bekommt der AVR-GCC dann Probleme.

CA Dirk

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen!

Wie ich sehe, scheint das Thema ja einige zu interessieren. Schön. So, 
anbei habe ich nun ein kleines Beispielprojekt für WinAVR bzw. AVRStudio 
4.14. Die Vermutung bestätigt sich: Wenn sprintf oberhalb 128kB gelinkt 
wird, stürzt das Programm auch im Simulator ab. Hier meine 
main-Funktion:

int main(void)
{

char str[20];
int i=0;

dummy_funktion_1();
dummy_funktion_2();
dummy_funktion_3();
dummy_funktion_4();
dummy_funktion_5();
dummy_funktion_6();
dummy_funktion_7();

sprintf(str,"Test %d",i);  //Hier Haltepunkt 1

i=1; //Haltepunkt 2

return i;
}


Wenn dummy 6 und 7 auskommentiert werden (und auch die 
Funktionsdefinitionen) läuft das Programm bis Haltepunkt 2. Mit dummy 6 
und 7 ist bei HP 1 finito.

Anbei habe ich das Paket fürs AVR-Studio (4.14). Schaut es Euch an.

Was kann man da machen???

von Andreas K. (a-k)


Lesenswert?

Kannst du das Paket mal mit einem .lss File anreichern?

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

Anbei das Projekt mitsamt lss Datei.

Zur Info: Das Makefile basiert auf der Standard-Vorlage, falls jemand 
was ändern möcht. Die Optimierung ist ausgeschaltet, da sonst meine 
dummy_funktionen geschrumpft werden.

von Chris (Gast)


Lesenswert?

Ich habe den Test gerade auch mal mit der neusten WinAVR 20080610 / GCC 
4.3.0 Version durchgeführt. --> Leider der gleiche Fehler wie bei der 
alten.

???

von Chris (Gast)


Lesenswert?

Das Problem scheint an der printf-library zu liegen, nicht am Compiler.

Denn eine Funktion die aktuell compiliert und >128kB gelinkt wurde läuft 
korrekt (z.B. dummy_funktion_7 bei 0x000208f6).

Nur Funktionen, die aus der Library angespungen werden und >128kB liegen 
führen zum Absturz. Vielleicht wäre die Lösung, dass man die printf- und 
andere libs nochmal mitkompiliert, anstatt sie als lib einzubinden ?

von P. S. (Gast)


Lesenswert?

Das duerfte das Problem loesen - alternativ den Compiler anpassen, dass 
er vorkompilierte Bibliotheken immer im unteren Bereich ablegt. Kannst 
dir ueberlegen, welche Loesung einfacher ist ;-)

von Chris (Gast)


Lesenswert?

Ja, nur wie?

Idee 1) librarys neu kompilieren:
Wo finde ich die printf und die anderen Libs als source? Die sind im 
WinAVR-Paket nur als fertige libs dabei.

Idee 2) libs in den Bereich <128kB linken.
Wie geht das? Wie muss ich das Makefile modifizieren oder ein geht das 
über ein Linkerskript? Es gibt ja eine sektion .lowtext. Man könnte 
versuchen die libs in diese sektion reinzulinken. Oder man macht eine 
neue Sektion zwischen .lowtext und .text, in die man die libs packt, das 
geht ja über ein Linkerskript.
Nur wie sagt man dem Linker, dass er die libs da reinlinken soll?

von Simon K. (simon) Benutzerseite


Lesenswert?


von Chris (Gast)


Lesenswert?

Danke für den Tip.
Ich habe mir die Librarys heruntergeladen und angeschaut. Das 
Neukompilieren kommt mir doch etwas komplizierter vor, als ich dachte, 
wenn ich mir die Makefiles anschaue. Da gibt es ja eine Unmenge von 
Optionen und Variablen. Vielleicht versuce ich erst die 2. Lösung - 
Linken in den unteren Bereich. Nur wie geht das?

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


Lesenswert?

Das Neucompilieren wird dir nicht viel helfen, es wird lediglich zum
gleichen Ergebnis führen (hoffentlich -- sonst hätten wir was falsch
gemacht).

Du solltest das Problem erstmal analysieren.

Sorry, ich habe diese Woche selbst keinerlei Zeit, mir das anzusehen.

von Chris (Gast)


Lesenswert?

Ich komme nicht dazu, das Problem noch weiter zu analysieren, habe 
einfach zu wenig Zeit und Ahnung, mich mit den Details des Compilers zu 
beschäftigen. Ich habe den Bug bei Sourceforge gemeldet und auch schon 
die Antwort erhalten, dass der in der kommenden WinAVR Version behoben 
sein wird.
Siehe:
https://sourceforge.net/tracker/?func=detail&atid=520074&aid=2064430&group_id=68108

Nun noch die Frage an die Entwickler: Wann kommt die nächste WinAVR 
Version raus?

Denn ich stehe wegen diesem Bug auch finanziell ganz schön auf dem 
Schlauch. Ich werde nach Projektfortschritt bezahlt. Und es ist ja auch 
ein Problem das ALLE Atmega 2560/2561 - Programme betrifft - in welchem 
Programm kommt keine printf-Funktion vor?

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


Lesenswert?

Chris wrote:

> Ich komme nicht dazu, das Problem noch weiter zu analysieren,...

OK, das hat ja offenbar auch schon jemand getan.

Entsprechend Anatoliys Antwort würdest du übrigens offenbar zuerst
einen neu gebauten Compiler benötigen und mit diesem dann die
avr-libc neu compilieren müssen.

> Nun noch die Frage an die Entwickler: Wann kommt die nächste WinAVR
> Version raus?

Keine Ahnung im Moment, wie Erics Pläne dafür aussehen.  Ich bin
gerade aus dem Urlaub zurück.

> Denn ich stehe wegen diesem Bug auch finanziell ganz schön auf dem
> Schlauch.

Ist es denn eine Option, dass du auf die 20071224-Version von WinAVR
zurück gehst?  Die sollte davon nicht betroffen sein.

von Chris (Gast)


Lesenswert?

Hallo Jörg, danke für die schnelle Antwort.
Du meinst wahrscheinlich die 20071221er Version. Leider hat diese auch 
das Problem. In diesem Jahr habe ich bisher nur diese Version 
eingesetzt. Mit den 2008er Versionen hatte ich ein anderes Problem mit 
Assemblercode (aber nicht ganz so gravierend, lässt sich wohl 
work-arounden)
Gruß
Christian

von P. S. (Gast)


Lesenswert?

Wie viele Funktionen aus der Library brauchst du denn? printf() ist zwar 
maechtig, aber auch kein Hexenwerk, liese sich zur Not auch selbst 
schreiben (oder eben "leihen" und in den eigenen Code einpassen).

von Andreas K. (a-k)


Lesenswert?

Wenn der Compiler selber der Übeltäter ist, dann ist der Ersatz von 
printf nur begrenzt hilfreich, denn das Problem kann dann auch anderswo 
auftreten. Das es grad printf erwischt hat, ist dann eher darauf 
zurückzuführen, dass der Linker die Funktionen der Lib hinten dran 
hängt.

von Tmo (Gast)


Lesenswert?

Hi,

der Fehler ist zu umgehen. Nur auf -mcall-prologues verzichten und die 
paar libc-Funktionen, die scheinbar mit dieser Option kompiliert sind 
via Linkerscript in die unteren 128k lokatieren. Dazu gehören folgende 
Funktionen, dei ich in meinem Projekt identifiziert habe (ist 
wahrscheinlich nicht vollständig, lässt sich aber im .map-File durch 
Suche nach _prologue_saves__ und __epilogue_restores_ verifizieren) 
Alle Funktionen, die diese Beiden benutzen müssen unterhalb der 128k 
Grenze liegen. Auszug aus Linkerscript:

    /* for code that needs to reside in the lower 128k progmem */
    _unord_sf.o (.text) /* used by vprintf */
    _prologue.o (.text.libgcc) /* prolog routine */
    _epilogue.o (.text.libgcc) /* epilog routine */
    *(.lowtext)
    *(.lowtext*)

Alle weiteren projektspezifischen Funktionen, die prolog und epilog 
benutzen, gehören dann auch noch in diese Sektion.

Gruss und hoffe es hilft
Tmo

von Chris (Gast)


Lesenswert?

Hallo Tmo,

danke für den Tip. Ich denke auch das ist die Lösung.
Bei mir kommt nur eine Fehlermeldung, wenn ich das das Projekt mit dem 
modifizierten Linkerskript kompiliere:

...ld.exe: cannot find _prologue.o

Warum findet er nach der Modifikation des Linkeskripts diesen Objektcode 
auf einmal nicht? Ich habe versucht, im WinAVR-Makefile die 
entsprechende Bibliothek (libgcc.a) nochmal manuell nachzulinken:

LDFLAGS = -Wl,-lgcc
LDFLAGS = -Wl,-L"C:\Program Files\WinAVR\lib\gcc\avr\4.2.2\avr6"

, das hilft aber nicht.

Gruß
Christian

von Tmo (Gast)


Lesenswert?

Hi,

sorry, habe Dir wohl einen Auszug aus einem Testscript geschickt :-(

Anbei das Richtige. Die Fehlermeldung kommt wohl von internen 
Namenserweiterungen, wenn eine Lib erstellt wurde, deswegen:

    /* for code that needs to reside in the lower 128k progmem */
    _unord_sf.o (.text)
    _prologue.o (.text.libgcc)
    _epilogue.o (.text.libgcc)
    *(.lowtext)
    *(.lowtext*)

Gruss

von Tmo (Gast)


Lesenswert?

Hi,

habe jetzt gesehen, das die Erweiterungen hier im Web verschluckt 
werden:

Also nochmal:
1
 /* for code that needs to reside in the lower 128k progmem */
2
    *_unord_sf*.o (.text)
3
    *_prologue*.o (.text.libgcc)
4
    *_epilogue*.o (.text.libgcc)
5
    *(.lowtext)
6
    *(.lowtext*)

Gruss

von Chris (Gast)


Lesenswert?

Hallo Tmo,

VIELEN VIELEN DANK !!!

Es funktioniert jetzt. Dank Deinem Tip kann es jetzt wieder weitergehen.

Schönen Gruß aus Berlin
Christian

von Peter D. (peda)


Lesenswert?

Ich grab mal den Thread aus, weil das Problem ja immer noch besteht 
(WinAVR 20100110).
1
0002239c <fputc>:
2
   2239c:       0f 93           push    r16
3
   2239e:       1f 93           push    r17
4
   223a0:       cf 93           push    r28
5
   223a2:       df 93           push    r29
6
   223a4:       8c 01           movw    r16, r24
7
   223a6:       eb 01           movw    r28, r22
8
   223a8:       8b 81           ldd     r24, Y+3        ; 0x03
9
   223aa:       81 ff           sbrs    r24, 1
10
   223ac:       1b c0           rjmp    .+54            ; 0x223e4 <fputc+0x48>
11
   223ae:       82 ff           sbrs    r24, 2
12
   223b0:       0d c0           rjmp    .+26            ; 0x223cc <fputc+0x30>
13
   223b2:       2e 81           ldd     r18, Y+6        ; 0x06
14
   223b4:       3f 81           ldd     r19, Y+7        ; 0x07
15
   223b6:       8c 81           ldd     r24, Y+4        ; 0x04
16
   223b8:       9d 81           ldd     r25, Y+5        ; 0x05
17
   223ba:       28 17           cp      r18, r24
18
   223bc:       39 07           cpc     r19, r25
19
   223be:       64 f4           brge    .+24            ; 0x223d8 <fputc+0x3c>
20
   223c0:       e8 81           ld      r30, Y
21
   223c2:       f9 81           ldd     r31, Y+1        ; 0x01
22
   223c4:       01 93           st      Z+, r16
23
   223c6:       f9 83           std     Y+1, r31        ; 0x01
24
   223c8:       e8 83           st      Y, r30
25
   223ca:       06 c0           rjmp    .+12            ; 0x223d8 <fputc+0x3c>
26
   223cc:       e8 85           ldd     r30, Y+8        ; 0x08
27
   223ce:       f9 85           ldd     r31, Y+9        ; 0x09
28
   223d0:       80 2f           mov     r24, r16
29
   223d2:       19 95           eicall                  ; ====> Krach Boom Bang

Es wird einfach vergessen, das EIND Register zu setzen.
Es wird nur einmalig zu Programmbeginn gesetzt:
1
00000234 <__ctors_end>:
2
     234:       11 24           eor     r1, r1
3
     236:       1f be           out     0x3f, r1        ; 63
4
     238:       cf ef           ldi     r28, 0xFF       ; 255
5
     23a:       d1 e2           ldi     r29, 0x21       ; 33
6
     23c:       de bf           out     0x3e, r29       ; 62
7
     23e:       cd bf           out     0x3d, r28       ; 61
8
     240:       00 e0           ldi     r16, 0x00       ; 0
9
     242:       0c bf           out     0x3c, r16       ; 60 = EIND

Gibt es da wirklich keine Lösung?
Warum überhaupt ein EICALL an dieser Stelle?
Ich arbeite doch bisher nirgends mit Funktionspointern.

Ich würde das natürlich auch gerne noch machen für meinen Scheduler.
Kann man Funktionspointer als far (32Bit Pointer) deklarieren?


Peter

von Stefan E. (sternst)


Lesenswert?

Peter Dannegger schrieb:
> Kann man Funktionspointer als far (32Bit Pointer) deklarieren?

Nein. Du kannst aber auch mit den normalen 16Bit Pointern eine Funktion 
oberhalb 128k aufrufen. Dann wird im unteren Bereich ein Trampoline 
angelegt. Diesbezüglich könnte dieser Thread für dich interessant sein:
Beitrag "warning: internal error: out of range error"

von Peter D. (peda)


Lesenswert?

Stefan Ernst schrieb:
> Peter Dannegger schrieb:
>> Kann man Funktionspointer als far (32Bit Pointer) deklarieren?
>
> Nein. Du kannst aber auch mit den normalen 16Bit Pointern eine Funktion
> oberhalb 128k aufrufen. Dann wird im unteren Bereich ein Trampoline
> angelegt.

Wie schaltet man denn dieses Trampoline ein?
Ist das dann nur für meine Funktionen oder auch für die Lib?


Peter

von Stefan E. (sternst)


Lesenswert?

Peter Dannegger schrieb:

> Wie schaltet man denn dieses Trampoline ein?

Die produziert der Linker automatisch, wenn dem Funktionszeiger eine 
Funktion zugewiesen wird, die jenseits der 128k liegt.

> Ist das dann nur für meine Funktionen oder auch für die Lib?

Sollte auch für Lib-Funktionen funktionieren.

PS: Wichtig ist, dass du beim Linken die Option -Wl,--relax benutzt.

von Peter D. (peda)


Lesenswert?

Stefan Ernst schrieb:
> Sollte auch für Lib-Funktionen funktionieren.

Leider nicht wirklich.

In dem Trampolin stehen brav alle Funktionen meines Schedulers drin.
Auch ein "__muldi3+0xc" steht drin, welches "__prologue_saves__" 
aufruft.
Soweit also alles o.k.

Aber das verflixte "fputc" macht weiter seinen EICALL in den Wald.
Da scheint also ein schwerer Bug in der fputc/fgetc-Lib zu sein.


Peter

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


Lesenswert?

Peter Dannegger schrieb:
> Da scheint also ein schwerer Bug in der fputc/fgetc-Lib zu sein.

Nein.  Die Bibliothek enthält ja nur C-Code.  Wenn, müsste es ein
Bug im Compiler sein.

Der Bug liegt aber im Prinzip.  Das Trampolin nützt hier nichts.
Das fdevopen() (oder der vergleichbare Makro) trägt brav die Adresse
der put-Funktion in die interne Struktur ein, die hinter FILE steht.
An dieser Stelle weiß es einfach nicht, aus welchem der 128-KiB-
Segmente es später benutzt wird, es kann also nur die direkte Adresse
eintragen.  Da der GCC nie für eine Harvard-Architektur geschrieben
worden ist, kann er für eine Zielplattform auch nur eine Größe von
Zeiger implementieren.  Da nun niemand alle SRAM-Zeiger plötzlich auf
32 bit haben will, bleibt die Zeigergröße natürlich nach wie vor
16 bit.

Wenn der Compiler nun in fputc() die "put"-Funktion aufrufen will,
dann hat er also nur 16 bit an Information vorliegen.  Er tut sein
bestes und implementiert einen EICALL, aber das EIND fasst er in der
Tat nicht an -- die Information, die er in EIND hinein schreiben
müsste, besitzt er schlicht und ergreifend gar nicht, denn die steht
im genannten Funktionszeiger gar nicht drin!

Möglicherweise könnte man einen würgaround in der Bibliothek
implementieren, der auf CPUs mit > 128 KiB Flash-ROM statt eines
Funktionszeigers eine uint32_t-Zahl nimmt und dann die Indirektion
später zu Fuß in inline asm schreiben.  Allerdings kann einen
natürlich diese böse Falle immer wieder einholen...

Patches welcome. ;)

von Peter D. (peda)


Lesenswert?

Jörg Wunsch schrieb:
> Das fdevopen() (oder der vergleichbare Makro) trägt brav die Adresse
> der put-Funktion in die interne Struktur ein, die hinter FILE steht.

Danke für die Erklärung.


Also muß ich alle Funktionspointer, die an fdevopen()übergeben werden, 
nach unten linken lassen.
Und alles andere funktioniert dann über das Trampolin.


Peter

von Falk B. (falk)


Lesenswert?

Wenn ich das so lese werde ich wohl nie einen AVR mit mehr als 128k 
nutzen sondern gleich auf nen ARM gehen, dort sollte dieser Hickhack 
nicht auftauchen.

MFG
Falk

von 900ss (900ss)


Lesenswert?

Falk Brunner schrieb:
> dort sollte dieser Hickhack
> nicht auftauchen.

Nein, tut er nicht. Dafür ist der ARM dann an anderen Stellen deutlich 
komplizierter als ein AVR.
Also mal eben mit einer Minimalbeschaltung ganz schnell etwas 
ausprobieren geht nicht immer. Trotzdem arbeite ich auch gerne mit den 
ARM (Cortex-M3).

von netb (Gast)


Lesenswert?

Das 64KiB (Datenspeicher) und 64KiWord (Programmspeicher) Problem hat 
sich ja durch die XMega auch noch etwas verschärft. Ich denke, dass hier 
auf jeden Fall eine Lösung gefunden werden muss und zwar auch für 
Datenspeicherzugriffe im 24 Bit Adressraum. Es wäre schade, wenn die 
Möglichkeiten des XMegas und der großen AVRs am Ende an 
Compilerlimitierungen scheitern.

von Tmo (Gast)


Lesenswert?

@Joerg:

Ich dachte für diesen Fall gibt es extra die Trampolines. Wenn ich die 
Ausgabefunktion in die Filestruktur eintragen lasse, dann wird doch auf 
die Funktionsadresse indirekt zugeriffen und der Linker erzeugt 
automatisch dann einen Trampolineeintrag, nur wenn die referenzierte 
Funktion auch in den oberen 128kb liegt. Das erlaubt dann das 
Funktionieren des EICALL mit EIND=0. Funktioniert bei meinem OS schon 
seit WinAVR2007schiessmichtot probelmlos. Das wirkliche Problem war 
meines Wissens nur das Erstellen der Libs mit 
save_call_prologues/epilogues in Verbindung mit dem erweiterten 
Stackpointer, wofür ich oben eine Lösung gepostet hatte.

Trampolines tauchen bei mir nur unter zwei Bedingungen auf:
- es wird eine Funktionsadresse im Code verwendet (z.B. 
Funktionpointerarray, Taskfunktionen, fputc mit Stream-IO ...)
- die indirekt verwendete Funktion liegt in den oberen 128kb Flash

Oder habe ich da was falsch verstanden ?!

Gruss
tmo

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


Lesenswert?

Trampolines müssen auch benutzt werden, um von einem 128-KiB-Block
eine Funktion in einem anderen 128-KiB-Block zu rufen.

Was soll das Trampoline bei einem Funktionszeiger helfen?  Entweder,
er liegt im ersten 128er Segment und ist per EIND = 0 (was der
default sein sollte) erreichbar, oder das Trampoline hilft auch
nicht.

Oder habe ich das was falsch verstanden? ;-)

von Tmo (Gast)


Lesenswert?

das Trampoline hilft schon dabei, da der EICALL nicht auf dei Funktion 
in den oberen 128kb geht, sondern auf den Trampolineeinsprung und somit 
immer in den unteren 128kb landet ...

Gruss

von Tmo (Gast)


Lesenswert?

... der RCALL beim 2560 kann auch den ganzen 256kb Flash dirket ohne 
Trampoline ansprechen. Lediglich bei indirektem Funktionsaufruf via 
EICALL wird ein Trampoline fällig (wegen der EIND-Problematik). EICALL's 
werden aber vom Compiler nur erzeut, wenn ein Funktionszeiger verwendet 
wird ...

oder bin ich da falsch ...

Gruss
tmo

von Falk B. (falk)


Lesenswert?

Ohje Ohje, Würg around ^3.

Kennen wir diesen Unsinn nicht aus 286er Zeiten, mit Segmenten.
Weg mit dem Müll!!

Wie wäre eine Compileroption, welche zwischen 16 und 24(32) Bit Pointern 
umschaltet? Machbar? Sinnvoll?

MFG
Falk

von tmo (Gast)


Lesenswert?

ja Falk, das wäre sicher wünschenswert. Führt aber natürlich zu einem 
kompletten Umbau des Compilers für das AVR-Target und sicher zur 
Vergrösserung des Codes und RAM-Bedarfs, da ja dann alle Pointer 24 oder 
32 Bit sein müssten. Die Lösung mit den Trampolines funktioniert recht 
zuverlässig, verbraucht nicht zuviel Speicher und Rechenzeit und wird 
nur bei indirekten Funktionsaufrufen benötigt (falls ich mich nicht 
komplett irre), da ja sonst ein rcall problemlos seinen Dienst tut (das 
hier beim 2560 zusätzliche Byte beim rcall auf dem Stack hat auch die 
Probleme mit den prologues/epilogues gemacht). Die Lösung von IAR mit 
den getaggten/smarten Pointern wäre auch eine Lösung ist aber so im GCC 
sicher nicht vorgesehen und erfordert ähnlichen Umbauaufwand. Zusätzlih 
gibt es ja leider unter C auch keinen nativen 24Bit Datentypen ...

Gruss
tmo

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


Lesenswert?

Tmo schrieb:
> ... der RCALL beim 2560 kann auch den ganzen 256kb Flash dirket ohne
> Trampoline ansprechen.

Ein RCALL?  Eher nicht. ;-)  Der kann +-4 Kib adressieren.

Du hast aber Recht, ein CALL kann den kompletten Adressbereich
ansprechen.

Ich bin da mittlerweile auch ein wenig verwirrt mit den Trampolines,
muss ich zugeben.

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


Lesenswert?

Falk Brunner schrieb:
> Wie wäre eine Compileroption, welche zwischen 16 und 24(32) Bit Pointern
> umschaltet? Machbar?

Das wäre eine komplett neue Portierung für den AVR, im Prinzip ein
zweiter Prozessor, selbst wenn man es noch im derzeitigen Port
unterbekommt.  Soll nicht heißen, dass es gar nicht machbar wäre,
aber es wäre zumindest ein immenser Aufwand, einschließlich neuer
Bugs...

von tmo (Gast)


Lesenswert?

@Joerg:

mea culpa, Du hast recht ich meinte den CALL. Ich habe jetzt mal mit dem 
aktuellen Compiler getestet. Es ist so wie beschrieben:

- Trampoline wird vom Linker nur bei indirekt referenzierten Funktionen 
die in den oberen 128kb liegen erzeugt.

- der EICALL geht dann auf das Trampoline und wird dort via JMP in die 
oberen 128kb gelenkt.

- alle normalen/anderen Aufrufe via RCALL oder CALL ohne Trampoline.

Um die Performance zu verbessern, empfiehlt es sich aber trotzdem alle 
Funktionen, die indirekt referenziert werden (meist Taskfunktionen, 
Stream-IO ...) in die unteren 128kb zu lokatieren. Das spart den 
Trampolineeintrag und den zusätzlichen JMP. Als Alternative kann man ja 
alle Interruptfunktionen in die oberen 128kb lokatieren, da die ja 
sowieso mit einem JMP aus dem Int-Table gestartet werden.

Gruss
tmo

von 900ss (900ss)


Lesenswert?

tmo schrieb:
> - Trampoline wird vom Linker nur bei indirekt referenzierten Funktionen
> die in den oberen 128kb liegen erzeugt.
>
> - der EICALL geht dann auf das Trampoline und wird dort via JMP in die
> oberen 128kb gelenkt.
>
> - alle normalen/anderen Aufrufe via RCALL oder CALL ohne Trampoline.

Gibt es zu diesem Thema irgendwo eine Doku? Hab schon mal kurz gegraben, 
aber außer hier im Forum verstreute Infos hab ich nichts gefunden.
Also ich meine, wie der Machnismus im WinAVR implementiert ist.

von tmo (Gast)


Lesenswert?

nein, wüsste ich nicht :-(

Habe alles aus diversion Foren, Quellcodes und rumprobieren für mich und 
meine Projekte ermittelt.

Gruss
tmo

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Das wäre eine komplett neue Portierung für den AVR, im Prinzip ein
>zweiter Prozessor, selbst wenn man es noch im derzeitigen Port
>unterbekommt.

Und wo bleibt da die vielzitierte Portabilität und Wartbarkeit, wenn 
eine Umstellung der Pointer von 16 auf 32 Bit soooooo aufwändig ist?
Das es nicht mit einem einfachen define getan ist ist schon klar, aber 
eine "komplett neue Portierung" halte ich für deutlich daneben.

>aber es wäre zumindest ein immenser Aufwand,

Wieso? Es muss doch nicht jede Funktion manuell komplett neu gemacht 
werden, oder?

MfG
Falk

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


Lesenswert?

Falk Brunner schrieb:

> Und wo bleibt da die vielzitierte Portabilität und Wartbarkeit, wenn
> eine Umstellung der Pointer von 16 auf 32 Bit soooooo aufwändig ist?

"Portabel" heißt doch nicht, dass du eine neue CPU gewissermaßen
"kostenlos" bekommst.

> Das es nicht mit einem einfachen define getan ist ist schon klar, aber
> eine "komplett neue Portierung" halte ich für deutlich daneben.

Eine neue CPU-Portierung ist es schon.  Die 95 % maschinenunabhängige
Dinge kannst du ja trotzdem weiter benutzen, dort liegt die eigentliche
Portabilität (einschließlich der vielen Optimierungen, die bereits auf
diesem Niveau laufen).

> Wieso? Es muss doch nicht jede Funktion manuell komplett neu gemacht
> werden, oder?

Guck dir doch einfach mal an, wie viel es ist. ;-)

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.