Hallo
Ich versuche grade die Firmware von TV-B-Gone mit dem AVRGCC zu
kompilieren, dabei gibt es viele Arrays der Form
1
constuint16_tcode_na003Times[]PROGMEM=
2
{
3
26,185,
4
27,80,
5
27,185,
6
27,4549,
7
};
Das Problem dabei ist jetzt aber, dass dieses Array nie direkt mit Namen
angesprochen wird, sondern nur indirekt über ein durch den Flash
laufenden Zeiger. Der Kompiler erkennt dies und optimiert die Variable
raus. Wie kann ich dieses Verhalten am besten unterbinden, ohne jedoch
auf Optimierungen zu verzichten?
MfG Hexfile
Hallo Stefan
Das erkenne ich daran, dass der Kompiler nur 744 Bytes für den Flash
vorsieht. Schwer vorstellbar wenn die Arrays mehrere KB groß sind und
grade so in den AVR (ATTiny85) passen. Das ganze Projekt besteht aus
einem Hauptprogramm was die Codes aus dem Flash läd (dieses Programm ist
wohl 744 Byte groß) und mehreren KB von LUTs die aus dem Flash gelesen
werden. Da alle hintereinander stehen werden sie der Reihe nach aus dem
Flash gelesen, ohne sie direkt mit Namen anzusprechen, was bei mehreren
100 Namen auch etwas viel wäre. Im Code wird ein Zeiger auf den ersten
Eintrag definiert welcher dann durch die Arrays durchläuft, folglich
wird auch nur der erste Eintrag referenziert, der Rest wird vom Kompiler
als "unused" erkannt und landet dementsprechend nicht im fertigen hex.
Ich möchte auch nicht umbedingt alle Symbole einzeln per dummy-verweiß
(welcher ja auch Platz kostet) einbinden, das ist bei über 100 einfach
zu Fehleranfällig und zu unflexibel.
Ein dummy-read auf das erste Element am Programmanfang meldet dem
Compiler das Vorhandensein dieser Datenstruktur und bindet sie dann im
hexfile mit ein. Andernfalls müsstest du diese Tabellen händisch an das
Ende des erzeugten hexfiles selbst anfügen.
@ Hexfile (Gast)
>Das Problem dabei ist jetzt aber, dass dieses Array nie direkt mit Namen>angesprochen wird, sondern nur indirekt über ein durch den Flash>laufenden Zeiger.
Na und der muss ja irgendwann mal initialisiert werden. Dann kann der
Compiler ihn auch nicht wegoptimieren. Lass die sinnlosen Hackertricks
stecken und programmiere normales C, dann braucht es auch keine
zusätzlichen Hackertricks, um den Compiler auszutricksen.
Der Code ist nicht von mir, sondern kommt aus dem Projekt TV-B-Gone.
Irgentwie werden diese netten Leute das Ding kompiliert bekommen haben,
es muss also gehen. Das erste Array wird wohl auch im Flash stehen (kann
das nur anhand der Größe überprüfen), aber wie gesagt, in dem Programm
befinden sich hunderte von Arrays, welche alle indirekt angesprochen
werden.
Siehe:
http://code.google.com/p/tv-b-gone/source/browse/trunk/codes/codes.h
Auch volatile hat nichts gebracht, was auch zu erwarten war. Selbst wenn
die Variable veränderlich ist, was nie gelesen wird wird entfernt.
Falk Brunner schrieb:> Na und der muss ja irgendwann mal initialisiert werden. Dann kann der> Compiler ihn auch nicht wegoptimieren. Lass die sinnlosen Hackertricks> stecken und programmiere normales C, dann braucht es auch keine> zusätzlichen Hackertricks, um den Compiler auszutricksen.
1) so wie ich das verstehe handelt es sich um mehrere hintereinander
liegende Arrays. D.h. durch die Initialisierung bleibt genau das erste
Array erhalten, die nachfolgenden werden ja nicht angesprochen.
2) das ist nicht auf seinem Mist gewachsen sondern der TE versucht ein
relativ bekanntes Projekt zu kompilieren.
>Sorry, aber volatile MUSS die Variable erhalten. Das ist die Definition>von volatile!
Ich denke nicht, wenn sie gar nie verwendet wird.
>welche alle indirekt angesprochen werden.
Zeige ein Beispiel, wie sie angesprochen werden. Irgend woher musst Du
ja die Adresse wissen, bzw. einen Pointer auf die Variablen definieren.
Wenn Du dies den Compiler über den Array-Namen machen lässt, sollte es
eigentlich gehen!
Peter schrieb:> Ich denke nicht, wenn sie gar nie verwendet wird.
Doch, genau dazu ist doch volatile da verdammt nochmal!
wenn ich folgenden Code compiliere
1
intmain(void)
2
{
3
volatileintfoo=0;
4
5
}
dann kommt das raus
gcc -c -g -Wa,-a,-ad -O3 volatile.c | less
666 schrieb:> Peter schrieb:>> Ich denke nicht, wenn sie gar nie verwendet wird.>> Doch, genau dazu ist doch volatile da verdammt nochmal!
Eigentlich nicht.
Der C Standard sagt über volatile
1
An object that has volatile-qualified type may be modified in ways
2
unknown to the implementation or have other unknown side effects.
3
Therefore any expression referring to such an object shall be evaluated
4
strictly according to the rules of the abstract machine, as described in
5
5.1.2.3. Furthermore, at every sequence point the value last stored in
6
the object shall agree with that prescribed by the abstract machine,
7
except as modified by the unknown factors mentioned previously.114)
8
What constitutes an access to an object that has volatile-qualified
9
type is implementation-defined.
Davon, dass volatile dafür sorgt, dass eine überhaupt nicht benutzte
Variable erhalten bleibt, davon steht da nichts.
Hexfile schrieb:> Siehe:> http://code.google.com/p/tv-b-gone/source/browse/trunk/codes/codes.h
Habe mir den Code gerade angeschaut. Sämtliche Arrays/Strukturen in
codes.h werden in powerCodes[NUM_CODES] referenziert. In makebin.c sieht
man, dass genau auf dieses Array vom Programm zugegriffen wird. Daher
sehe ich überhaupt nicht, was da wegoptimiert werden sollte.
> Auch volatile hat nichts gebracht, was auch zu erwarten war. Selbst wenn> die Variable veränderlich ist, was nie gelesen wird wird entfernt.
volatile ist hier NICHT das Mittel der Wahl, sondern Referenzierung. Und
die ist gegeben. Auf powerCodes wird innerhalb main() in makebin.c
zugegriffen. Da kann nichts wegoptimiert werden. Die Daten werden daher
auch im Flash stehen.
Du bist da irgendwo auf dem Holzweg. Wie kommst Du auf 744 Bytes?
Wahrscheinlich lässt Du Dich von der Ausgabe von avr-size in die Irre
führen.
Gruß,
Frank
> Das Problem dabei ist jetzt aber, dass dieses Array nie direkt mit> Namen angesprochen wird, sondern nur indirekt über ein durch den> Flash laufenden Zeiger.
Und genau das ist das, was mir Angst macht.
In irgendeiner Form MUSS jedes Array irgendwo referenziert sein, selbst
wenn danach über Zeiger darauf zugegriffen wird.
Ansonsten kann man auch gleich einen Zeiger irgendwo im Flash aufsetzen
und dann auf gut Glück einfach irgendwas aus dem Flash lesen.
Also, noch mal den Code studieren, wie der Erfinder sich das ganze
gedacht haben könnte.
Du setzt die Variable ja auch auf null. Also greifst du auf sie zu, das
ist keine Kunst. Im Projekt sieht es so aus:
(gekürzt)
1
// for every POWER code in our collection
2
for(i=0;i<j;i++)
3
{
4
// point to next POWER code, from the right database
5
if(region==US){
6
code_ptr=(PGM_P)pgm_read_word(NApowerCodes+i);
7
}else{
8
code_ptr=(PGM_P)pgm_read_word(EUpowerCodes+i);
9
}
NApowerCodes und EUpowerCodes zeigen dabei auf jeweils ein Array was wie
folgt definiert ist:
(gekürzt)
1
conststructIrCode*NApowerCodes[]PROGMEM={
2
#ifdef NA_CODES
3
&code_na000Code,
4
&code_na001Code,
5
&code_na002Code,
6
&code_na003Code,
7
&code_na004Code,
8
&code_na005Code,
9
&code_na006Code,
10
&code_na007Code,
11
&code_na008Code,
12
&code_na009Code,
13
&code_na010Code,
14
&code_na011Code,
Es sind die Startaddressen von allen Arrays eingetragen. Trotzdem
scheint das nicht auszureichen den Kompiler dazu zu bewegen alle in das
Hexfile zu schreiben. Das ganze Projekt soll ca 8Kb groß sein. Das
Hexfile ist grade mal 3Kb groß. Da stimmt einfach was nicht. Die
Tabellen sind nicht drin...
Hexfile schrieb:> Du setzt die Variable ja auch auf null. Also greifst du auf sie zu, das>> ist keine Kunst. Im Projekt sieht es so aus:
Äh, ja und? Deine Variable wird ja auch initialisiert. Ich seh da
nämlich ein fettes Gleichheitszeichen nach dem PROGMEM.
Hexfile schrieb:> Mal die Ausgabe des Kompilers>> [code]> ...> avr-gcc -mmcu=attiny85 -Wall -gdwarf-2 -std=gnu99> -DF_CPU=10000000UL -Os -funsigned-char -funsigned-bitfields> -fpack-struct -fshort-enums -MD -MP -MT main.o -MF dep/main.o.d -c> ../main.c> ../main.c: In function 'main':> ../main.c:270: warning: passing argument 1 of 'putnum_uh' makes integer> from pointer without a cast
Zeig mal Deinen Code. Unter Deinem angegebenen Link
http://code.google.com/p/tv-b-gone/source/browse/trunk/codes/
kann ich kein main.c entdecken. Auch kein ../WORLDcodes.c. Greifst Du
überhaupt irgendwo auf powerCodes[] zu? Da sind alle Referenzen auf die
in codes.h definierten Arrays/Strukturen drin.
Frank M. schrieb:> Hexfile schrieb:>> Mal die Ausgabe des Kompilers>>>> [code]>> ...>> avr-gcc -mmcu=attiny85 -Wall -gdwarf-2 -std=gnu99>> -DF_CPU=10000000UL -Os -funsigned-char -funsigned-bitfields>> -fpack-struct -fshort-enums -MD -MP -MT main.o -MF dep/main.o.d -c>> ../main.c>> ../main.c: In function 'main':>> ../main.c:270: warning: passing argument 1 of 'putnum_uh' makes integer>> from pointer without a cast>> Zeig mal Deinen Code. Unter Deinem angegebenen Link>> http://code.google.com/p/tv-b-gone/source/browse/trunk/codes/
so wie ich das sehe, handelt es sich bei dem dortigen Programm um ein
Hilfsprogramm, welches die Codetabellen für eine Assembler-Lösung
erzeugt.
Ich schätze mal, er hat die #define übersehen, die im dortigen makebin.c
für dem #include "codes.h" eine gewisse Steuerungsmöglichkeit bieten,
welche Codes inkludiert werden sollen.
Im Original ....
1
#ifndef NA_CODES //select default code-set
2
#ifndef EU_CODES
3
//#define NA_CODES
4
#define EU_CODES
5
#endif
6
#endif
7
8
...
9
10
#include"codes.h" //the original code file (remove #includes inside this file)
666 schrieb:> Hexfile schrieb:>> Du setzt die Variable ja auch auf null. Also greifst du auf sie zu, das>>>> ist keine Kunst. Im Projekt sieht es so aus:>> Äh, ja und? Deine Variable wird ja auch initialisiert. Ich seh da> nämlich ein fettes Gleichheitszeichen nach dem PROGMEM.
Deine Variable ist lokal, seine global.
D.h. da hat auch noch der Linker ein Wörtchen mitzureden.
Und der schmeisst Unreferenziertes üblicherweise raus, was im Normalfall
auch gut ist. Denn du willst nicht alle Funktionen und Variablen der
Runtime-Library immer mitgelinkt haben, nur weil sie im Linkerinput
auftauchen aber nirgends benutzt werden.
Hexfile schrieb:> Da alle hintereinander stehen
Wer garantiert das denn?
Das ist ein mächtiges va-banque-Spiel.
Wenn man das sauber machen will, packt man jeden Eintrag in eine
eigene section und erklärt den Eintrag als "benutzt":
1
...__attribute__((section("flashdata"),used))
Dazu dann ein Linkerscript, das alle "flashdata"-Abschnitte
zusammenfügt und davor und danach noch ein globales Symbol anlegt.
Auf diese beiden globalen Symbole bezieht sich dann die Schleife,
die da durch alle Einträge durchgeht.
(So ähnlich erfolgt die Laufzeitinitialisierung von Variablen im
data-Segment, die ja mit Werten aus dem Flash vorbelegt werden
müssen.)
Klingt umständlich, aber alles andere ist einfach Pfusch.
Hallo,
ich hatte gefragt
Stefan++ schrieb:> woran erkennst du dass der Compiler die "Variable weg optimiert hat" ???
und hätte als Antwort erwartet: "wenn ich die ... Optimierung einschalte
ist das Array da und wenn ich die ... ein/ausschalte, dann nicht !!!
Aufgrund der Länge des erzeugten HEX-Files zu sagen "hat der Compiler
wegoptimiert" ist ganz einfach suboptimal
weil es da viele andere Sachen gibt die da Einfluss haben wie z.B. die
genannten "#defines ..." mit "#ifdef" die den Compiler "steuern"
Ansonsten ist im gcc folgende Option zuständig
> -fkeep-static-consts> Emit variables declared static const when optimization isn't turned on,> even if the variables aren't referenced.>> GCC enables this option by default. If you want to force the compiler> to check if a variable is referenced, regardless of whether or not> optimization is turned on, use the -fno-keep-static-consts option.
Stefan++ schrieb:>> -fkeep-static-consts>> Emit variables declared static const when optimization isn't turned on,>> even if the variables aren't referenced.
So ein (schlechter) Hack ist hier überhaupt nicht notwendig.
Der TO geht irrigerweise davon aus, dass die unzähligen globalen Arrays
im FLASH einfach über einen (wie auch immer gearteten) Zeiger
angesprochen werden, der "irgendwie" über den Flash-Speicher "wandert" -
siehe Ausgangsposting.
Das was er im Ausgangsposting erzählt, ist schlichtweg Unsinn. Er hat
einfach übersehen, dass sämtliche Arrays/Strukturen (z.B. sein zitiertes
code_na003Times) in powerCodes referenziert sind. Wenn er aber
powerCodes nicht nutzt, wirft der Compiler alles raus.
Frank M. schrieb:> Das was er im Ausgangsposting erzählt, ist schlichtweg Unsinn. Er hat> einfach übersehen, dass sämtliche Arrays/Strukturen (z.B. sein zitiertes> code_na003Times) in powerCodes referenziert sind. Wenn er aber> powerCodes nicht nutzt, wirft der Compiler alles raus.
Entweder das oder er hat schlicht die #ifdef übersehen oder ihnen keine
Beachtung geschenkt. Ich tendiere zu letzterer Erklärung.
Kurz und gut: Der Compiler hat genau das gemacht, was zu erwarten ist.
Der Fehler sitzt vor dem Monitor und nicht im Compiler. Macht man es im
Source Code richtig, gibt es auch das Problem nicht.
Stimmt, ihr habt recht, der Fehler war (wie so oft) vor dem Monitor.
Tatsächlich haben die beiden defines gefehlt. Beim durchgucken des
Headers ist mir ein ähnliches define aufgefallen, daher dachte ich, das
macht das schon... fixed... Danke an euch alle, der Fehler hat mich
lange Zeit gekostet weil ich an alles gedacht hab nur nicht an diese
einfache Lösung...
MfG Hexfile
In einer vernünftigen IDE, zB Eclipse, werden solche blöcke ausgegraut
wenn das dazugehörige define fehlt.
Und jetzt schnell weg bevor die vim fraktion auftaucht :)