Inkonsistente Codegenerierung bei avr-gcc?

Gast #3594746
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
Gast #3594768
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).
#3594769
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
Persönliche Seite #3594774
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".

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren