【问题标题】:section .data will not fit in region 'dff' error部分 .data 将不适合区域 \'dff\' 错误
【发布时间】:2022-11-14 17:19:56
【问题描述】:

我试图在 RISCV 处理器上运行一些 c 程序,我得到了这个:

/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

根据this线程中的评论,这可能是由于声明了一些大型全局数组引起的。对我来说确实如此,我在全球范围内拥有这些(在主要功能之外):

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};

我需要将这些数据从 RISCV 发送到某个数字电路。我怎样才能做到这一点(如果有办法)。谢谢你。

链接器文件

/* 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));

【问题讨论】:

  • 您可能需要提供有关您的区域大小、RAM、节...以及链接器设置的其他详细信息的更多信息。
  • 那是真实数据还是接近真实数据?所有值都在 1 位范围内吗?它们是否需要以与 thea 存储在内存中的方式相同的方式发送?您可以通过使用uint8_t 而不是int 来减小数组的大小,并且在发送前仅转换为int
  • Bits 的值是多少?
  • 谢谢大家的cmets。我将 int 更改为 uint8_t 并且错误现在消失了@Gerhardh - 是的,这些是我要发送的完全相同的数据。
  • 运行时数组是否不变?如果您制作这样的数组const,它们不会填满您宝贵的 RAM。如果您的链接描述文件设计良好,它们将被分配到 ROM(闪存等)。

标签: c gcc ram riscv


【解决方案1】:

能否请您指向一个链接以自己理解链接器脚本? – 温度1445

我在"linker script" documentation 上进行了网络搜索并得到(在 1.2M 中):https://wiki.osdev.org/Linker_Scripts

我下载了您链接到的存储库 [全部 14 GB ;-)]。在 repo 中,我们有几个文件:

./verilog/dv/caravel/sections.lds
./verilog/dv/caravel/mgmt_soc/irq/sections.lds

除了RAM 的源地址之外,它们是相似的。这是第一个的sn-p:

MEMORY {
    FLASH (rx)  : ORIGIN = 0x10000000, LENGTH = 0x400000    /* 4MB */
    RAM(xrw)    : ORIGIN = 0x00000000, LENGTH = 0x0400      /* 256 words (1 KB) */
}

这意味着你只要1 KB公羊!

但是,您的示例指的是dff。有一个 python 脚本通过该名称引用链接器脚本,但它必须是 [auto-] 生成的,因为树中没有 dff.lds


AFAICT,caravel用于 riscv FPGA 或 ASIC 实现的级别 verilog/VHDL 设计。

完成 [linux] S/W 内核移植到新的 ASIC CPU 设计 [20 年前],使用水平模拟器。

但是,这可以非常减缓。

例如,在启动期间,linux 会进入一个自旋循环来计算 CPU 速度(即 BogoMIPS)。这个测试,在真实的硬件上只需要一小部分时间(例如 1 毫秒)。在模拟器上,花了一整天的时间。

所以,我用 NOP 替换了那个循环,并硬连线了频率(使用(例如)):

#ifdef _USE_GATE_SIMULATOR_
bogoMIPS = 200;
#else
while (...) {
}
bogoMIPS = ...;
#endif

然后,我们必须为 [提议的] H/W 开发 S/W 设备驱动程序。某些硬件的verilog 代码不完整。

但是,我们确实有硬件的功能规格。

我们的解决方案是在以下方面进行大部分软件开发:

  1. 一个功能性的模拟器(类似于qemu),我们在其中添加了硬件设备的仿真。
  2. 用户空间代码,在运行 x86 代码的开发机器(例如 x86 PC)上运行,并有一个库允许我们调用硬件仿真函数。
  3. 具有相似硬件的真正硬件 SDK 板
  4. 门级模拟器

    我们将 S/W 配置为能够通过条件编译在任何这些环境中工作。

    我们使用 (2) 和 (1) 完成了大部分 S/W 开发工作。当我们 99.44% 确定没有软件错误(例如 UB 等),只有这样我们才能使用 (3) 进行完整验证。

    这样,我们就没有燃烧小时在 5 秒内在 SDK 板或模拟器上找到一个 [微不足道的] S/W 错误的模拟器时间。

    这也使程序员能够独立于硬件设计人员的 verilog 代码调试软件 [通常有更多的比 S/W 做的错误]。


    您没有指定您的主要目标是什么,但我强烈推荐这样的构建环境。

    如果您只是想在装配级别试验 riscv 架构,那么我会使用 qemu 或等效的。

    如果您尝试编写 S/W 来驱动当前/建议的 H/W 设备,我仍然会推荐与我们所拥有的类似的策略。

【讨论】:

  • 有价值的东西。非常感谢您的分享。很高兴你浏览了 caravel :) 它是用于 asic 设计的,它有一个用户空间来适应我们的设计,我们使用 riscv(核心管理包装器)来配置 padframe 上的 gpio pad,并将其用作输入/输出源/sink(我打算这样做)
【解决方案2】:

您的程序定义了一些比可用 RAM 更大的大数组。错误消息说(用链接器的路径剪切前缀):

test_la.elf section `.data' will not fit in region `dff'
region `dff' overflowed by 1624 bytes

.data 部分收集所有可写静态*变量,这包括数组。由于此部分分配在区域dff 中,因此会溢出。

现在你至少有两个选择。

1.减小数组的大小

您在评论中说数组中的所有值都如图所示小,范围为 0 到 6。元素数据类型为 int,其大小似乎为 4 个字节。这对于存储小值来说很多。

您可以发明一些方法将只需要的位打包到可用空间中,但这需要在运行时进行一些解包代码,具体取决于值的用途。

一种更简单的方法是使用尽可能最小且适当的数据类型,在您的情况下为uint8_t。正如您在评论中确认的那样,您这样做了,它暂时解决了这个问题。

但是,一旦您在程序中添加更多变量,同样的问题就会再次出现。因此,我建议使用第二个选项。

根据值的使用,您还可以组合这两个选项,从而最大限度地减少 ROM 中阵列的占用空间。

2.将阵列移动到ROM

正如您在评论中确认的那样,您的程序只读取这些数组的值,它们的内容是固定的。

将修饰符 const 添加到它们。这会将它们放入.rodata 部分,这意味着“只读数据”。由于此部分分配在flash 区域中,因此它不会填满您稀缺的 RAM。

注意:请注意,某些处理器可能需要特殊指令才能从 ROM 读取数据。根据编译器的必要性和聪明程度,这可能需要更改您的代码,也可能不需要。只是说。

无论如何,您应该始终使用修饰符来显示这些特征。初学者的课程很少能做到这一点,而在个人电脑上他们没有。但在嵌入式世界中,始终使用const 修改只读变量。


这是检查内存使用情况的提示:让链接器生成一个映射文件。对于基于 GNU 的工具链,请查找 the option -Map。例如,如果您通过前端“gcc”运行链接器,您可以将-Wl,-Map=output.map 添加到命令行。


*) 全局变量也是静态的。

【讨论】:

  • 非常感谢您的参与。很棒的信息。事情现在更清楚了。抱歉,在哪里查找 -Map 选项?
  • 查看我的编辑,它添加了一个链接。对“gnu linker map”的网络搜索揭示了这一点。如果您认为这回答了您的问题,请将其标记为已接受。
猜你喜欢
  • 1970-01-01
  • 2017-06-21
  • 2016-04-02
  • 2013-08-24
  • 1970-01-01
  • 2014-10-08
  • 2022-11-23
  • 2017-03-05
  • 2021-11-16
相关资源
最近更新 更多