Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ elf.Write(outStream);
- Symbol Table
- Relocation Table: supported I386, X86_64, ARM and AARCH64 relocations (others can be exposed by adding some mappings)
- Note Table
- Dynamic Linking Table (`SHT_DYNAMIC`)
- Other sections fallback to `ElfCustomSection`
- Program headers with or without sections
- Print with `readelf` similar output
Expand Down
125 changes: 125 additions & 0 deletions src/LibObjectFile.Tests/Elf/ElfSimpleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,131 @@ public async Task SimpleProgramHeaderAndCodeSectionAndSymbolSectionAndRelocation
}


[TestMethod]
public async Task SimpleDynamicSection()
{
var elf = new ElfFile(ElfArch.X86_64);

var dynstr = new ElfStringTable() { Name = ".dynstr" };
elf.Add(dynstr);

var dynamic = new ElfDynamicLinkingTable() { Link = dynstr };
dynamic.AddNeededLibrary("libc.so.6");
dynamic.AddNeededLibrary("libm.so.6");
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Flags1, Value = 0x08000001 });
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Null });
elf.Add(dynamic);

elf.Add(new ElfSectionHeaderStringTable());
elf.Add(new ElfSectionHeaderTable());

// The read helpers resolve DT_NEEDED offsets through the linked .dynstr.
CollectionAssert.AreEqual(new[] { "libc.so.6", "libm.so.6" }, dynamic.GetNeededLibraries().ToList());

await AssertReadElf(elf, "test_dynamic.elf");

// Round-trip the entries and confirm the resolved library names survive write -> read.
var memoryStream = new MemoryStream();
elf.Write(memoryStream);
memoryStream.Position = 0;
var roundTrip = ElfFile.Read(memoryStream);
var roundTripDynamic = roundTrip.Sections.OfType<ElfDynamicLinkingTable>().Single();
Assert.AreEqual(dynamic.Entries.Count, roundTripDynamic.Entries.Count);
CollectionAssert.AreEqual(new[] { "libc.so.6", "libm.so.6" }, roundTripDynamic.GetNeededLibraries().ToList());
}

[TestMethod]
public void DynamicSectionStreamRoundTrip()
{
var elf = new ElfFile(ElfArch.X86_64);
var dynstr = new ElfStringTable() { Name = ".dynstr" };
elf.Add(dynstr);

var dynamic = new ElfDynamicLinkingTable() { Link = dynstr };
dynamic.AddNeededLibrary("libc.so.6");
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Flags1, Value = 0x08000001 });
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Null });
elf.Add(dynamic);

// Serialize just the .dynamic entries to a standalone stream (64-bit -> 16 bytes each).
var stream = new MemoryStream();
dynamic.Write(stream);
Assert.AreEqual(dynamic.Entries.Count * 16, stream.Length);

// Read them back into a fresh table attached to another file and confirm value equality.
var elf2 = new ElfFile(ElfArch.X86_64);
var dynamic2 = new ElfDynamicLinkingTable();
elf2.Add(dynamic2);
stream.Position = 0;
dynamic2.Read(stream);

CollectionAssert.AreEqual(dynamic.Entries, dynamic2.Entries);
}

[TestMethod]
public void DynamicSection32Bit()
{
var elf = new ElfFile(ElfArch.I386);
var dynstr = new ElfStringTable() { Name = ".dynstr" };
elf.Add(dynstr);

var dynamic = new ElfDynamicLinkingTable() { Link = dynstr };
dynamic.AddNeededLibrary("libc.so.6");
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Flags, Value = 0x8 }); // DF_BIND_NOW
dynamic.Entries.Add(new ElfDynamic { Tag = (long)ElfDynamicTag.Null });
elf.Add(dynamic);

// The printer uses 8-digit tag hex for 32-bit files.
var writer = new StringWriter();
ElfPrinter.PrintDynamicSections(elf, writer);
var text = writer.ToString();
StringAssert.Contains(text, " 0x00000001 (NEEDED)");
StringAssert.Contains(text, "Shared library: [libc.so.6]");
StringAssert.Contains(text, " 0x0000001e (FLAGS)");
StringAssert.Contains(text, "BIND_NOW");

// The Read32/Write32 path uses 8-byte Elf32_Dyn records.
var stream = new MemoryStream();
dynamic.Write(stream);
Assert.AreEqual(dynamic.Entries.Count * 8, stream.Length);

var elf2 = new ElfFile(ElfArch.I386);
var dynamic2 = new ElfDynamicLinkingTable();
elf2.Add(dynamic2);
stream.Position = 0;
dynamic2.Read(stream);

CollectionAssert.AreEqual(dynamic.Entries, dynamic2.Entries);
}

