Forum: Compiler & IDEs Registernutzung in Asm-Funktionen


von Sam .. (sam1994)


Lesenswert?

Hallo,

Auf http://www.rn-wissen.de/index.php/Avr-gcc/Interna#Registerverwendung 
steht:
1
R0, R18 – R27, R30, R31
2
    können durch Funktionsaufrufe verändert werden, ohne restauriert zu werden

Ich habe noch keinen Code im Netz gesehen (in Assemblerfunktionen), der 
die diese Register nutzt ohne sie zu sichern. Muss man sie nun sichern 
oder nicht? r0 muss man auf keinem Fall sichern, oder?

Sollte man sie sichern müssen:
Wenn ein Byte an eine Funktion in r24 übergeben wird, darf man das 
zugehörige zerstören (r25)?

von Stefan E. (sternst)


Lesenswert?

Samuel K. schrieb:
> Muss man sie nun sichern oder nicht?

Nein, außer die Funktion ist eine ISR.

Samuel K. schrieb:
> r0 muss man auf keinem Fall sichern, oder?

Außer die Funktion ist eine ISR.

von Sam .. (sam1994)


Lesenswert?

Stefan Ernst schrieb:
> Samuel K. schrieb:
>> Muss man sie nun sichern oder nicht?
>
> Nein, außer die Funktion ist eine ISR.
>
> Samuel K. schrieb:
>> r0 muss man auf keinem Fall sichern, oder?
>
> Außer die Funktion ist eine ISR.

Ach du schon wieder ;)

Danke für die Antwort. Dass es in der ISR nicht erlaubt ist, ist klar. 
Da hat der Compiler schließlich kaum Einfluss.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Samuel K. schrieb:
1
> R0, R18 – R27, R30, R31
2
>     können durch Funktionsaufrufe verändert werden, ohne restauriert zu
3
> werden
> Ich habe noch keinen Code im Netz gesehen (in Assemblerfunktionen), der
> die diese Register nutzt ohne sie zu sichern.

Das Zitat bezieht sich auf die Registerverwendung im avr-gcc. Wenn ein 
Assembler-Code nicht mit avr-gcc zusammenarbeitet, dann braucht er sich 
um dessen ABI auch keine Gedanken zu machen.

Übrigens gibt's auch entsprechende Codebeispiele:
AVR Arithmetik: Wurzel
http://www.mikrocontroller.net/articles/AVR_Arithmetik/Sinus_und_Cosinus_(CORDIC)#cordic-asm.S

von Sam .. (sam1994)


Lesenswert?

Johann L. schrieb:
> Das Zitat bezieht sich auf die Registerverwendung im avr-gcc. Wenn ein
> Assembler-Code nicht mit avr-gcc zusammenarbeitet, dann braucht er sich
> um dessen ABI auch keine Gedanken zu machen.

Ja ich meinte Assemblerfunktionen in C-Programmen.

von Sam .. (sam1994)


Lesenswert?

Kann man avrgcc sagen, dass er nicht so viele Register für (bestimmte) 
Funktionen bereitstellen soll? Ich habe eine Funktion in meinem 
Programm, welche nur Funktionen aufruft (50% Asm-Funktionen). Am Anfang 
dieser Funktion sichert avrgcc erstmal ein Haufen Low-Register. Meine 
Funktion brauchen gar nicht so viele Register - das push/pop ist für die 
Katz.

von (prx) A. K. (prx)


Lesenswert?

Samuel K. schrieb:

> Am Anfang
> dieser Funktion sichert avrgcc erstmal ein Haufen Low-Register. Meine
> Funktion brauchen gar nicht so viele Register - das push/pop ist für die
> Katz.

Er sichert nur die Register, dir er in der Funktion selbst verwendet. 
Fürs Sichern der Register einer aufgerufenen Funktion ist diese selbst 
verantwortlich.

Ausnahme: Es handelt sich um einen Interrupt-Handler. Da er nicht weiss, 
welche der Scratch-Register in den aufgerufenen Funktionen verwendet 
werden, muss er alle davon sichern. Das sind aber überwiegend 
High-Register.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Beispiel:
1
extern void callee (int);
2
3
void caller (int n)
4
{
5
    callee (n);
6
    callee (n+1);
7
    callee (2);
8
}
Ob callee in asm implementiert ist oder in C ist dem Compiler egal. For 
einen ATmega8 und mit rößenoptimierung wird das übersetzt zu
1
caller:
2
  push r28
