Linker symbols have a name and a value. The value is a 48-bit address contained in a 64-bit unsigned long.
The most common kind of symbol is generated by the compiler for each function and variable. The value represents the target address where that function or variable is located. When you refer to the symbol by name in the linker command file, you get that 48-bit value.
However, in C and C++ names mean something different. If you have a variable named x that contains the value Y, and you use the name "x" in your C program, you are actually referring to the contents of variable x. If "x" is used on the right-hand side of an expression, the compiler fetches the value Y. To realize this variable, the compiler generates a linker symbol named x with the value &x. Even though the C/C++ variable and the linker symbol have the same name, they don't represent the same thing. In C, x is a variable name with the address &x and content Y. For linker symbols, x is an address, and that address contains the value Y.
Because of this difference, there are some tricks to referring to linker symbols in C code. The basic technique is to cause the compiler to create a "fake" C variable or function and take its address. The details differ depending on the type of linker symbol.
Linker symbols that represent a function address: In C code, declare the function as an extern function. Then, refer to the value of the linker symbol using the same name. This works because function pointers "decay" to their address value when used without adornment. For example:
extern void _c_int00(void);
printf("_c_int00 %lx\n", (unsigned long) &_c_int00);
Suppose your linker command file defines the following linker symbol:
func_sym=other_sym+100;
Your C application can refer to this symbol as follows:
extern void func_sym(void);
printf("func_sym %lx\n", (unsigned long) &func_sym);
Linker symbols that represent a data address or an arbitrary address: In C code, declare the variable as an extern variable. Then, refer to the value of the linker symbol using the & operator. Because the variable is at a valid data address, we know that a data pointer can represent the value. Suppose your linker command file defines the following linker symbols:
data_sym=.data+100;
xyz=12345
Your C application can refer to these symbols as follows:
extern char data_sym;
extern int xyz;
printf("data_sym %p\n", &data_sym);
int another_var = &xyz;
On C7000 devices, all symbol references are handled in a position-independent manner through a PC-relative offset. However, linker-defined symbols may have a value that does not resolve to a valid symbol address or resolves to an address that is beyond the +/- 2 GB reach of normal PC-relative addressing. When accessing such symbols, you must use the _symval() intrinsic to force the use of absolute addressing. Such addressing prevents the compiler from generating PC-relative offsets/relocations for symbols that don't actually correspond to addresses or to addresses that are beyond the +/- 2 GB reach of PC-relative addressing.
Therefore, if the data symbol in the above example is more than +/- 2 GB from where it is used, you must use the _symval() operator to force an absolute addressing mechanism, because the PC-relative addressing mechanism won't reach:
printf("data_sym %p\n", _symval(&data_sym));