链接期间阵列多个定义错误

Arrays multiple definition errors during linking

我正在尝试制作 GNUK software buildable with PlatformIO 系统。我已将 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,
};

我得到的错误是:

.pio\build\OLIMEX_STM32_H103\src\sys.o:(.sys.version+0x0): multiple definition of `sys_version'
.pio\build\OLIMEX_STM32_H103\src\sys.o:(.sys.version+0x0): first defined here
.pio\build\OLIMEX_STM32_H103\src\sys.o:(.vectors+0x0): multiple definition of `vector'
.pio\build\OLIMEX_STM32_H103\src\sys.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)
    src\sys.o(.text)
    src\sys.o(.text.*)
    src\sys.o(.rodata)
    src\sys.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__;

解决方案是将 linker 脚本中的 src\sys.o 替换为 *sys.o

如ld手册所述,

In any place where you may use a specific file or section name, you may also use a wildcard pattern. The linker handles wildcards much as the Unix shell does. A '*' character matches any number of characters. A '?' character matches any single character. The sequence '[chars]' will match a single instance of any of the chars; the '-' character may be used to specify a range of characters, as in '[a-z]' to match any lower case letter. A '' character may be used to quote the following character.

When a file name is matched with a wildcard, the wildcard characters will not match a '/' character (used to separate directory names on Unix). A pattern consisting of a single '*' character is an exception; it will always match any file name. In a section name, the wildcard characters will match a '/' character.

Wildcards only match files which are explicitly specified on the command line. The linker does not search directories to expand wildcards. However, if you specify a simple file name --a name with no wildcard characters-- in a linker script, and the file name is not also specified on the command line, the linker will attempt to open the file as though it appeared on the command line.

sys.o 文件在命令行中指定的路径与 linker 文件中的路径不同,因此 linker 尝试 link 它两次。