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

时间:2011-12-06 10:57:34

标签: c linker iar

在我的链接描述文件中,我定义了两个符号

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 

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

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;

从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;
}

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

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

解决方案 感谢上午为答案

  unsigned int address_1 = (unsigned int) (&_region_RAM_start__);

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

3 个答案:

答案 0 :(得分:18)

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

来自ld manual

  

从源代码访问链接器脚本定义的变量是     不直观。特别是链接器脚本符号不是     相当于高级语言中的变量声明,     它是一个没有值的符号。

     

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

extern int foo;
     

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

_foo = 1000;
     

在其余的例子中,假设没有名字     转型已经发生。

     

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

int foo = 1000;
     

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

     

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

foo = 1;
     

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

int * a = & foo;
     

在符号表中查找符号foo,获取地址     然后将此地址复制到相关的内存块中     使用变量" a"。

     相反,

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

foo = 1000;
     

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

     

因此,当您在源中使用链接器脚本定义符号时     代码你应该总是采取符号的地址,永远不要     试图使用它的价值。例如,假设您要复制     一段内存的内容称为.ROM到一节     调用.FLASH和链接描述文件包含这些声明:

start_of_ROM   = .ROM;
end_of_ROM     = .ROM + sizeof (.ROM);
start_of_FLASH = .FLASH;
     

然后执行复制的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);
     

请注意使用"&"运营商。他们是对的。

答案 1 :(得分:4)

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

extern void _region_RAM_START;

然后& _region_RAM_START将具有相应的类型'void *'。

答案 2 :(得分:1)

下面的代码应该按预期工作:

extern const volatile unsigned int _region_RAM_start__;

extern const volatile 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;

}