[dlfcn] E: Add tests for ctors/dtors and DT_RUNPATH#2
Conversation
[ci] Sync zutils v0.10.3
[ci] Sync zutils v0.10.3
The reusable workflow at nanvix/workflows v2.1.0 no longer accepts the zutil-version input; the zutil version is now resolved from the .zutils-version file at the repo root.
[ci] E: Update nanvix workflow refs to v2.1.0
[ci] Sync zutils v0.10.4
[ci] Sync zutils v0.10.4
[ci] Sync zutils v0.11.0
[ci] E: Update nanvix workflow refs to v2.2.0
Add a new test suite (`dlfcn-init-runpath-c`) that exercises the
three System V ABI capabilities the Nanvix dynamic loader now
implements (esaurez/nanvix PR `feat/dlfcn-init-array-and-runpath`):
1. `libctor.so` defines `.init_array` and `.fini_array` entries via
`__attribute__((constructor))` / `((destructor))`. The
constructor writes a sentinel into a library-local global; the
destructor writes a different sentinel into the test program's
exported `g_dtor_ran` global so the witness survives the
library being unloaded. The test asserts both sentinels appear
in the expected order.
2. `libparent.so` is linked against `libchild.so` (creating a
`DT_NEEDED` edge) and built with `-Wl,--enable-new-dtags,
-rpath,lib/subdir`, which the linker emits as `DT_RUNPATH
lib/subdir`. At runtime `libchild.so` is staged into
`lib/subdir/` only — never `lib/` — so the only way `dlopen`
can succeed is by honouring `libparent.so`'s `DT_RUNPATH`.
Both libraries are built flat in `build/` and re-staged into the
correct ramfs paths via the existing `SUITE_RAMFS_LIBS` mechanism
in `.nanvix/z.py`, matching the pattern already used by
`dlfcn-c`. The suite is registered in `STANDALONE_ONLY_SUITES`
because it requires ramfs-bundled `.so` files, and in
`ALL_SUITES`, the host `Makefile`, and the container
`src/Makefile`.
Test output on a standalone Nanvix VM running the updated loader:
=== dlfcn init_array + DT_RUNPATH tests ===
PASS: init_array fires on dlopen
PASS: fini_array fires on dlclose
PASS: DT_RUNPATH dependency search
3 passed, 0 failed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
04b2a38 to
ee7a87a
Compare
|
Superseded by upstream PR nanvix/posix-tests#174, which carries the same test contribution -- rebased onto current upstream/main (pulled in zutils v0.11.1 from #175), deep-reviewed, validated end-to-end against the local nanvix init-array build (all 3 cases plus the full posix-tests suite pass). One MUST FIX applied: stripped a non-ASCII em-dash from main.c. One SHOULD FIX applied: added build-time readelf assertions in the suite Makefile that libctor.so contains INIT_ARRAY+FINI_ARRAY, libparent.so contains DT_NEEDED libchild.so + DT_RUNPATH lib/subdir, AND that the legacy DT_RPATH is NOT present (prevents silent regression if a future toolchain change flips --enable-new-dtags). The upstream loader companion is nanvix/nanvix#2473. Closing this fork PR; tracking continues upstream. |
Summary
Add a new test suite
dlfcn-init-runpath-cthat exercises the three System V ABI capabilities the Nanvix dynamic loader now implements (esaurez/nanvix#27):.init_arrayconstructor invocation ondlopen.fini_arraydestructor invocation ondlcloseDT_RUNPATH-drivenDT_NEEDEDresolutionTest design
libctor.so— has__attribute__((constructor))writing a sentinel to a library-local global, and__attribute__((destructor))writing a different sentinel to the test program'sextern volatile int g_dtor_ran(exported by-rdynamic). The destructor witness survives the library being unloaded because the global lives in the main executable.libparent.so— linked with-lchild -Wl,--enable-new-dtags,-rpath,lib/subdir. The linker emitsDT_NEEDED libchild.soplusDT_RUNPATH lib/subdir.libchild.so— staged intolib/subdir/only (neverlib/) viaSUITE_RAMFS_LIBS. The only way the loader can find it is by honouring libparent'sDT_RUNPATH.Hooks
src/dlfcn-init-runpath-c/{Makefile,main.c,libs/*}Makefile,src/Makefiledlfcn-init-runpath-cinSUITES.nanvix/z.pyALL_SUITES,STANDALONE_ONLY_SUITES, andSUITE_RAMFS_LIBS(the latter stageslibchild.sounderlib/subdir/)Validation
Run on a standalone Nanvix VM with the loader changes from esaurez/nanvix#27:
All 15 testable suites pass (the new suite plus the 14 pre-existing ones).
ELF metadata sanity check
Companion PR
esaurez/nanvix#27 — the loader changes this suite exercises. This PR is unlinked-but-meaningful without it: the test would fail with "destructor sentinel not set" / "DT_RUNPATH dependency search" / "constructor sentinel not set" on an unpatched loader.