Repository navigation
fix(relinker): rebase the relocated program header table at a fixed Linux base - #6224
Conversation
|
Independent Windows validation on current PR head |
Thanks for independently validating the PR on the current head and confirming that both the build and the focused regression test pass. Appreciate the additional validation! |
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
I found the same |
|
@MarcZX100 — folded the #6403 coverage into this PR as offered, in Integrated into the existing relocated-table case in
Your Verified fail-before/pass-after: a temporary worktree of Thanks for offering to close #6403 — the coverage is present on this branch now. Written with AI assistance (OpenCode). |
|
Tested 2cf75db, which folds in the #6403 coverage (merge base d92a8da; it merges cleanly into
I also relinked a real eboot with
#6406 and this PR merge together without conflicts. #6447 carries the same Not run: Windows, macOS, a hardware GPU, a boot past 90 s. AI-assisted: yes |
What
--linux-fixed-baserebases the output program header table at the input'se_phoffinstead of the table the relinker actually wrote. When the input ELF declares fewer program header slots than the output layout needs, the relinker moves the table to the end of the output and updatese_phoff; the fixed-base rebase then ran against the stale location. This passes the relocated table offset (tableOff) toRebaseProgramHeaders, so every declared program header is rebased regardless of where the table lives.Fixes #6393.
Why
LinuxElfPatcher::Patch(core/relinker/elfpatcher/src/linux/LinuxElfPatcher.cpp) moves the output program header table totableOffwhenRequiredProgramHeaderCount(kept headers + 5 synthetic) exceeds the input'se_phnum, writes the new layout there (layoutRequest.PhOff = tableOff,WriteLayout) and updatese_phoff. The fixed-base step then calledRebaseProgramHeaders(buf, phOff, ...)with the original table offset, so:p_vaddr/p_paddrwere never rebased, whilee_entry, the dynamic segment addresses and the relocations were. The output is anET_EXECwhose program headers still describe the image at the original addresses (lowestPT_LOADvaddr 0) while its entry point is atbase+..., so it cannot run at the fixed base, againstdocs/user/USAGE.md("every virtual address of the image is offset by it").writtenPhentries at the original table offset, overwriting input bytes that follow the table. When those bytes decode as headers with large addresses, the conversion aborts with an unrelated error (Program header address 0x4141414141414141 lies outside the Linux user address space at fixed base 0x400000) although the same input converts without the option.Both halves reproduce deterministically with the existing
test_linux_fixed_base.pyfixture trimmed to 5 program header slots (1 keptPT_LOAD+ 5 synthetic = 6 required > 5, so the table is relocated;SegmentFilterskipsPT_DYNAMICand thePT_SCE_*fillers). With the fixture's default 6 slots the table stays in place, which is why the existing tests never distinguish the two paths.Tested
Relinker-only build on Linux x86-64 (CMake 4.4.4, GCC 16.2.1, Python 3.14.7), head
2cf75dbbfbased ond92a8dad3:upstream/main5d9dcc42d(still passingphOff) was configured relinker-only and built; running the updated test against that binary fails with exit 1, and a focused probe of the grown-table assertions shows the failures they catch — the rebased entry0x401118is covered by noPT_LOAD(unmapped) and the lowest outputPT_LOADvaddr is0x0, not0x400000. The worktree was discarded afterwards; the PR branch was not modified for this check.python3 core/relinker/relinker/tests/test_linux_fixed_base.py build-relinker/core/relinker/relinkerpasses. The relocated-table case asserts: the output table grew past the input's slot count (e_phnum5 → 6) and moved (e_phoffis no longer0x40); every output header equals the plain relink's withp_vaddr/p_paddrshifted by the base; the image starts at the base; the entry point equals the plain relink's entry plus the base; the entry is covered by a file-backedPT_LOADand that file offset lies inside the output; and the covering segment is executable. The x86-64 execution check to the designedSIGTRAPand the filled-input conversion check are unchanged.ctest --test-dir build-relinker --output-on-failure -j4: 100% tests passed, 0 failed out of 172, 26.15 s total.python3 tools/check_conventions.py --base upstream/main(base5d9dcc42d): all conventions checks passed.python3 tools/check_test_registration.py build-relinker: 29 test executables, none built and not run.git diff --check: clean.python3 tools/pr_overlap.py --branch fix/linux-fixed-base-relocated-phdrs: only fix(relinker): rebase the grown Linux program header table #6403 overlaps (test_linux_fixed_base.py); that PR's author has offered to close it once this coverage is present here (the grown-table assertions proposed there are consolidated in this PR's relocated-table case).Not run: the full (non-relinker-only) build, Windows or macOS relinker output tests,
--to-intel/--to-rosettaconversions, and conversions of real titles. An independent contributor built and ran the focused test on Windows/MinGW-w64 at head8e5073ebe; that run predates this commit.Scope and limitations
Linux output only; the fix touches one call in
LinuxElfPatcher::Patch. No GPU, Windows, macOS or game behavior was tested, and no real title was converted. The execution check runs only on x86-64 Linux, under the same guard as the existing fixed-base execution check; on other hosts the test verifies output bytes only. The3-slot fixture proposed in #6403 takes the same relocation path (required > e_phnum) as the 5-slot fixture used here, so its coverage was consolidated into the existing relocated-table case rather than duplicated.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file (n/a: no library code changed).mdfiles or images added to the repository (attach them to this PR)