32

RealView ARM C 编译器支持使用变量属性将变量放置在给定的内存地址at(address)

int var __attribute__((at(0x40001000)));
var = 4;   // changes the memory located at 0x40001000

GCC 是否有类似的变量属性?

4

7 回答 7

26

我不知道,但您可以轻松创建这样的解决方法:

int *var = (int*)0x40001000;
*var = 4;

它不完全相同,但在大多数情况下是完美的替代品。它适用于任何编译器,而不仅仅是 GCC。

如果您使用 GCC,我假设您也使用GNU ld(当然,虽然不确定)并且 ld 支持将变量放置在您想要的任何位置

我想让链接器完成这项工作是很常见的。

受@rib 回答的启发,我将补充一点,如果绝对地址用于某个控制寄存器,我将添加volatile到指针定义中。如果只是RAM,没关系。

于 2010-11-01T09:40:33.123 回答
19

您可以使用节属性和 ld链接描述文件来定义该节所需的地址。这可能比您的替代方案更混乱,但它是一种选择。

于 2010-11-02T19:54:05.227 回答
11

您回答了您的问题,在上面的链接中它指出:

使用 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

于 2010-11-01T09:52:57.607 回答
11

最小的可运行链接描述文件示例

该技术在以下位置提到: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))}
}

GitHub 上游.

编译并运行:

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 上测试。

于 2019-01-10T12:21:15.423 回答
4
    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]);
于 2016-06-01T12:00:46.343 回答
0

在 GCC 中,您可以将变量放入特定部分:

__attribute__((section (".foo"))) static uint8_t * _rxBuffer;

或者

static uint8_t * _rxBuffer __attribute__((section (".foo")));

然后在 GNU Linker Memory Settings 中指定该部分的地址:

.foo=0x800000 
于 2021-07-03T18:12:57.437 回答
0

我有一个类似的问题。我想在我定义的部分中以特殊偏移量分配一个变量。同时我希望代码是可移植的(我的 C 代码中没有明确的内存地址)。所以我在链接描述文件中定义了 RAM 部分,并定义了一个与我的部分长度相同的数组(.noinit部分是 0x0F 长度)。

uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));

此数组映射此部分的所有位置。当部分很大时,此解决方案不适合,因为分配的数组中未使用的位置将浪费数据存储器中的空间。

于 2022-02-23T14:48:40.810 回答