gcc 节,数据将不适合区域“dff”错误

rqqzpn5f  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(171)

我试着在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线程中的一个注解,这可能是由于声明了一些大型的全局数组引起的。对我来说也是如此,我在全局(main函数之外)有这些数组:

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));
aiazj4mn

aiazj4mn1#

你能不能给我一个链接,让我自己理解链接器脚本?-temp1445
我在"linker script" documentation上做了一个网络搜索,得到了(在120万中):https://wiki.osdev.org/Linker_Scripts
我下载了你链接到的回购协议[全部14 GB; - )].在repo中,我们有几个文件:

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

除了源地址RAM之外,它们是相似的。

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)。在真实的硬件上,这个测试只需要一小部分秒(例如1ms)。在模拟器上,这个测试需要一整天。
因此,我用NOP替换了该环路,并将频率硬连线(使用(e.g.)):

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

然后,我们必须为[建议的]硬件开发软件设备驱动程序。某些硬件的verilog代码不完整。
但是,我们确实有硬件的功能规格。
我们的解决方案是在以下平台上进行大部分软件开发:
1.一个 * 功能 * 仿真器(类似于qemu),我们在其中添加了硬件设备的仿真。
1.用户空间代码,在运行x86代码的开发机器(例如x86 PC)上运行,并具有允许我们调用H/W仿真函数的库。
1.具有类似硬件的真实硬件SDK板
1.门级模拟器
我们将软件配置为能够在这些环境中使用条件编译工作。
我们使用(2)和(1)进行了大部分软件开发工作。当我们99.44%确定没有 * 软件 * 错误(例如UB等)时,我们才使用(3)进行全面验证。
这样,我们就不会浪费 * 小时 * 的模拟器时间来查找一个在SDK板或模拟器上5秒内发现的[微不足道的]软件错误。
这也允许程序员能够独立于硬件设计者的verilog代码(通常比软件有 * 更多 * 的错误)调试软件。
您没有指定您的主要目标是什么,但是我强烈推荐这样的构建环境。
如果您只是想在汇编级试验riscv架构,那么我会使用qemu或等效的代码。
如果您尝试编写软件来驱动当前/提议的硬件设备,我仍然建议采用与我们所采用的策略类似的策略。

wfauudbj

wfauudbj2#

你的程序定义了一些大的数组,它们比可用的RAM大。错误信息显示(用链接器的路径去掉前缀):

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

.data部分收集所有可写的static * 变量,其中包括数组。由于该部分被分配在dff区域中,它将溢出。
现在你至少有两个选择。

1.减小数组的大小

您在注解中说数组中的所有值都如图所示一样小,范围在0到6之间。元素数据类型为int,大小似乎为4个字节。这对于存储小值来说太大了。
您可以发明一些方法,只将所需的位压缩到可用空间中,但这需要在运行时使用一些解压缩代码,具体取决于值的用途。
一个更简单的方法是使用尽可能小的合适的数据类型,比如uint8_t
但是,一旦你在程序中添加更多的变量,同样的问题就会再次出现,因此,我建议使用第二种方法。
根据值的使用情况,您还可以将这两个选项结合使用,从而最大限度地减少ROM中数组的占用空间。

2.将阵列移动到ROM

正如你在注解中确认的那样,你的程序只读取这些数组的值,它们的内容是固定的。
给它们加上修饰符const。这会把它们放到.rodata部分,意思是"只读数据"。因为这个部分是在flash区域中分配的,所以它不会填满你稀缺的RAM。

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

无论如何,你应该总是使用修饰符来显示这些特征。初学者的课程很少涉及到这一点,在PC上他们也不需要。但在嵌入式世界中,总是用const来修改只读变量。
下面是检查内存使用情况的提示:让链接器生成一个Map文件。对于基于GNU的工具链,查找the option -Map。例如,如果你通过前端"gcc"运行链接器,你可以在命令行中添加-Wl,-Map=output.map

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

相关问题