简体   繁体   中英

Getting the lower 16 bits of a pointer compile time in GCC

I'm working on an embedded project. I'm trying to use the GNU linker to layout some variables stored in a external eeprom. I do this by assigning the eeprom variable with

int __attribute__ ((section (".eeprom")))  eeprom_var1;

I've will also to define initialized variables for the eeprom, ie like this:

int __attribute__ ((section (".eeprom")))  eeprom_var2 = 0x42;

The idea is then; upon initialization of the eeprom the initialized variables copied from somewhere in the .text section to the eeprom by the running application, just like the initializing the data section. Obviously the eeprom variables cannot be read/written but must be accessed though functions like:

eeprom_read(data, &eeprom_var,sizeof(eeprom_var)).

So far so good,

Now I want to initialize an eeprom variable with the pointer of another variable:

unsigned long long __attribute__ ((section (".eeprom"))) eeprom_var1 = 0x42;
unsigned short __attribute__ ((section (".eeprom"))) eeprom_var2 = (unsigned short )&eeprom_var1;

Note that the eeprom uses a 16bit address space

But this gives the following error

foo.c:4:1: error: initializer element is not constant
  unsigned short __attribute__ ((section (".eeprom"))) eeprom_var2 = (unsigned short )&eeprom_var1;

^

This is because the cast to (unsigned short) is read as an operation as an initializer, which is not allowed in C. In C++ however the above expression is ok.

Can any one think of way to get around the error above?

/Anders

  • When placing variables in on-chip eeprom, they always need to be of type const type .
  • When placing pointers in on-chip eeprom, they always need to be of type type* const (constant pointer to non-constant data) or const type* const (constant pointer to constant data).

This seems to be the true source of your problem. And of course, once they are declared as const you shouldn't cast away the const-ness.

Also, if it is on-chip eeprom, is there a reason why you can't access the memory cells directly? On most systems you are able to do this, although access times may be slower than the equivalent access to a RAM variable.

As a side note, casting to uint16_t (or unsigned short) will only give you the 16 least significant bits on a little endian machine. The code isn't portable to big endian. Portable code would be ((uint32_t)pointer >> 16) .

In C++ however the above expression is ok.

The initialization is accepted by the C++ compiler, but carried out at runtime (see Spurious error: initializer element is not computable at load time ), which may be not what you want.

Can any one think of way to get around the error above?

Even after getting around that error, eg with

__asm__(".section   .eeprom,\"aw\"\n"
        ".globl eeprom_var2\n"
        "eeprom_var2:   .short  eeprom_var1");
extern unsigned short eeprom_var2;

the linker exits with an error:

…: relocation truncated to fit: R_386_16 against symbol `eeprom_var1' defined in .eeprom section in /tmp/…

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM