https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81073

--- Comment #8 from Georg-Johann Lay <gjl at gcc dot gnu.org> ---
(In reply to Jason Merrill from comment #7)
> > To make things even worse, all the PROGMEM + inline asm +
> > statement-expression stuff is hidden behind common usability macros that are
> > used by actually every avr-g++ user like Arduino.
> 
> Hmm.  Which macros?

It's macros from AVR-LibC, the only C-library used for AVR.

http://nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

The statement expression is introduced by PSTR. For example:


#include <avr/pgmspace.h>

struct menu { int id; const char *text; };

// m and m->text will reside in flash.
extern const menu* get_menu()
{
    static const menu m PROGMEM = { 1, PSTR ("Hallo") };
    return &m;
}

extern void print_prog_string (const char *s);

// m and m->text must reside in flash, otherwise (e.g. .rodata) code
// will print garbage.
extern void print_something (const menu *m)
{
    const char *str = (const char*) pgm_read_word (&m->text);
    print_prog_string (str);
    print_prog_string (PSTR ("some text"));
}


PSTR is used to cook up a string in flash and yields its address.  Any read
from flash must be performed by inline asm, here by pgm_read_word macro.
print_prog_string() similarly must use pgm_read_byte to retrieve chars from
flash.  Just *s would read from RAM and get garbage.  The code expands to
(snipped for legibility):

typedef unsigned int uint8_t __attribute__((__mode__(__QI__)));
typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__)));

struct menu { int id; const char *text; };

extern const menu* get_menu()
{
    static const menu m __attribute__((__progmem__))
       = { 1, (__extension__({static const char __c[]
__attribute__((__progmem__)) = ("Hallo"); &__c[0];})) };
    return &m;
}

extern void print_prog_string (const char *s);
extern void print_something (const menu *m)
{
    const char *str = (const char*) (__extension__(
       {
           uint16_t __addr16 = (uint16_t)((uint16_t)(&m->text));
           uint16_t __result;
           __asm__ __volatile__ ("lpm %A0, Z+" "\n\t"
                                 "lpm %B0, Z" "\n\t"
                                 : "=r" (__result), "=z" (__addr16)
                                 : "1" (__addr16) );
           __result;
       }
    ));
    print_prog_string (str);
    print_prog_string ((__extension__({static const char __c[]
__attribute__((__progmem__)) = ("some text"); &__c[0];})));
}

Reply via email to