如何在GNU链接器脚本中获取C符号大小,实现堆与变量的地址布局
GNU链接器脚本:低地址堆+高地址全局变量实现方案
需求
在APPL_STATE内存段中同时放置:
- 可变长度堆(位于低地址,可向高地址扩展)
- 全局变量
foo(位于高地址)
要求无需硬编码foo的大小,由链接器自动计算空间。
原实现(堆在高地址)
原脚本将全局变量放在低地址,堆占据剩余高地址空间:
MEMORY { APPL_STATE (rwx): ORIGIN = 0x002B8000, LENGTH = 0x00030000 /* 192kb */ } SECTIONS { .shared_state (NOLOAD) : ALIGN(16) { *(SORT_BY_ALIGNMENT(.shared_state*)) shared_state_heap_start = .; shared_state_heap_end = ORIGIN(APPL_STATE) + LENGTH(APPL_STATE); } >APPL_STATE }
正确实现(堆在低地址)
通过反向定位的方式,先为全局变量预留高地址空间,再确定堆的范围,无需硬编码变量大小:
方案1:先标记堆起始,再放置全局变量
MEMORY { APPL_STATE (rwx): ORIGIN = 0x002B8000, LENGTH = 0x00030000 /* 192kb */ } SECTIONS { .shared_state (NOLOAD) : ALIGN(16) { // 堆的起始地址 = 段的起始(低地址) shared_state_heap_start = .; // 跳转到内存段末尾,反向对齐以满足变量的16字节对齐要求 . = ORIGIN(APPL_STATE) + LENGTH(APPL_STATE); . = ALIGN(16, DOWN); // 放置全局变量foo所在的段(KEEP避免被链接器优化) KEEP(*(SORT_BY_ALIGNMENT(.shared_state*))); // 堆的结束地址 = 全局变量的起始地址 shared_state_heap_end = .; } >APPL_STATE }
方案2:先确定全局变量位置,再计算堆范围
MEMORY { APPL_STATE (rwx): ORIGIN = 0x002B8000, LENGTH = 0x00030000 /* 192kb */ } SECTIONS { .shared_state (NOLOAD) : ALIGN(16) { // 跳转到内存段末尾,反向对齐 . = ORIGIN(APPL_STATE) + LENGTH(APPL_STATE); . = ALIGN(16, DOWN); // 记录全局变量的起始地址 foo_segment_start = .; // 放置全局变量段 KEEP(*(SORT_BY_ALIGNMENT(.shared_state*))); // 堆的范围:从段起始到全局变量起始 shared_state_heap_start = ORIGIN(APPL_STATE); shared_state_heap_end = foo_segment_start; } >APPL_STATE }
核心逻辑
- 利用
ALIGN(16, DOWN)从内存段末尾反向对齐,确保全局变量的地址符合对齐要求 - 依赖链接器自动计算
.shared_state*段的大小,无需手动指定foo的长度 KEEP关键字确保全局变量段不会被链接器优化丢弃
内容的提问来源于stack exchange,提问作者Allan
相关产品推荐
相关产品推荐

