c-在链接过程中排列多个定义错误



我正在尝试使用PlatformIO系统构建GNUK软件。我已经将Makefile转换为platformio.ini项目文件,所有源文件都编译得很好,但我的一个C源文件中定义的两个数组的链接器多个定义错误。我的源文件的相关部分是:

typedef void (*handler)(void);
handler vector[] __attribute__ ((section(".vectors"))) = {
(handler)&__ram_end__,
reset,
(handler)set_led,
flash_unlock,
(handler)flash_program_halfword,
(handler)flash_erase_page,
(handler)flash_check_blank,
(handler)flash_write,
(handler)flash_protect,
(handler)flash_erase_all_and_exec,
usb_lld_sys_init,
usb_lld_sys_shutdown,
nvic_system_reset,
};
const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = {
3*2+2,         /* bLength */
0x03,          /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE*/
/* sys version: "1.0" */
'1', 0, '.', 0, '0', 0,
};

我得到的错误是:

.piobuildOLIMEX_STM32_H103srcsys.o:(.sys.version+0x0): multiple definition of `sys_version'
.piobuildOLIMEX_STM32_H103srcsys.o:(.sys.version+0x0): first defined here
.piobuildOLIMEX_STM32_H103srcsys.o:(.vectors+0x0): multiple definition of `vector'
.piobuildOLIMEX_STM32_H103srcsys.o:(.vectors+0x0): first defined here

我被它卡住了,甚至不知道从哪里开始。如果我在源文件中添加新的变量,我也会得到类似的链接器错误。看起来同一个文件被链接了两次?

链接器脚本内容为:

__main_stack_size__     = 0x0400;
__process_stack_size__  = 0x0200;
__stacks_total_size__   = __main_stack_size__ + __process_stack_size__;
MEMORY
{
flash0 : org = 0x08000000, len = 4k
flash  : org = 0x08000000+0x1000, len = 128k - 4k
ram : org = 0x20000000, len = 20k
}
/* __flash_start__: flash ROM start address regardless of DFU_SUPPORT */
__flash_start__         = 0x08001000;
__flash_end__       = ORIGIN(flash) + LENGTH(flash);
__ram_start__           = ORIGIN(ram);
__ram_size__            = LENGTH(ram);
__ram_end__             = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
.sys : ALIGN(16) SUBALIGN(16)
{
_sys = .;
KEEP(*(.vectors))
. = ALIGN(16);
*(.sys.version)
srcsys.o(.text)
srcsys.o(.text.*)
srcsys.o(.rodata)
srcsys.o(.rodata.*)
. = ALIGN(1024);
*(.sys.0)
*(.sys.1)
*(.sys.2)
} > flash0
.text : ALIGN(16) SUBALIGN(16)
{
_text = .;
KEEP(*(vectors))
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > flash
.ctors :
{
PROVIDE(_ctors_start_ = .);
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
PROVIDE(_ctors_end_ = .);
} > flash
.dtors :
{
PROVIDE(_dtors_start_ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(_dtors_end_ = .);
} > flash
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)}
__exidx_start = .;
.ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > flash
__exidx_end = .;
.eh_frame_hdr : {*(.eh_frame_hdr)}
.eh_frame : ONLY_IF_RO {*(.eh_frame)}
. = ALIGN(4);
_etext = .;
_textdata = _etext;
.data :
{
_data = .;
*(.data)
. = ALIGN(4);
*(.data.*)
. = ALIGN(4);
*(.ramtext)
. = ALIGN(4);
_edata = .;
} > ram AT > flash
.bss :
{
_bss_start = .;
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(4);
_bss_end = .;
} > ram
PROVIDE(end = .);
_end            = .;
. = ALIGN(512);
_regnual_start = .;

.gnuk_flash :
{
. = ALIGN (1024);
_data_pool = .;
KEEP(*(.gnuk_data))
. = ALIGN(1024);
. += 1024;
_keystore_pool = .;
. += 512*3;
. = ALIGN(1024);
_updatekey_store = .;
. += 1024;
. = ALIGN(1024);
} > flash =0xffffffff
}
__heap_base__   = _end;
__heap_end__    = __ram_end__ - __stacks_total_size__;

解决方案是用*sys.o替换链接器脚本中的srcsys.o

如ld手册所述,

在任何可能使用特定文件或节名的地方也可以使用通配符模式。链接器处理通配符的方式与Unix shell就是这样。"*"字符与任意数量的字符匹配。A"?"字符匹配任何单个字符。序列"[chars]"将匹配任何字符的单个实例;"-"字符可以用于指定一个字符范围,如"[a-z]"中要匹配的字符任何小写字母。"字符可用于引用以下字符。

当文件名与通配符匹配时,通配符字符将与"/"字符(用于分隔上的目录名Unix(。由单个"*"字符组成的模式是一个例外;它将始终与任何文件名匹配。在节名称中,通配符字符将与"/"字符匹配。

通配符只匹配在命令行。链接器不搜索要展开的目录通配符。但是,如果您指定一个简单的文件名——一个没有通配符--在链接器脚本中,并且文件名不是在命令行上指定,链接器将尝试打开文件,就好像它出现在命令行上一样。

sys.o文件是在命令行上指定的,其路径与链接器文件中的路径不同,因此链接器尝试链接它两次。

最新更新