SPRUIG8J January 2018 – March 2024
When you declare a variable such as
int x = 1234;
in C/C++, an object with the identifier (name)
“x” is created at address &x with the contents 1234. In addition, a related
linker symbol named x
is created. That linker symbol represents
just the address, not the object itself. References to the linker symbol
x
result in the linker symbol’s value, which is the address.
However, references to the C/C++ identifier x
result in the
contents 1234. If you want the address of this C/C++ identifier, you need to use
&x
. Thus, the C/C++ expression &x
has
the same value as the linker expression x
, although the linker
symbol does not have an associated type.
Suppose a linker-defined symbol represents an integer rather than an address, such as __TI_STACK_SIZE. There is no way to refer to an integer linker symbol directly in the compiler, so we use a trick. First, pretend this linker symbol represents an address. Declare a fake variable with the same name in the C/C++ code. Now, refer to &__TI_STACK_SIZE, an expression that has the same value as the linker symbol __TI_STACK_SIZE. The value does have the wrong type, which you can change with a cast as follows:
extern unsigned char __TI_STACK_SIZE;
size_t stack_size = (size_t) &__TI_STACK_SIZE;
Leaving out _symval as shown in the above example works most of the time, but not always. In some cases, a pointer value is not adequate to represent a linker symbol value. For example, some targets have a 16-bit address space and thus 16-bit pointers. TI linker symbols are 64 bits, so a linker symbol can have a value that is larger than can be represented by a target pointer. In such cases, the expression &v reflects only the lower 16 bits of the actual value of the linker symbol “v”. To get around this problem, use the _symval built-in operator, which causes all of the value bits of the linker symbol to be copied:
extern void v;
unsigned long value = (unsigned long)_symval(&v);
For every kind of linker symbol, use this pattern:
extern void name;
desired_type name = (desired_type)_symval(&name);
For example,
extern void farfunc;
void foo()
{
void (*func)(void) = (void (*)(void))_symval(&farfunc);
func();
}
On C7000 devices, linker symbols that represent integers or that for some other reason do not represent valid addresses, cannot always be represented with a pointer value. Use _symval in such cases to make sure you get the right value.