Undocumented linker issue: "ld returned 253 exit status"

8

I am getting an error message that I cannot find any information on. Where can I find information on the 253 exit status for ld?

I cannot find anything anywhere. There is only one mention on Google, and it's seemingly unrelated with any solution.

Error message:

collect2.exe: error: ld returned 253 exit status

With verbose output for the linker and compiler there are no other warnings or errors that even vaguely relate to the above.

Attempts to find the issue

The error is related in some way to the program size, but the program has not reached the system flash size yet, so I'm a little confused.

If I run size, the following is the result (the device is limited to 64 KB):

text    data     bss     dec
45608     396    6200   52204

When I increase the device memory size to 128K, nothing changes, the same message...

However, if I reduce code size below approx 54 KB the program compiles, and doesn't matter which code I remove.

If I add only a little bit more code, the size of the binary should only increase by a few hundred bytes. But, when I do that the linker fails with the error above.

When inspecting the binary file created from objcopy, there is a huge vacant area in memory; the memory is definitely NOT full. The linker files are attached, but I don't see how they could be causing my issue:

Link removed in favor of including linker files in the question.

Update

The problem still exists, but I've noticed in the generated map file it appears to stop in the middle of a template object. It's as if the linker simply threw some exception and aborted. The line it stops at is pretty heavy template code, but it does instantiate instances of the exact thing it crashes on (or at least similar objects with the only difference being a captured lambda type. They are always a unique types as per the standard).

The last item in the map file is at 0x080008CE, and because the flash starts at address 0x08000000, this is effectively 0x08CE, which is nowhere near the end of the flash.

File sections.ld

/*
 * Default linker script for Cortex-M (it includes specifics for STM32F[34]xx).
 *
 * To make use of the multi-region initialisations, define
 * OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
 */

/*
 * The '__stack' definition is required by crt0, do not remove it.
 */
__stack = ORIGIN(RAM) + LENGTH(RAM);

_estack = __stack;     /* STM specific definition */

/*
 * Default stack sizes.
 * These are used by the startup in order to allocate stacks
 * for the different modes.
 */

__Main_Stack_Size = 1024 ;

PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;

__Main_Stack_Limit = __stack  - __Main_Stack_Size ;

/* "PROVIDE" allows to easily override these values from an
 * object file or the command line. */
PROVIDE ( _Main_Stack_Limit = __Main_Stack_Limit ) ;

/*
 * There will be a link error if there is not this amount of
 * RAM free at the end.
 */
_Minimum_Stack_Size = 256 ;

/*
 * Default heap definitions.
 * The heap start immediately after the last statically allocated
 * .sbss/.noinit section, and extends up to the main stack limit.
 */
PROVIDE ( _Heap_Begin = _end_noinit ) ;
PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;

/*
 * The entry point is informative, for debuggers and simulators,
 * since the Cortex-M vector points to it anyway.
 */
ENTRY(_start)


/* Sections Definitions */

SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .isr_vector section, which goes to FLASH.
     */
    .isr_vector : ALIGN(4)
    {
        FILL(0xFF)

        __vectors_start = ABSOLUTE(.) ;
        __vectors_start__ = ABSOLUTE(.) ;  /* STM specific definition */
        KEEP(*(.isr_vector))               /* Interrupt vectors */

        KEEP(*(.cfmconfig))                /* Freescale configuration words */

        /*
         * This section is here for convenience, to store
         * the startup code at the beginning of the flash
         * area, hoping that this will increase
         * the readability of the listing.
         */
        *(.after_vectors .after_vectors.*)  /* Startup code and ISR */

    } >FLASH

    .inits : ALIGN(4)
    {
        /*
         * Memory regions initialisation arrays.
         *
         * Thee are two kinds of arrays for each RAM region, one for
         * data and one for bss. Each is iterated at startup and the
         * region initialisation is performed.
         *
         * The data array includes:
         * - from (LOADADDR())
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * The bss array includes:
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * WARNING: It is mandatory that the regions are word aligned,
         * since the initialisation code works only on words.
         */

        __data_regions_array_start = .;

        LONG(LOADADDR(.data));
        LONG(ADDR(.data));
        LONG(ADDR(.data)+SIZEOF(.data));

        __data_regions_array_end = .;

        __bss_regions_array_start = .;

        LONG(ADDR(.bss));
        LONG(ADDR(.bss)+SIZEOF(.bss));

        __bss_regions_array_end = .;

        /* End of memory regions initialisation arrays. */

        /*
         * These are the old initialisation sections, intended to contain
         * naked code, with the prologue/epilogue added by crti.o/crtn.o
         * when linking with startup files. The standalone startup code
         * currently does not run these, better use the init arrays below.
         */
        KEEP(*(.init))
        KEEP(*(.fini))

        . = ALIGN(4);

        /*
         * The preinit code, i.e. an array of pointers to initialisation
         * functions to be performed before constructors.
         */
        PROVIDE_HIDDEN (__preinit_array_start = .);

        /*
         * Used to run the SystemInit() before anything else.
         */
        KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))

        /*
         * Used for other platform inits.
         */
        KEEP(*(.preinit_array_platform .preinit_array_platform.*))

        /*
         * The application inits. If you need to enforce some order in
         * execution, create new sections, as before.
         */
        KEEP(*(.preinit_array .preinit_array.*))

        PROVIDE_HIDDEN (__preinit_array_end = .);

        . = ALIGN(4);

        /*
         * The init code, i.e. an array of pointers
         * to static constructors.
         */
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);

        . = ALIGN(4);

        /*
         * The fini code, i.e. an array of pointers to static destructors.
         */
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP(*(SORT(.fini_array.*)))
        KEEP(*(.fini_array))
        PROVIDE_HIDDEN (__fini_array_end = .);

    } >FLASH


    /*
     * For some STRx devices, the beginning of the startup code
     * is stored in the .flashtext section, which goes to FLASH.
     */
    .flashtext : ALIGN(4)
    {
        *(.flashtext .flashtext.*)    /* Startup code */
    } >FLASH


    /*
     * The program code is stored in the .text section,
     * which goes to FLASH.
     */
    .text : ALIGN(4)
    {
        *(.text .text.*)            /* All remaining code */

         /* Read-only data (constants) */
        *(.rodata .rodata.* .constdata .constdata.*)

        *(vtable)                    /* C++ virtual tables */

        KEEP(*(.eh_frame*))

        /*
         * Stub sections generated by the linker, to glue together
         * ARM and Thumb code. .glue_7 is used for ARM code calling
         * Thumb code, and .glue_7t is used for Thumb code calling
         * ARM code. Apparently always generated by the linker,
         * for some architectures, so better leave them here.
         */
        *(.glue_7)
        *(.glue_7t)

    } >FLASH

    /* ARM magic sections */
    .ARM.extab : ALIGN(4)
       {
       *(.ARM.extab* .gnu.linkonce.armextab.*)
       } > FLASH

    . = ALIGN(4);
       __exidx_start = .;
       .ARM.exidx : ALIGN(4)
       {
       *(.ARM.exidx* .gnu.linkonce.armexidx.*)
       } > FLASH

       __exidx_end = .;

    . = ALIGN(4);
    _etext = .;
    __etext = .;


    /*
     * This address is used by the startup code to
     * initialise the .data section.
     */
    _sidata = LOADADDR(.data);

    .ConfigData : ALIGN(4)
    {
        KEEP(*(.ConfigData));
        PROVIDE (ConfigAddress = ABSOLUTE(.));
    } > CONFIG

    /*
     * The initialised data section.
     *
     * The program executes knowing that the data is in the RAM
     * but the loader puts the initial values in the FLASH (inidata).
     * It is one task of the startup to copy the initial values from
     * FLASH to RAM.
     */
    .data : ALIGN(4)
    {
        FILL(0xFF)
        /* This is used by the startup code
           to initialise the .data section */
        _sdata = . ;            /* STM specific definition */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)

        *(.data .data.*)
        *(.data_end .data_end.*)
        . = ALIGN(4);

        /* This is used by the startup code
           to initialise the .data section */
        _edata = . ;            /* STM specific definition */
        __data_end__ = . ;

    } >RAM AT>FLASH



    /* The primary uninitialised data section. */
    .bss (NOLOAD) : ALIGN(4)
    {
        __bss_start__ = .;         /* standard newlib definition */
        _sbss = .;              /* STM specific definition */
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)

        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;        /* Standard newlib definition */
        _ebss = . ;             /* STM specific definition */
    } >RAM

    .noinit (NOLOAD) : ALIGN(4)
    {
        _noinit = .;

        *(.noinit .noinit.*)

         . = ALIGN(4) ;
        _end_noinit = .;
    } > RAM


    /* Mandatory to be word aligned, _sbrk assumes this */
    PROVIDE ( end = _end_noinit ); /* was _ebss */
    PROVIDE ( _end = _end_noinit );
    PROVIDE ( __end = _end_noinit );
    PROVIDE ( __end__ = _end_noinit );

    /*
     * Used for validation only, do not allocate anything here!
     *
     * This is just to check that there is enough RAM left for the Main
     * stack. It should generate an error if it's full.
     */
    ._check_stack : ALIGN(4)
    {
        . = . + _Minimum_Stack_Size ;
    } >RAM

    /* After that there are only debugging sections. */
    /* This can remove the debugging information from the standard libraries */

    DISCARD :
    {
        libc.a ( * )
        libm.a ( * )
        libgcc.a ( * )
    }

    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /*
     * DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.
     */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
}

File mem.ld

