Reputation: 9203
I have a linker symbol (let's call it __BASE_ADDR), defined in a linker command script, which contains the address of the longword after a longword that I need to use (e.g. I need to check longword at address 0x0000000C and __BASE_ADDR is equal to 0x00000010). So in the code I try to use __BASE_ADDR and subtract 4 from it to access 0x0000000C.
My linker map output correctly shows the value of __BASE_ADDR to be 0x00000010. However when I try to access the location using the following C code it doesn't work:
extern unsigned char *__BASE_ADDR;
void someFunc( void )
{
unsigned long Val = *((unsigned long *) (__BASE_ADDR - 4));
/* Use Val for some comparison...*/
/* ... */
}
Val gets set to the wrong value. What appears to be happening is that whatever longword is at __BASE_ADDR is taken as an address, 4 is subtracted, and the contents of the resulting address is put into Val.
But when I do the following, it does work fine and Val is set correctly to whatever resides at address 0x0000000C:
extern unsigned char __BASE_ADDR[];
void someFunc( void )
{
unsigned long Val = *((unsigned long *) (__BASE_ADDR - 4));
/* Use Val for some comparison...*/
/* ... */
}
Can anyone shed light on this? I understand why you can't access a linker symbol's contents (it technically has no contents), but why would there be a difference between accessing the linker symbol as a pointer and accessing it as an array?
Thanks.
Upvotes: 4
Views: 7261
Reputation: 183888
(e.g. I need to check longword at address
0x0000000C
and__BASE_ADDR
is equal to0x00000010
)
The symptoms say that 0x00000010
is not the value of __BASE_ADDR
, but the address.
So
unsigned long Val = *((unsigned long *) (__BASE_ADDR - 4));
does indeed read the value at 0x00000010
(obtaining the value of __BASE_ADDR
), subtracts four from it and interprets the result as the address of the unsigned long
to store in val
.
With
extern unsigned char __BASE_ADDR[];
the address of the array __BASEADDR
is the same as the address of the array's first element, so in that case,
unsigned long Val = *((unsigned long *) (__BASE_ADDR - 4));
__BASE_ADDR
to a pointer to its first element, and the address that results in is the address of __BASE_ADDR
(just a different type), 0x00000010
;unsigned char*
, resulting in the address 0x0000000C
;unsigned long*
, dereferenced and the value located there stored in val
.(The last point very probably invokes undefined behaviour, but you may be in a situation where you know it works, if you deal with fixed addresses.)
Upvotes: 5