Skip to content

fix(relinker): keep weak undefined imports weak - #4510

Merged
oneandonlydean merged 3 commits into
boykopovar:mainfrom
simonbronk:fix/relinker-weak-imports
Oct 12, 2026
Merged

oneandonlydean merged 3 commits into
boykopovar:mainfrom
simonbronk:fix/relinker-weak-imports

Conversation

@simonbronk

Copy link
Copy Markdown
Contributor

What

Fixes #4497.

Weak undefined imports (STB_WEAK, section 0) in the input ELF were written to the relinked .dynsym as STB_GLOBAL, so a title that weak-imports a function no module exports stopped at startup instead of binding the import to null.

  • NidReference records whether the source symbol was weak; SysVDynamicSectionBuilder writes STB_WEAK for those imports instead of STB_GLOBAL. On Linux, ld.so then binds a missing weak import to 0.
  • Windows: WindowsRelocationBuilder reads the binding into PeImport::Weak. When no searched module exports a weak import, the startup stub writes 0 plus the addend to its slot and continues; it does not print unresolved ELF import or install a lazy stub. A weak import that is exported resolves as before.
  • Non-weak imports are unchanged: a missing one still fails at startup.

Guest module imports (LinuxGuestModuleWriter, WindowsGuestModuleWriter) are not touched.

Tested

macOS 27 (Apple Silicon, AppleClang 21), relinker-only build, Release:

  • ctest --test-dir build-relinker: 125/125 passed, including the new weak_imports.
  • weak_imports builds an executable with one weak GLOB_DAT import whose code returns 33 when the slot is null and calls through it otherwise:
    • Linux output: the import is STB_WEAK, and a non-weak import is still STB_GLOBAL. Without the fix the test fails with {'absent': 1}.
    • Windows output: relinks with the import missing and present; on Windows it runs and expects 33 (missing) and 11 (exported by a.prx). I could not run the Windows executables; this part needs Windows CI.
  • python3 tools/check_conventions.py --base origin/main: passed.

Porpoise itself not tested (no dump).

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: PPSA99764 (Porpoise), no Game bring-up discussion found
  • AI-assisted: yes (Claude Code, Opus 5.5)

🤖 Generated with Claude Code

Weak undefined imports in the input ELF became STB_GLOBAL in the relinked
output, so a title that weak-imports a function no module exports stopped
at startup instead of binding the import to null.

Keep STB_WEAK on the relinked dynamic symbols. On Windows, write 0 plus
the addend to the slot of a weak import that no searched module exports.

Fixes boykopovar#4497

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simonbronk

Copy link
Copy Markdown
Contributor Author

Overlaps with #4452 on the same lines in SysVDynamicSectionBuilder.cpp and RelinkerPipeline.cpp, but the changes are independent and compatible (#4452 handles all-zero symbol entries, this one keeps STB_WEAK from named symbols). Happy to rebase onto #4452 if it lands first.

The CMakeLists.txt overlap with #4062 is resolved: the test registration moved next to elf_header.

@gabichuuuuu

Copy link
Copy Markdown

Tested the Windows part on Windows.

Setup: Windows 11 Enterprise 10.0.26200 x64, WinLibs GCC 15.2.0 r7 (15.2.0posix-14.0.0-ucrt-r7, as in CI), CMake 4.3.1, Ninja 1.13.2, relinker-only Release build with BUILD_TESTING=ON, Python 3.12.

  • This PR (bdf003a5) merged into main 2a5eca11, as the CI merge step does: ctest --test-dir build-relinker --output-on-failure --timeout 120 passed 130/130, including weak_imports. main alone passed 129/129; no other test changed result.
  • weak_imports runs the converted executables here: windows-weak-missing exits 33, windows-weak-present exits 11.
  • Same Windows cases with the main relinker: windows-weak-missing stops with 0xc0000139 (FAIL: unresolved ELF import absent from a.prx, GetLastError: 127); windows-weak-present exits 11. The Linux part of the test fails on main with ('linux-weak', {'absent': 1}), as described above.

Review note, no change requested: the weak branch in WindowsEntryStubBuilder skips the RelocationType 16/17 loads that the non-weak resolved branch does. It is unreachable now, since only executable imports (type 1) set Weak and guest module imports keep Weak = false.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 12, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 12, 2026
…orts

# Conflicts:
#	core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp
#	core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp
@simonbronk

Copy link
Copy Markdown
Contributor Author

@gabichuuuuu thanks for running it on Windows.

#4452 is merged, so I merged main into this branch: symbolInfo from #4452 is kept (all-zero entries stay STB_WEAK | STT_NOTYPE) and named imports now take STB_WEAK or STB_GLOBAL from the source symbol. Relinker-only build on macOS: 134/134 tests pass; conventions check passes.

On the review note: agreed, the 16/17 loads are unreachable in the weak branch because only executable imports set Weak, so I left it as is.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 12, 2026
@oneandonlydean
oneandonlydean merged commit acf1dd7 into boykopovar:main Oct 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Relinker: weak undefined imports become required (STB_WEAK → STB_GLOBAL), so Porpoise stops at its weak chroot import

3 participants