RealView ARM C编译器supports使用变量属性at(address)
将变量放在给定的内存地址:
int var __attribute__((at(0x40001000)));
var = 4; // changes the memory located at 0x40001000
GCC是否有类似的变量属性?
答案 0 :(得分:18)
我不知道,但你可以轻松地创建一个这样的解决方法:
int *var = (int*)0x40001000;
*var = 4;
它不是完全相同的东西,但在大多数情况下是一个完美的替代品。它适用于任何编译器,而不仅仅是GCC。
如果您使用GCC,我假设您也使用GNU ld(当然,这不是确定的)并且ld支持放置变量wherever you want them。
我想让链接器完成这项工作非常普遍。
受到@rib的回答的启发,我将补充一点,如果绝对地址是针对某个控制寄存器的,我会将volatile
添加到指针定义中。如果它只是RAM,那没关系。
答案 1 :(得分:14)
您可以使用section attributes和ld linker script来定义该部分的所需地址。这可能比你的选择更麻烦,但它是一种选择。
答案 2 :(得分:6)
你回答了你的问题, 在上面的链接中指出:
使用GNU GCC编译器,您可以仅使用指针定义来访问绝对内存位置。例如:
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
IOPIN0 = 0x4;
Btw http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes
答案 3 :(得分:3)
extern const uint8_t dev_serial[12];
asm(".equ dev_serial, 0x1FFFF7E8");
/* or asm("dev_serial = 0x1FFFF7E8"); */
...
for (i = 0 ; i < sizeof(dev_serial); i++)
printf((char *)"%02x ", dev_serial[i]);
答案 4 :(得分:3)
最小的可运行链接描述文件示例
在https://stackoverflow.com/a/4081574/895245中提到了该技术,但现在我将提供一个具体示例。
main.c
#include <stdio.h>
int __attribute__((section(".mySection"))) myvar = 0x9ABCDEF0;
int main(void) {
printf("adr %p\n", (void*)&myvar);
printf("val 0x%x\n", myvar);
myvar = 0;
printf("val 0x%x\n", myvar);
return 0;
}
link.ld
SECTIONS
{
.mySegment 0x12345678 : {KEEP(*(.mySection))}
}
编译并运行:
gcc -fno-pie -no-pie -o main.out -std=c99 -Wall -Wextra -pedantic link.ld main.c
./main.out
输出:
adr 0x12345678
val 0x9abcdef0
val 0x0
所以我们看到它已经放在期望的地址上了。
我找不到GCC手册中记录的位置,但语法如下:
gcc link.ld main.c
似乎将给定的链接描述文件附加到将要使用的默认描述文件上。
-fno-pie -no-pie
是必需的,因为默认情况下,Ubuntu工具链现在已配置为生成PIE可执行文件,这导致Linux内核每次都将可执行文件放在不同的地址上,这与我们的实验相混淆。另请参阅:What is the -fPIE option for position-independent executables in gcc and ld?
TODO:编译产生警告:
/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?
我做错什么了吗?如何摆脱它?另请参阅:How to remove warning: link.res contains output sections; did you forget -T?
在Ubuntu 18.10,GCC 8.2.0上进行了测试。
答案 5 :(得分:0)
在 GCC 中,您可以将变量放入特定部分:
__attribute__((section (".foo"))) static uint8_t * _rxBuffer;
或
static uint8_t * _rxBuffer __attribute__((section (".foo")));
然后在 GNU Linker Memory Settings 中指定该部分的地址:
.foo=0x800000