Forum: Compiler & IDEs Ignoriert gcc 4.x Registerzuweisungen von Variablen?


von Malte _. (malte) Benutzerseite


Lesenswert?

Hallo,
ich hänge schon lange an einem Problem, welches ich hier:
Beitrag "Fehler beim compilieren mit gcc 4.2.1 den ich nicht verstehe"
beschrieben hatte.
Nun habe ich mir mal die Mühe gemacht den erzeugten Assembler Code 
durchzusehen:

Meine Funktion beginnt so:
1
void sched(void) __attribute__ ((naked));
2
void sched(void) {
3
register unsigned char sreg asm("r0");
4
register unsigned char sreg2 asm("r3");
5
sreg = SREG;
6
asm volatile ("push r0");
7
asm volatile ("push r2");

Daraus wird bei dem gcc 3.4:
1
/* prologue: frame size=0 */
2
/* prologue: naked */
3
/* prologue end (size=0) */
4
  .stabn 68,0,107,.LM17-sched
5
.LM17:
6
  in r0,95-0x20
7
  .stabn 68,0,108,.LM18-sched
8
.LM18:
9
/* #APP */
10
  push r0
11
  .stabn 68,0,109,.LM19-sched
12
.LM19:

bei dem gcc 4.1 jedoch:
1
/* prologue: frame size=0 */
2
/* prologue: naked */
3
/* prologue end (size=0) */
4
  .stabn  68,0,107,.LM15-sched
5
.LM15:
6
  in r17,95-0x20
7
  .stabn  68,0,108,.LM16-sched
8
.LM16:
9
/* #APP */
10
  push r0
11
  .stabn  68,0,109,.LM17-sched
12
.LM17:

Somit ließe sich erklären warum sich mein Programm doch recht 
"merkwürdig" verhält. r17 Muss laut avr libc doku bei einem 
Funktionsaufruf gesichert werden, r0 jedoch nicht.

Bug beim GCC? oder ein Feature, oder habe ich die falsche Syntax 
verwendet?

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


Lesenswert?

An feste Register gebundene Variablen werden nur auf globaler Ebene
unterstützt.  Für lokale Variablen kannst du dem Registerallokator
nicht vorschreiben, wohin er sie legen soll.

naked functions are evil.
naked functions are evil.
naked functions are...

Schreib die komplette Funktion in eine Assemblerdatei.  Das
naked-Attribut hat wirklich nur Sinn für Dinge wie die
nicht-wirklich-Funktionen für die .initN sections.

von Peter D. (peda)


Lesenswert?

R0 und R1 sind außerdem reserviert (LPM, MUL) und R0 ist auch noch das 
Zero-Register.

Für globale Registervariablen sind nur R2..R17 frei.


Peter

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


Lesenswert?

r0 ist _tmp_reg_, r1 ist _zero_reg_.

Die Register ab r8 sind auch nur dann für fest gebundene Variablen
benutzbar, wenn man keine Funktionen mit vielen/großen Parametern
in der Applikation hat, ansonsten werden sie für die Parameterübergabe
mit genutzt.  In den Mini-Applikationen, in denen man typischerweise
versuchen wird, viele Variablen an Register zu binden, dürfte das
aber wohl eher eine untergeordnete Rolle spielen.

von Malte _. (malte) Benutzerseite


Lesenswert?

Jörg Wunsch wrote:
> An feste Register gebundene Variablen werden nur auf globaler Ebene
> unterstützt.  Für lokale Variablen kannst du dem Registerallokator
> nicht vorschreiben, wohin er sie legen soll.
Danke, das wusste ich nicht.

> naked functions are evil.
Ich sichere direkt alle Register, die die avr-libc als "Call-saved 
registers" nennt. Solange die Funktion nicht auch noch extra Speicher 
auf dem Stack benötigt sehe ich deswegen kein Problem. Ich könnte auch 
auf das Naked verzichten, aber dann wüsste ich nicht welche Register der 
Compiler für mich sichert und welche mir noch fehlen. Wenn ich dann 
allerdings weiterhin alle sicher würde, würde die Funktion unnötig 
Flash, Rechnenzeit und SRAM benötigen.

> Schreib die komplette Funktion in eine Assemblerdatei.
Dazu fehlen mir noch die nötigen Kentnisse, lassen sich aus 
Assemblerdateinen überhaupt in Header Dateien per #define definerten 
Werte und gewönliche Arrays (bzw dessen Startadresse) zugreifen? 
Außerdem wollte ich soweit wie möglich alles in C lösen.

Als simplen Workaround habe ich die Variablen Definitionen einfach 
global definiert und damit läuft mein Programm jetzt auch mit dem gcc 
4.1 :-)

