使用GCC将指向const数组的const指针数组放入只读内存遇段类型冲突怎么办?
我在为6809架构的Vectrex游戏机(RAM极少的8位微控制器)开发程序,需要将所有常量数据放入EPROM(只读内存),但遇到了段类型冲突的问题。
我的代码如下:
#include <stdio.h> __attribute__ ((section(".text"))) static const int one[2] = { 1, 2 }; __attribute__ ((section(".text"))) static const int two[2] = { 3, 4 }; static const int* parent[2] = { one, two };
若尝试把parent数组也放到.text段,会触发编译错误:
sections.c:5:54: error: parent causes a section type conflict with one
问题根源在于:尽管one和two的地址在链接时是确定的,但编译器仍将它们视为变量,导致parent被标记为需要运行时初始化,进而被分配到RAM中。但我的系统RAM严重不足,必须把这个指针数组也放到只读内存里。而且程序是在固定地址执行的,不存在重定位问题,EPROM固定在0000地址。
如果不添加section属性,代码能编译,但parent会被放到RAM,链接器会警告?ASlink-Warning-Size limit exceeded in bank ram,程序运行必然失败。
测试用的main函数:
int main(int argc, char **argv) { int i, j, k=0; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { k += parent[i][j]; } } fprintf(stderr, "tot = %d\n", k); return 0; }
针对GCC环境,有几种实用方法可以强制将这类指针常量数组放入只读内存:
方法1:双重const限定+指定只读数据段
核心是明确告诉编译器,指针数组本身及其指向的内容都是完全只读的,不需要运行时修改。推荐使用专门的只读数据段.rodata(比直接用.text更规范,避免和代码段冲突):
#include <stdio.h> __attribute__ ((section(".rodata"))) static const int one[2] = { 1, 2 }; __attribute__ ((section(".rodata"))) static const int two[2] = { 3, 4 }; // 双重const:第一个const修饰指针指向的内容,第二个const修饰指针数组元素本身 __attribute__ ((section(".rodata"))) static const int* const parent[2] = { one, two };
修改后编译器会识别到parent是纯只读常量,将其放入只读段,而非RAM。
方法2:添加used属性确保段不被优化
如果编译器因优化策略误将只读数组放入RAM,可以加上used属性,强制编译器保留该数组并放入指定只读段:
__attribute__ ((used, section(".rodata"))) static const int* const parent[2] = { one, two };
方法3:自定义链接器脚本(嵌入式系统专属)
若上述方法无效,可以通过自定义链接器脚本,明确将只读段映射到EPROM地址空间。示例脚本片段:
SECTIONS { .rom : { *(.rodata) *(.text) /* 可添加自定义只读段 */ } > EPROM .ram : { *(.data) *(.bss) } > RAM }
这样所有.rodata和.text内容都会被分配到EPROM,不会进入RAM。
方法4:使用编译选项统一处理const数据
部分GCC嵌入式目标支持-mconst-data-in-text-segment选项,会自动将所有const数据放入.text段,无需手动添加section属性:
#include <stdio.h> static const int one[2] = { 1, 2 }; static const int two[2] = { 3, 4 }; static const int* const parent[2] = { one, two };
编译时加上选项:
gcc -mconst-data-in-text-segment -o program sections.c
内容的提问来源于stack exchange,提问作者Graham Toal

