Forum: Mikrocontroller und Digitale Elektronik AVR-gcc: strukturen mit Funktions-pointern im progmem liefert falsche pointer


von Martin S. (msperl)


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

von Markus M. (adrock)


Lesenswert?

...auffällig ist, dass 0xa6 die Hälfte von 0x14c ist.

Das könte seine Richtigkeit haben, da der Programmcode in WORTEN 
adressiert wird. D.h. die "echte" Adresse ist der Ptr * 2.

Grüße
Markus

von Martin Beuttenmüller (Gast)


Lesenswert?

@Markus
Wow, genial erkannt ...
Ich hätte auch erst "den Wald gerodet, um den Baum zu finden"!  ;-}

Danke !
Martin

von Martin S. (msperl)


Lesenswert?

Danke - das half!

von Johann L. (gjlayde) Benutzerseite


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.

von Martin S. (msperl)


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

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.