[TestMethod]
public void SectionHeader64BitFieldsNotTruncated()
{
// Regression: the 64-bit section header writer cast sh_addr/sh_offset/sh_size/etc. to uint,
// truncating any value >= 4 GiB. A NOBITS section declares a huge address/size with no file bytes.
var elf = new ElfFile(ElfArch.X86_64);

var bss = new ElfNoBitsSection
{
Name = ".hugebss",
VirtualAddress = 0x1_0000_2000UL, // > 4 GiB
Size = 0x2_0000_1000UL, // > 4 GiB
VirtualAddressAlignment = 0x1000,
};
elf.Add(bss);
elf.Add(new ElfSectionHeaderStringTable());
elf.Add(new ElfSectionHeaderTable());

var stream = new MemoryStream();
elf.Write(stream);
stream.Position = 0;
var roundTrip = ElfFile.Read(stream);

var bss2 = roundTrip.Sections.OfType<ElfNoBitsSection>().Single();
Assert.AreEqual(0x1_0000_2000UL, bss2.VirtualAddress);
Assert.AreEqual(0x2_0000_1000UL, bss2.Size);
}

[TestMethod]
public async Task TestAlignedSection()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 0 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 0 (bytes)
Number of section headers: 4
Section header string table index: 3

Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .dynstr STRTAB 0000000000000000 000000 000000 00 0 0 0
[ 2] .dynamic DYNAMIC 0000000000000000 000000 000000 10 A 1 0 0
[ 3] .shstrtab STRTAB 0000000000000000 000000 000000 00 0 0 0
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

Dynamic section at offset 0x0 contains 4 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x0000000000000000 (NULL) 0x0

There are no relocations in this file.
No processor specific unwind information to decode

No version information found in this file.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,35 @@ Program Headers:
11
12 .init_array .fini_array .dynamic .got

There is no dynamic section in this file.
Dynamic section at offset 0x2dc8 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x1174
0x0000000000000019 (INIT_ARRAY) 0x3db8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x3dc0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x3b0
0x0000000000000005 (STRTAB) 0x480
0x0000000000000006 (SYMTAB) 0x3d8
0x000000000000000a (STRSZ) 141 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x3fb8
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x610
0x0000000000000007 (RELA) 0x550
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0x520
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x50e
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x550 contains 8 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,35 @@ Program Headers:
11
12 .init_array .fini_array .dynamic .got

There is no dynamic section in this file.
Dynamic section at offset 0x2dc8 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x1174
0x0000000000000019 (INIT_ARRAY) 0x3db8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x3dc0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x3b0
0x0000000000000005 (STRTAB) 0x480
0x0000000000000006 (SYMTAB) 0x3d8
0x000000000000000a (STRSZ) 141 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x3fb8
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x610
0x0000000000000007 (RELA) 0x550
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0x520
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x50e
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x550 contains 8 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,25 @@ Program Headers:
09
10 .init_array .fini_array .dynamic .got

There is no dynamic section in this file.
Dynamic section at offset 0x2e90 contains 17 entries:
Tag Type Name/Value
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x1130
0x0000000000000019 (INIT_ARRAY) 0x3e80
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x3e88
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x2f0
0x0000000000000005 (STRTAB) 0x3c0
0x0000000000000006 (SYMTAB) 0x318
0x000000000000000a (STRSZ) 122 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x4000
0x0000000000000007 (RELA) 0x440
0x0000000000000008 (RELASZ) 168 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x440 contains 7 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,38 @@ Program Headers:
10
11 .init_array .fini_array .data.rel.ro .dynamic .got

There is no dynamic section in this file.
Dynamic section at offset 0x223c90 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x000000000000000e (SONAME) Library soname: [libstdc++.so.6]
0x000000000000000c (INIT) 0x9a000
0x000000000000000d (FINI) 0x1aafc4
0x0000000000000019 (INIT_ARRAY) 0x21b880
0x000000000000001b (INIT_ARRAYSZ) 120 (bytes)
0x000000000000001a (FINI_ARRAY) 0x21b8f8
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x328
0x0000000000000005 (STRTAB) 0x2d310
0x0000000000000006 (SYMTAB) 0x90a0
0x000000000000000a (STRSZ) 302456 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x226000
0x0000000000000002 (PLTRELSZ) 25032 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x92f78
0x0000000000000007 (RELA) 0x7a8e8
0x0000000000000008 (RELASZ) 99984 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffc (VERDEF) 0x7a0c0
0x000000006ffffffd (VERDEFNUM) 48
0x000000006ffffffe (VERNEED) 0x7a758
0x000000006fffffff (VERNEEDNUM) 4
0x000000006ffffff0 (VERSYM) 0x77088
0x000000006ffffff9 (RELACOUNT) 899
0x0000000000000000 (NULL) 0x0

Relocation section '.rela.dyn' at offset 0x7a8e8 contains 4166 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
Expand Down
Loading
Loading