Skip to content

feat: Add support for linker plugins#1411

Merged
davidlattimore merged 1 commit into
mainfrom
push-lrmzyysnmpxr
Feb 13, 2026
Merged

feat: Add support for linker plugins#1411
davidlattimore merged 1 commit into
mainfrom
push-lrmzyysnmpxr

Conversation

@davidlattimore

Copy link
Copy Markdown
Member

Fixes #1

Comment thread linker-diff/src/section_map.rs Outdated
@davidlattimore

Copy link
Copy Markdown
Member Author

The test failures appear to be related to how I'm testing not due to the actual LTO implementation.

On older versions of Ubuntu the problem is because we're trying to use linker-plugin LTO with LLVM bitcode produced by rustc, but the plugin is for an older version of LLVM than what Rustc uses. My plan there is to check rust's version of LLVM (with rustc -vV) then disable the tests if it doesn't match the clang version.

On OpenSUSE, it seems that LLVMgold.so - the linker plugin for LLVM/clang just isn't installed. I haven't found a way to install it as yet, so probably I'll run a command like echo 'int main() {}' | clang -flto -xc -o a.out - and if it fails, disable clang-based LTO tests.

There are some Ubuntu aarch64 failures that appear to be linker-diff not knowing how to interpret a relaxation that happened.

On Alpine linux, the wild binary seems to be statically linked, so can't load the linker plugin shared object. Fixing this probably requires either switching our builds on alpine to use dynamic linking or detecting that we've been statically linked and skipping linker-plugin tests.

@lapla-cogito lapla-cogito left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karolzwolak

Copy link
Copy Markdown
Contributor

@davidlattimore is it possible to split the work? I'd like to help.

@davidlattimore

Copy link
Copy Markdown
Member Author

Thanks @karolzwolak. I'm doing some benchmarking work at the moment, then I'm going to do a release. After that, I intend to return to linker plugins.

I've just pushed my latest changes.

I think the main thing left to deal with is the aarch64 linker-diff failures, which look like this:

rel.match_failed.R_AARCH64_ADR_GOT_PAGE
  `/lib/aarch64-linux-gnu/Scrt1.o` .text _start
  ORIG 0x0001c: [ 00 00 00 90 ] adrp	x0, 0x0
                  ^^^^^^^^^^^ R_AARCH64_ADR_GOT_PAGE 
  ORIG 0x00020: [ 00 00 40 f9 ] ldr	x0, [x0]
                  ^^^^^ R_AARCH64_LD64_GOT_LO12_NC 
  ORIG main
  wild 0x10edc: [ 80 00 00 b0 ] adrp	x0, 0x21000
                  ^^^^^^^^^^^ R_AARCH64_ADR_GOT_PAGE NoOp 
  wild 0x10ee0: [ 00 50 41 f9 ] ldr	x0, [x0, #672]
                  ^^^^^ R_AARCH64_LD64_GOT_LO12_NC NoOp 
  wild GOT->main
  wild TRACE: relocation applied flags=NON_INTERPOSABLE | DIRECT | GOT,
  wild TRACE: rel_kind=GotRelative,
  wild TRACE: value=0x11000, symbol_name=main
  wild TRACE: relocation applied flags=NON_INTERPOSABLE | DIRECT | GOT,
  wild TRACE: rel_kind=Got,
  wild TRACE: value=0x212a0, symbol_name=main
  lld  0x1075c: [ 1f 20 03 d5 ] nop
                  ^^^^^^^^ R_AARCH64_ADR_PREL_LO21 AdrpToAdr Relaxation output didn't match: [0, 0, 0, 10] != [1f, 0, 0, 95]
  lld  0x10760: [ 40 08 00 10 ] adr	x0, 0x10868
  lld             ^^^^^^^^^^^ R_AARCH64_ADR_GOT_PAGE NoOp Relaxation output didn't match: [0, 0, 0, 90] != [1f, 0, 0, 95]
  lld             ^^^^^ R_AARCH64_LD64_GOT_LO12_NC NoOp Relaxation output didn't match: [0, 0, 40, f9] != [40, 0, 0, 10]
  lld  ??

You're welcome to have a look at the aarch64 failure if you want. I'm not sure how straightforward it will be.

There are a few other failures besides those, but I haven't look at them yet.

Another option is you could try compiling a few things, especially C and C++ projects, with linker-plugin LTO and see if it works.

In addition to fixing failing tests, I should probably do a thorough review of the change myself to look for stuff that I meant to come back to, but forgot, stuff that shouldn't be in the commit etc. You're welcome to review the change yourself and ask questions if things aren't clear. I'll then try to add comments or make other changes accordingly.

@bjorn3

bjorn3 commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

How much space would it take for rustc itself to ship a linker plugin matching the LLVM version it uses? If it is only a tiny bit, maybe we could just do that on the rustc side and then you could use it during testing?

@davidlattimore

Copy link
Copy Markdown
Member Author

Interesting idea. On my system /usr/lib/llvm-20/bin/../lib/LLVMgold.so is 88KB. It dynamically links against libLLVM.

@bjorn3

bjorn3 commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

We don't dynamically link against LLVM on all targets, but on those where we do, 88kb wouldn't even need a separate component. Adding it to the rustc component would be just fine. That I think just leaves a policy question about if we want to provide a linker plugin (I think we should. It would make cross-lang LTO easier.) and what to do about the targets where we statically link LLVM. I don't know the exact reason we statically link on those targets.

@mati865

mati865 commented Jan 17, 2026

Copy link
Copy Markdown
Member

Rustc part discussion should probably move to another place....

I don't know the exact reason we statically link on those targets.

When it comes to Windows, dynamic linking of libLLVM is supported only when building with Clang in MinGW mode: llvm/llvm-project@c5b3de6#diff-c32cf5f1ab46b94ceac7f7597aace44624436f439c8304c029feca005c000a4bR245-R247
Linked feature translates ELF symbol visibility into Windows directives that exclude symbols from being exported. That allows Clang to avoid that dumb PE ~2^16 exported symbols limit.

@davidlattimore davidlattimore force-pushed the push-lrmzyysnmpxr branch 4 times, most recently from 9248b5b to 9629937 Compare January 22, 2026 03:18
@davidlattimore davidlattimore marked this pull request as ready for review January 22, 2026 03:25
@davidlattimore

Copy link
Copy Markdown
Member Author

All tests now pass :)

