diff --git a/src/elf/elf.c b/src/elf/elf.c new file mode 100644 index 00000000..1a094baa --- /dev/null +++ b/src/elf/elf.c @@ -0,0 +1,143 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: 32 => 64 bit conversions + +internal ELF_Hdr64 +elf_hdr64_from_hdr32(ELF_Hdr32 h32) +{ + ELF_Hdr64 h64 = {0}; + MemoryCopy(h64.e_ident, h32.e_ident, sizeof(h64.e_ident)); + h64.e_type = h32.e_type; + h64.e_machine = h32.e_machine; + h64.e_version = h32.e_version; + h64.e_entry = (U64)h32.e_entry; + h64.e_phoff = (U64)h32.e_phoff; + h64.e_shoff = (U64)h32.e_shoff; + h64.e_flags = h32.e_flags; + h64.e_ehsize = h32.e_ehsize; + h64.e_phentsize = h32.e_phentsize; + h64.e_phnum = h32.e_phnum; + h64.e_shentsize = h32.e_shentsize; + h64.e_shnum = h32.e_shnum; + h64.e_shstrndx = h32.e_shstrndx; + return h64; +} + +internal ELF_Shdr64 +elf_shdr64_from_shdr32(ELF_Shdr32 h32) +{ + ELF_Shdr64 h64 = {0}; + h64.sh_name = h32.sh_name; + h64.sh_type = h32.sh_type; + h64.sh_flags = (U64)h32.sh_flags; + h64.sh_addr = (U64)h32.sh_addr; + h64.sh_offset = (U64)h32.sh_offset; + h64.sh_size = (U64)h32.sh_size; + h64.sh_link = h32.sh_link; + h64.sh_info = h32.sh_info; + h64.sh_addralign = (U64)h32.sh_addralign; + h64.sh_entsize = (U64)h32.sh_entsize; + return h64; +} + +internal ELF_Phdr64 +elf_phdr64_from_phdr32(ELF_Phdr32 h32) +{ + ELF_Phdr64 h64 = {0}; + h64.p_type = h32.p_type; + h64.p_flags = h32.p_flags; + h64.p_offset = (U64)h32.p_offset; + h64.p_vaddr = (U64)h32.p_vaddr; + h64.p_paddr = (U64)h32.p_paddr; + h64.p_filesz = (U64)h32.p_filesz; + h64.p_memsz = (U64)h32.p_memsz; + h64.p_align = (U64)h32.p_align; + return h64; +} + +internal ELF_Dyn64 +elf_dyn64_from_dyn32(ELF_Dyn32 h32) +{ + ELF_Dyn64 h64 = {0}; + h64.tag = (U64)h32.tag; + h64.val = (U64)h32.val; + return h64; +} + +internal ELF_Sym64 +elf_sym64_from_sym32(ELF_Sym32 sym32) +{ + ELF_Sym64 sym64 = {0}; + sym64.st_name = sym32.st_name; + sym64.st_value = sym32.st_value; + sym64.st_size = sym32.st_size; + sym64.st_info = sym32.st_info; + sym64.st_other = sym32.st_other; + sym64.st_shndx = sym32.st_shndx; + return sym64; +} + +internal ELF_Rel64 +elf_rel64_from_rel32(ELF_Rel32 rel32) +{ + U32 sym = SYMS_ELF32_R_SYM(rel32.r_info); + U32 type = SYMS_ELF32_R_TYPE(rel32.r_info); + ELF_Rel64 rel64 = {0}; + rel64.r_info = SYMS_ELF64_R_INFO(sym, type); + rel64.r_offset = rel32.r_offset; + return rel64; +} + +internal ELF_Rela64 +elf_rela64_from_rela32(ELF_Rela32 rela32) +{ + U32 sym = SYMS_ELF32_R_SYM(rela32.r_info); + U32 type = SYMS_ELF32_R_TYPE(rela32.r_info); + ELF_Rela64 rela64 = {0}; + rela64.r_offset = rela32.r_info; + rela64.r_info = SYMS_ELF64_R_INFO(sym, type); + rela64.r_addend = rela32.r_addend; + return rela64; +} + +internal ELF_Chdr64 +elf_chdr64_from_chdr32(ELF_Chdr32 chdr32) +{ + ELF_Chdr64 chdr64 = {0}; + chdr64.ch_type = chdr32.ch_type; + chdr64.ch_size = chdr32.ch_size; + chdr64.ch_addr_align = chdr32.ch_addr_align; + return chdr64; +} + +//////////////////////////////// + +internal String8 +elf_string_from_class(Arena *arena, ELF_Class v) +{ + switch (v) { + case ELF_Class_None: return str8_lit("None"); + case ELF_Class_32: return str8_lit("32Bit"); + case ELF_Class_64: return str8_lit("64Bit"); + } + return push_str8f(arena, "%#x", v); +} + +//////////////////////////////// + +internal Arch +arch_from_elf_machine(ELF_MachineKind e_machine) +{ + Arch arch = Arch_Null; + switch (e_machine) { + case ELF_MachineKind_None: arch = Arch_Null; break; + case ELF_MachineKind_AARCH64: arch = Arch_arm32; break; + case ELF_MachineKind_ARM: arch = Arch_arm32; break; + case ELF_MachineKind_386: arch = Arch_x86; break; + case ELF_MachineKind_X86_64: arch = Arch_x64; break; + default: NotImplemented; break; + } + return arch; +} diff --git a/src/elf/elf.h b/src/elf/elf.h new file mode 100644 index 00000000..2ee63aa3 --- /dev/null +++ b/src/elf/elf.h @@ -0,0 +1,992 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ELF_H +#define ELF_H + +typedef U8 ELF_Class; +enum +{ + ELF_Class_None = 0, + ELF_Class_32 = 1, + ELF_Class_64 = 2, + ELF_Class_Count = 3 +}; + +typedef U8 ELF_OsAbi; +enum +{ + ELF_OsAbi_None, + ELF_OsAbi_SYSV, + ELF_OsAbi_HPUX, + ELF_OsAbi_NETBSD, + ELF_OsAbi_GNU, + ELF_OsAbi_LINUX, + ELF_OsAbi_SOLARIS, + ELF_OsAbi_IRIX, + ELF_OsAbi_FREEBSD, + ELF_OsAbi_TRU64, + ELF_OsAbi_ARM = 97, + ELF_OsAbi_STANDALONE = 255, +}; + +typedef U8 ELF_Version; +enum +{ + ELF_Version_None, + ELF_Version_Current, +}; + +typedef U16 ELF_MachineKind; +enum +{ + ELF_MachineKind_None = 0, + ELF_MachineKind_M32 = 1, + ELF_MachineKind_SPARC = 2, + ELF_MachineKind_386 = 3, + ELF_MachineKind_68K = 4, + ELF_MachineKind_88K = 5, + ELF_MachineKind_IAMCU = 6, + ELF_MachineKind_860 = 7, + ELF_MachineKind_MIPS = 8, + ELF_MachineKind_S370 = 9, + ELF_MachineKind_MIPS_RS3_LE = 10, + // 11-14 reserved + ELF_MachineKind_PARISC = 15, + // 16 reserved + ELF_MachineKind_VPP500 = 17, + ELF_MachineKind_SPARC32PLUS = 18, + // nick: Sun's "v8plus" + ELF_MachineKind_INTEL960 = 19, + ELF_MachineKind_PPC = 20, + ELF_MachineKind_PPC64 = 21, + ELF_MachineKind_S390 = 22, + ELF_MachineKind_SPU = 23, + // 24-35 reserved + ELF_MachineKind_V800 = 36, + ELF_MachineKind_FR20 = 37, + ELF_MachineKind_RH32 = 38, + ELF_MachineKind_MCORE = 39, + ELF_MachineKind_ARM = 40, + ELF_MachineKind_SH = 42, + ELF_MachineKind_ALPHA = 41, + ELF_MachineKind_SPARCV9 = 43, + ELF_MachineKind_TRICORE = 44, + ELF_MachineKind_ARC = 45, + ELF_MachineKind_H8_300 = 46, + ELF_MachineKind_H8_300H = 47, + ELF_MachineKind_H8S = 48, + ELF_MachineKind_H8_500 = 49, + ELF_MachineKind_IA_64 = 50, + ELF_MachineKind_MIPS_X = 51, + ELF_MachineKind_COLDFILE = 52, + ELF_MachineKind_68HC12 = 53, + ELF_MachineKind_MMA = 54, + ELF_MachineKind_PCP = 55, + ELF_MachineKind_NCPU = 56, + ELF_MachineKind_NDR1 = 57, + ELF_MachineKind_STARCORE = 58, + ELF_MachineKind_ME16 = 59, + ELF_MachineKind_ST100 = 60, + ELF_MachineKind_TINYJ = 61, + ELF_MachineKind_X86_64 = 62, + ELF_MachineKind_AARCH64 = 183, + ELF_MachineKind_TI_C6000 = 140, + ELF_MachineKind_L1OM = 180, + ELF_MachineKind_K1OM = 181, + ELF_MachineKind_RISCV = 243, + ELF_MachineKind_S390_OLD = 0xA390, +}; + +typedef U16 ELF_Type; +enum +{ + ELF_Type_None, + ELF_Type_Rel, + ELF_Type_Exec, + ELF_Type_Dyn, + ELF_Type_Core, +}; + +typedef U8 ELF_Data; +enum +{ + ELF_Data_None = 0, + ELF_Data_2LSB = 1, + ELF_Data_2MSB = 2, +}; + +typedef U32 ELF_PType; +enum +{ + ELF_PType_Null = 0, + ELF_PType_Load = 1, + ELF_PType_Dynamic = 2, + ELF_PType_Interp = 3, + ELF_PType_Note = 4, + ELF_PType_ShLib = 5, + ELF_PType_PHdr = 6, + ELF_PType_Tls = 7, + ELF_PType_LoOs = 0x60000000, + ELF_PType_HiOs = 0x6fffffff, + + ELF_PType_LowProc = 0x70000000, + ELF_PType_HighProc = 0x7fffffff, + + // specific to Sun + ELF_PType_LowSunW = 0x6ffffffa, + ELF_PType_SunWBSS = 0x6ffffffb, + ELF_PType_GnuEHFrame = 0x6474E550, + + ELF_PType_GnuStack = ELF_PType_LoOs + 0x474e550, // frame unwind information + ELF_PType_GnuRelro = ELF_PType_LoOs + 0x474e551, // stack flags + ELF_PType_GnuProperty = ELF_PType_LoOs + 0x474e552, // read-only after relocations + ELF_PType_SunEHFrame = ELF_PType_GnuEHFrame, +}; + +typedef U32 ELF_PFlag; +enum +{ + ELF_PFlag_Exec = (1 << 0), + ELF_PFlag_Write = (1 << 1), + ELF_PFlag_Read = (1 << 2), +}; + +typedef U32 ELF_SectionCode; +enum +{ + ELF_SectionCode_Null = 0, + ELF_SectionCode_ProgBits = 1, + ELF_SectionCode_Symtab = 2, + ELF_SectionCode_Strtab = 3, + ELF_SectionCode_Rela = 4, + ELF_SectionCode_Hash = 5, + ELF_SectionCode_Dynamic = 6, + ELF_SectionCode_Note = 7, + ELF_SectionCode_NoBits = 8, + ELF_SectionCode_Rel = 9, + ELF_SectionCode_Shlib = 10, + ELF_SectionCode_Dynsym = 11, + ELF_SectionCode_InitArray = 14, + ELF_SectionCode_FiniArray = 15, // Array of ptrs to init functions + ELF_SectionCode_PreinitArray = 16, // Array of ptrs to finish functions + ELF_SectionCode_Group = 17, // Array of ptrs to pre-init funcs + ELF_SectionCode_SymtabShndx = 18, // Section contains a section group + ELF_SectionCode_GNU_IncrementalInputs = 0x6fff4700, // Indices for SHN_XINDEX entries + ELF_SectionCode_GNU_Attributes = 0x6ffffff5, // Incremental build data + ELF_SectionCode_GNU_Hash = 0x6ffffff6, // Object attributes + ELF_SectionCode_GNU_LibList = 0x6ffffff7, // GNU style symbol hash table + ELF_SectionCode_SUNW_verdef = 0x6ffffffd, + ELF_SectionCode_SUNW_verneed = 0x6ffffffe, // Versions defined by file + ELF_SectionCode_SUNW_versym = 0x6fffffff, // Versions needed by file + + // Symbol versions + ELF_SectionCode_GNU_verdef = ELF_SectionCode_SUNW_verdef, + ELF_SectionCode_GNU_verneed = ELF_SectionCode_SUNW_verneed, + ELF_SectionCode_GNU_versym = ELF_SectionCode_SUNW_versym, + ELF_SectionCode_Proc, + ELF_SectionCode_User, +}; + +typedef U32 ELF_SectionIndex; +enum +{ + + ELF_SectionIndex_Undef = 0, // Symbol with section index is undefined and must be resolved by the link editor + ELF_SectionIndex_Abs = 0xfff1, // Symbol has absolute value and wont change after relocations + ELF_SectionIndex_Common = 0xfff2, // This symbol indicates to linker to allocate the storage at address multiple of st_value + + ELF_SectionIndex_LoReserve = 0xff00, + ELF_SectionIndex_HiReserve = 0xffff, + + // Processor specific + ELF_SectionIndex_LoProc = ELF_SectionIndex_LoReserve, + ELF_SectionIndex_HiProc = 0xff1f, + + // Reserved for OS + ELF_SectionIndex_LoOs = 0xff20, + ELF_SectionIndex_HiOs = 0xff3f, + + ELF_SectionIndex_IA64_ASNI_Common = ELF_SectionIndex_LoProc, + ELF_SectionIndex_X8664_LCommon = 0xff02, + ELF_SectionIndex_MIPS_SCommon = 0xff03, + + ELF_SectionIndex_TIC6X_Common = ELF_SectionIndex_LoReserve, + ELF_SectionIndex_MIPS_SUndefined = 0xff04, +}; + +typedef U32 ELF_SectionFlag; +enum +{ + ELF_Shf_Write = (1 << 0), + ELF_Shf_Alloc = (1 << 1), + ELF_Shf_ExecInstr = (1 << 2), + ELF_Shf_Merge = (1 << 4), + ELF_Shf_Strings = (1 << 5), + ELF_Shf_InfoLink = (1 << 6), + ELF_Shf_LinkOrder = (1 << 7), + ELF_Shf_OsNonConforming = (1 << 8), + ELF_Shf_Group = (1 << 9), + ELF_Shf_Tls = (1 << 10), + ELF_Shf_Compressed = (1 << 11), + ELF_Shf_MaskOs_Shift = 16, ELF_Shf_MaskOs_Mask = 0xff, + ELF_Shf_AMD64Large = (1 << 28), + ELF_Shf_Ordered = (1 << 30), + ELF_Shf_Exclude = (1 << 31), + ELF_Shf_MaskProc_Shift = 28, ELF_Shf_MaskProc_Mask = 0xf, +}; + +#define ELF_SectionFlag_Extract_MaskOs(f) (U8)(((f) >> ELF_SectionFlag_MaskOs_Shift) & ELF_SectionFlag_MaskOs_Mask) +#define ELF_SectionFlag_Extract_MaskProc(f) (U8)(((f) >> ELF_SectionFlag_MaskProc_shift) & ELF_SectionFlag_MaskProc_Mask) +typedef U32 ELF_AuxType; +enum +{ + ELF_AuxType_Null = 0, + ELF_AuxType_Phdr = 3, // program headers + ELF_AuxType_Phent = 4, // size of a program header + ELF_AuxType_Phnum = 5, // number of program headers + ELF_AuxType_Pagesz = 6, // system page size + ELF_AuxType_Base = 7, // interpreter base address + ELF_AuxType_Flags = 8, + ELF_AuxType_Entry = 9, // program entry point + ELF_AuxType_Uid = 11, + ELF_AuxType_Euid = 12, + ELF_AuxType_Gid = 13, + ELF_AuxType_Egid = 14, + ELF_AuxType_Platform = 15, + ELF_AuxType_Hwcap = 16, + ELF_AuxType_Clktck = 17, + ELF_AuxType_DCacheBSize = 19, + ELF_AuxType_ICacheBSize = 20, + ELF_AuxType_UCacheBSize = 21, + ELF_AuxType_IgnorePPC = 22, + ELF_AuxType_Secure = 23, + ELF_AuxType_BasePlatform = 24, + ELF_AuxType_Random = 25, + ELF_AuxType_Hwcap2 = 26, // addres to 16 random bytes + ELF_AuxType_ExecFn = 31, + ELF_AuxType_SysInfo = 32, // file name of executable + ELF_AuxType_SysInfoEhdr = 33, + ELF_AuxType_L1I_CacheSize = 40, + ELF_AuxType_L1I_CacheGeometry = 41, + ELF_AuxType_L1D_CacheSize = 42, + ELF_AuxType_L1D_CacheGeometry = 43, + ELF_AuxType_L2_CacheSize = 44, + ELF_AuxType_L2_CacheGeometry = 45, + ELF_AuxType_L3_CacheSize = 46, + ELF_AuxType_L3_CacheGeometry = 47, +}; + +typedef U32 ELF_DynTag; +enum +{ + ELF_DynTag_Null = 0, + + ELF_DynTag_Needed = 1, + ELF_DynTag_PltRelsz = 2, + ELF_DynTag_PltGot = 3, + ELF_DynTag_Hash = 4, + ELF_DynTag_Strtab = 5, + ELF_DynTag_Symtab = 6, + ELF_DynTag_Rela = 7, + ELF_DynTag_Relasz = 8, + ELF_DynTag_Relaent = 9, + ELF_DynTag_Strsz = 10, + ELF_DynTag_Syment = 11, + ELF_DynTag_Init = 12, + ELF_DynTag_Fini = 13, + ELF_DynTag_SoName = 14, + ELF_DynTag_RPath = 15, + ELF_DynTag_Symbolic = 16, + ELF_DynTag_Rel = 17, + ELF_DynTag_Relsz = 18, + ELF_DynTag_Relent = 19, + ELF_DynTag_Pltrel = 20, + ELF_DynTag_Debug = 21, + ELF_DynTag_TextRel = 22, + ELF_DynTag_JmpRel = 23, + ELF_DynTag_BindNow = 24, + ELF_DynTag_InitArray = 25, + ELF_DynTag_FiniArray = 26, + ELF_DynTag_InitArraysz = 27, + ELF_DynTag_FIniArraysz = 28, + ELF_DynTag_RunPath = 29, + ELF_DynTag_Flags = 30, + ELF_DynTag_PreInitArray = 32, + ELF_DynTag_PreInitArraysz = 33, + ELF_DynTag_SymtabShndx = 34, + + ELF_DynTag_LoOs = 0x6000000D, + ELF_DynTag_HiOs = 0x6ffff000, + + ELF_DynTag_ValRngLo = 0x6ffffd00, + ELF_DynTag_GNU_PreLinked = 0x6ffffdf5, + ELF_DynTag_GNU_Conflictsz = 0x6ffffdf6, + ELF_DynTag_GNU_LibListsz = 0x6ffffdf7, + ELF_DynTag_Checksum = 0x6ffffdf8, + ELF_DynTag_Pltpadsz = 0x6ffffdf9, + ELF_DynTag_Moveent = 0x6ffffdfa, + ELF_DynTag_Movesz = 0x6ffffdfb, + ELF_DynTag_Feature = 0x6ffffdfc, + ELF_DynTag_PosFlag_1 = 0x6ffffdfd, + ELF_DynTag_SymInSz = 0x6ffffdfe, + ELF_DynTag_SymInEnt = 0x6ffffdff, + ELF_DynTag_ValRngHi = ELF_DynTag_SymInEnt, + + ELF_DynTag_AddrRngLo = 0x6ffffe00, + ELF_DynTag_GNU_Hash = 0x6ffffef5, + ELF_DynTag_TlsDescPlt = 0x6ffffef6, + ELF_DynTag_TlsDescGot = 0x6ffffef7, + ELF_DynTag_GNU_Conflict = 0x6ffffef8, + ELF_DynTag_GNU_LibList = 0x6ffffef9, + ELF_DynTag_Config = 0x6ffffefa, + ELF_DynTag_DepAudit = 0x6ffffefb, + ELF_DynTag_Audit = 0x6ffffefc, + ELF_DynTag_PltPad = 0x6ffffefd, + ELF_DynTag_MoveTab = 0x6ffffefe, + ELF_DynTag_SymInfo = 0x6ffffeff, + ELF_DynTag_AddrRngHi = ELF_DynTag_SymInfo, + + ELF_DynTag_RelaCount = 0x6ffffff9, + ELF_DynTag_RelCount = 0x6ffffffa, + ELF_DynTag_Flags_1 = 0x6ffffffb, + ELF_DynTag_VerDef = 0x6ffffffc, + ELF_DynTag_VerDefNum = 0x6ffffffd, + ELF_DynTag_VerNeed = 0x6ffffffe, + ELF_DynTag_VerNeedNum = 0x6fffffff, + ELF_DynTag_VerSym = 0x6ffffff0, + ELF_DynTag_LoProc = 0x70000000, + ELF_DynTag_HiProc = 0x7fffffff, +}; + +typedef U32 ELF_DynFlag; +enum +{ + ELF_DynFlag_Origin = (1 << 0), + ELF_DynFlag_Symbolic = (1 << 1), + ELF_DynFlag_TextTel = (1 << 2), + ELF_DynFlag_BindNow = (1 << 3), + ELF_DynFlag_StaticTls = (1 << 4), +}; + +typedef U32 ELF_DynFeatureFlag; +enum +{ + ELF_DynFeatureFlag_ParInit = (1 << 0), + ELF_DynFeatureFlag_ConfExp = (1 << 1), +}; + +typedef U8 ELF_SymBind; +enum +{ + // the same name may exists in multiple files without interfering with each other. + ELF_SymBind_Local = 0, + // Visible to all objects that are linked together. + ELF_SymBind_Global = 1, + // If there is a global symbol with identical name linker doesn't issue an error. + ELF_SymBind_Weak = 2, + ELF_SymBind_LoProc = 13, + ELF_SymBind_HiProc = 15, +}; + +typedef U8 ELF_SymType; +enum +{ + ELF_SymType_NoType = 0, + // Type is not specified. + ELF_SymType_Object = 1, + // Symbol is associated with data object, such as a variable, an array, etc. + ELF_SymType_Func = 2, + // Symbol is associated with a function. + ELF_SymType_Section = 3, + // Symbol is used to relocate sections and normally have LOCAL binding. + ELF_SymType_File = 4, + // Gives name of the source file associated with object. + ELF_SymType_Common = 5, + ELF_SymType_Tls = 6, + ELF_SymType_LoProc = 13, + ELF_SymType_HiProc = 15, +}; + +typedef U8 ELF_SymVisibility; +enum +{ + ELF_SymVisibility_Default = 0, + ELF_SymVisibility_Internal = 1, + ELF_SymVisibility_Hidden = 2, + ELF_SymVisibility_Protected = 3, +}; + +typedef U32 ELF_RelocI386; +enum +{ + ELF_RelocI386_None = 0, + ELF_RelocI386_32 = 1, + ELF_RelocI386_PC32 = 2, + ELF_RelocI386_GOT32 = 3, + ELF_RelocI386_PLT32 = 4, + ELF_RelocI386_Copy = 5, + ELF_RelocI386_GlobDat = 6, + ELF_RelocI386_JumpSlot = 7, + ELF_RelocI386_Relative = 8, + ELF_RelocI386_GotOff = 9, + ELF_RelocI386_GotPc = 10, + ELF_RelocI386_32Plt = 11, + ELF_RelocI386_Tls_tpoff = 14, + ELF_RelocI386_Tls_ie = 15, + ELF_RelocI386_Tls_gotie = 16, + ELF_RelocI386_Tls_le = 17, + ELF_RelocI386_Tls_gd = 18, + ELF_RelocI386_Tls_ldm = 19, + ELF_RelocI386_16 = 20, + ELF_RelocI386_PC16 = 21, + ELF_RelocI386_8 = 22, + ELF_RelocI386_Pc8 = 23, + ELF_RelocI386_TlsGd32 = 24, + ELF_RelocI386_TlsGdPush = 25, + ELF_RelocI386_TlsGdCall = 26, + ELF_RelocI386_TlsGdPop = 27, + ELF_RelocI386_TlsLdm32 = 28, + ELF_RelocI386_TlsLdmPush = 29, + ELF_RelocI386_TlsLdmCall = 30, + ELF_RelocI386_TlsLdmPop = 31, + ELF_RelocI386_TlsLdo32 = 32, + ELF_RelocI386_TlsIe32 = 33, + ELF_RelocI386_TlsLe32 = 34, + ELF_RelocI386_TlsDtpmod32 = 35, + ELF_RelocI386_TlsDtpoff32 = 36, + ELF_RelocI386_TlsTpoff32 = 37, + // 38 is not taken + ELF_RelocI386_TlsGotDesc = 39, + ELF_RelocI386_TlsDescCall = 40, + ELF_RelocI386_TlsDesc = 41, + ELF_RelocI386_IRelative = 42, + ELF_RelocI386_Gotx32x = 43, + ELF_RelocI386_UsedByIntel200 = 200, + ELF_RelocI386_GNU_VTInherit = 250, + ELF_RelocI386_GNU_VTEntry = 251, +}; + +typedef U32 ELF_RelocX8664; +enum +{ + ELF_RelocX8664_None = 0, + ELF_RelocX8664_64 = 1, + ELF_RelocX8664_Pc32 = 2, + ELF_RelocX8664_Got32 = 3, + ELF_RelocX8664_Plt32 = 4, + ELF_RelocX8664_Copy = 5, + ELF_RelocX8664_GlobDat = 6, + ELF_RelocX8664_JumpSlot = 7, + ELF_RelocX8664_Relative = 8, + ELF_RelocX8664_GotPcRel = 9, + ELF_RelocX8664_32 = 10, + ELF_RelocX8664_32S = 11, + ELF_RelocX8664_16 = 12, + ELF_RelocX8664_Pc16 = 13, + ELF_RelocX8664_8 = 14, + ELF_RelocX8664_Pc8 = 15, + ELF_RelocX8664_DtpMod64 = 16, + ELF_RelocX8664_DtpOff64 = 17, + ELF_RelocX8664_TpOff64 = 18, + ELF_RelocX8664_TlsGd = 19, + ELF_RelocX8664_TlsLd = 20, + ELF_RelocX8664_DtpOff32 = 21, + ELF_RelocX8664_GotTpOff = 22, + ELF_RelocX8664_TpOff32 = 23, + ELF_RelocX8664_Pc64 = 24, + ELF_RelocX8664_GotOff64 = 25, + ELF_RelocX8664_GotPc32 = 26, + ELF_RelocX8664_Got64 = 27, + ELF_RelocX8664_GotPcRel64 = 28, + ELF_RelocX8664_GotPc64 = 29, + ELF_RelocX8664_GotPlt64 = 30, + ELF_RelocX8664_PltOff64 = 31, + ELF_RelocX8664_Size32 = 32, + ELF_RelocX8664_Size64 = 33, + ELF_RelocX8664_GotPc32TlsDesc = 34, + ELF_RelocX8664_TlsDescCall = 35, + ELF_RelocX8664_TlsDesc = 36, + ELF_RelocX8664_IRelative = 37, + ELF_RelocX8664_Relative64 = 38, + ELF_RelocX8664_Pc32Bnd = 39, + ELF_RelocX8664_Plt32Bnd = 40, + ELF_RelocX8664_GotPcRelx = 41, + ELF_RelocX8664_RexGotPcRelx = 42, + ELF_RelocX8664_GNU_VTInherit = 250, + ELF_RelocX8664_GNU_VTEntry = 251, +}; + +typedef U32 ELF_ExternalVerFlag; +enum +{ + ELF_ExternalVerFlag_Base = (1 << 0), + ELF_ExternalVerFlag_Weak = (1 << 1), + ELF_ExternalVerFlag_Info = (1 << 2), +}; + +typedef U32 ELF_NoteType; +enum +{ + ELF_NoteType_GNU_Abi = 1, + ELF_NoteType_GNU_HwCap = 2, + ELF_NoteType_GNU_BuildId = 3, + ELF_NoteType_GNU_GoldVersion = 4, + ELF_NoteType_GNU_PropertyType0 = 5, +}; + +typedef U32 ELF_GnuABITag; +enum +{ + ELF_GnuABITag_Linux = 0, + ELF_GnuABITag_Hurd = 1, + ELF_GnuABITag_Solaris = 2, + ELF_GnuABITag_FreeBsd = 3, + ELF_GnuABITag_NetBsd = 4, + ELF_GnuABITag_Syllable = 5, + ELF_GnuABITag_Nacl = 6, +}; + +typedef S32 ELF_GnuProperty; +enum +{ + ELF_GnuProperty_LoProc = 0xc0000000, + // processor-specific range + ELF_GnuProperty_HiProc = 0xdfffffff, + ELF_GnuProperty_LoUser = 0xe0000000, + // application-specific range + ELF_GnuProperty_HiUser = 0xffffffff, + ELF_GnuProperty_StackSize = 1, + ELF_GnuProperty_NoCopyOnProtected = 2, +}; + +typedef U32 ELF_GnuPropertyX86Isa1; +enum +{ + ELF_GnuPropertyX86Isa1_BaseLine = (1 << 0), + ELF_GnuPropertyX86Isa1_V2 = (1 << 1), + ELF_GnuPropertyX86Isa1_V3 = (1 << 2), + ELF_GnuPropertyX86Isa1_V4 = (1 << 3), +}; + +typedef U32 ELF_GnuPropertyX86Compat1Isa1; +enum +{ + ELF_GnuPropertyX86Compat1Isa1_486 = (1 << 0), + ELF_GnuPropertyX86Compat1Isa1_586 = (1 << 1), + ELF_GnuPropertyX86Compat1Isa1_686 = (1 << 2), + ELF_GnuPropertyX86Compat1Isa1_SSE = (1 << 3), + ELF_GnuPropertyX86Compat1Isa1_SSE2 = (1 << 4), + ELF_GnuPropertyX86Compat1Isa1_SSE3 = (1 << 5), + ELF_GnuPropertyX86Compat1Isa1_SSSE3 = (1 << 6), + ELF_GnuPropertyX86Compat1Isa1_SSE4_1 = (1 << 7), + ELF_GnuPropertyX86Compat1Isa1_SSE4_2 = (1 << 8), + ELF_GnuPropertyX86Compat1Isa1_AVX = (1 << 9), + ELF_GnuPropertyX86Compat1Isa1_AVX2 = (1 << 10), + ELF_GnuPropertyX86Compat1Isa1_AVX512F = (1 << 11), + ELF_GnuPropertyX86Compat1Isa1_AVX512ER = (1 << 12), + ELF_GnuPropertyX86Compat1Isa1_AVX512PF = (1 << 13), + ELF_GnuPropertyX86Compat1Isa1_AVX512VL = (1 << 14), + ELF_GnuPropertyX86Compat1Isa1_AVX512DQ = (1 << 15), + ELF_GnuPropertyX86Compat1Isa1_AVX512BW = (1 << 16), +}; + +typedef U32 ELF_GnuPropertyX86Compat2Isa1; +enum +{ + ELF_GnuPropertyX86Compat2Isa1_CMOVE = (1 << 0), + ELF_GnuPropertyX86Compat2Isa1_SSE = (1 << 1), + ELF_GnuPropertyX86Compat2Isa1_SSE2 = (1 << 2), + ELF_GnuPropertyX86Compat2Isa1_SSE3 = (1 << 3), + ELF_GnuPropertyX86Compat2Isa1_SSE4_1 = (1 << 4), + ELF_GnuPropertyX86Compat2Isa1_SSE4_2 = (1 << 5), + ELF_GnuPropertyX86Compat2Isa1_AVX = (1 << 6), + ELF_GnuPropertyX86Compat2Isa1_AVX2 = (1 << 7), + ELF_GnuPropertyX86Compat2Isa1_FMA = (1 << 8), + ELF_GnuPropertyX86Compat2Isa1_AVX512F = (1 << 9), + ELF_GnuPropertyX86Compat2Isa1_AVX512CD = (1 << 10), + ELF_GnuPropertyX86Compat2Isa1_AVX512ER = (1 << 11), + ELF_GnuPropertyX86Compat2Isa1_AVX512PF = (1 << 12), + ELF_GnuPropertyX86Compat2Isa1_AVX512VL = (1 << 13), + ELF_GnuPropertyX86Compat2Isa1_AVX512DQ = (1 << 14), + ELF_GnuPropertyX86Compat2Isa1_AVX512BW = (1 << 15), + ELF_GnuPropertyX86Compat2Isa1_AVX512_4FMAPS = (1 << 16), + ELF_GnuPropertyX86Compat2Isa1_AVX512_4VNNIW = (1 << 17), + ELF_GnuPropertyX86Compat2Isa1_AVX512_BITALG = (1 << 18), + ELF_GnuPropertyX86Compat2Isa1_AVX512_IFMA = (1 << 19), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VBMI = (1 << 20), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VBMI2 = (1 << 21), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VNNI = (1 << 22), + ELF_GnuPropertyX86Compat2Isa1_AVX512_BF16 = (1 << 23), +}; + +typedef S32 ELF_GnuPropertyX86; +enum +{ + ELF_GnuPropertyX86_Feature1And = 0xc0000002, + ELF_GnuPropertyX86_Feature2Used = 0xc0010001, + ELF_GnuPropertyX86_Isa1needed = 0xc0008002, + ELF_GnuPropertyX86_Isa2Needed = 0xc0008001, + ELF_GnuPropertyX86_Isa1Used = 0xc0010002, + ELF_GnuPropertyX86_Compat_isa_1_used = 0xc0000000, + ELF_GnuPropertyX86_Compat_isa_1_needed = 0xc0000001, + ELF_GnuPropertyX86_UInt32AndLo = ELF_GnuPropertyX86_Feature1And, + ELF_GnuPropertyX86_UInt32AndHi = 0xc0007fff, + ELF_GnuPropertyX86_UInt32OrLo = 0xc0008000, + ELF_GnuPropertyX86_UInt32OrHi = 0xc000ffff, + ELF_GnuPropertyX86_UInt32OrAndLo = 0xc0010000, + ELF_GnuPropertyX86_UInt32OrAndHi = 0xc0017fff, +}; + +typedef U32 ELF_GnuPropertyX86Feature1; +enum +{ + ELF_GnuPropertyX86Feature1_Ibt = (1 << 0), + ELF_GnuPropertyX86Feature1_Shstk = (1 << 1), + ELF_GnuPropertyX86Feature1_LamU48 = (1 << 2), + ELF_GnuPropertyX86Feature1_LamU57 = (1 << 3), +}; + +typedef U32 ELF_GnuPropertyX86Feature2; +enum +{ + ELF_GnuPropertyX86Feature2_X86 = (1 << 0), + ELF_GnuPropertyX86Feature2_X87 = (1 << 1), + ELF_GnuPropertyX86Feature2_MMX = (1 << 2), + ELF_GnuPropertyX86Feature2_XMM = (1 << 3), + ELF_GnuPropertyX86Feature2_YMM = (1 << 4), + ELF_GnuPropertyX86Feature2_ZMM = (1 << 5), + ELF_GnuPropertyX86Feature2_FXSR = (1 << 6), + ELF_GnuPropertyX86Feature2_XSAVE = (1 << 7), + ELF_GnuPropertyX86Feature2_XSAVEOPT = (1 << 8), + ELF_GnuPropertyX86Feature2_XSAVEC = (1 << 9), + ELF_GnuPropertyX86Feature2_TMM = (1 << 10), + ELF_GnuPropertyX86Feature2_MASK = (1 << 11), +}; + +#define ELF_HdrIs64Bit(e_ident) (e_ident[ELF_Identifier_Class] == ELF_Class_64) +#define ELF_HdrIs32Bit(e_ident) (e_ident[ELF_Identifier_Class] == ELF_Class_32) + +typedef enum ELF_Identifier +{ + ELF_Identifier_Mag0 = 0, + ELF_Identifier_Mag1 = 1, + ELF_Identifier_Mag2 = 2, + ELF_Identifier_Mag3 = 3, + ELF_Identifier_Class = 4, + ELF_Identifier_Data = 5, + ELF_Identifier_Version = 6, + ELF_Identifier_OsAbi = 7, + ELF_Identfiier_AbiBersion = 8, + ELF_Identifier_Max = 16, +} ELF_Identifier; + +typedef struct ELF_Hdr64 +{ + U8 e_ident[ELF_Identifier_Max]; + U16 e_type; + U16 e_machine; + U32 e_version; + U64 e_entry; + U64 e_phoff; + U64 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Hdr64; + +typedef struct ELF_Hdr32 +{ + U8 e_ident[ELF_Identifier_Max]; + U16 e_type; + U16 e_machine; + U32 e_version; + U32 e_entry; + U32 e_phoff; + U32 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Hdr32; + +typedef struct ELF_Shdr64 +{ + U32 sh_name; + U32 sh_type; + U64 sh_flags; + U64 sh_addr; + U64 sh_offset; + U64 sh_size; + U32 sh_link; + U32 sh_info; + U64 sh_addralign; + U64 sh_entsize; +} ELF_Shdr64; + +typedef struct ELF_Shdr32 +{ + U32 sh_name; + U32 sh_type; + U32 sh_flags; + U32 sh_addr; + U32 sh_offset; + U32 sh_size; + U32 sh_link; + U32 sh_info; + U32 sh_addralign; + U32 sh_entsize; +} ELF_Shdr32; + +typedef struct ELF_Phdr64 +{ + U32 p_type; + U32 p_flags; + U64 p_offset; + U64 p_vaddr; + U64 p_paddr; + U64 p_filesz; + U64 p_memsz; + U64 p_align; +} ELF_Phdr64; + +typedef struct ELF_Phdr32 +{ + U32 p_type; + U32 p_offset; + U32 p_vaddr; + U32 p_paddr; + U32 p_filesz; + U32 p_memsz; + U32 p_flags; + U32 p_align; +} ELF_Phdr32; + +//////////////////////////////// +// Auxiliary Vectors + +// these appear in /proc//auxv of a process, they are not in elf files + +typedef struct ELF_Auxv32 +{ + U32 a_type; + U32 a_val; +} ELF_Auxv32; + +typedef struct ELF_Auxv64 +{ + U64 a_type; + U64 a_val; +} ELF_Auxv64; + +//////////////////////////////// +// Dynamic Structures + +// these appear in the virtual address space of a process, they are not in elf files + +typedef struct ELF_Dyn32 +{ + U32 tag; + U32 val; +} ELF_Dyn32; + +typedef struct ELF_Dyn64 +{ + U64 tag; + U64 val; +} ELF_Dyn64; + +typedef struct ELF_LinkMap32 +{ + U32 base; + U32 name; + U32 ld; + U32 next; +} ELF_LinkMap32; + +typedef struct ELF_LinkMap64 +{ + U64 base; + U64 name; + U64 ld; + U64 next; +} ELF_LinkMap64; + +//////////////////////////////// +// Imports and Exports + +typedef struct +{ + U32 st_name; // Holds index into files string table. + U32 st_value; // Depending on the context, this may be address, size, etc. + U32 st_size; // Data size in bytes. Zero when size is unknown. + U8 st_info; // Contains symbols type and binding. + U8 st_other; // Reserved for future use, currenly zero. + U16 st_shndx; // Section index to which symbol is relevant. +} ELF_Sym32; + +typedef struct +{ + U32 st_name; + U8 st_info; + U8 st_other; + U16 st_shndx; + U64 st_value; + U64 st_size; +} ELF_Sym64; + +#define ELF_ST_INFO(b,t) (((b) << 4) + ((t) & 0xF)) +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) ((x) & 0xF) +#define ELF_ST_VISIBILITY(v) ((v) & 0x3) + +typedef struct +{ + U32 r_offset; + U32 r_info; +} ELF_Rel32; + +typedef struct +{ + U32 r_offset; + U32 r_info; + S32 r_addend; +} ELF_Rela32; + +typedef struct +{ + U64 r_offset; + U64 r_info; +} ELF_Rel64; + +typedef struct +{ + U64 r_offset; + U64 r_info; + S64 r_addend; +} ELF_Rela64; + +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xFF) + +#define ELF64_R_INFO(s,t) (((U64)(s) << 32) | (U64)t) +#define ELF64_R_SYM(x) ((x) >> 32) +#define ELF64_R_TYPE(x) ((x) & 0xffffffff) + +// This flag is set to indicate that symbol is not available outside shared object +#define ELF_EXTERNAL_VERSYM_HIDDEN 0x8000 +#define ELF_EXTERNAL_VERSYM_MASK 0x7FFF + +// Appears in .gnu.verdef (SHT_GNU_verdef) +typedef struct +{ + U16 vd_version; + U16 vd_flags; + U16 vd_ndx; + U16 vd_cnt; + U32 vd_hash; + U32 vd_aux; + U32 vd_next; +} ELF_ExternalVerdef; + +// Appears in .gnu.verdef (SHT_GNU_verdef) +typedef struct +{ + U32 vda_name; + U32 vda_next; +} ELF_ExternalVerdaux; + +// Appears in .gnu.verneed (SHT_GNU_verneed) +typedef struct +{ + U16 vn_version; + U16 vn_cnt; + U32 vn_file; + U32 vn_aux; + U32 vn_next; +} ELF_ExternalVerneed; + +// Appears in .gnu.verneed (SHT_GNU_verneed) +typedef struct +{ + U32 vna_hash; + U16 vna_flags; + U16 vna_other; + U32 vna_name; + U32 vna_next; +} ELF_ExternalVernaux; + +// Appears in .gnu.version (SHT_GNU_versym) +typedef struct +{ + U16 vs_vers; +} ELF_ExternalVersym; + +typedef struct +{ + U32 name_size; + U32 desc_size; + U32 type; + // name + desc + // U8 data[1]; +} ELF_Note; + +//////////////////////////////// +// Extensions + +typedef U8 ELF_CompressType; +enum ELF_CompressTypeEnum +{ + ELF_CompressType_None = 0, + ELF_CompressType_ZLib = 1, + ELF_CompressType_ZStd = 2, + + ELF_CompressType_LoOs = 0x60000000, + ELF_CompressType_HiOs = 0x6fffffff, + + ELF_CompressType_LoProc = 0x70000000, + ELF_CompressType_HiProc = 0x7fffffff, +}; + +typedef struct ELF_Chdr32 +{ + U32 ch_type; + U32 ch_size; + U32 ch_addr_align; +} ELF_Chdr32; + +typedef struct ELF_Chdr64 +{ + U64 ch_type; + U64 ch_size; + U64 ch_addr_align; +} ELF_Chdr64; + +//////////////////////////////// + +internal ELF_Hdr64 elf_hdr64_from_ehdr32(ELF_Hdr32 h32); +internal ELF_Shdr64 elf_shdr64_from_shdr32(ELF_Shdr32 h32); +internal ELF_Phdr64 elf_phdr64_from_phdr32(ELF_Phdr32 h32); +internal ELF_Dyn64 elf_dyn64_from_dyn32 (ELF_Dyn32 h32); +internal ELF_Sym64 elf_sym64_from_sym32 (ELF_Sym32 sym32); +internal ELF_Rel64 elf_rel64_from_rel32 (ELF_Rel32 rel32); +internal ELF_Rela64 elf_rela64_from_rela32(ELF_Rela32 rela32); +internal ELF_Chdr64 elf_chdr64_from_chdr32(ELF_Chdr32 chdr32); + +//////////////////////////////// + +internal String8 elf_string_from_class(Arena *arena, ELF_Class v); + +//////////////////////////////// + +internal Arch arch_from_elf_machine(ELF_MachineKind machine); + +#endif // ELF_H + diff --git a/src/elf/elf_parse.c b/src/elf/elf_parse.c new file mode 100644 index 00000000..22bb47be --- /dev/null +++ b/src/elf/elf_parse.c @@ -0,0 +1,90 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +elf_check_magic(String8 data) +{ + U8 sig[ELF_Identifier_Max] = {0}; + str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1); + B32 is_magic_valid = (sig[ELF_Identifier_Mag0] == 0x7f && sig[ELF_Identifier_Mag1] == 'E' && sig[ELF_Identifier_Mag2] == 'L' && sig[ELF_Identifier_Mag3] == 'F'); + return is_magic_valid; +} + +internal ELF_BinInfo +elf_bin_from_data(String8 data) +{ + ELF_Hdr64 hdr64 = {0}; + Rng1U64 sh_name_range = rng_1u64(0,0); + + if (elf_check_magic(data)) { + U8 sig[ELF_Identifier_Max] = {0}; + str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1); + + switch (sig[ELF_Identifier_Class]) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Hdr32 hdr32 = {0}; + U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr32); + if (hdr_size == sizeof(hdr32)) { + hdr64 = elf_hdr64_from_hdr32(hdr32); + + U64 shstr_off = hdr32.e_shoff + hdr32.e_shentsize*hdr32.e_shstrndx; + ELF_Shdr32 shdr = {0}; + U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr); + + if (shdr_size == sizeof(shdr)) { + sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size); + } + } + } break; + case ELF_Class_64: { + U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr64); + if (hdr_size == sizeof(hdr64)) { + U64 shstr_off = hdr64.e_shoff + hdr64.e_shentsize*hdr64.e_shstrndx; + ELF_Shdr64 shdr = {0}; + U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr); + + if (shdr_size == sizeof(shdr)) { + sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size); + } + } + } break; + default: Assert(!"invalid elf header"); break; + } + } + + ELF_BinInfo info = {0}; + info.hdr = hdr64; + info.sh_name_range = sh_name_range; + + return info; +} + +internal ELF_Shdr64Array +elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr) +{ + Rng1U64 shdr_range = rng_1u64(hdr->e_shoff, hdr->e_shoff + hdr->e_shentsize*hdr->e_shnum); + String8 shdr_data = str8_substr(raw_data, shdr_range); + + ELF_Shdr64Array result = {0}; + result.count = hdr->e_shnum; + result.v = push_array(arena, ELF_Shdr64, hdr->e_shnum); + + for(U64 shdr_idx = 0; shdr_idx < hdr->e_shnum; ++shdr_idx) { + switch (hdr->e_ident[ELF_Identifier_Class]) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Shdr32 shdr32 = {0}; + str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr32), &shdr32); + result.v[shdr_idx] = elf_shdr64_from_shdr32(shdr32); + } break; + case ELF_Class_64: { + str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr64), &result.v[shdr_idx]); + } break; + default: InvalidPath; break; + } + } + + return result; +} + diff --git a/src/elf/elf_parse.h b/src/elf/elf_parse.h new file mode 100644 index 00000000..fccbc233 --- /dev/null +++ b/src/elf/elf_parse.h @@ -0,0 +1,29 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ELF_PARSE_H +#define ELF_PARSE_H + +//////////////////////////////// + +typedef struct ELF_BinInfo +{ + ELF_Hdr64 hdr; + Rng1U64 sh_name_range; +} ELF_BinInfo; + +typedef struct ELF_Shdr64Array +{ + U64 count; + ELF_Shdr64 *v; +} ELF_Shdr64Array; + +//////////////////////////////// + +internal B32 elf_check_magic(String8 data); +internal ELF_BinInfo elf_bin_from_data(String8 data); + +internal ELF_Shdr64Array elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr); +internal String8 elf_name_from_shdr64(String8 raw_data, ELF_Hdr64 *hdr, Rng1U64 sh_name_range, ELF_Shdr64 *shdr); + +#endif // ELF_PARSE_H