llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.26k stars 12.08k forks source link

[LLD] [AVR] Linker script error: LLD unable to SORT by filename pattern #115266

Open dakkshesh07 opened 2 weeks ago

dakkshesh07 commented 2 weeks ago

Trying to cross compile AVR program but the final linking seems to fail due to some syntax error in the linkerscript.

clang++ --target=avr -o firmware.elf -mmcu=atmega2560 --sysroot=${SYSROOT_DIR} -I${SYSROOT_DIR}/avr/include -L"${SYSROOT_DIR}/lib" -ffunction-sections -fdata-sections -fpermissive -fno-exceptions -fno-threadsafe-statics -fno-rtti -Wl,--gc-sections out/main/main.cpp.o out/libArduinoCore.a -lm -fuse-linker-plugin -fuse-ld=lld

error:

ld.lld: error: /mnt/c/Users/chana/Downloads/Arch/sysroot/lib/gcc/avr/14.1.0/../../../../avr/lib/ldscripts/avr6.x:115: ) expected, but got (
>>>     KEEP(SORT(*)(.ctors))
>>>                 ^
clang++: error: avr-ld command failed with exit code 1 (use -v to see invocation)

linkerscript snip:

/* Internal text space or external memory.  */
  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    /* PR 13812: Placing the trampolines here gives a better chance
       that they will be in range of the code that uses them.  */
    . = ALIGN(2);
    __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
    *(.trampolines*)
    __trampolines_end = . ;
    /* avr-libc expects these data to reside in lower 64K. */
    *libprintf_flt.a:*(.progmem.data)
    *libc.a:*(.progmem.data)
    *(.progmem.*)
    . = ALIGN(2);
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
    *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we do not bother about whether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))

Is this because LLD expects it in a different syntax? because all these linkerscripts from gnu binutils have been in use with gcc avr from a long time. Im just trying to fix things and get it working with LLVM as well.

llvmbot commented 2 weeks ago

@llvm/issue-subscribers-lld-elf

Author: Dakkshesh (dakkshesh07)

Trying to cross compile AVR program but the final linking seems to fail due to some syntax error in the linkerscript. ``` clang++ --target=avr -o firmware.elf -mmcu=atmega2560 --sysroot=${SYSROOT_DIR} -I${SYSROOT_DIR}/avr/include -L"${SYSROOT_DIR}/lib" -ffunction-sections -fdata-sections -fpermissive -fno-exceptions -fno-threadsafe-statics -fno-rtti -Wl,--gc-sections out/main/main.cpp.o out/libArduinoCore.a -lm -fuse-linker-plugin -fuse-ld=lld ``` error: ``` ld.lld: error: /mnt/c/Users/chana/Downloads/Arch/sysroot/lib/gcc/avr/14.1.0/../../../../avr/lib/ldscripts/avr6.x:115: ) expected, but got ( >>> KEEP(SORT(*)(.ctors)) >>> ^ clang++: error: avr-ld command failed with exit code 1 (use -v to see invocation) ``` linkerscript snip: ``` /* Internal text space or external memory. */ .text : { *(.vectors) KEEP(*(.vectors)) /* For data that needs to reside in the lower 64k of progmem. */ *(.progmem.gcc*) /* PR 13812: Placing the trampolines here gives a better chance that they will be in range of the code that uses them. */ . = ALIGN(2); __trampolines_start = . ; /* The jump trampolines for the 16-bit limited relocs will reside here. */ *(.trampolines) *(.trampolines*) __trampolines_end = . ; /* avr-libc expects these data to reside in lower 64K. */ *libprintf_flt.a:*(.progmem.data) *libc.a:*(.progmem.data) *(.progmem.*) . = ALIGN(2); /* For code that needs to reside in the lower 128k progmem. */ *(.lowtext) *(.lowtext*) __ctors_start = . ; *(.ctors) __ctors_end = . ; __dtors_start = . ; *(.dtors) __dtors_end = . ; KEEP(SORT(*)(.ctors)) KEEP(SORT(*)(.dtors)) /* From this point on, we do not bother about whether the insns are below or above the 16 bits boundary. */ *(.init0) /* Start here after reset. */ KEEP (*(.init0)) *(.init1) KEEP (*(.init1)) ``` Is this because LLD expects it in a different syntax? because all these linkerscripts from gnu binutils have been in use with gcc avr from a long time. Im just trying to fix things and get it working with LLVM as well.
smithp35 commented 2 weeks ago

A minimal reproducer

  SECTIONS {
  .text   :
  {
    SORT(*)(.ctors)
  }
}

With ld.lld --script=avr.lds start.o

ld.lld: error: avr.lds:4: CONSTRUCTORS expected, but got *
>>>     SORT(*)(.ctors)
>>>

The documentation for SORT in the GNU manual isn't particularly helpful https://sourceware.org/binutils/docs/ld/Input-Section-Wildcards.html

It says

You can change this by using the SORT_BY_NAME keyword, which appears before a wildcard pattern in parentheses (e.g., SORT_BY_NAME(.text*))

Given https://sourceware.org/binutils/docs/ld/Input-Section-Basics.html

An input section description consists of a file name optionally followed by a list of section names in parentheses.

I think (SORT()(.ctors)) is sort the files denoted by () by name followed the input section pattern (.ctors). I've not yet gone through the parsing code to work out what LLD is expecting.

As to what to do about this. What where you intending by that linker script pattern? To me it looks superfluous as there is already a *(.ctors) higher up that will match .ctors before the KEEP pattern.

As an aside. the LLD error message is a bit different to when I use KEEP(SORT(*)(.CTORS))

ld.lld: error: avr.lds:4: ) expected, but got (
>>>     KEEP(SORT(*)(.ctors))
>>>  
smithp35 commented 2 weeks ago

Looks like LLD's SORT grammar does not permit separate sorting of filenames. From ScriptParser.cpp

// Reads contents of "SECTIONS" directive. That directive contains a
// list of glob patterns for input sections. The grammar is as follows.
//
// <patterns> ::= <section-list>
//              | <sort> "(" <section-list> ")"
//              | <sort> "(" <sort> "(" <section-list> ")" ")"
//
// <sort>     ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
//              | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
//
// <section-list> is parsed by readInputSectionsList().

GNU ld's grammar separates out SORT for filenames and sections.

If you are able to change your issue title I recommend something like: LLD linker script unable to SORT by filename pattern.

dakkshesh07 commented 2 weeks ago

I think (SORT()(.ctors)) is sort the files denoted by () by name followed the input section pattern (.ctors).

Not quite, I believe SORT in SORT(*)(.ctors) sorts the .ctors sections by section name within the .ctors pattern across all matching input files, not the files themselves.

As to what to do about this. What where you intending by that linker script pattern? To me it looks superfluous as there is already a *(.ctors) higher up that will match .ctors before the KEEP pattern.

Not quite sure about it but its origin dates way back when initial linker relaxation support was added to AVR targets.

dakkshesh07 commented 2 weeks ago

If you are able to change your issue title I recommend something like: LLD linker script unable to SORT by filename pattern.

Yes sure, let me do that.