Skip to content

Commit 4d19e45

Browse files
committed
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.
1 parent 517bea8 commit 4d19e45

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

cpython-unix/build-cpython.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ if [ -n "${CROSS_COMPILING}" ]; then
8585
fi
8686
fi
8787

88+
# Inject -Bsymbolic* on shared library to force direct symbol resolution
89+
# and potentially unlock more compiler+linker optimizations.
90+
#
91+
# Patch is safe on all arches but runs into context conflict on macOS.
92+
# It isn't needed for macOS. So workaround by not applying there.
93+
if [[ "${PYBUILD_PLATFORM}" != macos* ]]; then
94+
patch -p1 -i "${ROOT}/patch-configure-linker-symbolic.patch"
95+
fi
96+
8897
# LIBTOOL_CRUFT is unused and breaks cross-compiling on macOS. Nuke it.
8998
# Submitted upstream at https://github.com/python/cpython/pull/101048.
9099
if [ -n "${PYTHON_MEETS_MAXIMUM_VERSION_3_11}" ]; then
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
diff --git a/configure.ac b/configure.ac
2+
index a1f4a567095..f7aa69556e5 100644
3+
--- a/configure.ac
4+
+++ b/configure.ac
5+
@@ -3489,8 +3489,16 @@ then
6+
LDSHARED='$(CC) -shared'
7+
LDCXXSHARED='$(CXX) -shared';;
8+
Linux*|GNU*|QNX*|VxWorks*|Haiku*)
9+
- LDSHARED='$(CC) -shared'
10+
- LDCXXSHARED='$(CXX) -shared';;
11+
+ # See https://maskray.me/blog/2021-05-16-elf-interposition-and-bsymbolic.
12+
+ # This is related to the -fno-semantic-interposition optimization that
13+
+ # --enable-optimizations engages automatically. It changes the linkage
14+
+ # behavior so the runtime loader searches the current DSO first before
15+
+ # falling back to the default search mechanism of the executable plus
16+
+ # all its loaded DSOs. It has much the same effect as
17+
+ # -fno-semantic-interposition but can also enable optimizations across
18+
+ # translation units.
19+
+ LDSHARED='$(CC) -shared -Wl,-Bsymbolic-functions'
20+
+ LDCXXSHARED='$(CXX) -shared -Wl,-Bsymbolic-functions';;
21+
FreeBSD*)
22+
if [[ "`$CC -dM -E - </dev/null | grep __ELF__`" != "" ]]
23+
then

docs/quirks.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,22 @@ compile extensions, too.
194194
If there is a build time normalization that you think should be performed to
195195
make distributions more portable, please file a GitHub issue.
196196

197+
.. _quirk_ld_preload_doesnt_work:
198+
199+
``LD_PRELOAD`` Does Not Work
200+
============================
201+
202+
This project applies various build optimizations that undermine the
203+
ability for ``LD_PRELOAD`` to reliably intercept symbols provided by
204+
``libpython``:
205+
206+
* Functions can be aggressively inlined - bypassing the PLT - and inlined
207+
function calls cannot be intercepted by ``LD_PRELOAD``'d libraries.
208+
* Use of the linker option ``-Bsymbolic-functions`` on ``libpython`` forces
209+
symbols to resolve to the local library (``libpython``) instead of going
210+
through the regular loader lookup sequence, which would otherwise process
211+
``LD_PRELOAD``'d libraries before ``libpython``.
212+
197213
.. _quirk_former:
198214
.. _quirk_missing_libcrypt:
199215
.. _quirk_linux_libx11:

0 commit comments

Comments
 (0)