Forum: Compiler & IDEs Inkonsistente Codegenerierung bei avr-gcc?


von Florian (Gast)


Lesenswert?

Hi,
mir ist bei der Suche nach einem anderem Fehler ggf. ein Problem mit dem 
Compiler aufgefallen:
Im folgendem der Ausschnitt aus dem C code und darauf folgend der 
assembler code:
1
uint8_t spi_exchangebyte( uint8_t data )
2
{
3
  SPDR = data;
4
  while( ! (  SPSR & ( 1 << SPIF ) ) );
5
  return SPDR;
6
}
1
00000026 <spi_exchangebyte>:
2
  26:   8e bd           out     0x2e, r24       ; 46
3
  28:   0d b4           in      r0, 0x2d        ; 45
4
  2a:   07 fe           sbrs    r0, 7
5
  2c:   00 c0           rjmp    .+0             ; 0x2e <spi_exchangebyte+0x8>
6
  2e:   8e b5           in      r24, 0x2e       ; 46
7
  30:   08 95           ret
Zum ersten würde ich wissen wollen was ".+0" bedeutet? Derzeit gehe ich 
davon aus, dass "." die aktuelle Adresse ist.

Zum zweiten scheint die while Schleife nicht zu funktionieren, da es 
egal ist ob ich "rjmp" überspringe oder nicht, weil der Sprung auch bei 
0x2e endet?(Unter Annahme meiner Vermutung zu ".")

GCC 4.8.2, OPT=s

Danke im Voraus!
Gruß
Florian

von Peter D. (peda)


Lesenswert?

Beim 4.3.3 sieht der Code o.k. aus (ATmega16):
1
uint8_t spi_exchangebyte( uint8_t data )
2
{
3
  SPDR = data;
4
  6c:  8f b9         out  0x0f, r24  ; 15
5
  while( ! (  SPSR & ( 1 << SPIF ) ) );
6
  6e:  77 9b         sbis  0x0e, 7  ; 14
7
  70:  fe cf         rjmp  .-4        ; 0x6e <spi_exchangebyte+0x2>
8
  return SPDR;
9
  72:  8f b1         in  r24, 0x0f  ; 15
10
}
11
  74:  08 95         ret

von Mike (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Beim 4.3.3 sieht der Code o.k. aus (ATmega16):
>
1
> uint8_t spi_exchangebyte( uint8_t data )
2
> {
3
>   SPDR = data;
4
>   6c:  8f b9         out  0x0f, r24  ; 15
5
>   while( ! (  SPSR & ( 1 << SPIF ) ) );
6
>   6e:  77 9b         sbis  0x0e, 7  ; 14
7
>   70:  fe cf         rjmp  .-4        ; 0x6e <spi_exchangebyte+0x2>
8
>   return SPDR;
9
>   72:  8f b1         in  r24, 0x0f  ; 15
10
> }
11
>   74:  08 95         ret
12
>

4.8.1 liefert den gleichen Code (Mega8).

von (prx) A. K. (prx)


Lesenswert?

Verlass dich nicht auf den Disassembler.

Assembler-Code (atmega88):

spi_exchangebyte:
  out 0x2e,r24
.L2:
  in _tmp_reg_,0x2d
  sbrs _tmp_reg_,7
  rjmp .L2
  in r24,0x2e
  ret
avr-gcc (GCC) 4.7.2

Disassembly:

00000000 <spi_exchangebyte>:
   0:  8e bd         out  0x2e, r24  ; 46
   2:  0d b4         in  r0, 0x2d  ; 45
   4:  07 fe         sbrs  r0, 7
   6:  00 c0         rjmp  .+0        ; 0x8 <spi_exchangebyte+0x8>
   8:  8e b5         in  r24, 0x2e  ; 46
   a:  08 95         ret
GNU objdump (GNU Binutils) 2.20.1.20100303

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


Lesenswert?

Das sieht aus wie der Dump eines Objects, also .o das noch nicht 
lokatiert ist, was zu verwirrenden Dumps führen kann.  Mit -r bei 
objdump wirds dann etwas klarer, denn es wird Info zu den RELOCs 
(Platzhalter für Symbole) ausgegeben.

Beispiel:
1
#include <avr/io.h>
2
3
uint8_t spi_exchangebyte (uint8_t data)
4
{
5
  SPDR = data;
6
  while (!(SPSR & (1 << SPIF)))
7
    ;
8
  return SPDR;
9
}
10
11
int main;

übersetzt mit

$ avr-gcc foo.c -mmcu=atmega8 -Os -save-temps -c
$ avr-gcc -mmcu=atmega8 foo.o -o foo.elf
$ avr-objdump -x -d -r foo.o > foo.lss
$ avr-objdump  -d -j .text -j .data -j .rodata foo.elf > foo.lst

== foo.s ==

Sieht gut aus, der RJMP geht zu einem lokalen Label (.L3) wie erwartet:
1
spi_exchangebyte:
2
  out 0xf,r24
3
.L3:
4
  sbis 0xe,7
5
  rjmp .L3
6
  in r24,0xf
7
  ret

== foo.lss ==

Das "RJMP .+0" ist verwirred, der Kommentar danach auch (auch wenn er 
konsistent mit dem .+0 ist).  Was wirklich geschieht zeigt der RELOC in 
der nächsten Zeile: Der Sprung geht zum SBIS, also entsprechend dem .L3 
wie oben auch.
1
Disassembly of section .text:
2
3
00000000 <spi_exchangebyte>:
4
   0:  8f b9         out  0x0f, r24  ; 15
5
   2:  77 9b         sbis  0x0e, 7  ; 14
6
   4:  00 c0         rjmp  .+0        ; 0x6 <spi_exchangebyte+0x6>
7
      4: R_AVR_13_PCREL  .text+0x2
8
   6:  8f b1         in  r24, 0x0f  ; 15
9
   8:  08 95         ret

== foo.lst ==

Das Zeug ist lokatiert (und gelinkt) und der Sprung wird wieder wie 
erwartet dargestellt:
1
00000048 <spi_exchangebyte>:
2
  48:  8f b9         out  0x0f, r24  ; 15
3
  4a:  77 9b         sbis  0x0e, 7  ; 14
4
  4c:  fe cf         rjmp  .-4        ; 0x4a <spi_exchangebyte+0x2>
5
  4e:  8f b1         in  r24, 0x0f  ; 15
6
  50:  08 95         ret

Also alles im grünen Bereich! Das ".-4" bedeutet: Spring zu PC -4 Bytes; 
hier gezählt ab dem Byte, das auf den Sprung folgt (also ab 4e 
rückwärts).  Eine Endlosschleife ist also "RJMP .-2" oder "JMP .-4".

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.