Linker compatibility and the "User-Agent" problem
2024-7-7 15:0:0 Author: maskray.me(查看原文) 阅读量:9 收藏

The output of ld.lld -v includes a message "compatible with GNU linkers" to address detection mechanism used by GNU Libtool. This problem is described by Software compatibility and our own "User-Agent" problem.

The latest m4/libtool.m4 continues to rely on a GNU check.

1
2
3
4
5
6
7
8
9
10
[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
[# I'd rather use --version here, but apparently some GNU lds only accept -v.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
lt_cv_prog_gnu_ld=yes
;;
*)
lt_cv_prog_gnu_ld=no
;;
esac])

Check-based configuration can be a valuable tool, ensuring software remains functional in the future. However, this example highlights how overly specific checks can lead to unintended consequences.

This blog post explores more forms of the "User-Agent" problem exposed by an LLD patch changing the version message format.

LLD supports many object file formats. It mimicks GNU ld for ELF and MSVC link.exe for PE/COFF. Previously, the ELF port displays the version information like this:

1
2
% /tmp/out/custom2/bin/ld.lld --version
LLD 19.0.0 (compatible with GNU linkers)

A recent patch (llvm-project#97323) changed it to one of the following formats, depending on the build-time variable LLVM_APPEND_VC_REV:

With LLVM_APPEND_VC_REV=on:

1
2
% /tmp/out/custom2/bin/ld.lld --version
LLD 19.0.0 ([email protected]:llvm/llvm-project.git 0f9fbbb63cfcd2069441aa2ebef622c9716f8dbb), compatible with GNU linkers

With LLVM_APPEND_VC_REV=off:

1
2
% /tmp/out/custom2/bin/ld.lld --version
LLD 19.0.0, compatible with GNU linkers

Meson

In Meson, mesonbuild/linkers/detect.py:guess_win_linker checks the --version output to determine whether the LLD invocation is for ELF or PE/COFF. It performed an overly strict check "(compatible with GNU linkers)", which failed when the parentheses were stripped by #97323.

1
2
3
4
5
6
7
8
9
10

if 'LLD' in o.split('\n', maxsplit=1)[0]:
if '(compatible with GNU linkers)' in o:
return linkers.LLVMDynamicLinker(
compiler, for_machine, comp_class.LINKER_PREFIX,
override, version=search_version(o))
elif not invoked_directly:
return linkers.ClangClDynamicLinker(
for_machine, override, exelist=compiler, prefix=comp_class.LINKER_PREFIX,
version=search_version(o), direct=False, machine=None)

The latest Meson has loosened the check (meson#13383).

Linux kernel

The Linux kernel's scripts/ld-version.sh script detects linker versions. Introduced in 2014, it initially checked for GNU ld compatibility with GCC LTO (though LTO support remains unmerged). It was later revamped to handle LLD versions as well. While it can handle suffixes like 2.34-4.fc32, it struggles with versions containing with comma suffix (19.0.0,).

1
2
% scripts/ld-version.sh /tmp/out/custom2/bin/ld.lld
scripts/ld-version.sh: line 19: 10000 * 19 + 100 * 0 + 0,: syntax error: operand expected (error token is ",")

The script extracts the version string from the --version output and parses it as major.minor.patch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

IFS='
'
set -- $(LC_ALL=C "$@" --version)


IFS=' '
set -- $1

...



version=${version%-*}

To support suffixes starting with either - or ,, the script will employ a POSIX shell trick utilizing the "Remove Largest Suffix Pattern" feature:

1
version=${version%%[!0-9.]*}

More fun with versions

Ever wondered what the subtle differences are between -v, -V, and --version when using GNU ld? Let's break it down:

  • --version skips linker input processing and displays brief copyright information.
  • -v and -V keep processing input files.
  • -V goes a step further than -v by including a list of supported BFD emulations alongside the version information.

Prior to September 2022, -V in ld.lld used to an alias for --version. This caused issues when using gcc -v -fuse-ld=lld on certain targets like *-freebsd and powerpc-*: gcc passes -V to the linker, expecting it to process the input files and complete the linking step. However, ld.lld's behavior with -V skipped this process.

I made an adjustment by making -V an alias for -v instead. This ensures that gcc -v -fuse-ld=lld performs the linking step.


文章来源: https://maskray.me/blog/2024-07-07-linker-compatibility-and-the-user-agent-problem
如有侵权请联系:admin#unsafe.sh