early-access version 2760

This commit is contained in:
pineappleEA 2022-06-06 03:42:24 +02:00
parent 113987ecc4
commit bfd71d72cb
6 changed files with 372 additions and 264 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 2758. This is the source code for early-access 2760.
## Legal Notice ## Legal Notice

View file

@ -58,6 +58,7 @@ add_library(common STATIC
div_ceil.h div_ceil.h
dynamic_library.cpp dynamic_library.cpp
dynamic_library.h dynamic_library.h
elf.h
error.cpp error.cpp
error.h error.h
expected.h expected.h

333
src/common/elf.h Executable file
View file

@ -0,0 +1,333 @@
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common_types.h"
namespace Common {
namespace ELF {
/* Type for a 16-bit quantity. */
using Elf32_Half = u16;
using Elf64_Half = u16;
/* Types for signed and unsigned 32-bit quantities. */
using Elf32_Word = u32;
using Elf32_Sword = s32;
using Elf64_Word = u32;
using Elf64_Sword = s32;
/* Types for signed and unsigned 64-bit quantities. */
using Elf32_Xword = u64;
using Elf32_Sxword = s64;
using Elf64_Xword = u64;
using Elf64_Sxword = s64;
/* Type of addresses. */
using Elf32_Addr = u32;
using Elf64_Addr = u64;
/* Type of file offsets. */
using Elf32_Off = u32;
using Elf64_Off = u64;
/* Type for section indices, which are 16-bit quantities. */
using Elf32_Section = u16;
using Elf64_Section = u16;
/* Type for version symbol information. */
using Elf32_Versym = Elf32_Half;
using Elf64_Versym = Elf64_Half;
constexpr size_t ElfIdentSize = 16;
/* The ELF file header. This appears at the start of every ELF file. */
struct Elf32_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
};
struct Elf64_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
};
constexpr u8 ElfClass32 = 1; /* 32-bit objects */
constexpr u8 ElfClass64 = 2; /* 64-bit objects */
constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */
constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */
constexpr u8 ElfOsAbiNone = 0; /* System V ABI */
constexpr u16 ElfTypeNone = 0; /* No file type */
constexpr u16 ElfTypeRel = 0; /* Relocatable file */
constexpr u16 ElfTypeExec = 0; /* Executable file */
constexpr u16 ElfTypeDyn = 0; /* Shared object file */
constexpr u16 ElfMachineArm = 40; /* ARM */
constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */
constexpr std::array<u8, ElfIdentSize> Elf32Ident{
0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
constexpr std::array<u8, ElfIdentSize> Elf64Ident{
0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
/* Section header. */
struct Elf32_Shdr {
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
};
struct Elf64_Shdr {
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
};
constexpr u32 ElfShnUndef = 0; /* Undefined section */
constexpr u32 ElfShtNull = 0; /* Section header table entry unused */
constexpr u32 ElfShtProgBits = 1; /* Program data */
constexpr u32 ElfShtSymtab = 2; /* Symbol table */
constexpr u32 ElfShtStrtab = 3; /* String table */
constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */
constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */
constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */
constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */
constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */
/* Symbol table entry. */
struct Elf32_Sym {
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
};
struct Elf64_Sym {
Elf64_Word st_name; /* Symbol name (string tbl index) */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf64_Section st_shndx; /* Section index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Symbol size */
};
/* How to extract and insert information held in the st_info field. */
static inline u8 ElfStBind(u8 st_info) {
return st_info >> 4;
}
static inline u8 ElfStType(u8 st_info) {
return st_info & 0xf;
}
static inline u8 ElfStInfo(u8 st_bind, u8 st_type) {
return static_cast<u8>((st_bind << 4) + (st_type & 0xf));
}
constexpr u8 ElfBindLocal = 0; /* Local symbol */
constexpr u8 ElfBindGlobal = 1; /* Global symbol */
constexpr u8 ElfBindWeak = 2; /* Weak symbol */
constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */
constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */
constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */
static inline u8 ElfStVisibility(u8 st_other) {
return static_cast<u8>(st_other & 0x3);
}
constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */
constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */
constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */
constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */
/* Relocation table entry without addend (in section of type ShtRel). */
struct Elf32_Rel {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
};
/* Relocation table entry with addend (in section of type ShtRela). */
struct Elf32_Rela {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
Elf32_Sword r_addend; /* Addend */
};
struct Elf64_Rela {
Elf64_Addr r_offset; /* Address */
Elf64_Xword r_info; /* Relocation type and symbol index */
Elf64_Sxword r_addend; /* Addend */
};
/* How to extract and insert information held in the r_info field. */
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
return r_info >> 8;
}
static inline u8 Elf32RelType(Elf32_Word r_info) {
return static_cast<u8>(r_info & 0xff);
}
static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) {
return (sym_index << 8) + type;
}
static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) {
return static_cast<u32>(r_info >> 32);
}
static inline u32 Elf64RelType(Elf64_Xword r_info) {
return r_info & 0xffffffff;
}
static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) {
return (static_cast<Elf64_Xword>(sym_index) << 32) + type;
}
constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */
constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */
constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */
constexpr u32 ElfArmRelative = 23; /* Adjust by program base */
constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */
constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */
constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */
constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */
/* Program segment header. */
struct Elf32_Phdr {
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
};
struct Elf64_Phdr {
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
};
/* Legal values for p_type (segment type). */
constexpr u32 ElfPtNull = 0; /* Program header table entry unused */
constexpr u32 ElfPtLoad = 1; /* Loadable program segment */
constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */
constexpr u32 ElfPtInterp = 3; /* Program interpreter */
constexpr u32 ElfPtNote = 4; /* Auxiliary information */
constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */
constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */
/* Legal values for p_flags (segment flags). */
constexpr u32 ElfPfExec = 0; /* Segment is executable */
constexpr u32 ElfPfWrite = 1; /* Segment is writable */
constexpr u32 ElfPfRead = 2; /* Segment is readable */
/* Dynamic section entry. */
struct Elf32_Dyn {
Elf32_Sword d_tag; /* Dynamic entry type */
union {
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
};
struct Elf64_Dyn {
Elf64_Sxword d_tag; /* Dynamic entry type */
union {
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
};
/* Legal values for d_tag (dynamic entry type). */
constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */
constexpr u32 ElfDtNeeded = 1; /* Name of needed library */
constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */
constexpr u32 ElfDtPltGot = 3; /* Processor defined value */
constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */
constexpr u32 ElfDtStrtab = 5; /* Address of string table */
constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */
constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */
constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */
constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */
constexpr u32 ElfDtStrsz = 10; /* Size of string table */
constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */
constexpr u32 ElfDtInit = 12; /* Address of init function */
constexpr u32 ElfDtFini = 13; /* Address of termination function */
constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */
constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */
constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */
constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */
constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */
constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */
constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */
constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */
constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
} // namespace ELF
} // namespace Common

