C语言 我如何分组RAM变量以防止Gnu编译器工具链填充?

xytpbqjk  于 2023-03-17  发布在  其他
关注(0)|答案(2)|浏览(103)

我们有一个使用ARM Cortex M33处理器的大型嵌入式项目,用大约30,000行“C”编写。我们使用Gnu编译器/链接器工具链。其中混合了定制软件和一些开源库(例如- FatFS),和特定于供应商的库(例如-蓝牙堆栈)。我们有大约500个命名的静态变量和数据结构占用RAM。变量的大小范围从一个字节到数百个字节的结构。在大多数情况下,变量是一个、两个或四个字节。
链接器按大小对单个文件中的所有变量进行分组,并在四字节和两字节变量或两字节和一字节变量的组之间切换时添加对齐字节。由于RAM有限,因此这种对齐丢失的RAM量已成为一个问题。
我想以某种方式指示编译器和链接器将所有一个字节的变量放入一个链接器部分,将两个字节放入另一个链接器部分,将四个字节放入第三个链接器部分,和其他所有内容添加到第四个链接器部分中。然后可以控制每个部分的对齐,对齐填充应该消失或最小化。如果我能告诉链接器在分配内存地址时按大小对变量排序,它也会起作用。
我怎样才能做到这一点,或者类似的事情呢?gnu编译器和链接器手册似乎并没有说明如何告诉编译器去做类似的事情。已经消失的内存量填补了裂缝,现在大约是我们总可用内存的3%,我们正在耗尽。我正在寻找创造性的建议,并希望听到任何你可能知道的部分解决方案。

inb24sb2

inb24sb21#

你可以告诉链接器按对齐方式排序,全局的,或者按节排序。要对所有节都这样做,添加:

--sort-section=alignment

传递给ld的标志。
如果您使用gcc来调用链接器,则需要将以下代码添加到CFLAGS中:

-Wl,--sort-section=alignment

或者,您可以在链接器文件中逐节执行此操作,例如:

*(.data*)

*(SORT_BY_ALIGNMENT(.data*))

并且如果需要,.bss部分也是如此。

zhte4eai

zhte4eai2#

我想以某种方式指示编译器和链接器将所有一个字节的变量放入一个链接器部分,将两个字节的变量放入另一个链接器部分
在链接器脚本中定义要放置特定大小数据的部分。这个例子只针对1字节和2字节-因为它们可能会有问题。

_sidata8 = LOADADDR(.data8);
  .data8 : ALIGN(1)
  {
    _sdata8 = .;      
    KEEP(*(.data8))          
    KEEP(*(.data8*))         
    _edata8 = .;      

  } >RAM AT> FLASH
  
  _sidata16 = LOADADDR(.data16);
  .data16 : ALIGN(2)
  {
    _sdata16 = .;      
    KEEP(*(.data16))          
    KEEP(*(.data16*))         
    _edata16 = .;      

  } >RAM AT> FLASH

KEEP只是因为我不使用那些变量,编译器很可能会优化掉它们)
当你声明变量时,把它们放在正确的部分。

char   __attribute__((section(".data8"))) a;
short __attribute__((section(".data16"))) d;
char   __attribute__((section(".data8"))) b;
short __attribute__((section(".data16"))) e;
char   __attribute__((section(".data8"))) c;
short __attribute__((section(".data16"))) f;

结果是:

请记住,您需要添加一些启动代码来初始化或清零您的特定部分。
示例

#if defined(__GNUC__)

extern uint8_t _sdata8[];
extern uint8_t _sdata16[];
extern uint8_t _edata8[];
extern uint8_t _edata16[];
extern uint8_t _sidata8[];
extern uint8_t _sidata16[];

static void __attribute__((constructor)) initDatax(void)
{
    memcpy(_sdata8, _sidata8, _edata8 - _sdata8);
    memcpy(_sdata16, _sidata16, _edata16 - _sdata16);
}

#endif

这将需要一些工作(添加属性-您可以使用宏定义来缩短它),但您可以组织您的数据以避免变量之间的填充。它将在项目范围内工作-因此任何定义为.data8的数据都将放置在此部分中。

相关问题