Skip to content

fix(relinker): reject ambiguous dynamic table metadata - #1938

Closed
Zinebyte wants to merge 1 commit into
boykopovar:mainfrom
Zinebyte:fix/dynamic-table-ambiguity
Closed

Zinebyte wants to merge 1 commit into
boykopovar:mainfrom
Zinebyte:fix/dynamic-table-ambiguity

Conversation

@Zinebyte

@Zinebyte Zinebyte commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

What

The main relinker reads the first PT_DYNAMIC header and the first occurrence of consumed table metadata. A second header is ignored on Linux, while conflicting relocation tags can select different tables in the pipeline and strict reachability's relative-relocation index. Windows detects some duplicates later, after an optional import registry has been written. Reject multiple dynamic headers before reading the dynamic table, and reject a repeated tag when the pipeline consumes its value, before either output patcher runs.

Identical duplicates are rejected too. This is AnyPS5's supported-input policy, consistent with the bundled-module reader's duplicate guards; it is not a claim that the ELF gABI requires every dynamic header or tag to be unique. The tag guard covers only the 11 currently consumed standard/SCE pairs for string, symbol, RELA and PLT table addresses, sizes, strides and type. DT_NEEDED, distinct SCE module-import records and ignored tags retain their existing behavior. Other tags, including the existing DT_INIT ambiguity, are outside this change. Existing OS-versus-standard ambiguity diagnostics remain intact.

Extend dynamic_segment with the same, different, empty and out-of-bounds second table in both header orders. Register dynamic_tag_duplicates for identical and conflicting values in both tag orders and both tag families. Every duplicate rejection must return status 2, identify the duplicate, and create neither an executable nor an import registry. Valid controls include trailing records after DT_NULL, repeatable imports, and output DT_NEEDED order in both libA.so, libB.so and reverse lexical libB.so, libA.so order. Tests use synthetic input and generate both Linux ELF and Windows PE output.

Tested

The duplicate-header and duplicate-tag regressions fail against base f145139 and pass with this patch. Reverse lexical DT_NEEDED order passes without sorting the dependencies. Zorin OS 18.1 x86-64, GCC 13.3.0, Python 3.12 and CMake 3.28.3, relinker-only Release/static, one build job. Author validation of the composed four patches passed all 39 configured CTest registrations in 6.06 s, including progress_report and import_audit; exact-base baseline passed 38/38 in 5.93 s. A separate independent review rebuilt the composed revision and passed 39/39 in 6.03 s. Focused baseline and patched checks use small synthetic inputs. Existing assertions are retained; no real game, firmware, private asset or GPU input was used.

No native Windows or macOS runtime, real title, firmware, private asset or GPU input was tested. Windows PE generation on Linux is structural coverage. No cross-PR merge or runtime validation is claimed.

Checklist

  • Exact base: f145139676a48306681d3a4d5fabf83938759daf; the 2026-10-09 overlap audit found no equivalent implementation
  • One topic: reject ambiguous dynamic table metadata in the shared pipeline
  • No added code comments, investigation files or third-party dependencies in the patch
  • Generic input validation; existing missing-table, malformed-table and repeatable-tag behavior is preserved
  • Depends on: none
  • AI-assisted: yes; the author remains responsible for every line

Open PRs #1272, #1446, #1617 and #1690 share RelinkerPipeline.cpp for other work. #1690 and #1913 also change test registration. A fresh overlap check found no equivalent open implementation. No functional dependency on those PRs.

@Zinebyte

Zinebyte commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Regarding the overlap warning: #2001 deletes test_dynamic_segment.py and removes nearby CMake registrations that this PR extends. I reproduced the CMake three-way conflict; the test has a modify/delete conflict. I found no equivalent duplicate-metadata validation or functional dependency, so Depends on: none remains accurate. No current code change is justified at verified head 8ee833159f27cb16c0d25eca0f90569152c2942c. These test/registration conflicts need resolution if either PR changes main first.

Fresh, serial relinker-only Release tests on Zorin OS 18.1 x86-64 / GCC 13.3: PR head 39/39 passed (6.32 s); exact base f145139676a48306681d3a4d5fabf83938759daf 38/38 passed (6.19 s). Both published duplicate regressions fail against base and pass on the PR head. Windows PE generation was structural coverage on Linux; native Windows/macOS and hardware execution were not tested. This review and validation were AI-assisted.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Closing: no title is shown with a second PT_DYNAMIC or repeated table tags, and rejecting identical duplicates could refuse an input the console loads. Please reopen with the title whose conversion goes wrong because of it.

@Zinebyte

Zinebyte commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Understood. The synthetic tests do not establish a title whose conversion fails because of this metadata. Rejecting identical duplicates could also reject input the console accepts; the tests do not establish compatibility. I have no affected-title evidence supporting this change and accept keeping the PR closed.

AI-assisted review and reply.

oneandonlydean pushed a commit that referenced this pull request Oct 25, 2026
…pipeline reads

getTagValue returned the first entry of a dynamic tag, so an executable
with DT_RELASZ 0 followed by DT_RELASZ 24 converted for Linux with exit
0 and an output without DT_RELA, while the reverse order kept the
relocation. getTagValue now scans every entry and throws "Conflicting
duplicate <NAME> tags" when a tag it is asked for repeats with a
different value, the rule RelativeRelocationIndex already applies with
unused-filter=1. The pipeline check accepts a repeat with the same
value: it is not ambiguous, and #1938, which rejected it, was closed
because no title was shown and because rejecting it could refuse an
input the console loads. The code analysis on Windows and macOS and the
strict filter keep their own duplicate checks. Inputs without such a
conflict convert as before, and an input with one now fails with the
same message on every target.
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.

2 participants