View file

@ -3,73 +3,14 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/elf.h"
#include "core/arm/symbols.h" #include "core/arm/symbols.h"
#include "core/core.h" #include "core/core.h"
#include "core/memory.h" #include "core/memory.h"
using namespace Common::ELF;
namespace Core { namespace Core {
namespace {
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
enum class ELFSymbolType : u8 {
None = 0,
Object = 1,
Function = 2,
Section = 3,
File = 4,
Common = 5,
TLS = 6,
};
enum class ELFSymbolBinding : u8 {
Local = 0,
Global = 1,
Weak = 2,
};
enum class ELFSymbolVisibility : u8 {
Default = 0,
Internal = 1,
Hidden = 2,
Protected = 3,
};
struct ELF64Symbol {
u32 name_index;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
u64 value;
u64 size;
};
static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
struct ELF32Symbol {
u32 name_index;
u32 value;
u32 size;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
};
static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
} // Anonymous namespace
namespace Symbols { namespace Symbols {
template <typename Word, typename ELFSymbol, typename ByteReader> template <typename Word, typename ELFSymbol, typename ByteReader>
@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
const Word value = ReadWord(dynamic_index + sizeof(Word)); const Word value = ReadWord(dynamic_index + sizeof(Word));
dynamic_index += 2 * sizeof(Word); dynamic_index += 2 * sizeof(Word);
if (tag == ELF_DYNAMIC_TAG_NULL) { if (tag == ElfDtNull) {
break; break;
} }
if (tag == ELF_DYNAMIC_TAG_STRTAB) { if (tag == ElfDtStrtab) {
string_table_offset = value; string_table_offset = value;
} else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { } else if (tag == ElfDtSymtab) {
symbol_table_offset = value; symbol_table_offset = value;
} else if (tag == ELF_DYNAMIC_TAG_SYMENT) { } else if (tag == ElfDtSyment) {
symbol_entry_size = value; symbol_entry_size = value;
} }
} }
@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
ELFSymbol symbol{}; ELFSymbol symbol{};
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
VAddr string_offset = string_table_offset + symbol.name_index; VAddr string_offset = string_table_offset + symbol.st_name;
std::string name; std::string name;
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
name += static_cast<char>(c); name += static_cast<char>(c);
} }
symbol_index += symbol_entry_size; symbol_index += symbol_entry_size;
out[name] = std::make_pair(symbol.value, symbol.size); out[name] = std::make_pair(symbol.st_value, symbol.st_size);
} }
return out; return out;
@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
if (is_64) { if (is_64) {
return GetSymbols<u64, ELF64Symbol>(ReadBytes); return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else { } else {
return GetSymbols<u32, ELF32Symbol>(ReadBytes); return GetSymbols<u32, Elf32_Sym>(ReadBytes);
} }
} }
@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) {
}}; }};
if (is_64) { if (is_64) {
return GetSymbols<u64, ELF64Symbol>(ReadBytes); return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else { } else {
return GetSymbols<u32, ELF32Symbol>(ReadBytes); return GetSymbols<u32, Elf32_Sym>(ReadBytes);
} }
} }

