按应用程序访问链接描述文件中定义的符号

ka0*_*a05 19 c linker iar

在我的链接器脚本文件中,我定义了两个符号

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 
Run Code Online (Sandbox Code Playgroud)

然后我将它们导出,如下所示

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;
Run Code Online (Sandbox Code Playgroud)

从applciation代码,我尝试访问这些符号

extern const unsigned int _region_RAM_start__;
extern const unsigned int _region_RAM_end__;
....
int GetRAMSize()
{
    int size = 0;
    unsigned int address_1 = _region_RAM_start__;
    unsigned int address_2 = _region_RAM_end__;
    size = address_2 - address_1 + 1U;
    return size;
}
Run Code Online (Sandbox Code Playgroud)

现在,我希望返回值为0x00100000,但是,我得到的只是0.所以,当我转向调试器时,我注意到_region_RAM_start__和_region_RAM_end__分别具有值0xC0000000和0xC00fffff,但是address_1和address_2的值为0 .

编译器优化设置为"无".这一直困扰着我一段时间.在这里我是否有一些非常明显的东西(除了我不应该首先这样做)

解决方案 感谢nm的答案

  unsigned int address_1 = (unsigned int) (&_region_RAM_start__);
Run Code Online (Sandbox Code Playgroud)

否则address_1和address_2都包含垃圾值(即分别在地址0xC0000000和0xC00fffff处可用的值,但从此代码的角度来看是垃圾)

Kei*_*Ape 21

那有点旧了,但无论如何我都会回答它......

ld手册:

从源代码访问链接器脚本定义的变量并不直观.特别是链接描述符号不等同于高级语言中的变量声明,而是一个没有值的符号.

在进一步说明之前,请务必注意,编译器在将源代码中的名称存储在符号表中时,通常会将其转换为不同的名称.例如,Fortran编译器通常在前缀或附加下划线,并且C++执行广泛的名称修改.因此,在源代码中使用的变量名称与在链接描述文件中定义的同一变量的名称之间可能存在差异.例如,在C中,链接器脚本变量可能被称为:

extern int foo;
Run Code Online (Sandbox Code Playgroud)

但在链接描述文件中,它可能被定义为:

_foo = 1000;
Run Code Online (Sandbox Code Playgroud)

然而,在其余示例中,假设没有发生名称变换.

当用C等高级语言声明符号时,会发生两件事.第一个是编译器在程序的内存中保留足够的空间来保存符号的.第二个是编译器在程序的符号表中创建一个条目,该表保存符号的地址.即符号表包含保存符号值的存储块的地址.例如,在文件范围内的以下C声明:

int foo = 1000;
Run Code Online (Sandbox Code Playgroud)

在符号表中创建一个名为"foo"的条目.此条目保存int大小的内存块的地址,其中最初存储数字1000.

当程序引用符号时,编译器会生成代码,该代码首先访问符号表以查找符号的内存块的地址,然后编写代码以从该内存块中读取值.所以:

foo = 1;
Run Code Online (Sandbox Code Playgroud)

在符号表中查找符号foo,获取与此符号关联的地址,然后将值1写入该地址.鉴于:

int * a = & foo;
Run Code Online (Sandbox Code Playgroud)

在符号表中查找符号foo,获取地址,然后将该地址复制到与变量"a"相关联的内存块中.

相反,链接器脚本符号声明在符号表中创建一个条目,但不为它们分配任何内存.因此,它们是没有价值的地址.例如,链接器脚本定义:

foo = 1000;
Run Code Online (Sandbox Code Playgroud)

创建名为@samp {} foo的持有存储位置1000的地址符号表中的条目,但没有什么特别的是存储在地址1000这意味着你不能访问链接脚本定义符号的-它没有价值- 您所能做的就是使用链接器脚本定义符号的地址.

因此,当您在源代码中使用链接器脚本定义符号时,应始终使用符号的地址,而不要尝试使用其值.例如,假设您要将名为.ROM的内存部分的内容复制到名为.FLASH的部分中,并且链接描述文件包含以下声明:

start_of_ROM   = .ROM;
end_of_ROM     = .ROM + sizeof (.ROM);
start_of_FLASH = .FLASH;
Run Code Online (Sandbox Code Playgroud)

然后执行复制的C源代码将是:

extern char start_of_ROM, end_of_ROM, start_of_FLASH;

memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);
Run Code Online (Sandbox Code Playgroud)

注意使用"&"运算符.他们是对的.

  • 如果你从其他来源复制粘贴,你应该引用它.https://sourceware.org/binutils/docs/ld/Source-Code-Reference.html (4认同)

Joh*_*ham 7

由于它们是您尝试访问的通用地址符号,而不一定是指向特定类型的指针,因此您不想将它们声明为 unsigned int,而是将它们声明为

外部无效_region_RAM_START;

那么 &_region_RAM_START 将具有适当的类型“void *”。