[En-Nut-Discussion] cortex_init.c breaks strict-aliasing rules

Harald Kipp harald.kipp at egnite.de
Fri Sep 13 13:10:33 CEST 2013


Hi Philipp,

This unanswered post is quite old. I stumbled over it while fighting
with a similar problem and will try to answer it for later reference.

On 10.11.2012 23:58, Philipp Burch wrote:
> How could this be solved? _etext and friends are declared this way:
> 
> ------- 8< --------- 8< ----------
> extern void * _etext;           /* Start of constants in FLASH */
> extern void * _sidata;          /* Start of variables in FLASH */
> extern void * _sdata;           /* Start of variables in RAM */
> extern void * _edata;           /* End of variables in RAM */
> extern void * _sbss;            /* Start of unset variables in RAM */
> extern void * _ebss;            /* End of unset variables in RAM */
> ------- 8< --------- 8< ----------
> 
> So these are of type void*, while MemInit() uses uint32_t*. What's the
> point of declaring them as void* in the first place? Is that required
> because they are defined in the linker file with some (unknown) type?

Symbols from linker scripts are just entries in the compiler's internal
symbol table. In C declarations you can assign any type.


> But then I see something else: _etext is already a pointer and
> Cortex_MemInit() takes the variable's address (&_etext). How can this
> work? In my opinion, this would result in a type void**, which is then
> casted to uint32_t*.

Again, you can assign any type. The authors of the code above decided to
use a void pointer, but it could have been any other type.


> Is there anyone who could clarify this for me?

As stated above, linker script symbol are compiler symbol table entries.
No storage is assigned to them. The resulting restriction is, that you
can only reference the address of a linker script symbol, never its value.

Let's assume we have

 _ldvar = 0x1000;

in our linker script. In the C source file we may declare

 extern int _ldvar;

Now, _ldvar is declared as an integer, located at address 0x1000. But
there is no real storage assigned to _ldvar. If we read from or write to
_ldvar, strange things may happen. But we can reference its address with

 int *ptr = &_ldvar;

Of course, it makes sense to declare the right type to avoid unnecessary
type casting and possible alignment warnings from the compiler. Instead of

 extern int _ldvar;
 uint32_t *ptr = (uint32_t *) &_ldvar;

we should use

 extern uint32_t _ldvar;
 uint32_t *ptr = &_ldvar;


Regards,

Harald



More information about the En-Nut-Discussion mailing list