Wahrscheinlich werde ich noch die globalen Variablen weglassen und das 
Einlesen statt durch
sreg = SREG;
mit
asm volatile ("in r0, %0" : : "I" (_SFR_IO_ADDR(SREG)): "r0");
erledigen.

von Rolf Magnus (Gast)


Lesenswert?

>> naked functions are evil.
> Ich sichere direkt alle Register, die die avr-libc als "Call-saved
> registers" nennt. Solange die Funktion nicht auch noch extra Speicher
>auf dem Stack benötigt sehe ich deswegen kein Problem. Ich könnte auch
> auf das Naked verzichten, aber dann wüsste ich nicht welche Register
> der Compiler für mich sichert und welche mir noch fehlen.

Warum mußt du denn überhaupt irgendwelche Register manuell sichern?

> Dazu fehlen mir noch die nötigen Kentnisse, lassen sich aus
> Assemblerdateinen überhaupt in Header Dateien per #define definerten
> Werte und gewönliche Arrays (bzw dessen Startadresse) zugreifen?

Kommt auf den Header an, aber im Prinzip ja. gcc benutzt für Assembler 
denselben Präprozessor wie für C, also kann er auch #defines auflösen, 
sofern sie nicht durch was C-spezifisches ersetzt werden. Dort, wo es 
für C und Assembler unterschiedlich ist, könnte man im Header auch eine 
Fallunterscheidung einbauen. Und externe Symbole können im Assembler 
natürlich auch genutzt werden. Schließlich macht auch der Compiler aus 
dem C-Code erstmal Assembler-Code.

> Außerdem wollte ich soweit wie möglich alles in C lösen.

Dann drängt sich umso mehr die Frage auf, warum du dann überhaupt 
irgendwelche Register sichern willst.

> Wahrscheinlich werde ich noch die globalen Variablen weglassen und das
> Einlesen statt durch
> sreg = SREG;
> mit
> asm volatile ("in r0, %0" : : "I" (_SFR_IO_ADDR(SREG)): "r0");
> erledigen.

Warum muß es unbedingt r0 sein? Gerade von r0 sollte man die Finger 
lassen, denn es ist ja wie schon erwähnt im Compiler bereits mehrfach 
belegt. Ich würde dem Compiler die Registerverwaltung überlassen, etwa 
so:

uint8_t sreg;
asm volatile ("in %0, %1" : "=r" (sreg): "I" (_SFR_IO_ADDR(SREG)));

von Malte _. (malte) Benutzerseite


Lesenswert?

Rolf Magnus wrote:
> Warum mußt du denn überhaupt irgendwelche Register manuell sichern?
Bei dem Programm Teil handelt es sich um einen kooperativen Scheduler. 
Es werden also alle Register bei der sich die libc auf ein Beibehalten 
des Inhalts bei einem Funktionsaufruf verlässt gesichert, der SP auf den 
Stack eines anderen Task gesetzt und für diesen alle Register wieder 
hergestellt. Das Ganze funktioniert auch inzwischen wunderbar.

> Kommt auf den Header an, aber im Prinzip ja. gcc benutzt für Assembler
> denselben Präprozessor wie für C, also kann er auch #defines auflösen,
> sofern sie nicht durch was C-spezifisches ersetzt werden. Dort, wo es
> für C und Assembler unterschiedlich ist, könnte man im Header auch eine
> Fallunterscheidung einbauen. Und externe Symbole können im Assembler
> natürlich auch genutzt werden. Schließlich macht auch der Compiler aus
> dem C-Code erstmal Assembler-Code.
Gut zu wissen.

> Warum muß es unbedingt r0 sein? Gerade von r0 sollte man die Finger
> lassen, denn es ist ja wie schon erwähnt im Compiler bereits mehrfach
> belegt.
Es muss nicht r0 sein, sondern einfach eins welches
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage
nicht als "Call-saved registers" aufführt. r0 habe ich genommen weil 
dort steht "may be used to remember something for a while within one 
piece of assembler code" und ich denke einen Wert einlesen und im 
nächsten Schritt sichern fällt darunter. Danach brauche ich den Inhalt 
nicht mehr.

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


Lesenswert?

Malte __ wrote:

>> Warum mußt du denn überhaupt irgendwelche Register manuell sichern?

> Bei dem Programm Teil handelt es sich um einen kooperativen Scheduler.

Das ist aber nun wirklich ein typischer Kandidad dafür, dass man das
Stück komplett in eine Assemblerdatei schreibt.

von Rolf Magnus (Gast)


Lesenswert?

Oder eine naked-Funktion in C, die dann aber den ganzen Code als 
Inline-Assembler enthält, was aber letztendlich dann auch keinen Vorteil 
mehr gegenüber einer reinen Assembler-Datei hat. Aber den Compiler 
seinen Teil erledigen lassen und dann irgendwie in Inline-Assembler den 
Rest dranflanschen ist eher keine gute Idee.

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.