在我的链接描述文件中,我定义了两个符号
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处可用的值,但从此代码的角度来看是垃圾)
答案 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;
}