Forum: Compiler & IDEs AVR-GCC: PUSH-/Pop-Orgie verhinern


von Karl (Gast)


Lesenswert?

In der main() sichert der AVR-GCC (ATTiny13-Quelltext) einen Haufen 
Register (s. u.)und restauriert sie am Ende wieder.

Wie kann man das verhindern?
1
int main(void)
2
{
3
 124:  2f 92         push  r2
4
 126:  3f 92         push  r3
5
 128:  4f 92         push  r4
6
 12a:  5f 92         push  r5
7
 12c:  6f 92         push  r6
8
 12e:  7f 92         push  r7
9
 130:  8f 92         push  r8
10
 132:  9f 92         push  r9
11
 134:  af 92         push  r10
12
 136:  bf 92         push  r11
13
 138:  cf 92         push  r12
14
 13a:  df 92         push  r13
15
 13c:  ef 92         push  r14
16
 13e:  ff 92         push  r15
17
 140:  0f 93         push  r16
18
 142:  1f 93         push  r17
19
 144:  cf 93         push  r28
20
 146:  df 93         push  r29
21
22
...
23
24
 2d4:  df 91         pop  r29
25
 2d6:  cf 91         pop  r28
26
 2d8:  1f 91         pop  r17
27
 2da:  0f 91         pop  r16
28
 2dc:  ff 90         pop  r15
29
 2de:  ef 90         pop  r14
30
 2e0:  df 90         pop  r13
31
 2e2:  cf 90         pop  r12
32
 2e4:  bf 90         pop  r11
33
 2e6:  af 90         pop  r10
34
 2e8:  9f 90         pop  r9
35
 2ea:  8f 90         pop  r8
36
 2ec:  7f 90         pop  r7
37
 2ee:  6f 90         pop  r6
38
 2f0:  5f 90         pop  r5
39
 2f2:  4f 90         pop  r4
40
 2f4:  3f 90         pop  r3
41
 2f6:  2f 90         pop  r2
42
 2f8:  08 95         ret

von Karl (Gast)


Lesenswert?

Das war einfach:

[/C]

...

__attribute__((naked)) int main(void)

...

[C]

von Stefan E. (sternst)


Lesenswert?

Karl schrieb:
> Das war einfach:

Aber falsch. Das "naked" eliminiert auch Sachen, auf die du nicht 
verzichten möchtest, wie z.B. einen Stack-Frame bei lokalen Daten. Nimm 
lieber OS_main:
1
__attribute__ ((OS_main)) int main(void)

von Karl (Gast)


Lesenswert?

Stefan E. schrieb:
> Karl schrieb:
>> Das war einfach:
>
> Aber falsch. Das "naked" eliminiert auch Sachen, auf die du nicht
> verzichten möchtest, wie z.B. einen Stack-Frame bei lokalen Daten. Nimm
> lieber OS_main:
>
>
1
__attribute__ ((OS_main)) int main(void)

Der Code wird dadurch 6 Bytes länger.

Beide Attribute funktionieren mit meinem Programm.

Was hat es mit dem Stack-Frame auf sich?

Wo kann man näheres nachlesen?

von Karl (Gast)


Lesenswert?


von Kevin (Gast)


Lesenswert?

Welche avr-gcc-Version setzt du denn ein?? Das sollte schon lange kein 
Thema mehr sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kevin schrieb:
> Welche avr-gcc-Version setzt du denn ein?? Das sollte schon lange kein
> Thema mehr sein.

avr-gcc übersetzt main als Funktion mit normalem ABI, also so, dass sie 
returnt bzw. returnen kann.  Um dieses verhalten zu ändern braucht man 
dann Function Attribute wie OS_main.

Beispielsweise sichert avr-gcc-8 -Os für
1
long long vv;
2
3
int main()
4
{
5
    return vv + (vv >> 60);
6
}
Y und R8...R16 und legt brav einen Frame an.  Mit OS_main wird immer 
noch ein Frame angelegt aber keine Regs gesichert.

..und mit "naked" erhält man ein nicht-funktionierendes Programm.

von Carl D. (jcw2)


Lesenswert?

Karl schrieb:
> Stefan E. schrieb:
>> Karl schrieb:
>>> Das war einfach:
>>
>> Aber falsch. Das "naked" eliminiert auch Sachen, auf die du nicht
>> verzichten möchtest, wie z.B. einen Stack-Frame bei lokalen Daten. Nimm
>> lieber OS_main:
>>
>>
1
__attribute__ ((OS_main)) int main(void)
>
> Der Code wird dadurch 6 Bytes länger.
>

Geht es darum, mit den knappen FLASH auszukommen?
Mit
-mcall-prologues
erzeugt der avr-gcc Aufrufe zur nur noch einer zentralen Push/Pop-Orgie, 
was wenn mehrere Funktionen mit kräftigem Registerbedarf existieren, 
deutlich FLASH einspart. Der dabei genutzte Code wird je nachdem wie 
viele Register gesichert werden müssen mit unterschiedlichen 
Einsprungadressen aufgerufen und sichert/restored jeweils nur die 
gewünschten Register.
Diese Option hat schon mal einem Nachbauer des Transistortesters 
geholfen von seiner 110% FLASH-Belegung weg zu kommen.

: Bearbeitet durch User
von MWS (Gast)


Lesenswert?

Johann L. schrieb:
> ..und mit "naked" erhält man ein nicht-funktionierendes Programm

Das ist eine falsche Aussage wenn die mainloop leer ist, denn dann wird 
nichts unterbrochen, was gesichert werden müsste. So ein Programm 
funktioniert durchaus.

von Karl (Gast)


Lesenswert?

Was genau bewirkt der fehlende Stack-Frame bei _attribute_ 
((_naked_))?

Mein Programm läuft mit "__naked__" und "__OS_main__". Wobei 
"__OS_main__" 8 Bytes vom kostbaren RAM abzeigt.

von Falk B. (falk)


Lesenswert?

@Karl (Gast)

>Was genau bewirkt der fehlende Stack-Frame bei _attribute_
>((naked))?

Daß rein gar nichts an Speicherplatz für lokale Varialen in main() 
angelegt wird, sprich, man kann keine lokalen Variabeln in main() 
nutzen. Das ist aber unbedeutend, denn die kann man einfach global 
machen.

von Oliver S. (oliverso)


Lesenswert?

Kevin schrieb:
> Welche avr-gcc-Version setzt du denn ein?? Das sollte schon lange
> kein
> Thema mehr sein.

Wann war das denn überhaupt mal ein Thema?

Üblicherweise macht das weder der steinzeitliche avr-gcc aus WinAVR, 
noch irgend eine aktuelle Version, auch nicht ohne jede Optimierung. 
Zumindest nicht die Versionen, die mir unter Windows bisher begegnet 
sind. Und ich schaue mir sehr regelmäßig die generierten 
Assemblerlistings an.

Oliver

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

MWS schrieb:
> Johann L. schrieb:
>> ..und mit "naked" erhält man ein nicht-funktionierendes Programm
>
> Das ist eine falsche Aussage wenn die mainloop leer ist,

Lies mein Beispiel nochmals. Da ist main nicht leer.

> denn dann wird nichts unterbrochen,

Es geht nicht um "unterbrechen", meine Aussage ist unabhängig von 
Nebenläufigkeit.

von Stefan E. (sternst)


Lesenswert?

Oliver S. schrieb:
> Zumindest nicht die Versionen, die mir unter Windows bisher begegnet
> sind. Und ich schaue mir sehr regelmäßig die generierten
> Assemblerlistings an.

Dann ist deine main() einfach nur nicht "kompliziert" genug. Natürlich 
werden diese Register nur gesichert, wenn sie in der Funktion auch 
benutzt werden. Und auf die call-saved Register greift der Compiler erst 
zurück, wenn ihm die call-clobbered ausgehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan E. schrieb:
> Oliver S. schrieb:
>> Zumindest nicht die Versionen, die mir unter Windows bisher begegnet
>> sind. Und ich schaue mir sehr regelmäßig die generierten
>> Assemblerlistings an.
>
> Dann ist deine main() einfach nur nicht "kompliziert" genug. Natürlich
> werden diese Register nur gesichert, wenn sie in der Funktion auch
> benutzt werden.

Genau.  Und der komplizierte Code sieht im Original so aus:


Karl schrieb:
>
> ...
>

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kevin schrieb:
> Welche avr-gcc-Version setzt du denn ein?? Das sollte schon lange kein
> Thema mehr sein.

Eine entsprechende Optimierung ist ab avr-gcc v8 verfügbar (PR83738).

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.