avr-gcc:如何将 __attribute__((address)) 与 EEMEM 一起使用?

Posted

技术标签:

【中文标题】avr-gcc:如何将 __attribute__((address)) 与 EEMEM 一起使用?【英文标题】:avr-gcc: How to use __attribute__((address)) with EEMEM? 【发布时间】:2022-01-15 14:57:12 【问题描述】:

这些属性不兼容吗?地址属性似乎被忽略,不发出警告(-Wall)。

(作为参考,EEMEM 在 eeprom.h 中定义为:#define EEMEM __attribute__((section(".eeprom")))。)

使用如下声明:

uint8_t storedFlags EEMEM __attribute__((address (100)));

(对于所有其他人也是如此)导致变量以链接器喜欢的任何顺序放置,而忽略我的属性。属性的顺序没有影响。

我知道首选方法(创建节并将其位置传递给链接器)。我只是想暂时推开它们,因为我正在积极开发并在 EEPROM 中添加和删除分配;我宁愿事情不要在其他所有版本中移动,这样我就不必每次都从默认值重新编程 EEPROM。最糟糕的是,我敢肯定我以前就做过这个,并且成功了。版本差异?巧合的任务? (我有 GCC 3.4 和 8.1,不确定那个项目使用的是什么;我使用的是 8.1。)

【问题讨论】:

【参考方案1】:

address 属性的documentation 声明:

具有地址属性的变量用于寻址可能位于 io 地址范围之外的内存映射外设。

查看AVR memory space 显示 I/O 地址位于 SRAM 数据存储空间之下。

这解释了为什么您的构造不能按预期工作,因为 EEMEM 和 address 属性映射到冲突的内存部分。

编辑:使用 avr-gcc 3.6.2 进行的测试表明 section 属性覆盖了 address 属性(没有警告)。使用 eeprom_read_byte 从 EEPROM 读取数据,下面的例子被 avr-gcc 正确编译(正确,因为地址 0x0123 被传递给 eeprom_read_byte 函数):

#include <avr/eeprom.h>

uint8_t __attribute__((address (0x0123))) storedFlags;
int main(void)
  if (eeprom_read_byte(&storedFlags) == 1)
    return 1;
  

Edit2:在 avr-gcc 11.1 上测试,也生成正确的指令。

【讨论】:

我不确定他们的意思; IO 空间位于 SRAM 中,仅通过使用某些快速指令(IN、OUT 等)访问它的能力来区分。基本上所有外围设备都已经超出了该范围。官方标题只是访问那些带有原始(文字)指针的标题。另外,如果它取决于部分,它不应该说它需要哪个部分(例如.data)吗?那么这只是一个多余的属性吗?还是记录不全? 用 avr-gcc 3.6.2 进行的一些测试表明,section 属性似乎覆盖了地址。因此,指定节属性将擦除地址属性,链接器会将变量从地址 0 开始放置在 EEPROM 空间中。似乎只使用地址属性会导致正确的明显位置。由于需要使用 eeprom_* 函数来访问 EEPROM 地址,因此无需指定 .eeprom 部分 AFAICS。我将添加一个示例。 有趣:无论如何都在 .data 中使用它,这很愚蠢,因为那里链接了其他东西,但无论如何,这都是外围空间(0 到 0xfff 或大约在大多数情况下)芯片,而 EEPROM 更小),所以实际上不会有任何冲突。缺点:无法初始化 .eeprom,仍然需要以某种方式链接。所以这个用例的原始问题仍然存在,嗯。

以上是关于avr-gcc:如何将 __attribute__((address)) 与 EEMEM 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

__attribute__((constructor)) 究竟是如何工作的?

__attribute__如何使用的记录

字段的 __attribute__((packed)) 如何影响包含该字段的结构?

如果我将字节数组转换为 __attribute__((packed, aligned(2))) 结构会发生啥?

gcc - 如何在结构定义中结合 __attribute__((dllexport)) 和 [[nodiscard]]?

GCC的__attribute__ ((constructor))和__attribute__ ((destructor))