RealView ARM C编译器supports使用变量属性at(address)将变量置于给定的内存地址:
at(address)
int var __attribute__((at(0x40001000))); var = 4; // changes the memory located at 0x40001000
GCC有类似的变量属性吗?
klh5stk11#
我不知道,但你可以很容易地创建一个这样的解决方案:
int *var = (int*)0x40001000; *var = 4;
这不是完全一样的东西,但在大多数情况下是一个完美的替代品。它可以与任何编译器一起工作,不仅仅是GCC。如果您使用GCC,我假设您也使用GNU ld(当然,这并不一定),并且ld支持将变量放置在您想要的任何位置。我想让链接器做这项工作是很常见的。受@rib回答的启发,我将补充一点,如果绝对地址是某个控制寄存器的,我将在指针定义中添加volatile,如果只是RAM,则无所谓。
volatile
1bqhqjot2#
您可以使用section attributes和ld链接器脚本来定义该节所需的地址,这可能比您的替代方案要混乱,但这是一个选项。
g6baxovj3#
该技术在以下网址中提及:https://stackoverflow.com/a/4081574/895245,但现在我将提供一个具体的示例。main.c
#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; }
link.ld
SECTIONS { .mySegment 0x12345678 : {KEEP(*(.mySection))} }
GitHub upstream.编译并运行:
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:编译产生警告:
-fno-pie -no-pie
/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上测试。
7ajki6be4#
你回答了你的问题,在你上面的链接它指出:使用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
ajsxfq5m5#
下面是一个解决方案,它实际上在内存中的固定地址保留了空间,而不必编辑链接器文件:
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]);
lyr7nygr6#
在GCC中,您可以将变量放入特定的部分:
__attribute__((section (".foo"))) static uint8_t * _rxBuffer;
或
static uint8_t * _rxBuffer __attribute__((section (".foo")));
然后在GNU链接器内存设置中指定该部分的地址:
.foo=0x800000
mccptt677#
我也遇到过类似的问题。我想在我定义的节中分配一个特殊偏移量的变量。同时我想代码是可移植的(在我的C代码中没有显式的内存地址)。所以我在链接器脚本中定义了RAM节,并定义了一个与我的节长度相同的数组(.noinit节的长度为0x0F)。uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));此数组Map此节的所有位置。此解决方案不适用于节很大的情况,因为已分配数组中未使用的位置将浪费数据内存中的空间。
.noinit
uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));
7条答案
按热度按时间klh5stk11#
我不知道,但你可以很容易地创建一个这样的解决方案:
这不是完全一样的东西,但在大多数情况下是一个完美的替代品。它可以与任何编译器一起工作,不仅仅是GCC。
如果您使用GCC,我假设您也使用GNU ld(当然,这并不一定),并且ld支持将变量放置在您想要的任何位置。
我想让链接器做这项工作是很常见的。
受@rib回答的启发,我将补充一点,如果绝对地址是某个控制寄存器的,我将在指针定义中添加
volatile
,如果只是RAM,则无所谓。1bqhqjot2#
您可以使用section attributes和ld链接器脚本来定义该节所需的地址,这可能比您的替代方案要混乱,但这是一个选项。
g6baxovj3#
该技术在以下网址中提及:https://stackoverflow.com/a/4081574/895245,但现在我将提供一个具体的示例。
main.c
link.ld
GitHub upstream.
编译并运行:
输出:
所以我们看到它被放置在所需的地址。
我找不到GCC手册中的文档位置,但找到了以下语法:
似乎将给定的链接器脚本附加到要使用的默认链接器脚本。
-fno-pie -no-pie
是必需的,因为Ubuntu工具链现在默认配置为生成PIE可执行文件,这会导致Linux内核每次都将可执行文件放在不同的地址,这会扰乱我们的实验。gcc和ld中位置无关可执行文件的-fPIE选项是什么?TODO:编译产生警告:
我做错了什么吗?如何摆脱它?另见:How to remove warning: link.res contains output sections; did you forget -T?
在Ubuntu 18.10和GCC 8.2.0上测试。
7ajki6be4#
你回答了你的问题,在你上面的链接它指出:
使用GNU GCC编译器,你可以只使用指针定义来访问绝对内存位置。
顺便说一http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes
ajsxfq5m5#
下面是一个解决方案,它实际上在内存中的固定地址保留了空间,而不必编辑链接器文件:
lyr7nygr6#
在GCC中,您可以将变量放入特定的部分:
或
然后在GNU链接器内存设置中指定该部分的地址:
mccptt677#
我也遇到过类似的问题。我想在我定义的节中分配一个特殊偏移量的变量。同时我想代码是可移植的(在我的C代码中没有显式的内存地址)。所以我在链接器脚本中定义了RAM节,并定义了一个与我的节长度相同的数组(
.noinit
节的长度为0x0F)。uint8_t no_init_sec[0x0f] __attribute__ ((section (".noinit")));
此数组Map此节的所有位置。此解决方案不适用于节很大的情况,因为已分配数组中未使用的位置将浪费数据内存中的空间。