From 868c3fada142820e2b36dd424cb335736fa6fa2a Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Fri, 20 Mar 2026 14:40:42 +0800 Subject: [PATCH] unix: link libpython with `-Bsymbolic-functions` This changes the runtime loader lookup semantics for libpython so function references are resolved in the local library first. * May improve startup time by eliding symbol lookups in the executable and other libraries. * Prevents symbols provided by libpython from resolving to other loaded libraries. * Enables additional compiler+linker optimizations by guaranteeing that libpython symbols resolve to the local library. (e.g. more aggressive inlining across translations units.) I believe this change is safe since we're already disabling semantic interposition and PGO+LTO+BOLT result in substantial inlining. However, this change can break `LD_PRELOAD` where a separate DSO providing libpython symbols is injected at the front of the loader search path. In this scenario, the libpython symbol will be used instead of the variant injected via `LD_PRELOAD`. I'm unsure if any popular software (that isn't malware) is relying on intercepting libpython symbols via `LD_PRELOAD`. But because of our aggressive build optimizations, various functions would have been inlined and wouldn't have been `LD_PRELOAD` interceptable anyway since the PLT was already elided. So this change effectively finishes the "migration" of making `LD_PRELOAD` unreliable. --- cpython-unix/build-cpython.sh | 13 +++++++++++ ...patch-configure-linker-symbolic-3.10.patch | 23 +++++++++++++++++++ .../patch-configure-linker-symbolic.patch | 23 +++++++++++++++++++ docs/quirks.rst | 16 +++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 cpython-unix/patch-configure-linker-symbolic-3.10.patch create mode 100644 cpython-unix/patch-configure-linker-symbolic.patch diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 6df845881..d112f069a 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -85,6 +85,19 @@ if [ -n "${CROSS_COMPILING}" ]; then fi fi +# Inject -Bsymbolic* on shared library to force direct symbol resolution +# and potentially unlock more compiler+linker optimizations. +# +# Patch is safe on all arches but runs into context conflict on macOS. +# It isn't needed for macOS. So workaround by not applying there. +if [[ "${PYBUILD_PLATFORM}" != macos* ]]; then + if [ -n "${PYTHON_MEETS_MINIMUM_VERSION_3_11}" ]; then + patch -p1 -i "${ROOT}/patch-configure-linker-symbolic.patch" + else + patch -p1 -i "${ROOT}/patch-configure-linker-symbolic-3.10.patch" + fi +fi + # LIBTOOL_CRUFT is unused and breaks cross-compiling on macOS. Nuke it. # Submitted upstream at https://github.com/python/cpython/pull/101048. if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_11}" ]; then diff --git a/cpython-unix/patch-configure-linker-symbolic-3.10.patch b/cpython-unix/patch-configure-linker-symbolic-3.10.patch new file mode 100644 index 000000000..045d1c4e3 --- /dev/null +++ b/cpython-unix/patch-configure-linker-symbolic-3.10.patch @@ -0,0 +1,23 @@ +diff --git a/configure.ac b/configure.ac +index ac3be3850a9..88a2027f517 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2713,8 +2713,16 @@ then + fi + ;; + Linux*|GNU*|QNX*|VxWorks*) +- LDSHARED='$(CC) -shared' +- LDCXXSHARED='$(CXX) -shared';; ++ # See https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic. ++ # This is related to the -fno-semantic-interposition optimization that ++ # --enable-optimizations engages automatically. It changes the linkage ++ # behavior so the runtime loader searches the current DSO first before ++ # falling back to the default search mechanism of the executable plus ++ # all its loaded DSOs. It has much the same effect as ++ # -fno-semantic-interposition but can also enable optimizations across ++ # translation units. ++ LDSHARED='$(CC) -shared -Wl,-Bsymbolic-functions' ++ LDCXXSHARED='$(CXX) -shared -Wl,-Bsymbolic-functions';; + FreeBSD*) + if [[ "`$CC -dM -E -