AVR-gcc: strukturen mit Funktions-pointern im progmem liefert falsche pointer

OP #2944799
Lesenswert?

Hallo!

Habe da einen seltsamen "Effekt" bei meinem neuen Projekt:

Der folgende Code-schnipsel:
1
void loop4ever(uint16_t *t);
2
typedef struct test {
3
        void (*init)(uint16_t* t);
4
} test_t;
5
const test_t mytest __attribute__((progmem)) __attribute__((aligned (8))) = {
6
        .init=&loop4ever,
7
};
8
void loop4ever(uint16_t *t) { while(1) { t++;} }

produziert im gedumpten elf (avr-objdump -Dz main.elf):
1
...
2
00000088 <mytest>:
3
  88:   a6 00           .word   0x00a6  ; ????
4
  8a:   00 00           nop
5
  8c:   00 00           nop
6
  8e:   00 00           nop
7
...
8
0000014c <loop4ever>:
9
 14c:   ff cf           rjmp    .-2             ; 0x14c <loop4ever>

man sieht, daß der Pointer in mytest eindeutig an eine falsche Adresse 
zeigt (0x00a6 und nicht an 0x014c) - und ja, ich sehe es auch wenn ich 
mir die Adresse von meinem Code auf USART ausgeben lasse...

Sitze ich da einem compiler/linker bug auf?
Denn IMO sollte der code eigentlich ja korrekte Pointer produzieren...

Hat jemand schon ein ähnliches Problem gehabt und auch vielleicht auch 
gelöst?

Danke,
        Martin

P.s: und das nicht funktionierende Alignment in C mit progmem sei hier 
nur eine Randnotiz

P.s: der avr-gcc ist 4.7.0
Persönliche Seite #2944975
Lesenswert?

Martin Sperl schrieb:
> Hallo!
>
> Der folgende Code-schnipsel:
>
> void loop4ever(uint16_t *t);
> typedef struct test {
>         void (*init)(uint16_t* t);
> } test_t;
> const test_t mytest __attribute__((progmem)) __attribute__((aligned
> (8))) = {
>         .init=&loop4ever,
> };
> void loop4ever(uint16_t *t) { while(1) { t++;} }

Tu dir einen Gefallen und formatiere den Code :-)

> P.s: und das nicht funktionierende Alignment in C mit progmem sei hier
> nur eine Randnotiz

Wieso? mytest ist doch auf 8 Bytes aligned?

> P.s: der avr-gcc ist 4.7.0

Nicht wirklich empfohlen, insbesondere wenn du Xmega oder Devices mit 
8-Bit SP verwendest.  Immer die Release Notes lesen!!!

http://gcc.gnu.org/gcc-4.7/changes.html

Seit mehreren Monaten gibt es avr-gcc 4.7.2.

Mit 4.7 brauchst du auch kein progmem mehr.  Wenn mytest im Flash liegt 
willst du wahrscheinlich auch irgendwann drauf zugreifen?
1
#include <stdint.h>
2

3
typedef struct 
4
{
5
    void (*init)(uint16_t*);
6
} test_t;
7

8
static void loop4ever (uint16_t *t)
9
{
10
    (void) t;
11
    while(1);
12
}
13

14
const __flash test_t mytest __attribute__((aligned(8))) =
15
{
16
    .init = loop4ever
17
};
18

19
void runtest (const __flash test_t *t, uint16_t *val)
20
{
21
    t->init (val);
22
    mytest.init (0);
23
}
 
Das ergibt:
 
1
loop4ever:
2
.L2:
3
  rjmp .L2
4

5
runtest:
6
  movw r30,r24
7
  lpm r0,Z+
8
  lpm r31,Z
9
  mov r30,r0
10
  movw r24,r22
11
  icall
12
.L4:
13
  rjmp .L4
14

15
.global  mytest
16
  .section  .progmem.data,"a",@progbits
17
  .p2align  3
18
  .type  mytest, @object
19
  .size  mytest, 2
20
mytest:
21
  .word  gs(loop4ever)
22
  .ident  "GCC: (GNU) 4.7.2"
 
Wie man sieht ist da auch das gewünschte .p2align 3.
OP #2945041
Lesenswert?

Auf das mit dem align bin ich auch gekommen, daß es geht - bin über den 
Unterschied im align parameter zwischen gas und gcc gestolpert...

Das update mit dem Compiler ist nett - ich mache mich einmal auf die 
Suche nach neuen deb gcc-avr Paketen für den RPI... (updates dafür gibt 
es leider nicht im "Standard"...)

Danke nochmals allen Helfern!
Martin

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