Overridden weak symbol being discarded when using -flto

Asked by Kyle

Building a file which overrides _write (to enable redirection to an external communication interface) with link-time optimization produces the error:

`_write' referenced in section `.text._write_r' of c:/program files (x86)/gnu tools arm embedded/4.9 2014q4/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv6-m\libg_nano.a(lib_a-writer.o): defined in discarded section `.text' of main.o (symbol from plugin)
collect2.exe: error: ld returned 1 exit status

This is reproducible using both 4.8.4 and 4.9.3 (Q4 2014 release), only when using link-time optimization. I am running on Windows 7 64-bit edition. Is this a bug in the compiler, or is there a problem with my invocation? Thanks.

The compiler and linker are invoked as follows:
arm-none-eabi-gcc.exe -mcpu=cortex-m0 -mthumb -Wno-main -I. -g -D DEBUG -Wall -ffunction-sections -O0 -flto -c main.c -o main.o
arm-none-eabi-gcc.exe -Wl,--start-group -o Main.elf main.o -mthumb -march=armv6-m -T cm0gcc.ld -g -specs=nano.specs -flto -Os -Wl,--gc-sections -Wl,--end-group

The main.c in question is:
#include <stdio.h>

int _write(int file, char *ptr, int len)
{
    int i;
    file = file;
    for (i = 0; i < len; i++)
    {
         // put character to UART omitted
    }
    return len;
}

int main()
{
    for(;;)
    {
        printf("hello");
    }
}

/* [] END OF FILE */

cm0gcc.ld is as follows:
/* Linker script for ARM M-profile Simulator
 *
 * Version: Sourcery G++ Lite 2010q1-188
 * Support: https://support.codesourcery.com/GNUToolchain/
 *
 * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc.
 *
 * The authors hereby grant permission to use, copy, modify, distribute,
 * and license this software and its documentation for any purpose, provided
 * that existing copyright notices are retained in all copies and that this
 * notice is included verbatim in any distributions. No written agreement,
 * license, or royalty fee is required for any of the authorized uses.
 * Modifications to this software may be copyrighted by their authors
 * and need not follow the licensing terms described here, provided that
 * the new terms are clearly indicated on the first page of each file where
 * they apply.
 */
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  rom (rx) : ORIGIN = 0x0, LENGTH = 131072
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16384
}

/* Bring in the interrupt routines & vector */
EXTERN(main)

/* Provide fall-back values */
PROVIDE(__cy_heap_start = _end);
PROVIDE(__cy_region_num = (__cy_regions_end - __cy_regions) / 16);

/* Set stack top to end of RAM, and stack limit move down by
 * size of .stack section.
 */
PROVIDE(__cy_stack = ORIGIN(ram) + LENGTH(ram));

PROVIDE(__cy_heap_end = __cy_stack - 0x0800);

