ZHCU947E June 2015 – January 2023
链接器符号具有一个名称和一个值。值是 32 位无符号整数,即使目标的指针值小于 32 位也是如此。
最常用的符号类型是由编译器为每个函数和变量生成的符号。值表示函数或变量所在的目标地址。如果在链接器命令文件或汇编文件中按名称引用符号,可获得这个 32 位整数值。
但在 C 和 C++ 中名称的意义有所不同。如有一个值为 Y 的 x 变量,则在 C 程序中使用名称“x”时,实际上是在引用变量 x 的内容。如果“x”用在表达式的右侧,编译器会获取值 Y。若要实现此变量,编译器会生成值为 &x 的 x 链接器符号。即使 C/C++ 变量与链接器符号同名,它们表示的也是不同的内容。在 C 中,x 是变量名,其地址为 &x,内容为 Y。对于链接器符号,x 是地址,该地址包含值 Y。
由于存在此差别,在 C 代码中引用链接器符号时要掌握一些技巧。基本技巧是使编译器创建一个“假”C 变量或函数,并获取其地址。具体细节取决于链接器符号的类型。
表示函数地址的链接器符号:在 C 代码中,将函数声明为外部函数。然后使用相同的名称引用链接器符号的值。这是可行的,因为函数指针在使用时如果未加修饰,会“退化”为其地址值。例如:
extern void _c_int00(void);
printf("_c_int00 %lx\n", (unsigned long)&_c_int00);
假设链接器命令文件定义了以下链接器符号:
func_sym=printf+100;
C 应用可按如下方式引用此符号:
extern void func_sym(void);
printf("func_sym %lx\n", _symval(&func_sym)); /* these two are equivalent */
printf("func_sym %lx\n", (unsigned long)&func_sym);
表示数据地址的链接器符号:在 C 代码中,将变量声明为外部变量。然后使用 & 运算符引用链接器符号的值。由于变量位于有效的数据地址,可使用数据指针表示该值。
假设链接器命令文件定义了以下链接器符号:
data_sym=.data+100;
xyz=12345
C 应用可按如下方式引用这些符号:
extern far char data_sym;
extern far int xyz;
printf("data_sym %lx\n", _symval(&data_sym)); /* these two are equivalent */
printf("data_sym %p\n", &data_sym);
myvar = &xyz;
请注意,数据的链接器符号必须在 C 中使用 far
关键字声明。这是因为编译器假定,符号声明中没有“far”的,其地址是相对于数据页寄存器 (DP) 的地址。使用“far”关键字,编译器会将它们处理为绝对符号。
任意地址的链接器符号:在 C 代码中,将其声明为外部符号。类型无关紧要。如果使用 GCC 扩展,将其声明为“外部无效”。如果不使用 GCC 扩展,将其声明为“外部字符”。然后引用链接器符号 mySymbol 的值:_symval(&mySymbol)
。您必须使用 _symval 运算符,它与 cast 等效,因为链接器符号的 32 位值可能比一个数据指针宽。编译器以特殊方式处理 _symval(&mySymbol)
,可以将所有内容表示为 32 位,即使是 16 位的指针。目标如有 32 位指针,通常可使用 &mySymbol,而不必使用 _symval 运算符。但在各种 TI 目标中访问此类链接器符号的可移植方式为使用 _symval(&mySymbol)
。
假设链接器命令文件定义了以下链接器符号:
abs_sym=0x12345678;
C 应用可按如下方式引用此符号:
extern char abs_sym;
printf("abs_sym %lx\n", _symval(&abs_sym));