From 516e36d176c229f366f2cbedb0bfe30674433438 Mon Sep 17 00:00:00 2001 From: Ariel Lothlorien Date: Sat, 4 May 2024 22:05:03 -0500 Subject: [PATCH] [IO][External] ELF64 Parser (Headers) --- KANBAN.md | 23 +- src/Kore.Utility/Kore.Utility.csproj | 1 + src/Kore.Utility/elf.cs | 306 +++++++++++++++++++++++++++ 3 files changed, 326 insertions(+), 4 deletions(-) create mode 100644 src/Kore.Utility/elf.cs diff --git a/KANBAN.md b/KANBAN.md index 086dfe4..86321cf 100644 --- a/KANBAN.md +++ b/KANBAN.md @@ -1,12 +1,15 @@ - [Done](#done) - [Done 10/18/2021](#done-10182021) - [Done 10/21/2021](#done-10212021) + - [Done 11/16/2021](#done-11162021) - [Done 02/25/2023](#done-02252023) - [Done 2023/03/08](#done-20230308) - [Done 2023/05/20](#done-20230520) - [Done 2023/05/21](#done-20230521) - [Done 2023/05/26](#done-20230526) - [Next Commit (Eforen)](#next-commit-eforen) + - [Done 2024/05/04](#done-20240504) + - [Next Commit (Eforen)](#next-commit-eforen-1) - [Working On](#working-on) - [Working on (Eforen)](#working-on-eforen) - [Todos](#todos) @@ -28,6 +31,9 @@ * [KUICK][TOKENIZER] Write Tests for every Token * [KUICK][TOKENIZER] Implement all failing tests +## Done 11/16/2021 +* [KUICK][TOKENIZER] Implement all failing tests + ## Done 02/25/2023 * [KUICK][LEXER] Refactor switch the name of the parser and lexer because I had the definitions backwards * [KUICK][PARSER] Change to using a parser that makes an intermediary AST (Abstract Syntax Tree) @@ -91,8 +97,17 @@ * [KUICK][PARSER] Implement `LWU` * [KUICK][PARSER] Implement `LD` +## Done 2024/05/04 +### Next Commit (Eforen) +* [IO][External] ELF64 Parser (Headers) + # Working On ## Working on (Eforen) +* [IO][External] ELF64 Parser (Program Headers) +* [IO][External] ELF64 Parser (Sections) +* [IO][External] ELF64 Writer (Headers) +* [IO][External] ELF64 Writer (Program Headers) +* [IO][External] ELF64 Writer (Sections) * [KIUCK][PARSER] Implement Pseudo Instructions * [KIUCK][PARSER][TEST] Pseudo Instruction `beqz` * [KIUCK][PARSER][TEST] Pseudo Instruction `bnez` @@ -108,9 +123,10 @@ * [KUICK][ASSEMBLER] Write Tests for every Token # Todos -* [KUICK][PARSER] Impliment `%hi(msg)` -* [KUICK][PARSER] Impliment `%lo(msg)` -* [KUICK][PARSER] Impliment `msg: .string "Hello World\n"` +## Todo +* [KUICK][PARSER] Implement `%hi(msg)` +* [KUICK][PARSER] Implement `%lo(msg)` +* [KUICK][PARSER] Implement `msg: .string "Hello World\n"` * [KUICK][ASSEMBLER] Implement all failing tests * Implement all RISC-V ASM directives in (RISC-V ASSEMBLY LANGUAGE Programmer Manual - Part 1)[https://shakti.org.in/docs/risc-v-asm-manual.pdf] (contact @ shakti[dot]iitm[@]gmail[dot]com) * [KUICK][PARSER] Write Test for F Type Instruction `FADD.S` @@ -120,6 +136,5 @@ * [KUICK][PARSER] Write Test for RV64I/E Instruction Set Instruction `LD` * [KUICK][PARSER] Write Test for RV64I/E Instruction Set Instruction `SD` * [Cite] Email SHAKTI Development Team requesting to include their PDF in this repository (RISC-V ASSEMBLY LANGUAGE Programmer Manual - Part 1)[https://shakti.org.in/docs/risc-v-asm-manual.pdf] -## Todo ## Planned for some time later ## Wishlist \ No newline at end of file diff --git a/src/Kore.Utility/Kore.Utility.csproj b/src/Kore.Utility/Kore.Utility.csproj index 0f9c112..09a554d 100644 --- a/src/Kore.Utility/Kore.Utility.csproj +++ b/src/Kore.Utility/Kore.Utility.csproj @@ -41,6 +41,7 @@ + diff --git a/src/Kore.Utility/elf.cs b/src/Kore.Utility/elf.cs new file mode 100644 index 0000000..b9f3794 --- /dev/null +++ b/src/Kore.Utility/elf.cs @@ -0,0 +1,306 @@ +using System; +using System.IO; + +namespace Kore.Utility.ELF { + public enum ELFClass : byte { + ELFCLASSNONE = 0, + ELFCLASS32 = 1, + ELFCLASS64 = 2 + } + + public enum ELFFormat : byte { + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 + } + + public enum ELFType : ushort { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xff00, + ET_HIPROC = 0xffff + } + +/* +http://www.skyfree.org/linux/references/ELF_Format.pdf +https://interrupt.memfault.com/blog/elf-format-differences +*/ + + public struct Elf_Half { + public ushort Value; + public Elf_Half(ushort value) { + Value = value; + } + public Elf_Half(BinaryReader reader) { + Value = reader.ReadUInt16(); + } + public static implicit operator Elf_Half(ushort value) { + return new Elf_Half(value); + } + public static implicit operator ushort(Elf_Half value) { + return value.Value; + } + } + + public struct Elf_Word { + public uint Value; + public Elf_Word(uint value) { + Value = value; + } + public Elf_Word(BinaryReader reader) { + Value = reader.ReadUInt32(); + } + public static implicit operator Elf_Word(uint value) { + return new Elf_Word(value); + } + public static implicit operator uint(Elf_Word value) { + return value.Value; + } + } + + public struct Elf32_Addr { + public uint Value; + public Elf32_Addr(uint value) { + Value = value; + } + public Elf32_Addr(BinaryReader reader) { + Value = reader.ReadUInt32(); + } + public static implicit operator Elf32_Addr(uint value) { + return new Elf32_Addr(value); + } + public static implicit operator uint(Elf32_Addr value) { + return value.Value; + } + } + + public struct Elf64_Addr { + public ulong Value; + public Elf64_Addr(ulong value) { + Value = value; + } + public Elf64_Addr(BinaryReader reader) { + Value = reader.ReadUInt64(); + } + public static implicit operator Elf64_Addr(ulong value) { + return new Elf64_Addr(value); + } + public static implicit operator ulong(Elf64_Addr value) { + return value.Value; + } + } + + public struct Elf32_Off { + public uint Value; + public Elf32_Off(uint value) { + Value = value; + } + public Elf32_Off(BinaryReader reader) { + Value = reader.ReadUInt32(); + } + public static implicit operator Elf32_Off(uint value) { + return new Elf32_Off(value); + } + public static implicit operator uint(Elf32_Off value) { + return value.Value; + } + } + + public struct Elf64_Off { + public ulong Value; + public Elf64_Off(ulong value) { + Value = value; + } + public Elf64_Off(BinaryReader reader) { + Value = reader.ReadUInt64(); + } + public static implicit operator Elf64_Off(ulong value) { + return new Elf64_Off(value); + } + public static implicit operator ulong(Elf64_Off value) { + return value.Value; + } + } + + public struct Elf64_Xword { + public ulong Value; + public Elf64_Xword(ulong value) { + Value = value; + } + public Elf64_Xword(BinaryReader reader) { + Value = reader.ReadUInt64(); + } + public static implicit operator Elf64_Xword(ulong value) { + return new Elf64_Xword(value); + } + public static implicit operator ulong(Elf64_Xword value) { + return value.Value; + } + } + + public struct Elf64_Sxword { + public long Value; + public Elf64_Sxword(long value) { + Value = value; + } + public Elf64_Sxword(BinaryReader reader) { + Value = reader.ReadInt64(); + } + public static implicit operator Elf64_Sxword(long value) { + return new Elf64_Sxword(value); + } + public static implicit operator long(Elf64_Sxword value) { + return value.Value; + } + } + + /// + /// ELF Header + /// + /// + public class ELF_FILE{ + /// + /// 16 bytes 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 + /// + public e_ident e_ident; + /// + /// 2 bytes 02 00 for ET_EXEC (Executable file) No other types are supported atm + /// + public ushort e_type; + /// + /// 2 bytes we only support RISC-V atm so must be 0xf3 + /// + public ushort e_machine; + /// + /// 4 bytes 01 00 00 00 for version 1 should never change + /// + public uint e_version; + /// + /// 4 bytes entry point of the program in memory + /// + public ulong e_entry; + /// + /// 4 bytes offset of the program header table + /// + public ulong e_phoff; + /// + /// 4 bytes offset of the section header table + /// + public ulong e_shoff; + /// + /// 4 bytes flags usually 0 + /// + public uint e_flags; + /// + /// 2 bytes size of this header + /// + public ushort e_ehsize; + /// + /// 2 bytes size of a program header table entry + /// + public ushort e_phentsize; + /// + /// 2 bytes number of entries in the program header table + /// + public ushort e_phnum; + /// + /// 2 bytes size of a single section header table entry + /// + public ushort e_shentsize; + /// + /// 2 bytes number of entries in the section header table + /// + public ushort e_shnum; + /// + /// 2 bytes section header table index of the entry associated with the section name string table + /// + public ushort e_shstrndx; + public static ELF_FILE FromBinaryReader(System.IO.BinaryReader reader) { + ELF_FILE file = new ELF_FILE(); + file.e_ident = e_ident.FromBinaryReader(reader); + file.e_type = reader.ReadUInt16(); + file.e_machine = reader.ReadUInt16(); + file.e_version = reader.ReadUInt32(); + file.e_entry = reader.ReadUInt64(); + file.e_phoff = reader.ReadUInt64(); + file.e_shoff = reader.ReadUInt64(); + file.e_flags = reader.ReadUInt32(); + file.e_ehsize = reader.ReadUInt16(); + file.e_phentsize = reader.ReadUInt16(); + file.e_phnum = reader.ReadUInt16(); + file.e_shentsize = reader.ReadUInt16(); + file.e_shnum = reader.ReadUInt16(); + file.e_shstrndx = reader.ReadUInt16(); + return file; + } + } + + public class e_ident { + public byte EI_MAG0; + public byte EI_MAG1; + public byte EI_MAG2; + public byte EI_MAG3; + public byte EI_CLASS; + public byte EI_DATA; + public uint EI_VERSION; + public byte EI_OSABI; + public byte EI_ABIVERSION; + public byte[] EI_PAD = new byte[4]; + + public static e_ident FromBinaryReader(System.IO.BinaryReader reader) { + e_ident ident = new e_ident(); + ident.EI_MAG0 = reader.ReadByte(); + ident.EI_MAG1 = reader.ReadByte(); + ident.EI_MAG2 = reader.ReadByte(); + ident.EI_MAG3 = reader.ReadByte(); + if (ident.EI_MAG0 != 0x7f || ident.EI_MAG1 != 0x45 || ident.EI_MAG2 != 0x4c || ident.EI_MAG3 != 0x46) { + throw new Exception("Not an ELF file"); + } + ident.EI_CLASS = reader.ReadByte(); + if (ident.EI_CLASS != (byte)ELFClass.ELFCLASS64) { + throw new Exception("Not a 64-bit ELF file"); + } + ident.EI_DATA = reader.ReadByte(); + if (ident.EI_DATA != 1) { + throw new Exception("Not a little-endian ELF file"); + } + ident.EI_VERSION = reader.ReadUInt32(); + if (ident.EI_VERSION != 1) { + throw new Exception("Not an ELF version 1 file"); + } + ident.EI_OSABI = reader.ReadByte(); + if(ident.EI_OSABI != 0) { + throw new Exception("Not an ELF version 0 OSABI file"); + } + ident.EI_ABIVERSION = reader.ReadByte(); + if(ident.EI_ABIVERSION != 0) { + throw new Exception("Not an ELF version 0 ABI file"); + } + for(int i = 0; i < 4; i++) { + ident.EI_PAD[i] = reader.ReadByte(); + } + return ident; + } + + public static e_ident FromBytes(byte[] bytes) { + e_ident ident = new e_ident(); + ident.EI_MAG0 = bytes[0]; + ident.EI_MAG1 = bytes[1]; + ident.EI_MAG2 = bytes[2]; + ident.EI_MAG3 = bytes[3]; + ident.EI_CLASS = bytes[4]; + ident.EI_DATA = bytes[5]; + ident.EI_VERSION = BitConverter.ToUInt32(bytes, 6); + ident.EI_OSABI = bytes[7]; + ident.EI_ABIVERSION = bytes[8]; + for(int i = 0; i < 4; i++) { + ident.EI_PAD[i] = bytes[9 + i]; + } + return ident; + } + } + +} \ No newline at end of file