[nanvix] E: Unbundle libffi via DT_NEEDED libffi.so#14
Open
esaurez wants to merge 1 commit into
Open
Conversation
Switches the _ctypes.cpython-312.so extension from statically bundling libffi (744 KB per .so) to dlopen'ing libffi.so at runtime via DT_NEEDED. Saves ~700 KB by sharing libffi.so across all consumers; opens the door for future C-extension consumers of libffi to share the same .so. Mechanics: - Drop -lffi from python.elf LIBS (was eagerly pulling libffi.a into python.elf .dynsym). With libffi.so present in the sysroot, ld now resolves -lffi to libffi.so and emits a DT_NEEDED entry on _ctypes.cpython-312.so. libffi UND symbols (abort etc.) bind to python.elf .dynsym at dlopen time -- same model as the lxml/libxml2/libxslt .so chain. - z.py _DEP_EXPECTED_LIBS: libffi now expects both libffi.a and libffi.so in the buildroot (esaurez/libffi#1). - test.py / package.py: stage libffi.so into the ramfs sysroot at /lib/libffi.so. Hard-fail when missing, matching the lxml/libxml2 pattern. - docker.py Setup.local comment block updated to distinguish Group A (bundled into python.elf) from Phase 3b (libffi via DT_NEEDED .so). Validation: end-to-end _ctypes.so dlopen smoke test passes on nanvix-dev: STEP_1:python_started (3, 12, 3) STEP_2:_ctypes imported /lib/python3.12/lib-dynload/_ctypes.cpython-312.so STEP_6:ffi_call via callback returned 42 CTYPES_CHAIN_PASS _ctypes.cpython-312.so: 744 KB bundled -> 102 KB stripped shim; libffi.so 16 KB ships once in /lib/. python.elf size unchanged (was already gc-section-eliminating unreached libffi code). Depends on: esaurez/libffi#1 (libffi.so build target + nested-archive fix), esaurez/nanvix#27 (DT_RUNPATH / .init_array walking). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Jun 5, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Unbundle
libffifrom_ctypes.cpython-312.so. Switches the extension from statically bundling its own copy of libffi (744 KB) todlopen'ing a sharedlibffi.soat runtime viaDT_NEEDED. Companion to esaurez/libffi#1, which produces thelibffi.so.This is the first of the deferred Group B unbundlings tracked in nanvix-todo/phase2-3-unbundle-bundled-libs.md.
Architecture
The Nanvix loader walks the chain at
dlopentime (esaurez/nanvix#27). libffi UND symbols (abort,memcpy, etc.) bind againstpython.elf's.dynsym— same model as the lxml / libxml2 / libxslt chain shipped in esaurez/cpython#11.Size impact
_ctypes.cpython-312.so(stripped)libffi.sopython.elf-lffiwas already dead-stripped)Net ramfs save: ~626 KB. More importantly, future libffi consumers (e.g. a hypothetical Python C API user) can share the same
.soinstead of carrying their own copy.Mechanics
.nanvix/config.py-lffifrompython.elfLIBS. Was eagerly pullinglibffi.aintopython.elf.dynsym. Withlibffi.sopresent in the sysroot,ldresolves-lffitolibffi.so(during the per-module_ctypeslink) and emits aDT_NEEDED libffi.soentry instead of bundling..nanvix/z.py_DEP_EXPECTED_LIBS["libffi"]now expects bothlibffi.aandlibffi.so(provided by esaurez/libffi#1)..nanvix/test.pylibffi.sointo the test ramfs sysroot at/lib/libffi.so. Hard-fail (FileNotFoundError) when missing, matching the lxml/libxml2 pattern already shipped in cpython#11..nanvix/package.py.nanvix/docker.pySetup.localcomment block updated to distinguish Group A (bundled intopython.elfvia--whole-archive) from Phase 3b (libffi viaDT_NEEDED .so). The_ctypesline is unchanged —LIBFFI_LIBS=-L$sr/lib -lffiwas already in place from Phase 3; the only difference is what-lffiresolves to oncelibffi.sois present.Validation
End-to-end test on
nanvix-dev:STEP_6exercises a realffi_callround-trip: Python -> C trampoline -> libffiffi_call-> Python callback -> result. Confirms the full machinery (CIF prep, closure allocation, calling-convention marshalling) works through the dlopen'dlibffi.so.readelfconfirms the DT_NEEDED chain:The lxml chain (shipped in cpython#11) is regression-tested and still passes (
LXML_CHAIN_PASS).Dependencies
libffi.so(and fixes the latent nested-archive bug inlibffi.athat prevented Group A--whole-archiveunbundling). Required at runtime. Must be merged and released before this PR's sysroot pin gets bumped..init_array+DT_RUNPATHwalking in the user-space loader. libffi has no global ctors of its own, but the loader needs to walk_ctypes.so → libffi.so → python.elfcleanly.required_soslists intest.pyandpackage.pyand reuses the staging pattern established there.Diamond fix (esaurez/nanvix#28) is not required for this PR — the libffi chain is linear (
_ctypes.so → libffi.so → python.elf), no diamond.Sequenced rollout
libffi.soships in the buildroot).nanvix.tomllibffi pin to the new release.Until step 2 the build will fail at the test/package staging step with
FileNotFoundError: libffi.so missing from buildroot/lib— by design (hard-fail rather than silently shipping a broken_ctypes.so).