Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
MaskRay opened this issue Nov 3, 2021 · 5 comments

Comments

@MaskRay
Copy link
Contributor

MaskRay commented Nov 3, 2021

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 added a commit to MaskRay/ldc that referenced this issue Nov 3, 2021
This removes an abuse of ELF linker behaviors while keeping
Mach-O/COFF/WebAssembly linker behaviors unchanged.

LLD 13.0.0 (default) and GNU ld 2.37 support `-z start-stop-gc` which enables
the linker to linker to garbage collect unreferenced C identifier name sections
in the presence of `__start_/__stop_`. The `__minfo` section is otherwise
unreferenced and may be garbage collected.

Add the global variables to `llvm.used` can prevent garbage collection.

Fixes ldc-developers#3861
@MaskRay MaskRay changed the title ELF: __minfo global variables are garbage collected by ld.lld>=13.0.0 ELF: __minfo global variables may be garbage collected by ld.lld>=13.0.0 if built with llvm-project<13.0.0 Nov 3, 2021
@JohanEngelen
Copy link
Member

  • 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 ?

@MaskRay
Copy link
Contributor Author

MaskRay commented Nov 3, 2021

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.

@kinke
Copy link
Member

kinke commented Nov 8, 2021

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 #3850 (comment).

@rikkimax
Copy link
Contributor

This has come up for GDC on OpenBSD, is this confirmed to be fixed now?

@kinke
Copy link
Member

kinke commented Sep 23, 2024

Yeah well nowadays we only support LLVM 15+, with 'proper' llvm.used semantics (SHF_GNU_RETAIN), so this can be closed for LDC.

@kinke kinke closed this as completed Sep 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants