ldc icon indicating copy to clipboard operation
ldc copied to clipboard

ELF: `__minfo` global variables may be garbage collected by ld.lld>=13.0.0 if built with llvm-project<13.0.0

Open MaskRay opened this issue 2 years ago • 3 comments

I maintain lld/ELF nowadays. Sorry for your inconvenience but for the benefit of better garbage collection for metadata sections (PGO/sanitizer and more future instrumentation), I changed a garbage collection rule in LLD 13.0.0 (https://releases.llvm.org/13.0.0/tools/lld/docs/ReleaseNotes.html):

A __start___minfo reference from a live input section no longer keeps a __minfo section live.

(The topic is complex. You may read https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order#garbage-collection-on-metadata-sections for more information.)

FreeBSD is trying to upgrade its /usr/bin/ld to LLD 13.0.0. If ldc is built with llvm-project<13.0.0 when host ld.lld >= 13.0.0, there can be breakage:

  • ld.lld>=13.0.0 defaults to -z start-stop-gc and discards unreferenced __minfo sections.
  • A __minfo section will be retained if it has the SHF_GNU_RETAIN flag.
  • Before llvm-project 13.0.0, llvm.used does not set SHF_GNU_RETAIN flag.

Some fixes:

  • Detect host linker flavor and version. If LDC_LLVM_VER < 1300 && ld.lld >= 13.0.0, pass -z nostart-stop-gc. This can be a CMake-time check.
  • FreeBSD uses llvm-project 13.0.0 to build ldc. Note: for LTO we really like the compiler and the linker to use the same LLVM version, though larger version linker usually works. IIUC FreeBSD's usage is not friendly to LTO.
  • Somehow places __minfo in a section group with a SHT_INIT_ARRAY section. This is a hack which should retire ASAP.
  • Disable --gc-sections
  • FreeBSD packager switches to a bundled ld.lld with a version matching llvm-project. This is the recommended way using LTO.

ld64 on Mach-O behaves similar to ld.lld -z nostart-stop-gc in the presence of -dead_strip.

MaskRay avatar Nov 03 '21 05:11 MaskRay

  • Detect host linker flavor and version. If LDC_LLVM_VER < 1300 && ld.lld >= 13.0.0, pass -z nostart-stop-gc. This can be a CMake-time check.

Would it help if we always pass -z nostart-stop-gc to the linker when LDC_LLVM_VER < 1300 ?

JohanEngelen avatar Nov 03 '21 19:11 JohanEngelen

The problem is that ld.lld errors for unknown -z options while GNU ld just warns.

% ld.bfd -z nostart-stop-gc a.o
ld.bfd: warning: cannot find entry symbol _start; defaulting to 0000000000401000

% ld.bfd -z unknown a.o 
ld.bfd: warning: -z unknown ignored
ld.bfd: warning: cannot find entry symbol _start; defaulting to 0000000000401000

% ~/llvm-prebuilt/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04/bin/ld.lld -z nostart-stop-gc a.o
ld.lld: error: unknown -z value: nostart-stop-gc

Perhaps @lwhsu can tag the https://www.freshports.org/lang/ldc maintainer here.

MaskRay avatar Nov 03 '21 19:11 MaskRay

I've seen these failures with lld v13; it's somehow fixed by declaring the start/stop symbols in one object file instead of each object file (and, FWIW, as IR constants if that makes a difference), in https://github.com/ldc-developers/ldc/pull/3850#issuecomment-952992369.

kinke avatar Nov 08 '21 13:11 kinke