C 按应用程序访问链接器脚本中定义的符号

C 按应用程序访问链接器脚本中定义的符号,c,linker,iar,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__; 从应用程序代码中,我尝试访问这些符号 extern const unsigned

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

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 
然后我将它们导出,如下所示

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;
从应用程序代码中,我尝试访问这些符号

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值

编译器优化设置为“无”。这已经困扰了我一段时间了。这里有没有什么很明显我遗漏的东西(除了我一开始不应该这样做之外)

解决方案 谢谢n.m.的回答

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

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

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

外部无效区域内存启动


然后&\u region\u RAM\u START将具有适当的类型“void*”。

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

从:

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

在进一步讨论之前,请务必注意编译器 通常将源代码中的名称转换为不同的名称 当它们存储在符号表中时。例如,Fortran 编译器通常会添加或附加下划线,以及C++。 执行扩展名称损坏。因此可能会有一个 在中使用的变量名称之间存在差异 源代码和定义的同一变量的名称 在链接器脚本中。例如,在C语言中,链接器脚本变量 可称为:

extern int foo;
但在链接器脚本中,它可能被定义为:

_foo = 1000;
然而,在剩下的示例中,假设没有名称 转变已经发生

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

int foo = 1000;
在符号表中创建一个名为“foo”的条目。此条目 保存一个整数大小的内存块的地址,其中 数字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);
注意“&”运算符的使用。他们是正确的


以下代码应按预期工作:

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;

}

这是一种正确和预期的行为。符号是地址的名称
extern xyz
的意思是“Linker先生,我不知道
xyz
的地址,请帮我解决”。太好了!感谢指针@n.m。因此解决方案是使用地址_1=(无符号int)(&_region_RAM_start_);我想问:
define
语法记录在哪里,但后来我终于看到了iar标记。世界上还有其他的链接器!:-)如果你从另一个来源复制粘贴,你应该引用它。多年来,我一直在编写链接器脚本和混合C/ASM代码,这一次让我大吃一惊。当然,链接器符号总是存储位置,而不是解释后的值,这是有道理的。谢谢。如果
\u region\u RAM\u end\u
无符号整数
,则表达式
无符号整数*
,不能分配给
无符号整数地址\u 2
。检查编译器消息输出。