Gcc 在数据内存输出节中放置C变量需要哪些输入节属性?

Gcc 在数据内存输出节中放置C变量需要哪些输入节属性?,gcc,linker-scripts,dspic,Gcc,Linker Scripts,Dspic,我的应用程序有许多模块,每个模块都需要一些变量存储在片外非易失性存储器中。为了使这些数据的读取和写入更容易,我尝试将它们收集到一个连续的RAM区域中,以便NVM驱动程序在与NVM设备通信时可以寻址单个内存块 为了实现这一点,我创建了一个自定义链接器脚本,其中包含以下节定义 .nvm_fram : { /* Include the "nvm_header" input section first. */ *(.nvm_header) /* Include all o

我的应用程序有许多模块,每个模块都需要一些变量存储在片外非易失性存储器中。为了使这些数据的读取和写入更容易,我尝试将它们收集到一个连续的RAM区域中,以便NVM驱动程序在与NVM设备通信时可以寻址单个内存块

为了实现这一点,我创建了一个自定义链接器脚本,其中包含以下节定义

.nvm_fram :
{
    /* Include the "nvm_header" input section first. */    
    *(.nvm_header)
    /* Include all other input sections prefixed with "nvm_" from all modules. */    
    *(.nvm_*)

    /* Allocate a 16 bit variable at the end of the section to hold the CRC. */
    . = ALIGN(2);
    _gld_NvmFramCrc = .;
    LONG(0);
} > data
_GLD_NVM_FRAM_SIZE = SIZEOF(.nvm_fram);
使用Microchip为目标设备提供的标准定义,在内存部分定义
数据
区域

data (a!xr) : ORIGIN = 0x1000, LENGTH = 0xD000
试图将其变量放入本节的C源文件的一个示例是NVM驱动程序本身。驱动程序在NVM部分的开头保存一个简短的头结构,以便在将NVM设备加载到RAM之前验证其内容。未报告此变量的链接器错误

// Locate the NVM configuration in the non-volatile RAM section.
nvm_header_t _nvmHeader  __attribute__((section(".nvm_header")));
另一个在.nvm_fram部分中存储变量的模块是通信(CANopen)堆栈。这将在NVM中保存模块ID和比特率

// Locate LSS Slave configuration in the non-volatile RAM section.
LSS_slave_config_t _slaveConfig __attribute__((section(".nvm_canopen"))) =
    { .BitRate = DEFAULT_BITRATE, .ModuleId = DEFAULT_MODULEID };
一切都可以很好地编译,但是当链接器运行时,以下错误会停止构建

elf-ld.exe: Link Error: attributes for input section '.nvm_canopen' conflict with
output section '.nvm_fram'
重要的是,如果NVM驱动程序无法从NVM设备加载变量(为空,或软件版本已更改等),crt启动时可以使用值初始化变量,如上面的
\u slaveConfig
声明所示。这就是导致属性不匹配的原因吗

这里和Microchip论坛上有几个问题,涉及从C访问链接器脚本中定义的符号。这些问题大多涉及程序闪存中的值以及如何从C访问这些值;我知道怎么做。有,但这似乎并没有解决属性问题,而且由于特定于不同目标处理器的链接器,因此有点混乱


我已经在线阅读了Microchip linker手册和各种GCC linker文档,但找不到相关章节,因为我不太理解错误的含义以及它与我的代码的关系。什么是“input and output section attributes”(输入和输出节属性),它们在我的代码中指定在哪里,以及如何使它们相互匹配?

问题是由于
\u nvmHeader
变量在C源代码中没有为其分配初始值,而
\u slaveConfig
变量有初始值

这导致链接器推断,
.nvm\u fram
输出部分未从
.nvm\u标题
输入部分属性初始化(nbss)。因此,当它从
\u slaveConfig
变量在
.nvm\u canopen
输入部分中输入初始化数据时,输入部分属性中存在不匹配:
.nvm\u fram
用于未初始化数据,但
.nvm\u canopen
包含初始化数据

解决方案是确保要放置在
.nvm\u fram
输出部分的所有变量都在C源代码中给定了初始值

// Type used to hold metadata for the content of the NVM.
typedef struct
{
    void*       NvmBase;    // The original RAM address.
    uint16_t    NvmSize;    // The original NVM section size.
}   nvm_header_t;

// The linker supplies the gld_NVM_FRAM_SIZE symbol as a 'number'.
// This is represented as the address of an array of unspecified 
// length, so that it cannot be implicitly dereferenced, and cast
// to the correct type when used.
extern char GLD_NVM_FRAM_SIZE[];

// The following defines are used to convert linker symbols into values that
// can be used to initialise the _nvmHeader structure below.
#define NVM_FRAM_BASE ((void*)&_nvmHeader)
#define NVM_FRAM_SIZE ((uint16_t)GLD_NVM_FRAM_SIZE)

// Locate the NVM configuration in the non-volatile RAM section.
nvm_header_t _nvmHeader  __attribute__((section(".nvm_header"))) =
{
    .NvmBase = NVM_FRAM_BASE, .NvmSize = NVM_FRAM_SIZE
};
因此,答案是,输出部分属性可以部分地由该部分将位于其中的存储器区域以及分配给它的第一输入部分的属性来确定。初始化和未初始化的C变量具有不同的输入节属性,因此不能位于同一输出节中