3
  push r29
4
  movw r28,r24
5
  rcall callee
6
  movw r24,r28
7
  adiw r24,1
8
  rcall callee
9
  ldi r24,lo8(2)
10
  clr r25
11
  pop r29
12
  pop r28
13
  rjmp callee
Da werden keine low-Register gesichert. Allerdings muss n gesichert 
werden (hier in Y), weil es den ersten Funktionsaufruf überleben muss.

von Sam .. (sam1994)


Lesenswert?

Avrgcc sichert hier 7 Register, obwohl er ohne Probleme r0, r18, r26, 
r27, r30, r31 benutzen dürfte, da diese in den Funktionen nicht benötigt 
werden.
Theoretisch müsste er dann nur 1 Register sichern.
1
 2b6:  bf 92         push  r11
2
 2b8:  cf 92         push  r12
3
 2ba:  df 92         push  r13
4
 2bc:  ef 92         push  r14
5
 2be:  ff 92         push  r15
6
 2c0:  0f 93         push  r16
7
 2c2:  1f 93         push  r17
8
 2c4:  d8 2e         mov  r13, r24
9
  uint32_t value = div16u(Game.player[player].time, 60);
10
 2c6:  e8 2f         mov  r30, r24
11
 2c8:  f0 e0         ldi  r31, 0x00  ; 0
12
 2ca:  ee 0f         add  r30, r30
13
 2cc:  ff 1f         adc  r31, r31
14
 2ce:  ee 0f         add  r30, r30
15
 2d0:  ff 1f         adc  r31, r31
16
 2d2:  eb 57         subi  r30, 0x7B  ; 123
17
 2d4:  ff 4f         sbci  r31, 0xFF  ; 255
18
 2d6:  87 81         ldd  r24, Z+7  ; 0x07
19
 2d8:  90 85         ldd  r25, Z+8  ; 0x08
20
 2da:  6c e3         ldi  r22, 0x3C  ; 60
21
 2dc:  70 e0         ldi  r23, 0x00  ; 0
22
 2de:  34 df         rcall  .-408      ; 0x148 <div16u>
23
 2e0:  7b 01         movw  r14, r22
24
 2e2:  8c 01         movw  r16, r24
25
  uint16_t v1 = bin2bcd8(value & 0xFF);
26
 2e4:  86 2f         mov  r24, r22
27
 2e6:  44 df         rcall  .-376      ; 0x170 <bin2bcd8>
28
 2e8:  b8 2e         mov  r11, r24
29
 2ea:  c9 2e         mov  r12, r25
30
  uint16_t v2 = bin2bcd8((value >> 16) & 0xFF);
31
 2ec:  78 01         movw  r14, r16
32
 2ee:  00 27         eor  r16, r16
33
 2f0:  11 27         eor  r17, r17
34
 2f2:  8e 2d         mov  r24, r14
35
 2f4:  3d df         rcall  .-390      ; 0x170 <bin2bcd8>
36
 2f6:  18 2f         mov  r17, r24

von (prx) A. K. (prx)


Lesenswert?

Samuel K. schrieb:

> da diese in den Funktionen nicht benötigt werden.

Das weiss der Compiler aber nicht. Der kennt nur die von dir zitierte 
Konvention, dergemäss eine aufgerufene Funktion bestimmte Register nicht 
sichern muss. Folglich muss er davon ausgehen, dass alle diese Register 
durch einen Aufruf verändert werden. Und muss für Daten, die einen 
Aufruf überleben sollen, andere Register verwenden. Das sind dann 
notwendigerweise solche, die er selbst sichern muss.

von (prx) A. K. (prx)


Lesenswert?

Es gibt eine Option, mit der für die PUSH/POP-Orgien Laufzeitfunktionen 
verwendet werden. Kostet Zeit, bringt aber bei grösseren Programmen 
einen Platzgewinn.

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.