链接器使用内存映射。

3

我该如何强制链接器将我的某些变量放置在内存的特定位置。例如,我想将整数name分配在0x8100000中。如果我没有误解,我可以使用:

int name __attribute__ ((section ("name_of_section")));

然后在链接脚本中:

 SECTIONS
 {
   ...
   . = 0x8100000;
   .data : { name_of_section }
   ...
 }

我希望使用类似的东西来映射uC端口。

但是有一些不匹配的地方,我不知道我哪里出了错误。(我从未使用过链接器脚本,所以如果我写了什么很愚蠢的东西,请原谅。)

3个回答

3
通常情况下,这是在没有链接脚本的情况下完成的。
int volatile * const portA = 0x8100000;  //portA is a constant pointer to a volatile int
...

*portA = 53;  //write value 53 to output port

如果你必须使用链接器脚本,那么它将是编译器和/或芯片特定的。请问您使用的芯片和工具链是什么?


谢谢回答。 我知道这个解决方案,但我想使用链接器来完成这个任务。 这是针对STM32微控制器的。我正在使用Sourcery G++ Lite的eclpis。 - qubu
如果您需要访问特定内存位置的设备寄存器或其他内容,我建议使用以下方式(并可能添加volatile以确保其正常工作)。如果您仅想在一般区域中获取数据,则我认为您上面的链接器脚本片段是可以的。您需要更详细地说明您的问题,而不是说“有些东西不匹配”。 - ams
@ams - 抱歉,我忘记加上volatile了。我现在会修复它。 - Luke Postema
我知道这取决于芯片,我提到的地址只是一个例子。我通过使用类似于您的技术实现了内存映射,并且它工作正常,但现在我想通过使用链接器脚本来实现它,但我不知道如何正确地做。我试图在此处找到一些示例: http://sourceware.org/binutils/docs-2.21/ld/ 但我没有看到任何为特定变量设置地址的示例。我知道我可以在gcc编译器中使用“section”属性。然后我尝试在链接器脚本中使用它,但我认为我做错了什么。 - qubu
1
你可以在链接脚本中定义变量(或标签)。请参考你提供的文档中的“简单赋值”部分。我认为你需要在C源文件中将该变量声明为extern - ams
@qubu:为什么你如此坚持使用链接器?如果这只是为了学习,我可以理解……但是在我的看法中,使用链接器并不(a)明显(portA在哪里?谁知道……链接脚本通常位于源代码树之外),(b) 还不够便携。Luke的答案是正确、明显、简单和可移植的。这些都是我希望在代码中看到的东西。 - Dan

2
感谢您的所有建议!现在它已经正常工作。 .ld文件:
SECTIONS
{
...
   .data: {
   ...
   }
   ...
   var_name = 0x40010CA0;
}

.c文件:

extern volatile int var_name;

在研究我上面链接的文档(输入部分示例)后,我也尝试了类似以下的操作:

.ld文件:

.hrd_map 0x40010CA0 : 
{       
    main.o(.b_section)  
}

.b_section是一个具有属性的全局变量:

int b __attribute__((section(".b_section")));

但是它不起作用,我得到了这种错误:multiple definition of `main'。 我认为这是因为在.ld文件中早期有其他的赋值,比如:.data: {...} .bss .text。 也许有人知道如何修复这个问题,或者如何在不使用section属性的情况下访问一些变量。我尝试在main.o文件中查找变量的符号,但除了使用section属性创建的.b_section和其他(默认创建的?).data .bss .text等之外,我没有看到任何像变量符号名称的东西。
@Dan 你是对的,我正在为了学习而做这个。但另一方面,我认为这段代码会相当可移植,因为每个芯片都需要.ld和启动文件,并且端口的定义也包含在库中。

谢谢,我一直在寻找这个。我不理解为什么大家都反对这样做。我见过商业产品中采用这种方法。我不同意“你的代码将更易于理解和维护等等”这种说法。这是无依据的。毕竟每个目标微控制器都需要不同的链接脚本。我认为这个解决方案相当优雅。 - user7048748

0

我建议不要使用链接器来访问硬件寄存器。如果您明确编写地址,您的代码将更易于理解和维护。将所有设备特定的寄存器信息收集在一个包含文件中是一个好主意。对于复杂的外设,通常最好为与外设相关联的寄存器块typedef一个结构,特别是当设备支持特定外设的多个实例时。然后使用Luke答案中的技术来访问寄存器或寄存器块。在访问硬件寄存器时,应始终使用volatile关键字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接