RISCV处理器运行C程序遇.data段无法放入dff区域错误求助
解决RISC-V中全局数组导致的链接器内存溢出问题
问题详情
链接器报错如下:
/foss/tools/riscv-gnu-toolchain-rv32i/217e7f3debe424d61374d31e33a091a630535937/lib/gcc/riscv32-unknown-linux-gnu/11.1.0/../../../../riscv32-unknown-linux-gnu/bin/ld: test_la.elf section `.data' will not fit in region `dff' /foss/tools/riscv-gnu-toolchain-rv32i/217e7f3debe424d61374d31e33a091a630535937/lib/gcc/riscv32-unknown-linux-gnu/11.1.0/../../../../riscv32-unknown-linux-gnu/bin/ld: region `dff' overflowed by 1624 bytes collect2: error: ld returned 1 exit status
报错原因是声明了多个大型全局初始化数组,占用过多.data段空间,超出dff区域容量。数组声明如下:
int sig_A [Bits] = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; int sig_B [Bits] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int sig_C [Bits] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}; int data_i [Bits] = { 0, 0, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 0};
当前使用的链接器脚本:
/* Copyright lowRISC contributors. Licensed under the Apache License, Version 2.0, see LICENSE for details. SPDX-License-Identifier: Apache-2.0 */ INCLUDE ../generated/output_format.ld OUTPUT_ARCH(riscv) /******* MEMORY { Change this if you'd like different sizes. Arty A7-100(35) has a maximum of 607.5KB(225KB) BRAM space. Configuration below is for maximum BRAM capacity with Artya A7-35 while letting CoreMark run (.vmem of 152.8KB). ram : ORIGIN = 0x00100000, LENGTH = 0x30000 * 192 kB * stack : ORIGIN = 0x00130000, LENGTH = 0x8000 * 32 kB * } **********/ _entry_point = _vectors_start + 0x80; ENTRY(_entry_point) /* The tohost address is used by Spike for a magic \"stop me now\" message. This is set to equal SIM_CTRL_CTRL (see simple_system_regs.h), which has that effect in simple_system simulations. Note that it must be 8-byte aligned. We don't read data back from Spike, so fromhost is set to some dummy value: we place it just above the top of the stack. */ tohost = 0x20008; fromhost = _stack_start + 0x10; SECTIONS { .vectors : { . = ALIGN(4); _vectors_start = .; KEEP(*(.vectors)) _vectors_end = .; } > flash .text : { . = ALIGN(4); *(.text) *(.text.*) } > flash .rodata : { . = ALIGN(4); /* Small RO data before large RO data */ *(.srodata) *(.srodata.*) *(.rodata); *(.rodata.*) } > flash .data : { . = ALIGN(4); /* Small data before large data */ *(.sdata) *(.sdata.*) *(.data); *(.data.*) } > dff AT > flash .bss : { . = ALIGN(4); _bss_start = .; /* Small BSS before large BSS */ *(.sbss) *(.sbss.*) *(.bss) *(.bss.*) *(COMMON) _bss_end = .; } > dff } PROVIDE(_stack_start = ORIGIN(sram) + LENGTH(sram));
需求是将这些数据从RISC-V发送到数字电路,以下是可行的解决方法:
解决方法
1. 将数组改为只读常量,移至Flash存储区
这些数组是初始化好的固定数据,不需要运行时修改,直接用const修饰,编译器会将其放入.rodata段,而链接器脚本中.rodata映射到flash区域(通常Flash空间远大于片内RAM),不会占用dff的空间。
修改后的数组声明:
const int sig_A [Bits] = { ... }; const int sig_B [Bits] = { ... }; const int sig_C [Bits] = { ... }; const int data_i [Bits] = { ... };
读取这些只读数据发送到数字电路的逻辑不受影响,因为只是读取操作,不需要修改数组内容。
2. 调整链接器脚本,扩大dff区域容量
检查链接器脚本中包含的output_format.ld文件,找到dff区域的定义,增大其LENGTH值,只要不超过硬件实际的RAM容量即可。如果dff就是注释中提到的ram区域,可以取消注释并调整ram的LENGTH:
MEMORY { ram : ORIGIN = 0x00100000, LENGTH = 0x38000 /* 增大到224KB,根据硬件实际情况调整 */ stack : ORIGIN = 0x00138000, LENGTH = 0x8000 /* 32KB栈空间 */ }
同时要确保SECTIONS中.data和.bss的> dff改为> ram(如果dff是ram的别名),或者直接修改dff的定义。
3. 动态分配内存存储数组
将全局数组改为在main函数中通过malloc动态分配堆内存,这样数据会放在堆区,不占用全局.data段空间:
#include <stdlib.h> #include <string.h> int main() { // 分配内存 int *sig_A = malloc(Bits * sizeof(int)); int *sig_B = malloc(Bits * sizeof(int)); int *sig_C = malloc(Bits * sizeof(int)); int *data_i = malloc(Bits * sizeof(int)); // 初始化数据(可以把原数组内容作为const数组放在.rodata,然后memcpy) const int sig_A_init[] = { ... }; memcpy(sig_A, sig_A_init, sizeof(sig_A_init)); // 其他数组同理 // 发送数据到数字电路的逻辑... // 释放内存(如果不再需要) free(sig_A); free(sig_B); free(sig_C); free(data_i); return 0; }
注意:需要确保链接器脚本配置了足够的堆空间,或者使用的libc支持动态内存分配。
4. 外部存储加载数据(适合超大数据)
如果数据量超过片内存储的最大容量,可以将数组数据存储在外部Flash、SD卡等存储设备中,程序启动后通过硬件总线读取数据到内存,再发送到数字电路。这种方法需要硬件支持外部存储,同时编写对应的驱动代码实现数据读取。
内容的提问来源于stack exchange,提问作者temp1445
相关产品推荐
相关产品推荐