MEMORY
{
  RAM          (xrw) : ORIGIN = 0x20000000,                    LENGTH = 0x4000
  FLASH        (rx)  : ORIGIN = 0x08000000,                    LENGTH = 0x1F800
  CONFIG       (rx)  : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 0x800
  FLASHB1      (rx)  : ORIGIN = 0x00000000,                    LENGTH = 0
  EXTMEMB0     (rx)  : ORIGIN = 0x00000000,                    LENGTH = 0
  EXTMEMB1     (rx)  : ORIGIN = 0x00000000,                    LENGTH = 0
  EXTMEMB2     (rx)  : ORIGIN = 0x00000000,                    LENGTH = 0
  EXTMEMB3     (rx)  : ORIGIN = 0x00000000,                    LENGTH = 0
  MEMORY_ARRAY (xrw) : ORIGIN = 0x00000000,                    LENGTH = 0
}

Update 2

The code in question, that is being linked at the time the error occurs, does link in Visual Studio.

Update 3

With fresh linker files and with the following flags, the bug still occurs:

arm-none-eabi-g++ -mcpu=cortex-m0 -march=armv6-m -mthumb -Os -fmessage-length=0 -ffreestanding -flto -Wunused -Wuninitialized -Wall -Wextra  -g -T "../ldscripts/mem.ld" -T "../ldscripts/sections.ld" -T "../ldscripts/libs.ld" -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"uSupply Firmware V1_0.map" --specs=nano.specs -o "uSupply Firmware V1_0.elf"  ./system/src/stm32f0-stdperiph/stm32f0xx_adc.o ./system/src/stm32f0-stdperiph/stm32f0xx_can.o ./system/src/stm32f0-stdperiph/stm32f0xx_cec.o ./system/src/stm32f0-stdperiph/stm32f0xx_comp.o ./system/src/stm32f0-stdperiph/stm32f0xx_crc.o ./system/src/stm32f0-stdperiph/stm32f0xx_crs.o ./system/src/stm32f0-stdperiph/stm32f0xx_dac.o ./system/src/stm32f0-stdperiph/stm32f0xx_dbgmcu.o ./system/src/stm32f0-stdperiph/stm32f0xx_dma.o ./system/src/stm32f0-stdperiph/stm32f0xx_exti.o ./system/src/stm32f0-stdperiph/stm32f0xx_flash.o ./system/src/stm32f0-stdperiph/stm32f0xx_gpio.o ./system/src/stm32f0-stdperiph/stm32f0xx_i2c.o ./system/src/stm32f0-stdperiph/stm32f0xx_iwdg.o ./system/src/stm32f0-stdperiph/stm32f0xx_misc.o ./system/src/stm32f0-stdperiph/stm32f0xx_pwr.o ./system/src/stm32f0-stdperiph/stm32f0xx_rcc.o ./system/src/stm32f0-stdperiph/stm32f0xx_rtc.o ./system/src/stm32f0-stdperiph/stm32f0xx_spi.o ./system/src/stm32f0-stdperiph/stm32f0xx_syscfg.o ./system/src/stm32f0-stdperiph/stm32f0xx_tim.o ./system/src/stm32f0-stdperiph/stm32f0xx_usart.o ./system/src/stm32f0-stdperiph/stm32f0xx_wwdg.o  ./system/src/newlib/_cxx.o ./system/src/newlib/_exit.o ./system/src/newlib/_sbrk.o ./system/src/newlib/_startup.o ./system/src/newlib/_syscalls.o ./system/src/newlib/assert.o  ./system/src/diag/Trace.o ./system/src/diag/trace_impl.o  ./system/src/cortexm/_initialize_hardware.o ./system/src/cortexm/_reset_hardware.o ./system/src/cortexm/exception_handlers.o  ./system/src/cmsis/system_stm32f0xx.o ./system/src/cmsis/vectors_stm32f0xx.o  ./src/peripherals/Interrupt.o  ./src/_write.o ./src/main.o
c++
ld
asked on Stack Overflow Nov 12, 2018 by David Ledger • edited Dec 18, 2019 by marc_s

1 Answer

4

The reason for the error was that VLA's were used in the implementation of Libiberty. VLA's are data structures placed on the stack which, when a program has a large numbers of symbols, blows through the application's stack limit. In Libiberty there is a flag that permits avoiding VLA's, and the result is use of alloca. This allocation occurs on the stack, and the same issue occurs.

GCC 7.2 generates much more symbol information than GCC 8.2.

Solutions are threefold:

  1. On Linux, use ulimit -s unlimited and launch GCC 7.2 from the same terminal window. ulimit only affects child processes.
  2. On Windows, recompile GCC ld.exe with a different stack size for Windows. editbin didn't work correctly on ld.exe.
  3. Windows/Linux: upgrade to GCC 8.2. This version of the compiler is much better with symbols, and the issue resolves itself in this scenario.

The issue has been raised with Libiberty by Tamar Christina, and I suspect that, just like the Linux kernel, VLA's will be removed from the implementation.

answered on Stack Overflow Jan 23, 2019 by David Ledger • edited Sep 4, 2019 by Peter Mortensen

User contributions licensed under CC BY-SA 3.0