27

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

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__的值分别为 0xC0000000和_region_RAM_end__0xC00fffff,但值为 0。address_1address_2

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

解决方案 感谢nm的回答

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

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

4

3 回答 3

30

这有点老了,但我还是会回答的……</p>

ld手册

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

在进一步讨论之前,重要的是要注意,当源代码中的名称存储在符号表中时,编译器通常会将它们转换为不同的名称。例如,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);

请注意“&”运算符的使用。他们是正确的。

于 2016-11-03T00:50:47.783 回答
4

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

外部无效_region_RAM_START;

然后 &_region_RAM_START 将具有适当的类型 'void *'。

于 2013-11-16T12:25:39.987 回答
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;

}
于 2018-03-06T14:25:33.900 回答