Hallo!
Ich wollte den seed "generator" von Johann L. in meinem Projekt mit
benutzen.
Jedoch startet der Controller die Main Schleife nicht, da er wie in
debug/testinit.lss
in Zeile a2: mit dem rjmp immer wieder nach oben springt und dort nie
wieder rauskommen kann.
Ineressanter weise höhrt dies auf wenn mann in
__init_seed()
p >= & __noinit_start + 1
gegen z.b.
p >0xff(warnung wegen falschen vergleichs)
tauscht?
jemand eine Idee wie man den Compiler das abgewöhnen könnte?
Gruß Stefan
Sieht tatsächlich nach einem Fehler des Compilers aus. Bei mir sieht das
Ergebnis übrigens so aus (also richtig):
1
74: 20 e0 ldi r18, 0x00 ; 0
2
76: 30 e0 ldi r19, 0x00 ; 0
3
78: e0 e0 ldi r30, 0x00 ; 0
4
7a: f5 e0 ldi r31, 0x05 ; 5
5
7c: 04 c0 rjmp .+8 ; 0x86 <__init_seed+0x12>
6
7e: 92 91 ld r25, -Z
7
80: 82 91 ld r24, -Z
8
82: 28 27 eor r18, r24
9
84: 39 27 eor r19, r25
10
86: 81 e0 ldi r24, 0x01 ; 1
11
88: e2 30 cpi r30, 0x02 ; 2
12
8a: f8 07 cpc r31, r24
13
8c: c0 f7 brcc .-16 ; 0x7e <__init_seed+0xa>
14
8e: 30 93 01 01 sts 0x0101, r19
15
92: 20 93 00 01 sts 0x0100, r18
16
17
96: 02 d0 rcall .+4 ; 0x9c <main>
18
98: 06 c0 rjmp .+12 ; 0xa6 <_exit>
Bevor wir uns den Fehler aber jetzt im Detail anschauen, erst noch eine
Frage. Du benutzt Eclipse, vielleicht auf Linux und vielleicht mit einem
fertigen AVR-GCC-Paket (z.B. von Ubuntu)?
Hallo Stefan!
Compiler läuft auf Windows XP SP 3
avr-gcc -v gibt aus:
Using built-in specs.
Target: avr
Configured with: ../gcc-4.3.2/configure
--enable-win32-registry=WinAVR-20090313
--with-gmp=/usr/local --with-mpfr=/usr/local --prefix=/c/WinAVR
--target=avr --enable-languages=c,c++,objc --with-dwarf2 --enable-doc
--disable-shared--disable
-libada --disable-libssp --disable-nls --with-pkgversion='WinAVR
20090313'
--with-bugurl='URL:http://sourceforge.net/tracker/?atid=520074&group_id=68108&func=browse';
Thread model: single
gcc version 4.3.2 (WinAVR 20090313)
Ich nutze Eclipse 3.4.2 mit AVR Plugin von Thomas Holland Version
2.3.1.20081204PRD
Gruß Stefan
Hallo Stefan!
Folgender Aufruf wird generiert.
avr-gcc -Wall -g2 -gstabs -O2 -fpack-struct -fshort-enums
-funsigned-char -funsigned-bitfields -mmcu=atmega168 -DF_CPU=1000000UL
-MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c"
Habe bei Eclipse neues Projekt angelegt, und nur den AVR Typ und die
Optimierungsstufe angepasst.
Mein generiertes Makefile liegt in dem Archiv unter Debug, erzeugt dann
diesen Aufruf.
Gruß Stefan
Hallo Stefan!
Habs gerade nochmal laufen lassen, tritt bei O2 und O3 auf.
Habe eignetlich keine konktreten grund für O2.
Ist aber Trotzdem nicht schön. Aber mann kann ja drumm schiffen.
Is das BUG Report Wert?
Gruß Stefan
Die Ursache liegt in dem "naked". Als normale Funktion sieht das nämlich
so aus:
1
0000007a <init_seed>:
2
7a: 82 e0 ldi r24, 0x02 ; 2
3
7c: 91 e0 ldi r25, 0x01 ; 1
4
7e: 81 50 subi r24, 0x01 ; 1
5
80: 95 40 sbci r25, 0x05 ; 5
6
82: 88 f4 brcc .+34 ; 0xa6 <init_seed+0x2c>
7
84: 20 e0 ldi r18, 0x00 ; 0
8
86: 30 e0 ldi r19, 0x00 ; 0
9
88: e0 e0 ldi r30, 0x00 ; 0
10
8a: f5 e0 ldi r31, 0x05 ; 5
11
8c: 92 91 ld r25, -Z
12
8e: 82 91 ld r24, -Z
13
90: 28 27 eor r18, r24
14
92: 39 27 eor r19, r25
15
94: 81 e0 ldi r24, 0x01 ; 1
16
96: e2 30 cpi r30, 0x02 ; 2
17
98: f8 07 cpc r31, r24
18
9a: c0 f7 brcc .-16 ; 0x8c <init_seed+0x12>
19
9c: 30 93 01 01 sts 0x0101, r19
20
a0: 20 93 00 01 sts 0x0100, r18
21
a4: 08 95 ret
22
a6: 20 e0 ldi r18, 0x00 ; 0
23
a8: 30 e0 ldi r19, 0x00 ; 0
24
aa: f8 cf rjmp .-16 ; 0x9c <init_seed+0x22>
Und dieser Code ist korrekt. Durch das "naked" fällt dann das "ret" weg
und du hast die Endlosschleife am Ende.
> Is das BUG Report Wert?
Ich bin mir gar nicht mal sicher, ob man das überhaupt als Bug
bezeichnen kann.
Sepp schrieb:
> Es ist doch Sinn und Zweck des naked-Attributs, daß das ret wegfällt...
Ja und?
Die Frage ist: Kann man es als Bug bezeichnen, wenn der Compiler dem
Code eine solche Struktur gibt, dass beim Wegfall des "ret" (eben naked)
eine Endlosschleife entsteht?
Ich tendiere eher zu Nein.
Stefan Ernst schrieb:
> Ich bin mir gar nicht mal sicher, ob man das überhaupt als Bug> bezeichnen kann.
Naja, etwas seltsam ist das schon, dass er für eine Funktion, die
als naked deklariert ist, dann trotzdem noch versucht, einen
Epilog zu erzeugen. Ich würde das schon als Bug bezeichnen.
1
.L6:
2
sts (seedram)+1,r19
3
sts seedram,r18
4
/* epilogue start */
5
.L11:
6
ldi r18,lo8(0)
7
ldi r19,hi8(0)
8
rjmp .L6
(Der Kommentar für "epilogue end" fehlt übrigens; auch ein Hinweis
darauf, dass hier im Compiler was schief gelaufen ist.)
Ich habe das Ganze mal mit einem GCC 4.2.2 übersetzt, der generiert
auch bei -O3 noch korrekten Code:
1
...
2
ldi r24,hi8(__noinit_start+2)
3
cpi r30,lo8(__noinit_start+2)
4
cpc r31,r24
5
brsh .L9
6
rjmp .L8
7
.L13:
8
ldi r18,lo8(0)
9
ldi r19,hi8(0)
10
.L8:
11
sts (seedram)+1,r19
12
sts seedram,r18
13
/* epilogue: frame size=0 */
14
/* epilogue: naked */
15
/* epilogue end (size=0) */
16
/* function __init_seed size 25 (25) */
Wäre die Frage, ob der Bug insbesondere in GCC 4.4.x noch drin ist.
Zwei Bemerkungen zu Stefans Code:
. Bitte #include <avr/io.h> schreiben, damit man das nicht extra
noch editieren muss, wenn man nicht auf Windows arbeitet. Der
Backslash ist da völlig unnötig.
. Die beiden extrem wichtigen Deklarationen der Attribute in ein
main.h auszulagern, widerspricht der Erwartungshaltung und hat
keinen wirklichen Sinn. Sowas gehört möglichst nahe an die
Definition der entsprechenden Funktion oder Variablen heran, damit
man es sofort beim Lesen bemerkt.
> Naja, etwas seltsam ist das schon, dass er für eine Funktion, die> als naked deklariert ist, dann trotzdem noch versucht, einen> Epilog zu erzeugen.
Inwieweit versucht er es denn? Das fragliche Stückchen Code ist doch
Bestandteil des eigentlichen Funktionscodes, es liegt nur hinter dem
Epilog. Das ist das Problem, dass der Epilog quasi mitten im restlichen
Code liegt.
Hallo!
Ich kann es nicht an 4.4 testen, bin halt nur unter Win unterwegs.
@Jörg:
werds mit mit den "/" anehmen, grundsätzlich.
das andere auch.
Ich ich denke das der Compiler auch bei unterschiedlichen
Optimierungsstuffen dann trotzdem immer zum selben Verhalten des
Programmes kommen müsste, oder?
Gruß Stefan
Stefan Ernst schrieb:
>> Naja, etwas seltsam ist das schon, dass er für eine Funktion, die>> als naked deklariert ist, dann trotzdem noch versucht, einen>> Epilog zu erzeugen.>> Inwieweit versucht er es denn?
Indem der Compiler davor schreibt: "epilogue start". Ich habe ja
den Vergleich mit dem GCC 4.2.2 gebracht, da steht auch beim
Epilog sauber drin "epilogue: naked". GCC 4.3.x schreibt das beim
Prolog auch so hin, aber beim Epilog verheddert er sich offenbar.
Ich finde auf Anhieb keinen Bug in GCCs Bugzilla, dessen Beschreibung
das Wort "naked" enthält und der irgendwie annähernd auf dieses
Symptom zu passen scheint. Scheint also ein neuer Bug zu sein.
Stefan schrieb:
> Ich ich denke das der Compiler auch bei unterschiedlichen> Optimierungsstuffen dann trotzdem immer zum selben Verhalten des> Programmes kommen müsste, oder?
Ja, zumindest grundlegend. Im Zeit- und Platzbedarf darf sich
natürlich schon mal etwas ändern.
Jörg Wunsch schrieb:
> . Die beiden extrem wichtigen Deklarationen der Attribute in ein> main.h auszulagern, widerspricht der Erwartungshaltung und hat> keinen wirklichen Sinn. Sowas gehört möglichst nahe an die> Definition der entsprechenden Funktion oder Variablen heran, damit> man es sofort beim Lesen bemerkt.
Stimmt, mit sowas rechnet man nicht.
Der Compiler hat also recht, bei naked muß er das RET weglassen und der
Autor hätte es händisch einfügen müssen.
Das es manchmal trotzdem geht, liegt daran, daß das RET zufällig am Ende
stünde und dann ohne RET in die nächste Funktion reingelaufen wird.
Der Compiler ist aber nicht verpflichtet, die Funktionen so zu
schreiben, daß das (virtuelle) RET immer am Ende steht, bzw. nur bei
-O0.
Peter
Jörg Wunsch schrieb:
> Indem der Compiler davor schreibt: "epilogue start". Ich habe ja> den Vergleich mit dem GCC 4.2.2 gebracht, da steht auch beim> Epilog sauber drin "epilogue: naked". GCC 4.3.x schreibt das beim> Prolog auch so hin, aber beim Epilog verheddert er sich offenbar.
In GCC 4.3 wurde die Generierung von Prolog und Epilog auf RTL-Code
umgebaut, dadurch sieht der Code völlig anders aus. Beim Prolog steht:
1
/* Prologue: naked. */
2
if(cfun->machine->is_naked)
3
{
4
return;
5
}
d.h. die Funktion zum Generieren des Prologs wird sofort verlassen,
wenn eine "naked" Funktion generiert wird. Beim Epilog dagegen
steht:
1
/* epilogue: naked */
2
if(cfun->machine->is_naked)
3
{
4
emit_jump_insn(gen_return());
5
return;
6
}
Dieses "emit_jump_insn (gen_return ());" scheint irgendwie die Ursache
des Problems zu sein. Ich finde auf Anhieb nicht, wie gen_return()
definiert ist. Man könnte natürlich mal probieren, diese Zeile ganz
auszukommentieren, und danach die GCC-Testsuite durchzuleiern um zu
sehen, ob daraus weitere regressions entstehen.
Ich würde auf jeden Fall empfehlen, einen GCC-Bugreport zu schreiben.
Der Bug ist übrigens rein AVR-spezifisch.
Peter Dannegger schrieb:
> Der Compiler hat also recht, bei naked muß er das RET weglassen und der> Autor hätte es händisch einfügen müssen.
Nein, in diesem Falle ist es Absicht, dass das RET fehlt, denn das
Ganze soll ja in die Startup-Sequenz eingebaut werden. Da darf
es kein CALL/RET geben, denn es gibt u. U. noch gar keinen initiali-
sierten Stack.
Jörg Wunsch schrieb:
>> Inwieweit versucht er es denn?>> Indem der Compiler davor schreibt: "epilogue start". Ich habe ja> den Vergleich mit dem GCC 4.2.2 gebracht, da steht auch beim> Epilog sauber drin "epilogue: naked". GCC 4.3.x schreibt das beim> Prolog auch so hin, aber beim Epilog verheddert er sich offenbar.
Gut, überzeugt. ;-)
Aber ich sehe noch nicht den direkten Zusammenhang. Der Epilog ist ja
mit naked leer (wenn auch unzureichend kommentiert). Er ist nur von
vornherein schlecht positioniert.
Peter Dannegger schrieb:
> Der Compiler hat also recht, bei naked muß er das RET weglassen und der> Autor hätte es händisch einfügen müssen.
Aber bei diesem Code hätte der Author nicht mal die Möglichkeit, das RET
selbst einzufügen.
Jörg Wunsch schrieb:
> Nein, in diesem Falle ist es Absicht, dass das RET fehlt, denn das> Ganze soll ja in die Startup-Sequenz eingebaut werden. Da /darf/> es kein CALL/RET geben, denn es gibt u. U. noch gar keinen initiali-> sierten Stack.
Dann müßte das naked aber eine Umsortierung des Codes verhindern.
Diese Konstrukte mit dem RET mittendrin sind mir auch schon oft
aufgefallen beim AVR-GCC 4.3.x.
Der Optimizer hält Indexoperationen mit Autoincrement für extrem teuer
und trennt das Increment ab, um das letzte (unnötige) Increment zu
sparen.
Peter
Stefan Ernst schrieb:
> Peter Dannegger schrieb:>>> Der Compiler hat also recht, bei naked muß er das RET weglassen und der>> Autor hätte es händisch einfügen müssen.>> Aber bei diesem Code hätte der Author nicht mal die Möglichkeit, das RET> selbst einzufügen.
Bitte streichen. :-)
Ein händisches RET am Ende der Funktion taucht auch mitten drin auf.
In diesem Fall endet die Funktion an 0xA2. Der Optimizer hat die
while-Schleife in die zeitlich geringfügig effizientere aber deutlich
längere if-do-while Form optimiert und hat den abweisenden Fall aus dem
sequentiellen Codeablauf rausoperiert:
1
if(p>=&__noinit_start+1){
2
do{
3
s^=*(--p);
4
}while(p>=&__noinit_start+1)
5
seedram=s;
6
return;
7
}
8
seedram=0;
Der "seedram = 0;" Schwanz beginnt nun hinter dem nicht vorhandenen
Epilog, teilt aber einen Teil der Zuweisung mit dem Schluss der
Hauptsequenz.
Sinn dieser Optimierung ist die Vermeidung von ausgeführten
Sprungbefehlen, die bei den meisten Zielarchitekturen recht teurer sind.
Das ist eine typische Optimierung for -O2/3, die bei der für AVRs m.E.
ohnehin empfehlenswerteren Optimierungsstufe -Os vermutlich verschwinden
wird.
Peter Dannegger schrieb:
>> Nein, in diesem Falle ist es Absicht, dass das RET fehlt, denn das>> Ganze soll ja in die Startup-Sequenz eingebaut werden. Da /darf/>> es kein CALL/RET geben, denn es gibt u. U. noch gar keinen initiali->> sierten Stack.>> Dann müßte das naked aber eine Umsortierung des Codes verhindern.
Nein, das RET irgendwo zwischendrin müsste wohl zu einem Sprung
hinter das Ende umgeformt werden. Möglicherweise ist das ja der
Sinn des "emit_jump_insn (gen_return ());", an der Stelle blicke
ich dann nicht mehr durch.
Stefan schrieb:
> Bug ist aufgenommen
Danke.
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42240
Einen Hinweis noch: die GCC-Leute möchten gern den Code nach dem
Präprozessor sehen. Dinge wie #include <avr/io.h> sollten da also
nicht mehr drin stehen. Du brauchst aber sowieso nicht viel davon,
den uint16_t kannst du so obendrüber selbst definieren:
1
typedefunsignedintuint16_t;
RAMEND kannst du durch eine beliebige Zahl ersetzen. Die deutschen
Kommentare braucht da sicher auch keiner. ;-) Ergebnis:
Wenn du jetzt noch das generierte Assemblerfile als zweites Attachment
bringst:
avr-gcc -O2 -S main.c
dann freuen sich die Leute, weil der Bug dann offensichtlich erkennbar
ist.
Sollte gut sein so.
Du kannst mal noch unter "known to fail" die Zahl eintragen:
4.3.2, 4.3.4
und wenn du willst unter "known to work" die 4.2.2. Ich darf's
nicht, hab's gerade probiert.
OK, danke. ;-)
Noch eine orthografische Korrektur, damit man das auch mit der
Suche findet:
Statt
wrong Epilog on nacked function
bitte
wrong epilogue on naked function
Hallo A.K.
Nach meinem verständinss muss der Compiller zumindest gleichbleibendes
Verhalten erzeugen.
Also geht entweder unter gar keiner Optimierungsstufe, oder unter allen.
Gruß
Stefan schrieb:
> Also geht entweder unter gar keiner Optimierungsstufe, oder unter allen.
Es hängt allein davon ab, ob durch die Optimierung der Code zufällig
hinten endet oder irgendwo zwischedrin.
Der Compiler ist in einer Zwickmühle:
Einerseits sagst Du ihm mit "naked", er soll keinen Epilog erzeugen,
gleichzeitig erwartest Du aber, daß er doch einen Epilog erzeugt (Sprung
zum Ende).
Meiner Meinung nach kann man bei "naked" Funktionen nur dann einen
zuverlässigen Code erwarten, wenn man ihn in Assembler schreibt oder bei
C-Code mit abgeschalteter Optimierung (-O0).
Peter
Stefan schrieb:
> Also geht entweder unter gar keiner Optimierungsstufe, oder unter allen.
Die Doku vom GCC sagt ausdrücklich, dass der Programmierer für
Prolog/Epilog selbst verantwortlich ist. Der Sinn der "naked" Option
dürfte ursprünglich in speziellen Interrupt-Handlern und ähnlichem Kram
liegen, sowas wird gern bei Realtime-Kernels verwendet.
Den Epilog einfach wegzulassen und zu hoffen, dass man wie zufällig
hinten passend rausfällt, das steht nicht in der Vorgabe. Es steht auch
nirgends in Stein gemeisselt, dass der Epilog einer C Funktion immer zu
allerletzt im Code kommt. Der darf auch mitten drin liegen. Was er hier
tut.
Es ist nicht weiter erstaunlich, dass das optimierungsabhängig ist. GCC
optimiert bei Fokus auf Laufzeit so, dass der von ihm als Hauptpfad
angesehene Codepfad mit so wenig Sprüngen wie möglich auskommt. Das kann
auch mal bedeutet, dass ein Nebenpfad aus dem Weg geräumt wird und dann
eben hinter dem für den Epilog vorgesehenen Platz landet. Genau das
geschieht hier. Das hat hier zur Folge, dass der Ablauf eben nicht am
letzten Byte endet, sondern mitten drin, und man folglich nicht wie
gewünscht hinten rausfällt. Pech für die Kuh Elsa.
Wenn man das gleiche Spielchen beim arm-gcc macht, dann wird das selbst
dann in die Hose gehen, wenn der Code wie angenommen tatsächlich hinten
rausfällt. Denn bei ARMs schliesst sich dort üblicherweise der constant
pool an, und der macht sich als auszuführender Code nicht wirklich gut.
Langer Rede kurzer Sinn: Eine "naked" Funktion komplett ohne explizit
programmiertem Epilog direkt in die .initN Sektionen reinzupinnen war
nie der Zweck dieser Option, hat aber eine Weile lang zufällig
funktioniert. Und funktioniert nun eben nicht mehr.
Stefan schrieb:
> Nach meinem verständinss muss der Compiller zumindest gleichbleibendes> Verhalten erzeugen.
Er muss sich an die Vorgabe halten. Das tut er.
Wer sich hier nicht an die Vorgabe hält ist der Programmierer, der es
unterlässt, selbst für einen passenden Epilog zu sorgen. Was seine
Pflicht wäre.
Dass der Programmierer damit ein Problem hat ist nicht Sache des
Compilers. Eine "naked" Funktion ist nun einmal eine Brechstange, die
dem Compiler ausdrücklich zu verstehen gibt, dass er nicht für einen
korrekten Abschluss sorgen muss.
Das sorgt dafür, das die Funktion nicht auf Geschwindigkeit sondern auf
Größe optimiert wird. Das Gegenstück dazu ist "hot". Leider scheint es
aber kein Attribut zu geben, daß die Optimierung für eine Funktion
komplett abschaltet.
Dürfte natürlich nicht in allen Fällen helfen, in diesem speziellen aber
schon (kompilliert mit -O3):
Peter Dannegger schrieb:
> Der Compiler ist in einer Zwickmühle:> Einerseits sagst Du ihm mit "naked", er soll keinen Epilog erzeugen,> gleichzeitig erwartest Du aber, daß er doch einen Epilog erzeugt (Sprung> zum Ende).
Offenbar erzeugt er ja auch einen minimalen Epilog, nur halt den
falschen (nämlich einen, der in die Funktion zurück springt).
> Meiner Meinung nach kann man bei "naked" Funktionen nur dann einen> zuverlässigen Code erwarten, wenn man ihn in Assembler schreibt oder bei> C-Code mit abgeschalteter Optimierung (-O0).
Beides wäre widersinnig. Im ersten Fall kann man die Funktion gleich
als Assemblerdatei reinklemmen, dann braucht man das "naked" einfach
mal gar nicht. Dem Linker ist es wurscht, ob der entsprechende
Objektmodul für die .initN-Teile aus C oder Assembler erzeugt worden
war. Der zweite Fall wäre widersinning, weil das Abschalten der
Optimierung nie eine Lösung ist, sondern nur das Problem kaschiert.
Optimierung soll man höchstens ausschalten müssen, um besser debuggen
zu können, aber nicht für produktiven Code.
Wenn eine naked-Funktion nicht garantieren kann, dass sie am Ende
der Abarbeitung auch am Ende der Funktion rauskommt, dann ist das
Attribut einfach nicht zu gebrauchen, denn es wäre dann auch nicht
möglich, da beispielsweise einen eigenen Epilog anzufügen.
Jörg Wunsch schrieb:
> Offenbar erzeugt er ja auch einen minimalen Epilog, nur halt den> falschen (nämlich einen, der in die Funktion zurück springt).
Nö, das ist kein Epilog, es gehört zu Code, der nach hinten verschoben
wurde.
Wenn man das naked wegläßt, bleibt der Sprung, nur dazwischen kommt noch
das RET rein.
Der Compiler hat einfach ganz formal das RET gelöscht, mehr nicht.
Der naked-Besen kehrt nach der Optimierung nochmal drüber und löscht
alle Epiloge.
Das Verhalten ist vielleicht nicht vom Nutzer erwünscht, aber streng
formal richtig.
Es wird daher sehr sehr schwer sein, einen Ausnahme-Epilog
reinzubasteln.
Peter
Jörg Wunsch schrieb:
> Wenn eine naked-Funktion nicht garantieren kann, dass sie am Ende> der Abarbeitung auch am Ende der Funktion rauskommt, dann ist das> Attribut einfach nicht zu gebrauchen, denn es wäre dann auch nicht> möglich, da beispielsweise einen eigenen Epilog anzufügen.
Doch. Das Attribut ist ursprünglich für diese Art Code vorgesehen:
1
voidsyscall_handler(void)
2
{
3
SAVE_CONTEXT();
4
...wasauchimmmer...
5
RESTORE_CONTEXT_AND_RETURN();
6
}
mit entprechenden ASM-Stücken für den handgebauten Prolog/Epilog. Da
funktioniert es weiterhin.
Peter Dannegger schrieb:
> Der Compiler hat einfach ganz formal das RET gelöscht, mehr nicht.> Der naked-Besen kehrt nach der Optimierung nochmal drüber und löscht> alle Epiloge.
Fast. Mit "naked" werden Prolog und Epilog nicht erst erzeugt und
gelöscht, sondern überhaupt nicht durchgeführt.
Mein Verdacht ist, dass Jörgs vermisster Sprung
emit_jump_insn (gen_return ())
nichts anderes als ein "return" ist und daher als Sprung auf den Epilog
verstanden wird. Und der Compiler einen Sprung auf sich selbst (denn
genau da steht er ja grad) als Unsinn entsorgt.
Statt dessen müsste der Compiler dort nicht ein "return" einfügen,
sondern einen Sprung auf ein Label, dass abschliessend nach dem letzten
Byte Code definiert wird.
In obigem Beispiel würde das allerdings Kritiker auf den Plan rufen, die
diesen Sprung als unnötigen Unsinn brandmarken. ;-)
A. K. schrieb:
> Mein Verdacht ist, dass Jörgs vermisster Sprung> emit_jump_insn (gen_return ())> nichts anderes als ein "return" ist und daher als Sprung auf den Epilog> verstanden wird. Und der Compiler einen Sprung auf sich selbst (denn> genau da steht er ja grad) als Unsinn entsorgt.
Ja, das ist möglich. Wenn man an dieser Stelle ein
asm("ret");
einbaut, dann wird es vor der Stelle ausgeführt, die da als
"epilogue" deklariert wird.
> Statt dessen müsste der Compiler dort nicht ein "return" einfügen,> sondern einen Sprung auf ein Label, dass abschliessend nach dem letzten> Byte Code definiert wird.
Ja, das wäre die sinnvollste Aktion.
Als Würgaround würde noch sowas helfen:
Sieht erstmal nicht schlecht aus.
Nun muß man bloß noch die Stelle finden, wo in Stein gemeißelt ist, daß
Funktionen in der init-Section nicht umsortiert werden dürfen.
In der text-Section stellt mir der Compiler gerne mal die
Funktionsreihenfolge um.
Peter
Peter Dannegger schrieb:
> Nun muß man bloß noch die Stelle finden, wo in Stein gemeißelt ist, daß> Funktionen in der init-Section nicht umsortiert werden dürfen.
Nirgends. Wenn du paranoid bist, dann:
. schreibst du den ganze Zinnober gleich in Assembler, oder
. schreibst ihn nach .init7 und setzt das Sprungziel in die .init8,
oder
. schreibst einen Linkerscript, der einen Label am Ende von .init8
generiert, und springst den an.
Im Übrigen wage ich die Sinnfälligkeit des ganzen Unternehmens zu
bezweifeln. SRAM hat eine Vorzugslage, die er mit einer gewissen
Wahrscheinlichkeit nach dem Einschalten einnimmt, und die letztlich
produktionsbedingt ist. Damit ist das sich ergebende seed gar nicht
so zufällig, wie man sich das erhoffen könnte.
Peter Dannegger schrieb:
> In der text-Section stellt mir der Compiler gerne mal die> Funktionsreihenfolge um.
Gibt's dafür nicht die Nummerierung der Init-Sektionen?
Jörg Wunsch schrieb:
> Nirgends. Wenn du paranoid bist, dann:
Das ist lustig.
Sonst bist Du doch immer derjenige, der einen darauf hinweist, daß ein
Compiler nicht denken kann, sondern stur formal arbeitet.
> Im Übrigen wage ich die Sinnfälligkeit des ganzen Unternehmens zu> bezweifeln.
Da stimme ich Dir zu.
Ich hatte mal versucht, einen AT89C2051 mir Warmstarterkennung zu
machen.
Dazu habe ich vor einem Warmreset ein Muster in den SRAM geschrieben und
nach dem Reset geprüft. Erstaunt mußte ich feststellen, daß das nicht
funktionierte.
Selbst nach einer Minute abschalten, VCC kurzschließen, wieder
anschalten, war der SRAM noch unverändert.
Für ne Zufallszahl würde ich nen Timer ohne Prescaler laufen lassen und
ne Taste auf den Input-Capture-Eingang.
Peter
Jörg Wunsch schrieb:> Peter Dannegger schrieb:>>>> Nein, in diesem Falle ist es Absicht, dass das RET fehlt, denn das>>> Ganze soll ja in die Startup-Sequenz eingebaut werden. Da /darf/>>> es kein CALL/RET geben, denn es gibt u. U. noch gar keinen initiali->>> sierten Stack.>>>> Dann müßte das naked aber eine Umsortierung des Codes verhindern.>> Nein, das RET irgendwo zwischendrin müsste wohl zu einem Sprung> hinter das Ende umgeformt werden. Möglicherweise ist das ja der> Sinn des "emit_jump_insn (gen_return ());", an der Stelle blicke> ich dann nicht mehr durch.
FYI, korrekt wäre beides. Die Lösung ist recht simpel und läuft auf
Peters Sichtweise hinaus.
@Jörg
Der Fix zu PR42240 ist dort beschrieben, er ist recht einfach und auch
relevant für 4.6.0. Kannst du ein Patch machen? Ich hab ja kein FSF CA.
Wenn Fragen sind wo was zu machen ist kann ich's erklären.
gen_foo ist eine Funktion, die während des builds durch gen-tools
erstellt wird. Die eigentliche Implementierung (afair insn-emit.c) ist
nicht sonderlich interessant. Die Funktion wird aus RTL aus dem md
erstellt für define_insn, define_insn_and_split oder define_expand mit
entsprechendem Name, in diesem Falle
1
(define_insn "return"
2
[(return)]
3
...
Das gen_-Präfix kommt von den gen-tools. RTL-matching geschieht ab dem
Zeitpunkt über das Pattern und die insn-Condition, hier also