View file

@ -11,10 +11,13 @@
#include "common/alignment.h" #include "common/alignment.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/div_ceil.h" #include "common/div_ceil.h"
#include "common/elf.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/service/jit/jit_context.h" #include "core/hle/service/jit/jit_context.h"
#include "core/memory.h" #include "core/memory.h"
using namespace Common::ELF;
namespace Service::JIT { namespace Service::JIT {
constexpr std::array<u8, 8> SVC0_ARM64 = { constexpr std::array<u8, 8> SVC0_ARM64 = {
@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{
"_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset",
}; };
struct Elf64_Dyn {
u64 d_tag;
u64 d_un;
};
struct Elf64_Rela {
u64 r_offset;
u64 r_info;
s64 r_addend;
};
static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) {
return static_cast<u32>(rela->r_info);
}
constexpr int DT_RELA = 7; /* Address of Rela relocs */
constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */
constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */
constexpr size_t STACK_ALIGN = 16; constexpr size_t STACK_ALIGN = 16;
class JITContextImpl; class JITContextImpl;
@ -206,17 +190,17 @@ public:
if (!dyn.d_tag) { if (!dyn.d_tag) {
break; break;
} }
if (dyn.d_tag == DT_RELA) { if (dyn.d_tag == ElfDtRela) {
rela_dyn = dyn.d_un; rela_dyn = dyn.d_un.d_ptr;
} }
if (dyn.d_tag == DT_RELASZ) { if (dyn.d_tag == ElfDtRelasz) {
num_rela = dyn.d_un / sizeof(Elf64_Rela); num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
} }
} }
for (size_t i = 0; i < num_rela; i++) { for (size_t i = 0; i < num_rela; i++) {
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) { if (Elf64RelType(rela.r_info) != ElfAArch64Relative) {
continue; continue;
} }
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};