SECTIONS
{
  appl_start = 0;

  .text appl_start :
  {
    CREATE_OBJECT_SYMBOLS

    *(.romvectors)

    . = MAX(., 0x100);

    *(.text .text.* .gnu.linkonce.t.*)
    *(.plt)
    *(.gnu.warning)
    *(.glue_7t) *(.glue_7) *(.vfp11_veneer)

    *(.ARM.extab* .gnu.linkonce.armextab.*)
    *(.gcc_except_table)
  } >rom
  .eh_frame_hdr : ALIGN (4)
  {
    KEEP (*(.eh_frame_hdr))
  } >rom
  .eh_frame : ALIGN (4)
  {
    KEEP (*(.eh_frame))
  } >rom
  /* .ARM.exidx is sorted, so has to go in its own output section. */
  PROVIDE_HIDDEN (__exidx_start = .);
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } >rom
  __exidx_end = .;
  .rodata : ALIGN (4)
  {
    *(.rodata .rodata.* .gnu.linkonce.r.*)

    . = ALIGN(4);
    KEEP(*(.init))

    . = ALIGN(4);
    __preinit_array_start = .;
    KEEP (*(.preinit_array))
    __preinit_array_end = .;

    . = ALIGN(4);
    __init_array_start = .;
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    __init_array_end = .;

    . = ALIGN(4);
    KEEP(*(.fini))

    . = ALIGN(4);
    __fini_array_start = .;
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    __fini_array_end = .;

    . = ALIGN(0x4);
    KEEP (*crtbegin.o(.ctors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*crtend.o(.ctors))

    . = ALIGN(0x4);
    KEEP (*crtbegin.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*crtend.o(.dtors))

    . = ALIGN(4);
    __cy_regions = .;
    LONG (__cy_region_init_ram)
    LONG (__cy_region_start_data)
    LONG (__cy_region_init_size_ram)
    LONG (__cy_region_zero_size_ram)
    __cy_regions_end = .;

    . = ALIGN (8);
    _etext = .;
  } >rom

  .ramvectors (NOLOAD) : ALIGN(8)
  {
    __cy_region_start_ram = .;
    KEEP(*(.ramvectors))
  }

  .noinit (NOLOAD) : ALIGN(8)
  {
    KEEP(*(.noinit))
  }

  .data : ALIGN(8)
  {
    __cy_region_start_data = .;

    KEEP(*(.jcr))
    *(.got.plt) *(.got)
    *(.shdata)
    *(.data .data.* .gnu.linkonce.d.*)
    . = ALIGN (8);
    *(.ram)
    _edata = .;
  } >ram AT>rom
  .bss : ALIGN(8)
  {
    PROVIDE(__bss_start__ = .);
    *(.shbss)
    *(.bss .bss.* .gnu.linkonce.b.*)
    *(COMMON)
    . = ALIGN (8);
    *(.ram.b)
    _end = .;
    __end = .;
  } >ram AT>rom
  PROVIDE(end = .);
  PROVIDE(__bss_end__ = .);

  __cy_region_init_ram = LOADADDR (.data);
  __cy_region_init_size_ram = _edata - ADDR (.data);
  __cy_region_zero_size_ram = _end - _edata;

  /* The .stack and .heap sections don't contain any symbols.
   * They are only used for linker to calculate RAM utilization.
   */
  .heap (NOLOAD) :
  {
    . = _end;
    . += 0x80;
    __cy_heap_limit = .;
  } >ram

  .stack (__cy_stack - 0x0800) (NOLOAD) :
  {
    __cy_stack_limit = .;
    . += 0x0800;
  } >ram

  /* Check if data + heap + stack exceeds RAM limit */
  ASSERT(__cy_stack_limit >= __cy_heap_limit, "region RAM overflowed with stack")

  .stab 0 (NOLOAD) : { *(.stab) }
  .stabstr 0 (NOLOAD) : { *(.stabstr) }
  /* 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) }
  /* DWARF 2.1 */
  .debug_ranges 0 : { *(.debug_ranges) }
  /* 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) }

  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
  /DISCARD/ : { *(.note.GNU-stack) }
}

Question information

Language:
English Edit question
Status:
Answered
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Terry Guo (terry.guo) said :
#1

For the time being, you can redefine your function as below to avoid such error:

int __attribute__((used)) _write(int file, char *ptr, int len)

In fact, it is still a problem of LTO. I am testing your case with latest gcc/binutils.

By the way, if you want to use -ffunction-sections, you need to add this option to all your build steps including the last link step.

Revision history for this message
Kyle (kyle-7) said :
#2

Thanks for investigating this and for the workaround. I have confirmed that this eliminates the error in 4.9.3 but not 4.8.4. Is that the expected behavior?

Revision history for this message
Terry Guo (terry.guo) said :
#3

The GCC LTO feature has been vastly changed and improved from 4.8.4 to 4.9.3. So what you are seeing in 4.8.4 could be a bug or missing part of old LTO. If you like LTO, I suggest you to stay with recent gcc like 4.9.3.

Can you help with this problem?

Provide an answer of your own, or ask Kyle for more information if necessary.

To post a message you must log in.