mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-10 05:11:37 -07:00
Add tilde
This commit is contained in:
+1101
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,330 @@
|
||||
// PE/COFF is the executable/object format used by Microsoft.
|
||||
#ifndef TB_COFF_H
|
||||
#define TB_COFF_H
|
||||
|
||||
#include "tb_formats.h"
|
||||
|
||||
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
|
||||
|
||||
#define IMAGE_SYM_CLASS_EXTERNAL 0x0002
|
||||
#define IMAGE_SYM_CLASS_STATIC 0x0003
|
||||
#define IMAGE_SYM_CLASS_LABEL 0x0006
|
||||
#define IMAGE_SYM_CLASS_FILE 0x0067
|
||||
#define IMAGE_SYM_CLASS_SECTION 0x0068
|
||||
#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069
|
||||
|
||||
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
|
||||
|
||||
#define IMAGE_REL_AMD64_ADDR64 0x0001
|
||||
#define IMAGE_REL_AMD64_ADDR32 0x0002
|
||||
#define IMAGE_REL_AMD64_ADDR32NB 0x0003
|
||||
#define IMAGE_REL_AMD64_REL32 0x0004
|
||||
#define IMAGE_REL_AMD64_REL32_1 0x0005
|
||||
#define IMAGE_REL_AMD64_REL32_2 0x0006
|
||||
#define IMAGE_REL_AMD64_REL32_3 0x0007
|
||||
#define IMAGE_REL_AMD64_REL32_4 0x0008
|
||||
#define IMAGE_REL_AMD64_REL32_5 0x0009
|
||||
#define IMAGE_REL_AMD64_SECTION 0x000A
|
||||
#define IMAGE_REL_AMD64_SECREL 0x000B
|
||||
|
||||
#define IMAGE_SCN_LNK_REMOVE 0x00000800
|
||||
#define IMAGE_SCN_LNK_COMDAT 0x00001000
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
|
||||
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
|
||||
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
|
||||
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
|
||||
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
|
||||
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
|
||||
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
|
||||
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
|
||||
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
|
||||
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
|
||||
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
||||
|
||||
typedef enum {
|
||||
TB_COFF_SECTION_NO_PAD = 0x00000008,
|
||||
TB_COFF_SECTION_CODE = 0x00000020,
|
||||
TB_COFF_SECTION_INIT = 0x00000040,
|
||||
TB_COFF_SECTION_UNINIT = 0x00000080,
|
||||
TB_COFF_SECTION_OTHER = 0x00000100,
|
||||
TB_COFF_SECTION_INFO = 0x00000200,
|
||||
TB_COFF_SECTION_REMOVE = 0x00000800,
|
||||
TB_COFF_SECTION_COMDAT = 0x00001000,
|
||||
|
||||
// this is actually a 4bit field
|
||||
TB_COFF_SECTION_ALIGN = 0x00F00000,
|
||||
|
||||
// if we have more than 65535 relocations we do this
|
||||
TB_COFF_SECTION_RELOC_OVR = 0x00F00000,
|
||||
|
||||
// memory flags
|
||||
TB_COFF_SECTION_DISCARDABLE = 0x02000000,
|
||||
TB_COFF_SECTION_NOT_CACHED = 0x04000000,
|
||||
TB_COFF_SECTION_NOT_PAGED = 0x08000000,
|
||||
TB_COFF_SECTION_SHARED = 0x10000000,
|
||||
TB_COFF_SECTION_EXECUTE = 0x20000000,
|
||||
TB_COFF_SECTION_READ = 0x40000000,
|
||||
TB_COFF_SECTION_WRITE = 0x80000000,
|
||||
} TB_COFF_SectionFlags;
|
||||
|
||||
typedef struct TB_COFF_Parser {
|
||||
// inputs
|
||||
TB_Slice name, file;
|
||||
|
||||
// results
|
||||
size_t section_count;
|
||||
size_t symbol_table, symbol_count;
|
||||
|
||||
// private
|
||||
TB_Slice string_table;
|
||||
} TB_COFF_Parser;
|
||||
|
||||
// fills the parser with results from the COFF header
|
||||
bool tb_coff_parse_init(TB_COFF_Parser* restrict parser);
|
||||
bool tb_coff_parse_section(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSection* out_sec);
|
||||
|
||||
// how many symbols does this one symbol take up (basically 1 + aux symbols).
|
||||
// returns 0 if error.
|
||||
size_t tb_coff_parse_symbol(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSymbol* restrict out_sym);
|
||||
|
||||
#endif // TB_COFF_H
|
||||
|
||||
#ifdef TB_COFF_IMPL
|
||||
#include <common.h>
|
||||
|
||||
#pragma pack(push, 2)
|
||||
typedef struct COFF_SectionHeader {
|
||||
char name[8];
|
||||
union {
|
||||
uint32_t physical_address;
|
||||
uint32_t virtual_size;
|
||||
} misc;
|
||||
uint32_t virtual_address;
|
||||
uint32_t raw_data_size;
|
||||
uint32_t raw_data_pos;
|
||||
uint32_t pointer_to_reloc;
|
||||
uint32_t pointer_to_lineno;
|
||||
uint16_t num_reloc;
|
||||
uint16_t num_lineno;
|
||||
uint32_t characteristics;
|
||||
} COFF_SectionHeader;
|
||||
|
||||
typedef struct COFF_FileHeader {
|
||||
uint16_t machine;
|
||||
uint16_t section_count;
|
||||
uint32_t timestamp;
|
||||
uint32_t symbol_table;
|
||||
uint32_t symbol_count;
|
||||
uint16_t optional_header_size;
|
||||
uint16_t flags;
|
||||
} COFF_FileHeader;
|
||||
|
||||
typedef struct COFF_Symbol {
|
||||
union {
|
||||
uint8_t short_name[8];
|
||||
uint32_t long_name[2];
|
||||
};
|
||||
uint32_t value;
|
||||
int16_t section_number;
|
||||
uint16_t type;
|
||||
uint8_t storage_class;
|
||||
uint8_t aux_symbols_count;
|
||||
} COFF_Symbol;
|
||||
|
||||
typedef struct COFF_ImageReloc {
|
||||
union {
|
||||
uint32_t VirtualAddress;
|
||||
uint32_t RelocCount;
|
||||
};
|
||||
uint32_t SymbolTableIndex;
|
||||
uint16_t Type;
|
||||
} COFF_ImageReloc;
|
||||
#pragma pack(pop)
|
||||
|
||||
// sanity checks
|
||||
static_assert(sizeof(COFF_SectionHeader) == 40, "COFF Section header size != 40 bytes");
|
||||
static_assert(sizeof(COFF_ImageReloc) == 10, "COFF Image Relocation size != 10 bytes");
|
||||
static_assert(sizeof(COFF_FileHeader) == 20, "COFF File header size != 20 bytes");
|
||||
static_assert(sizeof(COFF_Symbol) == 18, "COFF Symbol size != 18 bytes");
|
||||
|
||||
bool tb_coff_parse_init(TB_COFF_Parser* restrict parser) {
|
||||
TB_Slice file = parser->file;
|
||||
|
||||
if (file.length < sizeof(COFF_FileHeader)) return false;
|
||||
COFF_FileHeader* header = (COFF_FileHeader*) &parser->file.data[0];
|
||||
|
||||
// locate string table (it spans until the end of the file)
|
||||
size_t string_table_pos = header->symbol_table + (header->symbol_count * sizeof(COFF_Symbol));
|
||||
if (file.length < string_table_pos) return false;
|
||||
|
||||
parser->symbol_count = header->symbol_count;
|
||||
parser->symbol_table = header->symbol_table;
|
||||
parser->section_count = header->section_count;
|
||||
parser->string_table = (TB_Slice){
|
||||
.length = file.length - string_table_pos,
|
||||
.data = &file.data[string_table_pos]
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static long long tb__parse_decimal_int(size_t n, const char* str) {
|
||||
const char* end = &str[n];
|
||||
|
||||
int result = 0;
|
||||
while (str != end) {
|
||||
if (*str < '0' || *str > '9') break;
|
||||
|
||||
result *= 10;
|
||||
result += *str - '0';
|
||||
str++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tb_coff_parse_section(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSection* restrict out_sec) {
|
||||
TB_Slice file = parser->file;
|
||||
size_t section_offset = sizeof(COFF_FileHeader) + (i * sizeof(COFF_SectionHeader));
|
||||
|
||||
if (file.length < section_offset + sizeof(COFF_SectionHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
COFF_SectionHeader* sec = (COFF_SectionHeader*) &file.data[section_offset];
|
||||
*out_sec = (TB_ObjectSection) { .flags = sec->characteristics };
|
||||
|
||||
// Parse string table name stuff
|
||||
if (sec->name[0] == '/') {
|
||||
// string table access
|
||||
int offset = tb__parse_decimal_int(7, &sec->name[1]);
|
||||
if (file.length > offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* data = &parser->string_table.data[offset];
|
||||
out_sec->name = (TB_Slice){ strlen((const char*) data), data };
|
||||
} else {
|
||||
// normal inplace string
|
||||
size_t len = strlen(sec->name);
|
||||
out_sec->name = (TB_Slice){ len, (uint8_t*) sec->name };
|
||||
}
|
||||
|
||||
// Parse relocations
|
||||
if (sec->num_reloc > 0) {
|
||||
out_sec->relocation_count = sec->num_reloc;
|
||||
COFF_ImageReloc* src_relocs = (COFF_ImageReloc*) &file.data[sec->pointer_to_reloc];
|
||||
|
||||
TB_ObjectReloc* dst_relocs = tb_platform_heap_alloc(sec->num_reloc * sizeof(TB_ObjectReloc));
|
||||
FOREACH_N(j, 0, sec->num_reloc) {
|
||||
dst_relocs[j] = (TB_ObjectReloc){ 0 };
|
||||
switch (src_relocs[j].Type) {
|
||||
case IMAGE_REL_AMD64_ADDR32NB: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR32NB; break;
|
||||
case IMAGE_REL_AMD64_ADDR32: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR32; break;
|
||||
case IMAGE_REL_AMD64_ADDR64: dst_relocs[j].type = TB_OBJECT_RELOC_ADDR64; break;
|
||||
case IMAGE_REL_AMD64_SECREL: dst_relocs[j].type = TB_OBJECT_RELOC_SECREL; break;
|
||||
case IMAGE_REL_AMD64_SECTION: dst_relocs[j].type = TB_OBJECT_RELOC_SECTION; break;
|
||||
|
||||
case IMAGE_REL_AMD64_REL32:
|
||||
case IMAGE_REL_AMD64_REL32_1:
|
||||
case IMAGE_REL_AMD64_REL32_2:
|
||||
case IMAGE_REL_AMD64_REL32_3:
|
||||
case IMAGE_REL_AMD64_REL32_4:
|
||||
case IMAGE_REL_AMD64_REL32_5:
|
||||
dst_relocs[j].type = TB_OBJECT_RELOC_REL32;
|
||||
break;
|
||||
|
||||
default: tb_todo();
|
||||
}
|
||||
|
||||
if (src_relocs[j].Type >= IMAGE_REL_AMD64_REL32 && src_relocs[j].Type <= IMAGE_REL_AMD64_REL32_5) {
|
||||
dst_relocs[j].addend = 4 + (src_relocs[j].Type - IMAGE_REL_AMD64_REL32);
|
||||
}
|
||||
|
||||
dst_relocs[j].symbol_index = src_relocs[j].SymbolTableIndex;
|
||||
dst_relocs[j].virtual_address = src_relocs[j].VirtualAddress;
|
||||
}
|
||||
|
||||
out_sec->relocations = dst_relocs;
|
||||
}
|
||||
|
||||
// Parse virtual region
|
||||
out_sec->virtual_address = sec->virtual_address;
|
||||
out_sec->virtual_size = sec->misc.virtual_size;
|
||||
|
||||
// Read raw data (if applies)
|
||||
if (sec->raw_data_size) {
|
||||
assert(sec->raw_data_pos + sec->raw_data_size < file.length);
|
||||
out_sec->raw_data = (TB_Slice){ sec->raw_data_size, &file.data[sec->raw_data_pos] };
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TB_ObjectSymbolType classify_symbol_type(uint16_t st_class) {
|
||||
switch (st_class) {
|
||||
case 2: return TB_OBJECT_SYMBOL_EXTERN;
|
||||
case 3: return TB_OBJECT_SYMBOL_STATIC;
|
||||
case 6: return TB_OBJECT_SYMBOL_STATIC;
|
||||
case 0x68: return TB_OBJECT_SYMBOL_SECTION;
|
||||
case 0x69: return TB_OBJECT_SYMBOL_WEAK_EXTERN;
|
||||
default: return TB_OBJECT_SYMBOL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
size_t tb_coff_parse_symbol(TB_COFF_Parser* restrict parser, size_t i, TB_ObjectSymbol* restrict out_sym) {
|
||||
TB_Slice file = parser->file;
|
||||
size_t symbol_offset = parser->symbol_table + (i * sizeof(COFF_Symbol));
|
||||
|
||||
if (file.length < symbol_offset + sizeof(COFF_Symbol)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
COFF_Symbol* sym = (COFF_Symbol*) &file.data[symbol_offset];
|
||||
*out_sym = (TB_ObjectSymbol) {
|
||||
.ordinal = i,
|
||||
.type = classify_symbol_type(sym->storage_class),
|
||||
.section_num = sym->section_number,
|
||||
.value = sym->value
|
||||
};
|
||||
|
||||
// Parse string table name stuff
|
||||
if (sym->long_name[0] == 0) {
|
||||
// string table access (read a cstring)
|
||||
// TODO(NeGate): bounds check this
|
||||
const uint8_t* data = &parser->string_table.data[sym->long_name[1]];
|
||||
out_sym->name = (TB_Slice){ strlen((const char*) data), data };
|
||||
} else {
|
||||
// normal inplace string
|
||||
size_t len = strlen((const char*) sym->short_name);
|
||||
out_sym->name = (TB_Slice){ len, sym->short_name };
|
||||
}
|
||||
|
||||
// TODO(NeGate): Process aux symbols
|
||||
if (sym->aux_symbols_count) {
|
||||
out_sym->extra = &sym[1];
|
||||
|
||||
// FOREACH_N(j, 0, sym->aux_symbols_count) {}
|
||||
}
|
||||
|
||||
return sym->aux_symbols_count + 1;
|
||||
}
|
||||
|
||||
#endif // TB_COFF_IMPL
|
||||
@@ -0,0 +1,170 @@
|
||||
#ifndef TB_ELF_H
|
||||
#define TB_ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TB_EI_MAG0 0
|
||||
#define TB_EI_MAG1 1
|
||||
#define TB_EI_MAG2 2
|
||||
#define TB_EI_MAG3 3
|
||||
#define TB_EI_CLASS 4 /* Class of machine. */
|
||||
#define TB_EI_DATA 5 /* Data format. */
|
||||
#define TB_EI_VERSION 6 /* ELF format version. */
|
||||
#define TB_EI_OSABI 7 /* Operating system / ABI identification */
|
||||
#define TB_EI_ABIVERSION 8 /* ABI version */
|
||||
#define TB_OLD_EI_BRAND 8 /* Start of architecture identification. */
|
||||
#define TB_EI_PAD 9 /* Start of padding (per SVR4 ABI). */
|
||||
#define TB_EI_NIDENT 16 /* Size of e_ident array. */
|
||||
|
||||
/* Values for e_type. */
|
||||
#define TB_ET_NONE 0 /* Unknown type. */
|
||||
#define TB_ET_REL 1 /* Relocatable. */
|
||||
#define TB_ET_EXEC 2 /* Executable. */
|
||||
#define TB_ET_DYN 3 /* Shared object. */
|
||||
#define TB_ET_CORE 4 /* Core file. */
|
||||
#define TB_ET_LOOS 0xfe00 /* First operating system specific. */
|
||||
#define TB_ET_HIOS 0xfeff /* Last operating system-specific. */
|
||||
#define TB_ET_LOPROC 0xff00 /* First processor-specific. */
|
||||
#define TB_ET_HIPROC 0xffff /* Last processor-specific. */
|
||||
|
||||
/* Values for e_machine. */
|
||||
#define TB_EM_NONE 0 /* Unknown machine. */
|
||||
#define TB_EM_X86_64 62 /* Advanced Micro Devices x86-64 */
|
||||
#define TB_EM_AARCH64 183 /* AArch64 (64-bit ARM) */
|
||||
|
||||
/* sh_type */
|
||||
#define TB_SHT_NULL 0 /* inactive */
|
||||
#define TB_SHT_PROGBITS 1 /* program defined information */
|
||||
#define TB_SHT_SYMTAB 2 /* symbol table section */
|
||||
#define TB_SHT_STRTAB 3 /* string table section */
|
||||
#define TB_SHT_RELA 4 /* relocation section with addends */
|
||||
#define TB_SHT_NOBITS 8 /* no space section */
|
||||
|
||||
/* Flags for sh_flags. */
|
||||
#define TB_SHF_WRITE 0x1 /* Section contains writable data. */
|
||||
#define TB_SHF_ALLOC 0x2 /* Section occupies memory. */
|
||||
#define TB_SHF_EXECINSTR 0x4 /* Section contains instructions. */
|
||||
#define TB_SHF_MERGE 0x10 /* Section may be merged. */
|
||||
#define TB_SHF_STRINGS 0x20 /* Section contains strings. */
|
||||
#define TB_SHF_INFO_LINK 0x40 /* sh_info holds section index. */
|
||||
#define TB_SHF_LINK_ORDER 0x80 /* Special ordering requirements. */
|
||||
#define TB_SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */
|
||||
#define TB_SHF_GROUP 0x200 /* Member of section group. */
|
||||
#define TB_SHF_TLS 0x400 /* Section contains TLS data. */
|
||||
#define TB_SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */
|
||||
#define TB_SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */
|
||||
|
||||
/* Values for p_flags. */
|
||||
#define TB_PF_X 0x1 /* Executable. */
|
||||
#define TB_PF_W 0x2 /* Writable. */
|
||||
#define TB_PF_R 0x4 /* Readable. */
|
||||
#define TB_PF_MASKOS 0x0ff00000 /* Operating system-specific. */
|
||||
#define TB_PF_MASKPROC 0xf0000000 /* Processor-specific. */
|
||||
|
||||
/* Values for p_type. */
|
||||
#define TB_PT_NULL 0 /* Unused entry. */
|
||||
#define TB_PT_LOAD 1 /* Loadable segment. */
|
||||
#define TB_PT_DYNAMIC 2 /* Dynamic linking information segment. */
|
||||
#define TB_PT_INTERP 3 /* Pathname of interpreter. */
|
||||
#define TB_PT_NOTE 4 /* Auxiliary information. */
|
||||
#define TB_PT_SHLIB 5 /* Reserved (not used). */
|
||||
#define TB_PT_PHDR 6 /* Location of program header itself. */
|
||||
#define TB_PT_TLS 7 /* Thread local storage segment */
|
||||
|
||||
/* Values for relocation */
|
||||
typedef enum {
|
||||
TB_ELF_X86_64_NONE = 0,
|
||||
TB_ELF_X86_64_64 = 1,
|
||||
TB_ELF_X86_64_PC32 = 2,
|
||||
TB_ELF_X86_64_GOT32 = 3,
|
||||
TB_ELF_X86_64_PLT32 = 4,
|
||||
TB_ELF_X86_64_GOTPCREL = 9,
|
||||
} TB_ELF_RelocType;
|
||||
|
||||
// ST_TYPE
|
||||
#define TB_ELF64_STT_NOTYPE 0
|
||||
#define TB_ELF64_STT_OBJECT 1
|
||||
#define TB_ELF64_STT_FUNC 2
|
||||
#define TB_ELF64_STT_SECTION 3
|
||||
|
||||
// ST_INFO
|
||||
#define TB_ELF64_STB_LOCAL 0
|
||||
#define TB_ELF64_STB_GLOBAL 1
|
||||
#define TB_ELF64_STB_WEAK 2
|
||||
|
||||
/* Macros for accessing the fields of st_info. */
|
||||
#define TB_ELF64_ST_BIND(info) ((info) >> 4)
|
||||
#define TB_ELF64_ST_TYPE(info) ((info) & 0xf)
|
||||
|
||||
#define TB_ELF64_ST_INFO(b, t) (((b) << 4) | ((t) & 0xF))
|
||||
|
||||
#define TB_ELF64_R_SYM(i) ((i) >> 32u)
|
||||
#define TB_ELF64_R_TYPE(i) ((i)&0xffffffffULL)
|
||||
#define TB_ELF64_R_INFO(s, t) (((uint64_t)(s) << 32ULL) + ((uint64_t)(t) & 0xffffffffULL))
|
||||
|
||||
// http://web.mit.edu/freebsd/head/sys/sys/elf64.h
|
||||
// https://cirosantilli.com/elf-hello-world#minimal-elf-file
|
||||
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
typedef struct {
|
||||
uint8_t ident[16];
|
||||
uint16_t type;
|
||||
uint16_t machine;
|
||||
uint32_t version;
|
||||
uint64_t entry;
|
||||
uint64_t phoff;
|
||||
uint64_t shoff;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize;
|
||||
uint16_t phentsize;
|
||||
uint16_t phnum;
|
||||
uint16_t shentsize;
|
||||
uint16_t shnum;
|
||||
uint16_t shstrndx;
|
||||
} TB_Elf64_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t name;
|
||||
uint32_t type;
|
||||
uint64_t flags;
|
||||
uint64_t addr;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint64_t addralign;
|
||||
uint64_t entsize;
|
||||
} TB_Elf64_Shdr;
|
||||
|
||||
// Segment header for ELF64.
|
||||
typedef struct {
|
||||
uint32_t type; // Type of segment
|
||||
uint32_t flags; // Segment flags
|
||||
uint64_t offset; // File offset where segment is located, in bytes
|
||||
uint64_t vaddr; // Virtual address of beginning of segment
|
||||
uint64_t paddr; // Physical addr of beginning of segment (OS-specific)
|
||||
uint64_t filesz; // Num. of bytes in file image of segment (may be zero)
|
||||
uint64_t memsz; // Num. of bytes in mem image of segment (may be zero)
|
||||
uint64_t align; // Segment alignment constraint
|
||||
} TB_Elf64_Phdr;
|
||||
|
||||
typedef struct {
|
||||
uint32_t name;
|
||||
uint8_t info;
|
||||
uint8_t other;
|
||||
uint16_t shndx;
|
||||
uint64_t value;
|
||||
uint64_t size;
|
||||
} TB_Elf64_Sym;
|
||||
|
||||
typedef struct {
|
||||
uint64_t offset;
|
||||
uint64_t info;
|
||||
int64_t addend;
|
||||
} TB_Elf64_Rela;
|
||||
|
||||
typedef struct {
|
||||
uint64_t offset;
|
||||
uint64_t info;
|
||||
} TB_Elf64_Rel;
|
||||
|
||||
#endif /* TB_ELF_H */
|
||||
@@ -0,0 +1,132 @@
|
||||
// This handles the generalized executable/object format parsing stuff
|
||||
#ifndef TB_OBJECT_H
|
||||
#define TB_OBJECT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum {
|
||||
TB_OBJECT_RELOC_NONE, // how?
|
||||
|
||||
// Target independent
|
||||
TB_OBJECT_RELOC_ADDR32,
|
||||
TB_OBJECT_RELOC_ADDR64, // unsupported on 32bit platforms
|
||||
TB_OBJECT_RELOC_SECREL,
|
||||
TB_OBJECT_RELOC_SECTION,
|
||||
|
||||
// COFF only
|
||||
TB_OBJECT_RELOC_ADDR32NB, // Relative virtual address
|
||||
|
||||
// x64 only
|
||||
TB_OBJECT_RELOC_REL32, // relative 32bit displacement
|
||||
|
||||
// Aarch64 only
|
||||
TB_OBJECT_RELOC_BRANCH26, // 26bit displacement for B and BL instructions
|
||||
TB_OBJECT_RELOC_REL21, // for ADR instructions
|
||||
|
||||
// TODO(NeGate): fill in the rest of this later
|
||||
} TB_ObjectRelocType;
|
||||
|
||||
typedef struct {
|
||||
TB_ObjectRelocType type;
|
||||
uint32_t symbol_index;
|
||||
size_t virtual_address;
|
||||
size_t addend;
|
||||
} TB_ObjectReloc;
|
||||
|
||||
typedef enum {
|
||||
TB_OBJECT_SYMBOL_UNKNOWN,
|
||||
TB_OBJECT_SYMBOL_EXTERN, // exported
|
||||
TB_OBJECT_SYMBOL_WEAK_EXTERN, // weak
|
||||
TB_OBJECT_SYMBOL_IMPORT, // forward decl
|
||||
TB_OBJECT_SYMBOL_STATIC, // local
|
||||
TB_OBJECT_SYMBOL_SECTION, // local
|
||||
} TB_ObjectSymbolType;
|
||||
|
||||
typedef struct {
|
||||
TB_ObjectSymbolType type;
|
||||
int section_num;
|
||||
|
||||
uint32_t ordinal;
|
||||
uint32_t value;
|
||||
|
||||
TB_Slice name;
|
||||
|
||||
// for COFF, this is the auxillary
|
||||
void* extra;
|
||||
|
||||
// this is zeroed out by the loader and left for the user to do crap with
|
||||
void* user_data;
|
||||
} TB_ObjectSymbol;
|
||||
|
||||
typedef struct {
|
||||
TB_Slice name;
|
||||
uint32_t flags;
|
||||
|
||||
size_t virtual_address;
|
||||
size_t virtual_size;
|
||||
|
||||
// You can have a virtual size without having a raw
|
||||
// data size, that's how the BSS section works
|
||||
TB_Slice raw_data;
|
||||
|
||||
size_t relocation_count;
|
||||
TB_ObjectReloc* relocations;
|
||||
|
||||
// this is zeroed out by the loader and left for the user to do crap with
|
||||
void* user_data;
|
||||
} TB_ObjectSection;
|
||||
|
||||
typedef enum {
|
||||
TB_OBJECT_FILE_UNKNOWN,
|
||||
|
||||
TB_OBJECT_FILE_COFF,
|
||||
TB_OBJECT_FILE_ELF64
|
||||
} TB_ObjectFileType;
|
||||
|
||||
typedef struct {
|
||||
TB_ObjectFileType type;
|
||||
TB_Arch arch;
|
||||
|
||||
TB_Slice name;
|
||||
TB_Slice ar_name;
|
||||
|
||||
size_t symbol_count;
|
||||
TB_ObjectSymbol* symbols;
|
||||
|
||||
size_t section_count;
|
||||
TB_ObjectSection sections[];
|
||||
} TB_ObjectFile;
|
||||
|
||||
////////////////////////////////
|
||||
// Archive parser
|
||||
////////////////////////////////
|
||||
typedef struct {
|
||||
TB_Slice name;
|
||||
|
||||
// if import_name is empty, we're dealing with an object file
|
||||
TB_Slice import_name;
|
||||
uint16_t ordinal;
|
||||
|
||||
TB_Slice content;
|
||||
} TB_ArchiveEntry;
|
||||
|
||||
typedef struct {
|
||||
TB_Slice file;
|
||||
size_t pos;
|
||||
|
||||
size_t member_count;
|
||||
uint32_t* members;
|
||||
|
||||
size_t symbol_count;
|
||||
uint16_t* symbols;
|
||||
|
||||
TB_Slice strtbl;
|
||||
} TB_ArchiveFileParser;
|
||||
|
||||
// We do this to parse the header
|
||||
bool tb_archive_parse(TB_Slice file, TB_ArchiveFileParser* restrict out_parser);
|
||||
// After that we can enumerate any symbol entries to resolve imports
|
||||
size_t tb_archive_parse_entries(TB_ArchiveFileParser* restrict parser, size_t i, size_t count, TB_ArchiveEntry* out_entry);
|
||||
|
||||
#endif // TB_OBJECT_H
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef TB_X64_H
|
||||
#define TB_X64_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
// uses xmm registers for the reg array
|
||||
TB_X86_INSTR_XMMREG = (1u << 0u),
|
||||
|
||||
// r/m is a memory operand
|
||||
TB_X86_INSTR_USE_MEMOP = (1u << 1u),
|
||||
|
||||
// r/m is a rip-relative address (TB_X86_INSTR_USE_MEMOP is always set when this is set)
|
||||
TB_X86_INSTR_USE_RIPMEM = (1u << 2u),
|
||||
|
||||
// LOCK prefix is present
|
||||
TB_X86_INSTR_LOCK = (1u << 3u),
|
||||
|
||||
// uses a signed immediate
|
||||
TB_X86_INSTR_IMMEDIATE = (1u << 4u),
|
||||
|
||||
// absolute means it's using the 64bit immediate (cannot be applied while a memory operand is active)
|
||||
TB_X86_INSTR_ABSOLUTE = (1u << 5u),
|
||||
|
||||
// set if the r/m can be found on the right hand side
|
||||
TB_X86_INSTR_DIRECTION = (1u << 6u),
|
||||
|
||||
// uses the second data type because the instruction is weird like MOVSX or MOVZX
|
||||
TB_X86_INSTR_TWO_DATA_TYPES = (1u << 7u)
|
||||
} TB_X86_InstFlags;
|
||||
|
||||
typedef enum {
|
||||
TB_X86_SEGMENT_DEFAULT = 0,
|
||||
|
||||
TB_X86_SEGMENT_ES, TB_X86_SEGMENT_CS,
|
||||
TB_X86_SEGMENT_SS, TB_X86_SEGMENT_DS,
|
||||
TB_X86_SEGMENT_GS, TB_X86_SEGMENT_FS,
|
||||
} TB_X86_Segment;
|
||||
|
||||
typedef enum {
|
||||
TB_X86_TYPE_NONE = 0,
|
||||
|
||||
TB_X86_TYPE_BYTE, // 1
|
||||
TB_X86_TYPE_WORD, // 2
|
||||
TB_X86_TYPE_DWORD, // 4
|
||||
TB_X86_TYPE_QWORD, // 8
|
||||
|
||||
TB_X86_TYPE_PBYTE, // int8 x 16 = 16
|
||||
TB_X86_TYPE_PWORD, // int16 x 8 = 16
|
||||
TB_X86_TYPE_PDWORD, // int32 x 4 = 16
|
||||
TB_X86_TYPE_PQWORD, // int64 x 2 = 16
|
||||
|
||||
TB_X86_TYPE_SSE_SS, // float32 x 1 = 4
|
||||
TB_X86_TYPE_SSE_SD, // float64 x 1 = 8
|
||||
TB_X86_TYPE_SSE_PS, // float32 x 4 = 16
|
||||
TB_X86_TYPE_SSE_PD, // float64 x 2 = 16
|
||||
|
||||
TB_X86_TYPE_XMMWORD, // the generic idea of them
|
||||
} TB_X86_DataType;
|
||||
|
||||
typedef struct {
|
||||
int16_t type;
|
||||
|
||||
// registers (there's 4 max taking up 4bit slots each)
|
||||
uint16_t regs;
|
||||
uint8_t flags;
|
||||
|
||||
// bitpacking amirite
|
||||
TB_X86_DataType data_type : 4;
|
||||
TB_X86_DataType data_type2 : 4;
|
||||
TB_X86_Segment segment : 4;
|
||||
uint8_t length : 4;
|
||||
|
||||
// memory operand
|
||||
// X86_INSTR_USE_MEMOP
|
||||
int32_t disp;
|
||||
|
||||
// immediate operand
|
||||
// imm for INSTR_IMMEDIATE
|
||||
// abs for INSTR_ABSOLUTE
|
||||
union {
|
||||
int32_t imm;
|
||||
uint64_t abs;
|
||||
};
|
||||
} TB_X86_Inst;
|
||||
|
||||
TB_X86_Inst tb_x86_disasm(size_t length, const uint8_t data[length]);
|
||||
|
||||
#endif /* TB_X64_H */
|
||||
Reference in New Issue
Block a user