@bjorn3

bjorn3 commented Jan 22, 2026

Copy link
Copy Markdown
Contributor

Would it be possible to have this behind a feature flag for targets that don't support dynamic linking?

@davidlattimore

Copy link
Copy Markdown
Member Author

Would it be possible to have this behind a feature flag for targets that don't support dynamic linking?

Good idea. Will do.

The other blocker before I can merge this is that I've observed a 1.7% showdown when linking wild even without a linker plugin. I still need to figure out the cause.

@davidlattimore

Copy link
Copy Markdown
Member Author

I've made plugin support be a cargo feature (on by default).

I also hit some new test failures in CI which I've now fixed. It turned that that those failures were because the latest nightly builds of rustc are using LLVM 22, but the LLVM linker plugin on most of test systems is version 20. This wasn't being picked up by the LTO compatibility check, but is now. But it does raise an interesting point, which is that right now we're probably not actually testing rust linker plugin LTO, since we're using nightly for all our CI tests and I don't think any of our test systems have LLVM 22 yet. From the CI failure, It looks like Ubuntu 26.04 has LLVM 21.

I'm still investigating performance changes.

@davidlattimore

Copy link
Copy Markdown
Member Author

In order to get this large PR merged, I've decided to switch to having the plugins feature disabled by default. I hope to enable it later, once we're happy that we're not significantly regressing performance of linking without a plugin.

I did observe a performance change even with the feature disabled. This however appears to be due to some code being deleted, causing slightly different codegen units, resulting in different optimisations being applied. Once I did a performance test with codegen-units=1, the effect went away.

@davidlattimore davidlattimore merged commit f9192a6 into main Feb 13, 2026
20 checks passed
@davidlattimore davidlattimore deleted the push-lrmzyysnmpxr branch February 18, 2026 09:56
gentoo-bot pushed a commit to gentoo/gentoo that referenced this pull request Mar 3, 2026
The plugin is disabled by default upstream.

See-also: wild-linker/wild#1411
Signed-off-by: zyxhere💭 <zyx@envs.net>
Part-of: https://codeberg.org/gentoo/gentoo/pulls/77
Merges: https://codeberg.org/gentoo/gentoo/pulls/77
Signed-off-by: Sam James <sam@gentoo.org>
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 this pull request may close these issues.

About LTO

5 participants