Add ELF dynamic linking table (SHT_DYNAMIC) support#48
Merged
Conversation
(cherry picked from commit bf73964)
(cherry picked from commit c70e1a7)
(cherry picked from commit 1e985b2)
(cherry picked from commit e1fca63)
PR xoofx#45 added editable dynamic-section entries but left no public way to append a string to a string table. A new DT_NEEDED entry stores a raw .dynstr offset, so referencing a library name that is not already in the table was impossible. Exposes GetOrCreateString, which appends the string (or reuses an existing copy) and returns its byte offset.
The enum only defined tags through DT_PREINIT_ARRAYSZ, so tags that appear in ordinary shared objects and executables (GNU_HASH, VERSYM, VERDEF/VERNEED and their counts, RELACOUNT, FLAGS_1, the RELR family, and the GNU value/address range tags) had no named members and could only be handled as raw numbers. Adds those tags, mapped to the existing ElfNative constants, so callers and the printer can name them.
The Stream property on ElfDynamicLinkingTable was never wired into Read/Write (both go through Entries), so it was dead: it held an empty MemoryStream that was neither populated on load nor written on save. There was also no way to resolve a DT_NEEDED/DT_SONAME offset back to a library name, nor to serialize the entries on their own. Removes the dead Stream property and adds a resolution API over the linked .dynstr (StringTable, IsStringValueTag, TryGetString, GetNeededLibraries, AddNeededLibrary) that keeps entries as raw offsets. Adds standalone Read(Stream)/Write(Stream) that (de)serialize Entries through the ElfReader/ElfWriter factories, inferring the file class and byte order from the parent ElfFile.
PrintDynamicSections was a stub that always wrote "There is no dynamic section in this file", even for files that had one, so ElfPrinter output diverged from readelf for any dynamic binary. Implements the dump: one line per entry up to the DT_NULL terminator, with the tag name and a value rendered per tag (library names via the linked .dynstr, sizes as bytes, PLTREL as REL/RELA, DF_/DF_1_ flag names, and addresses as hex). Output matches readelf -d byte for byte on the test binaries. - src/LibObjectFile/Elf/ElfPrinter.cs: dump plus tag-name and value formatters - src/LibObjectFile.Tests/Verified/ElfSimpleTests.TestElf_name=*.verified.txt: regenerated snapshots now show the dynamic section
Nothing exercised the dynamic table outside the real-binary snapshots: building one from entries, resolving needed libraries, the standalone stream round-trip, and the 32-bit Read32/Write32 path were all untested. Adds SimpleDynamicSection (build, resolve, full-file round-trip), DynamicSectionStreamRoundTrip, and DynamicSection32Bit (Elf32_Dyn records plus the printer's 8-digit tag hex).
The 64-bit section header writer cast sh_addr, sh_offset, sh_size, sh_addralign and sh_entsize to uint, so any value >= 4 GiB (high load addresses, large NOBITS sections) was silently truncated on write. Passes the full ulong values to the matching Elf64 encode overloads. Output for sub-4 GiB values is unchanged. - src/LibObjectFile/Elf/ElfSectionHeaderTable.cs: drop the uint casts on the 64-bit Elf64_Shdr fields - src/LibObjectFile.Tests/Elf/ElfSimpleTests.cs: regression round-tripping a NOBITS section with a >4 GiB address and size
The ELF section list did not mention the dynamic linking table. Adds it to the supported sections.
Owner
|
Thanks! I will fix the build in a separate commit. |
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.
Supersedes #45 and builds on that initial work. Implements the
SHT_DYNAMICitem of #36, and a separate follow-up PR addsDT_NEEDEDdependency injection on top of this. I'll update a comment linking to that PR.This gives the
.dynamicsection its ownElfDynamicLinkingTabletype instead of loading it as a generic section, and fills out the dynamic-linking API and tooling around it.What's added/finished:
ElfDynamicLinkingTable: a dedicated section forSHT_DYNAMIC, wired into the section factory. Reads and writes the dynamic array for 32 and 64-bit and LSB/MSB, with full round-trips.ElfDynamicTag: completed with the tags that show up in binaries (GNU_HASH,VERSYM,VERDEF/VERNEEDand their counts,RELACOUNT,FLAGS_1,theRELRgroup of tags, and the GNU value/address-range tags)..dynstr:StringTable,IsStringValueTag,TryGetStringandGetNeededLibraries()turnDT_NEEDED/DT_SONAME/DT_RPATH/DT_RUNPATHoffsets into names.Read(Stream)/Write(Stream)on the dynamic table, following theElfFile/PEFileconvention (happy to drop it if you'd prefer sections stay pipeline-only).readelf -d-style printer (ElfPrinter.PrintDynamicSections); output matchesreadelf -dbyte for byte on the test binaries.Also fixed an issue with section truncation I noticed:
Elf64_Shdrwriter castsh_addr/sh_offset/sh_size/sh_addralign/sh_entsizetouint, silently truncating any value >= 4 GiB. It now writes the full 64-bit values (output for sub-4 GiB values is unchanged).Happy to split this into its own PR if you'd prefer.
Test coverage (tests the earlier draft didn't have yet):
readelf -d.