diff --git a/src/LibObjectFile/Elf/ElfSectionHeaderTable.cs b/src/LibObjectFile/Elf/ElfSectionHeaderTable.cs index dd17f04..0185874 100644 --- a/src/LibObjectFile/Elf/ElfSectionHeaderTable.cs +++ b/src/LibObjectFile/Elf/ElfSectionHeaderTable.cs @@ -133,6 +133,7 @@ private static ElfSection CreateElfSection(ElfReader reader, uint sectionIndex, ElfSectionType.Note => new ElfNoteTable(), ElfSectionType.SymbolTableSectionHeaderIndices => new ElfSymbolTableSectionHeaderIndices(), ElfSectionType.NoBits => new ElfNoBitsSection(), + ElfSectionType.DynamicLinking => new ElfDynamicLinkingTable(), _ => new ElfStreamSection(sectionType) }; } diff --git a/src/LibObjectFile/Elf/Sections/ElfDynamic.cs b/src/LibObjectFile/Elf/Sections/ElfDynamic.cs new file mode 100644 index 0000000..554e435 --- /dev/null +++ b/src/LibObjectFile/Elf/Sections/ElfDynamic.cs @@ -0,0 +1,32 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// This file is licensed under the BSD-Clause 2 license. +// See the license.txt file in the project root for more information. + +namespace LibObjectFile.Elf +{ + /// + /// Dynamic table entry for ELF. + /// + public record struct ElfDynamic + { + /// + /// Type of dynamic table entry. + /// + public long Tag { get; set; } + + /// + /// Integer value of entry. + /// + public ulong Value { get; set; } + + /// + /// Pointer value of entry. + /// + public ulong Pointer => Value; + + /// + /// Dynamic Tag + /// + public ElfDynamicTag TagType => (ElfDynamicTag)Tag; + } +} \ No newline at end of file diff --git a/src/LibObjectFile/Elf/Sections/ElfDynamicLinkingTable.cs b/src/LibObjectFile/Elf/Sections/ElfDynamicLinkingTable.cs new file mode 100644 index 0000000..ef19012 --- /dev/null +++ b/src/LibObjectFile/Elf/Sections/ElfDynamicLinkingTable.cs @@ -0,0 +1,166 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// This file is licensed under the BSD-Clause 2 license. +// See the license.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LibObjectFile.Diagnostics; +using LibObjectFile.IO; + +namespace LibObjectFile.Elf +{ + public class ElfDynamicLinkingTable : ElfSection + { + private Stream _stream; + private bool _is32; + + public Stream Stream + { + get => _stream; + set + { + ArgumentNullException.ThrowIfNull(value); + _stream = value; + Size = (ulong)_stream.Length; + } + } + + public List Entries { get; } + + public ElfDynamicLinkingTable() : base(ElfSectionType.DynamicLinking) + { + Name = ElfSectionSpecialType.Dynamic.GetDefaultName(); + Flags = ElfSectionSpecialType.Dynamic.GetSectionFlags(); + _stream = new MemoryStream(); + + Entries = []; + } + + public override void Read(ElfReader reader) + { + reader.Position = Position; + Entries.Clear(); + + var numberOfEntries = (int)(base.Size / base.TableEntrySize); + var entries = Entries; + CollectionsMarshal.SetCount(entries, numberOfEntries); + + if (_is32) + Read32(reader, numberOfEntries); + else + Read64(reader, numberOfEntries); + } + + private void Read32(ElfReader reader, int numberOfEntries) + { + using var batch = new BatchDataReader(reader.Stream, numberOfEntries); + var span = CollectionsMarshal.AsSpan(Entries); + ref var entry = ref MemoryMarshal.GetReference(span); + while (batch.HasNext()) + { + ref var dyn = ref batch.Read(); + + entry.Tag = reader.Decode(dyn.d_tag); + entry.Value = reader.Decode(dyn.d_un.d_val); + + entry = ref Unsafe.Add(ref entry, 1); + } + } + + private void Read64(ElfReader reader, int numberOfEntries) + { + using var batch = new BatchDataReader(reader.Stream, numberOfEntries); + var span = CollectionsMarshal.AsSpan(Entries); + ref var entry = ref MemoryMarshal.GetReference(span); + while (batch.HasNext()) + { + ref var dyn = ref batch.Read(); + + entry.Tag = reader.Decode(dyn.d_tag); + entry.Value = reader.Decode(dyn.d_un.d_val); + + entry = ref Unsafe.Add(ref entry, 1); + } + } + + public override void Write(ElfWriter writer) + { + if (_is32) + Write32(writer); + else + Write64(writer); + } + + private void Write32(ElfWriter writer) + { + var entries = CollectionsMarshal.AsSpan(Entries); + using var batch = new BatchDataWriter(writer.Stream, entries.Length); + var dyn = new ElfNative.Elf32_Dyn(); + for (int i = 0; i < entries.Length; i++) + { + ref var entry = ref entries[i]; + + writer.Encode(out dyn.d_tag, (int)entry.Tag); + writer.Encode(out dyn.d_un.d_val, (uint)entry.Value); + + batch.Write(dyn); + } + } + + private void Write64(ElfWriter writer) + { + var entries = CollectionsMarshal.AsSpan(Entries); + using var batch = new BatchDataWriter(writer.Stream, entries.Length); + var dyn = new ElfNative.Elf64_Dyn(); + for (int i = 0; i < entries.Length; i++) + { + ref var entry = ref entries[i]; + + writer.Encode(out dyn.d_tag, entry.Tag); + writer.Encode(out dyn.d_un.d_val, entry.Value); + + batch.Write(dyn); + } + } + + protected override unsafe void ValidateParent(ObjectElement parent) + { + base.ValidateParent(parent); + + var elf = (ElfFile)parent; + _is32 = elf.FileClass == ElfFileClass.Is32; + + BaseTableEntrySize = (uint)(_is32 ? sizeof(ElfNative.Elf32_Dyn) : sizeof(ElfNative.Elf64_Dyn)); + AdditionalTableEntrySize = 0; + } + + internal override unsafe void InitializeEntrySizeFromRead(DiagnosticBag diagnostics, ulong entrySize, bool is32) + { + _is32 = is32; + + if (is32) + { + if (entrySize != (ulong)sizeof(ElfNative.Elf32_Dyn)) + diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSectionEntrySize, $"Invalid size [{entrySize}] for dynamic entry. Expecting to be equal to [{sizeof(ElfNative.Elf32_Dyn)}] bytes."); + else + { + BaseTableEntrySize = (uint)sizeof(ElfNative.Elf32_Dyn); + AdditionalTableEntrySize = (uint)(entrySize - AdditionalTableEntrySize); + } + } + else + { + if (entrySize != (ulong)sizeof(ElfNative.Elf64_Dyn)) + diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSectionEntrySize, $"Invalid size [{entrySize}] for dynamic entry. Expecting to be equal to [{sizeof(ElfNative.Elf64_Dyn)}] bytes."); + else + { + BaseTableEntrySize = (uint)sizeof(ElfNative.Elf64_Dyn); + AdditionalTableEntrySize = (uint)(entrySize - AdditionalTableEntrySize); + } + } + } + } +} \ No newline at end of file diff --git a/src/LibObjectFile/Elf/Sections/ElfDynamicTag.cs b/src/LibObjectFile/Elf/Sections/ElfDynamicTag.cs new file mode 100644 index 0000000..17c7eef --- /dev/null +++ b/src/LibObjectFile/Elf/Sections/ElfDynamicTag.cs @@ -0,0 +1,202 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// This file is licensed under the BSD-Clause 2 license. +// See the license.txt file in the project root for more information. + +namespace LibObjectFile.Elf +{ + /// + /// Dynamic table entry tags. + /// + public enum ElfDynamicTag : uint + { + /// + /// Null + /// + Null = ElfNative.DT_NULL, + + /// + /// String table offset of needed library. + /// + Needed = ElfNative.DT_NEEDED, + + /// + /// Size of relocation entries in PLT. + /// + PltRelSz = ElfNative.DT_PLTRELSZ, + + /// + /// Address associated with linkage table. + /// + PltGot = ElfNative.DT_PLTGOT, + + /// + /// Address of symbolic hash table. + /// + Hash = ElfNative.DT_HASH, + + /// + /// Address of dynamic string table. + /// + StrTab = ElfNative.DT_STRTAB, + + /// + /// Address of dynamic symbol table. + /// + SymTab = ElfNative.DT_SYMTAB, + + /// + /// Address of relocation table (Rela entries). + /// + Rela = ElfNative.DT_RELA, + + /// + /// Size of Rela relocation table. + /// + RelaSz = ElfNative.DT_RELASZ, + + /// + /// Size of a Rela relocation entry. + /// + RelaEnt = ElfNative.DT_RELAENT, + + /// + /// Total size of the string table. + /// + StrSz = ElfNative.DT_STRSZ, + + /// + /// Size of a symbol table entry. + /// + SymEnt = ElfNative.DT_SYMENT, + + /// + /// Address of initialization function. + /// + Init = ElfNative.DT_INIT, + + /// + /// Address of termination function. + /// + Fini = ElfNative.DT_FINI, + + /// + /// String table offset of a shared object's name. + /// + SoName = ElfNative.DT_SONAME, + + /// + /// String table offset of library search path. + /// + RPath = ElfNative.DT_RPATH, + + /// + /// Changes symbol resolution algorithm. + /// + Symbolic = ElfNative.DT_SYMBOLIC, + + /// + /// Address of relocation table (Rel entries). + /// + Rel = ElfNative.DT_REL, + + /// + /// Size of Rel relocation table. + /// + RelSz = ElfNative.DT_RELSZ, + + /// + /// Size of a Rel relocation entry. + /// + RelEnt = ElfNative.DT_RELENT, + + /// + /// Type of relocation entry used for linking. + /// + PltRel = ElfNative.DT_PLTREL, + + /// + /// Reserved for debugger. + /// + Debug = ElfNative.DT_DEBUG, + + /// + /// Relocations exist for non-writable segments. + /// + TextRel = ElfNative.DT_TEXTREL, + + /// + /// Address of relocations associated with PLT. + /// + JmpRel = ElfNative.DT_JMPREL, + + /// + /// Process all relocations before execution. + /// + BindNow = ElfNative.DT_BIND_NOW, + + /// + /// Pointer to array of initialization functions. + /// + InitArray = ElfNative.DT_INIT_ARRAY, + + /// + /// Pointer to array of termination functions. + /// + FiniArray = ElfNative.DT_FINI_ARRAY, + + /// + /// Size of . + /// + InitArraySz = ElfNative.DT_INIT_ARRAYSZ, + + /// + /// Size of . + /// + FiniArraySz = ElfNative.DT_FINI_ARRAYSZ, + + /// + /// String table offset of library search path. + /// + RunPath = ElfNative.DT_RUNPATH, + + /// + /// Flags. + /// + Flags = ElfNative.DT_FLAGS, + + /// + /// Values from here to DT_LOOS follow the rules for the interpretation of the d_un union. + /// + Encoding = ElfNative.DT_ENCODING, + + /// + /// Pointer to array of preinit functions. + /// + PreInitArray = ElfNative.DT_PREINIT_ARRAY, + + /// + /// Size of the DT_PREINIT_ARRAY array. + /// + PreInitArraySz = ElfNative.DT_PREINIT_ARRAYSZ, + + /// + /// Start of environment specific tags. + /// + LoOs = ElfNative.DT_LOOS, + + /// + /// End of environment specific tags. + /// + HiOS = ElfNative.DT_HIOS, + + /// + /// Start of processor specific tags. + /// + LoProc = ElfNative.DT_LOPROC, + + /// + /// End of processor specific tags. + /// + HiProc = ElfNative.DT_HIPROC + } +} \ No newline at end of file diff --git a/src/LibObjectFile/Elf/Sections/ElfStringTable.cs b/src/LibObjectFile/Elf/Sections/ElfStringTable.cs index a54d9e0..abe0081 100644 --- a/src/LibObjectFile/Elf/Sections/ElfStringTable.cs +++ b/src/LibObjectFile/Elf/Sections/ElfStringTable.cs @@ -127,7 +127,7 @@ public ElfString Resolve(ElfString name) return newName; } - internal bool TryGetString(uint index, out string text) + public bool TryGetString(uint index, out string text) { if (index == 0) {