RealView ARM C 编译器支持使用变量属性将变量放置在给定的内存地址at(address)
:
int var __attribute__((at(0x40001000)));
var = 4; // changes the memory located at 0x40001000
GCC 是否有类似的变量属性?
您回答了您的问题,在上面的链接中它指出:
使用 GNU GCC 编译器,您可以只使用指针定义来访问绝对内存位置。例如:
#define IOPIN0 (*((volatile unsigned long *) 0xE0028000))
IOPIN0 = 0x4;
顺便说一句http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes
最小的可运行链接描述文件示例
该技术在以下位置提到:https ://stackoverflow.com/a/4081574/895245但现在我将提供一个具体示例。
主程序
#include <stdio.h>
int myvar __attribute__((section(".mySection"))) = 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;
}
链接.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 内核每次都将可执行文件放置在不同的地址上,这与我们的实验相混淆。另请参阅:gcc 和 ld 中与位置无关的可执行文件的 -fPIE 选项是什么?
TODO:编译产生警告:
/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?
难道我做错了什么?如何摆脱它?另请参阅:如何删除警告:link.res 包含输出部分;你忘了-T吗?
在 Ubuntu 18.10、GCC 8.2.0 上测试。
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]);
在 GCC 中,您可以将变量放入特定部分:
__attribute__((section (".foo"))) static uint8_t * _rxBuffer;
或者
static uint8_t * _rxBuffer __attribute__((section (".foo")));
然后在 GNU Linker Memory Settings 中指定该部分的地址:
.foo=0x800000
我有一个类似的问题。我想在我定义的部分中以特殊偏移量分配一个变量。同时我希望代码是可移植的(我的 C 代码中没有明确的内存地址)。所以我在链接描述文件中定义了 RAM 部分,并定义了一个与我的部分长度相同的数组(.noinit
部分是 0x0F 长度)。
uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));
此数组映射此部分的所有位置。当部分很大时,此解决方案不适合,因为分配的数组中未使用的位置将浪费数据存储器中的空间。