View file

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/elf.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_page_table.h"
@ -13,159 +14,7 @@
#include "core/loader/elf.h" #include "core/loader/elf.h"
#include "core/memory.h" #include "core/memory.h"
//////////////////////////////////////////////////////////////////////////////////////////////////// using namespace Common::ELF;
// ELF Header Constants
// File type
enum ElfType {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOPROC = 0xFF00,
ET_HIPROC = 0xFFFF,
};
// Machine/Architecture
enum ElfMachine {
EM_NONE = 0,
EM_M32 = 1,
EM_SPARC = 2,
EM_386 = 3,
EM_68K = 4,
EM_88K = 5,
EM_860 = 7,
EM_MIPS = 8
};
// File version
#define EV_NONE 0
#define EV_CURRENT 1
// Identification index
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16
// Sections constants
// Section types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xFFFFFFFF
// Section flags
enum ElfSectionFlags {
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKPROC = 0xF0000000,
};
// Segment types
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
// Segment flags
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PF_MASKPROC 0xF0000000
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;
////////////////////////////////////////////////////////////////////////////////////////////////////
// ELF file header
struct Elf32_Ehdr {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
};
// Section header
struct Elf32_Shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
};
// Segment header
struct Elf32_Phdr {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
};
// Symbol table entry
struct Elf32_Sym {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
};
// Relocation entries
struct Elf32_Rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// ElfReader class // ElfReader class
@ -193,11 +42,11 @@ public:
} }
// Quick accessors // Quick accessors
ElfType GetType() const { u16 GetType() const {
return (ElfType)(header->e_type); return header->e_type;
} }
ElfMachine GetMachine() const { u16 GetMachine() const {
return (ElfMachine)(header->e_machine); return header->e_machine;
} }
VAddr GetEntryPoint() const { VAddr GetEntryPoint() const {
return entryPoint; return entryPoint;
@ -220,13 +69,13 @@ public:
const u8* GetSectionDataPtr(int section) const { const u8* GetSectionDataPtr(int section) const {
if (section < 0 || section >= header->e_shnum) if (section < 0 || section >= header->e_shnum)
return nullptr; return nullptr;
if (sections[section].sh_type != SHT_NOBITS) if (sections[section].sh_type != ElfShtNobits)
return GetPtr(sections[section].sh_offset); return GetPtr(sections[section].sh_offset);
else else
return nullptr; return nullptr;
} }
bool IsCodeSection(int section) const { bool IsCodeSection(int section) const {
return sections[section].sh_type == SHT_PROGBITS; return sections[section].sh_type == ElfShtProgBits;
} }
const u8* GetSegmentPtr(int segment) { const u8* GetSegmentPtr(int segment) {
return GetPtr(segments[segment].p_offset); return GetPtr(segments[segment].p_offset);
@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) {
} }
const char* ElfReader::GetSectionName(int section) const { const char* ElfReader::GetSectionName(int section) const {
if (sections[section].sh_type == SHT_NULL) if (sections[section].sh_type == ElfShtNull)
return nullptr; return nullptr;
int name_offset = sections[section].sh_name; int name_offset = sections[section].sh_name;
@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
// Should we relocate? // Should we relocate?
relocate = (header->e_type != ET_EXEC); relocate = (header->e_type != ElfTypeExec);
if (relocate) { if (relocate) {
LOG_DEBUG(Loader, "Relocatable module"); LOG_DEBUG(Loader, "Relocatable module");
@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
u64 total_image_size = 0; u64 total_image_size = 0;
for (unsigned int i = 0; i < header->e_phnum; ++i) { for (unsigned int i = 0; i < header->e_phnum; ++i) {
const Elf32_Phdr* p = &segments[i]; const Elf32_Phdr* p = &segments[i];
if (p->p_type == PT_LOAD) { if (p->p_type == ElfPtLoad) {
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
} }
} }
@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
p->p_vaddr, p->p_filesz, p->p_memsz); p->p_vaddr, p->p_filesz, p->p_memsz);
if (p->p_type == PT_LOAD) { if (p->p_type == ElfPtLoad) {
Kernel::CodeSet::Segment* codeset_segment; Kernel::CodeSet::Segment* codeset_segment;
u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec);
if (permission_flags == (PF_R | PF_X)) { if (permission_flags == (ElfPfRead | ElfPfExec)) {
codeset_segment = &codeset.CodeSegment(); codeset_segment = &codeset.CodeSegment();
} else if (permission_flags == (PF_R)) { } else if (permission_flags == (ElfPfRead)) {
codeset_segment = &codeset.RODataSegment(); codeset_segment = &codeset.RODataSegment();
} else if (permission_flags == (PF_R | PF_W)) { } else if (permission_flags == (ElfPfRead | ElfPfWrite)) {
codeset_segment = &codeset.DataSegment(); codeset_segment = &codeset.DataSegment();
} else { } else {
LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,