pass over COFF layer

- updated naming convention on structs, enums, and macros to conform with code base style
- moved related structs closer to each other
- moved parser code to separate file
This commit is contained in:
Nikita Smith
2025-01-20 19:31:52 -08:00
parent 269dc33985
commit 153bbc7b1d
31 changed files with 2659 additions and 2772 deletions
+219 -1230
View File
File diff suppressed because it is too large Load Diff
+400 -711
View File
File diff suppressed because it is too large Load Diff
+226 -241
View File
@@ -21,54 +21,54 @@ read_only struct
String8 string;
COFF_MachineType machine;
} g_coff_machine_map[] = {
{ str8_lit_comp(""), COFF_MachineType_UNKNOWN },
{ str8_lit_comp("X86"), COFF_MachineType_X86 },
{ str8_lit_comp("AMD64"), COFF_MachineType_X64 },
{ str8_lit_comp("X64"), COFF_MachineType_X64 },
{ str8_lit_comp("AM33"), COFF_MachineType_AM33 },
{ str8_lit_comp("ARM"), COFF_MachineType_ARM },
{ str8_lit_comp("ARM64"), COFF_MachineType_ARM64 },
{ str8_lit_comp("ARMNT"), COFF_MachineType_ARMNT },
{ str8_lit_comp("EBC"), COFF_MachineType_EBC },
{ str8_lit_comp("IA64"), COFF_MachineType_IA64 },
{ str8_lit_comp("M32R"), COFF_MachineType_M32R },
{ str8_lit_comp("MIPS16"), COFF_MachineType_MIPS16 },
{ str8_lit_comp("MIPSFPU"), COFF_MachineType_MIPSFPU },
{ str8_lit_comp("MIPSFPU16"), COFF_MachineType_MIPSFPU16 },
{ str8_lit_comp("POWERPC"), COFF_MachineType_POWERPC },
{ str8_lit_comp("POWERPCFP"), COFF_MachineType_POWERPCFP },
{ str8_lit_comp("R4000"), COFF_MachineType_R4000 },
{ str8_lit_comp("RISCV32"), COFF_MachineType_RISCV32 },
{ str8_lit_comp("RISCV64"), COFF_MachineType_RISCV64 },
{ str8_lit_comp("SH3"), COFF_MachineType_SH3 },
{ str8_lit_comp("SH3DSP"), COFF_MachineType_SH3DSP },
{ str8_lit_comp("SH4"), COFF_MachineType_SH4 },
{ str8_lit_comp("SH5"), COFF_MachineType_SH5 },
{ str8_lit_comp("THUMB"), COFF_MachineType_THUMB },
{ str8_lit_comp("WCEMIPSV2"), COFF_MachineType_WCEMIPSV2 },
{ str8_lit_comp(""), COFF_Machine_Unknown },
{ str8_lit_comp("X86"), COFF_Machine_X86 },
{ str8_lit_comp("Amd64"), COFF_Machine_X64 },
{ str8_lit_comp("X64"), COFF_Machine_X64 },
{ str8_lit_comp("Am33"), COFF_Machine_Am33 },
{ str8_lit_comp("Arm"), COFF_Machine_Arm },
{ str8_lit_comp("Arm64"), COFF_Machine_Arm64 },
{ str8_lit_comp("ArmNt"), COFF_Machine_ArmNt },
{ str8_lit_comp("Ebc"), COFF_Machine_Ebc },
{ str8_lit_comp("Ia64"), COFF_Machine_Ia64 },
{ str8_lit_comp("M32r"), COFF_Machine_M32R },
{ str8_lit_comp("Mips16"), COFF_Machine_Mips16 },
{ str8_lit_comp("MipsFpu"), COFF_Machine_MipsFpu },
{ str8_lit_comp("MipsFpu16"), COFF_Machine_MipsFpu16 },
{ str8_lit_comp("PowerPc"), COFF_Machine_PowerPc },
{ str8_lit_comp("PowerPcFp"), COFF_Machine_PowerPcFp },
{ str8_lit_comp("R4000"), COFF_Machine_R4000 },
{ str8_lit_comp("RiscV32"), COFF_Machine_RiscV32 },
{ str8_lit_comp("RiscV64"), COFF_Machine_RiscV64 },
{ str8_lit_comp("Sh3"), COFF_Machine_Sh3 },
{ str8_lit_comp("Sh3Dsp"), COFF_Machine_Sh3Dsp },
{ str8_lit_comp("Sh4"), COFF_Machine_Sh4 },
{ str8_lit_comp("Sh5"), COFF_Machine_Sh5 },
{ str8_lit_comp("Thumb"), COFF_Machine_Thumb },
{ str8_lit_comp("WceMipsV2"), COFF_Machine_WceMipsV2 },
};
read_only static struct {
char * name;
COFF_ImportHeaderType type;
COFF_ImportType type;
} g_coff_import_header_type_map[] = {
{ "CODE", COFF_ImportHeaderType_CODE },
{ "DATA", COFF_ImportHeaderType_DATA },
{ "CONST", COFF_ImportHeaderType_CONST },
{ "Code", COFF_ImportHeader_Code },
{ "Data", COFF_ImportHeader_Data },
{ "Const", COFF_ImportHeader_Const },
};
internal String8
coff_string_from_comdat_select_type(COFF_ComdatSelectType select)
coff_string_from_comdat_select_type(COFF_ComdatSelectType type)
{
String8 result = str8(0,0);
switch (select) {
case COFF_ComdatSelectType_NULL: result = str8_lit("NULL"); break;
case COFF_ComdatSelectType_NODUPLICATES: result = str8_lit("NODUPLICATES"); break;
case COFF_ComdatSelectType_ANY: result = str8_lit("ANY"); break;
case COFF_ComdatSelectType_SAME_SIZE: result = str8_lit("SAME_SIZE"); break;
case COFF_ComdatSelectType_EXACT_MATCH: result = str8_lit("EXACT_MATCH"); break;
case COFF_ComdatSelectType_ASSOCIATIVE: result = str8_lit("ASSOCIATIVE"); break;
case COFF_ComdatSelectType_LARGEST: result = str8_lit("LARGEST"); break;
String8 result = str8_zero();
switch (type) {
case COFF_ComdatSelect_Null: result = str8_lit("Null"); break;
case COFF_ComdatSelect_NoDuplicates: result = str8_lit("NoDuplicates"); break;
case COFF_ComdatSelect_Any: result = str8_lit("Any"); break;
case COFF_ComdatSelect_SameSize: result = str8_lit("SameSize"); break;
case COFF_ComdatSelect_ExactMatch: result = str8_lit("ExactMatch"); break;
case COFF_ComdatSelect_Associative: result = str8_lit("Associative"); break;
case COFF_ComdatSelect_Largest: result = str8_lit("Largest"); break;
}
return result;
}
@@ -85,45 +85,45 @@ coff_string_from_machine_type(COFF_MachineType machine)
}
internal String8
coff_string_from_flags(Arena *arena, COFF_Flags flags)
coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (flags & COFF_Flag_RELOC_STRIPPED) {
if (flags & COFF_FileHeaderFlag_RelocStripped) {
str8_list_pushf(scratch.arena, &list, "Relocs Stripped");
}
if (flags & COFF_Flag_EXECUTABLE_IMAGE) {
if (flags & COFF_FileHeaderFlag_ExecutableImage) {
str8_list_pushf(scratch.arena, &list, "Executable");
}
if (flags & COFF_Flag_LINE_NUMS_STRIPPED) {
if (flags & COFF_FileHeaderFlag_LineNumbersStripped) {
str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped");
}
if (flags & COFF_Flag_SYM_STRIPPED) {
if (flags & COFF_FileHeaderFlag_SymbolsStripped) {
str8_list_pushf(scratch.arena, &list, "Symbols Stripped");
}
if (flags & COFF_Flag_LARGE_ADDRESS_AWARE) {
if (flags & COFF_FileHeaderFlag_LargeAddressAware) {
str8_list_pushf(scratch.arena, &list, "Large Address Aware");
}
if (flags & COFF_Flag_32BIT_MACHINE) {
if (flags & COFF_FileHeaderFlag_32BitMachine) {
str8_list_pushf(scratch.arena, &list, "32-Bit Machine");
}
if (flags & COFF_Flag_DEBUG_STRIPPED) {
if (flags & COFF_FileHeaderFlag_DebugStripped) {
str8_list_pushf(scratch.arena, &list, "Debug Stripped");
}
if (flags & COFF_Flag_REMOVABLE_RUN_FROM_SWAP) {
if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) {
str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap");
}
if (flags & COFF_Flag_NET_RUN_FROM_SWAP) {
if (flags & COFF_FileHeaderFlag_NetRunFromSwap) {
str8_list_pushf(scratch.arena, &list, "Net Run From Swap");
}
if (flags & COFF_Flag_SYSTEM) {
if (flags & COFF_FileHeaderFlag_System) {
str8_list_pushf(scratch.arena, &list, "System");
}
if (flags & COFF_Flag_DLL) {
if (flags & COFF_FileHeaderFlag_Dll) {
str8_list_pushf(scratch.arena, &list, "DLL");
}
if (flags & COFF_Flag_UP_SYSTEM_ONLY) {
if (flags & COFF_FileHeaderFlag_UpSystemOnly) {
str8_list_pushf(scratch.arena, &list, "Up System Only");
}
@@ -139,62 +139,62 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
if (flags & COFF_SectionFlag_TYPE_NO_PAD) {
str8_list_pushf(scratch.arena, &list, "TYPE_NO_PAD");
if (flags & COFF_SectionFlag_TypeNoPad) {
str8_list_pushf(scratch.arena, &list, "TypeNoPad");
}
if (flags & COFF_SectionFlag_CNT_CODE) {
str8_list_pushf(scratch.arena, &list, "CNT_CODE");
if (flags & COFF_SectionFlag_CntCode) {
str8_list_pushf(scratch.arena, &list, "CntCode");
}
if (flags & COFF_SectionFlag_CNT_INITIALIZED_DATA) {
str8_list_pushf(scratch.arena, &list, "CNT_INITIALIZED_DATA");
if (flags & COFF_SectionFlag_CntInitializedData) {
str8_list_pushf(scratch.arena, &list, "CntInitializedData");
}
if (flags & COFF_SectionFlag_CNT_UNINITIALIZED_DATA) {
str8_list_pushf(scratch.arena, &list, "CNT_UNINITIALIZED_DATA");
if (flags & COFF_SectionFlag_CntUninitializedData) {
str8_list_pushf(scratch.arena, &list, "CntUninitializedData");
}
if (flags & COFF_SectionFlag_LNK_OTHER) {
str8_list_pushf(scratch.arena, &list, "LNK_OTHER");
if (flags & COFF_SectionFlag_LnkOther) {
str8_list_pushf(scratch.arena, &list, "LnkOther");
}
if (flags & COFF_SectionFlag_LNK_INFO) {
str8_list_pushf(scratch.arena, &list, "LNK_INFO");
if (flags & COFF_SectionFlag_LnkInfo) {
str8_list_pushf(scratch.arena, &list, "LnkInfo");
}
if (flags & COFF_SectionFlag_LNK_COMDAT) {
str8_list_pushf(scratch.arena, &list, "LNK_COMDAT");
if (flags & COFF_SectionFlag_LnkCOMDAT) {
str8_list_pushf(scratch.arena, &list, "LnkCOMDAT");
}
if (flags & COFF_SectionFlag_GPREL) {
str8_list_pushf(scratch.arena, &list, "GPREL");
if (flags & COFF_SectionFlag_GpRel) {
str8_list_pushf(scratch.arena, &list, "GpRel");
}
if (flags & COFF_SectionFlag_MEM_16BIT) {
str8_list_pushf(scratch.arena, &list, "MEM_16BIT");
if (flags & COFF_SectionFlag_Mem16Bit) {
str8_list_pushf(scratch.arena, &list, "Mem16Bit");
}
if (flags & COFF_SectionFlag_MEM_LOCKED) {
str8_list_pushf(scratch.arena, &list, "MEM_LOCKED");
if (flags & COFF_SectionFlag_MemLocked) {
str8_list_pushf(scratch.arena, &list, "MemLocked");
}
if (flags & COFF_SectionFlag_MEM_PRELOAD) {
str8_list_pushf(scratch.arena, &list, "MEM_PRELOAD");
if (flags & COFF_SectionFlag_MemPreload) {
str8_list_pushf(scratch.arena, &list, "MemPreload");
}
if (flags & COFF_SectionFlag_LNK_NRELOC_OVFL) {
str8_list_pushf(scratch.arena, &list, "LNK_NRELOC_OVFL");
if (flags & COFF_SectionFlag_LnkNRelocOvfl) {
str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl");
}
if (flags & COFF_SectionFlag_MEM_DISCARDABLE) {
str8_list_pushf(scratch.arena, &list, "MEM_DISCARDABLE");
if (flags & COFF_SectionFlag_MemDiscardable) {
str8_list_pushf(scratch.arena, &list, "MemDiscardable");
}
if (flags & COFF_SectionFlag_MEM_NOT_CACHED) {
str8_list_pushf(scratch.arena, &list, "MEM_NOT_CACHED");
if (flags & COFF_SectionFlag_MemNotCached) {
str8_list_pushf(scratch.arena, &list, "MemNotCached");
}
if (flags & COFF_SectionFlag_MEM_NOT_PAGED) {
str8_list_pushf(scratch.arena, &list, "MEM_NOT_PAGED");
if (flags & COFF_SectionFlag_MemNotPaged) {
str8_list_pushf(scratch.arena, &list, "MemNotPaged");
}
if (flags & COFF_SectionFlag_MEM_SHARED) {
str8_list_pushf(scratch.arena, &list, "MEM_SHARED");
if (flags & COFF_SectionFlag_MemShared) {
str8_list_pushf(scratch.arena, &list, "MemShared");
}
if (flags & COFF_SectionFlag_MEM_EXECUTE) {
str8_list_pushf(scratch.arena, &list, "MEM_EXECUTE");
if (flags & COFF_SectionFlag_MemExecute) {
str8_list_pushf(scratch.arena, &list, "MemExecute");
}
if (flags & COFF_SectionFlag_MEM_READ) {
str8_list_pushf(scratch.arena, &list, "MEM_READ");
if (flags & COFF_SectionFlag_MemRead) {
str8_list_pushf(scratch.arena, &list, "MemRead");
}
if (flags & COFF_SectionFlag_MEM_WRITE) {
str8_list_pushf(scratch.arena, &list, "MEM_WRITE");
if (flags & COFF_SectionFlag_MemWrite) {
str8_list_pushf(scratch.arena, &list, "MemWrite");
}
U64 align = coff_align_size_from_section_flags(flags);
@@ -215,7 +215,7 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags)
}
internal String8
coff_string_from_import_header_type(COFF_ImportHeaderType type)
coff_string_from_import_header_type(COFF_ImportType type)
{
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
if (g_coff_import_header_type_map[i].type == type) {
@@ -229,10 +229,10 @@ internal String8
coff_string_from_sym_dtype(COFF_SymDType x)
{
switch (x) {
case COFF_SymDType_NULL: return str8_lit("NULL");
case COFF_SymDType_PTR : return str8_lit("PTR");
case COFF_SymDType_FUNC: return str8_lit("FUNC");
case COFF_SymDType_ARRAY: return str8_lit("ARRAY");
case COFF_SymDType_Null: return str8_lit("Null");
case COFF_SymDType_Ptr : return str8_lit("Ptr");
case COFF_SymDType_Func: return str8_lit("Func");
case COFF_SymDType_Array: return str8_lit("Array");
}
return str8_zero();
}
@@ -241,22 +241,22 @@ internal String8
coff_string_from_sym_type(COFF_SymType x)
{
switch (x) {
case COFF_SymType_NULL: return str8_lit("NULL");
case COFF_SymType_VOID: return str8_lit("VOID");
case COFF_SymType_CHAR: return str8_lit("CHAR");
case COFF_SymType_SHORT: return str8_lit("SHORT");
case COFF_SymType_INT: return str8_lit("INT");
case COFF_SymType_LONG: return str8_lit("LONG");
case COFF_SymType_FLOAT: return str8_lit("FLOAT");
case COFF_SymType_DOUBLE: return str8_lit("DOUBLE");
case COFF_SymType_STRUCT: return str8_lit("STRUCT");
case COFF_SymType_UNION: return str8_lit("UNION");
case COFF_SymType_ENUM: return str8_lit("ENUM");
case COFF_SymType_MOE: return str8_lit("MOE");
case COFF_SymType_BYTE: return str8_lit("BYTE");
case COFF_SymType_WORD: return str8_lit("WORD");
case COFF_SymType_UINT: return str8_lit("UINT");
case COFF_SymType_DWORD: return str8_lit("DWORD");
case COFF_SymType_Null: return str8_lit("Null");
case COFF_SymType_Void: return str8_lit("Void");
case COFF_SymType_Char: return str8_lit("Char");
case COFF_SymType_Short: return str8_lit("Short");
case COFF_SymType_Int: return str8_lit("Int");
case COFF_SymType_Long: return str8_lit("Long");
case COFF_SymType_Float: return str8_lit("Float");
case COFF_SymType_Double: return str8_lit("Double");
case COFF_SymType_Struct: return str8_lit("Struct");
case COFF_SymType_Union: return str8_lit("Union");
case COFF_SymType_Enum: return str8_lit("Enum");
case COFF_SymType_MemberOfEnumeration: return str8_lit("MOE");
case COFF_SymType_Byte: return str8_lit("Byte");
case COFF_SymType_Word: return str8_lit("Word");
case COFF_SymType_UInt: return str8_lit("UInt");
case COFF_SymType_DWord: return str8_lit("DWord");
}
return str8_zero();
}
@@ -265,33 +265,33 @@ internal String8
coff_string_from_sym_storage_class(COFF_SymStorageClass x)
{
switch (x) {
case COFF_SymStorageClass_NULL: break;
case COFF_SymStorageClass_END_OF_FUNCTION: return str8_lit("EOF");
case COFF_SymStorageClass_AUTOMATIC: return str8_lit("AUTOMATIC");
case COFF_SymStorageClass_EXTERNAL: return str8_lit("EXTERNAL");
case COFF_SymStorageClass_STATIC: return str8_lit("STATIC");
case COFF_SymStorageClass_REGISTER: return str8_lit("REGISTER");
case COFF_SymStorageClass_EXTERNAL_DEF: return str8_lit("DEF");
case COFF_SymStorageClass_LABEL: return str8_lit("LABEL");
case COFF_SymStorageClass_UNDEFINED_LABEL: return str8_lit("LABEL");
case COFF_SymStorageClass_MEMBER_OF_STRUCT: return str8_lit("STRUCT");
case COFF_SymStorageClass_ARGUMENT: return str8_lit("ARGUMENT");
case COFF_SymStorageClass_STRUCT_TAG: return str8_lit("TAG");
case COFF_SymStorageClass_MEMBER_OF_UNION: return str8_lit("UNION");
case COFF_SymStorageClass_UNION_TAG: return str8_lit("TAG");
case COFF_SymStorageClass_TYPE_DEFINITION: return str8_lit("DEFINITION");
case COFF_SymStorageClass_UNDEFINED_STATIC: return str8_lit("STATIC");
case COFF_SymStorageClass_ENUM_TAG: return str8_lit("TAG");
case COFF_SymStorageClass_MEMBER_OF_ENUM: return str8_lit("ENUM");
case COFF_SymStorageClass_REGISTER_PARAM: return str8_lit("PARAM");
case COFF_SymStorageClass_BIT_FIELD: return str8_lit("FIELD");
case COFF_SymStorageClass_BLOCK: return str8_lit("BLOCK");
case COFF_SymStorageClass_FUNCTION: return str8_lit("FUNCTION");
case COFF_SymStorageClass_END_OF_STRUCT: return str8_lit("STRUCT");
case COFF_SymStorageClass_FILE: return str8_lit("FILE");
case COFF_SymStorageClass_SECTION: return str8_lit("SECTION");
case COFF_SymStorageClass_WEAK_EXTERNAL: return str8_lit("EXTERNAL");
case COFF_SymStorageClass_CLR_TOKEN: return str8_lit("TOKEN");
case COFF_SymStorageClass_Null: break;
case COFF_SymStorageClass_EndOfFunction: return str8_lit("EndOfFunction");
case COFF_SymStorageClass_Automatic: return str8_lit("Automatic");
case COFF_SymStorageClass_External: return str8_lit("External");
case COFF_SymStorageClass_Static: return str8_lit("Static");
case COFF_SymStorageClass_Register: return str8_lit("Register");
case COFF_SymStorageClass_ExternalDef: return str8_lit("Def");
case COFF_SymStorageClass_Label: return str8_lit("Label");
case COFF_SymStorageClass_UndefinedLabel: return str8_lit("UndefinedLabel");
case COFF_SymStorageClass_MemberOfStruct: return str8_lit("Struct");
case COFF_SymStorageClass_Argument: return str8_lit("Argument");
case COFF_SymStorageClass_StructTag: return str8_lit("Tag");
case COFF_SymStorageClass_MemberOfUnion: return str8_lit("Union");
case COFF_SymStorageClass_UnionTag: return str8_lit("Tag");
case COFF_SymStorageClass_TypeDefinition: return str8_lit("Definition");
case COFF_SymStorageClass_UndefinedStatic: return str8_lit("Static");
case COFF_SymStorageClass_EnumTag: return str8_lit("Tag");
case COFF_SymStorageClass_MemberOfEnum: return str8_lit("Enum");
case COFF_SymStorageClass_RegisterParam: return str8_lit("Param");
case COFF_SymStorageClass_BitField: return str8_lit("Field");
case COFF_SymStorageClass_Block: return str8_lit("Block");
case COFF_SymStorageClass_Function: return str8_lit("Function");
case COFF_SymStorageClass_EndOfStruct: return str8_lit("Struct");
case COFF_SymStorageClass_File: return str8_lit("File");
case COFF_SymStorageClass_Section: return str8_lit("Section");
case COFF_SymStorageClass_WeakExternal: return str8_lit("External");
case COFF_SymStorageClass_CLRToken: return str8_lit("Token");
}
return str8_zero();
}
@@ -300,130 +300,115 @@ internal String8
coff_string_from_weak_ext_type(COFF_WeakExtType x)
{
switch (x) {
case COFF_WeakExtType_NOLIBRARY: return str8_lit("NOLIBRARY");
case COFF_WeakExtType_SEARCH_LIBRARY: return str8_lit("SEARCH_LIBRARY");
case COFF_WeakExtType_SEARCH_ALIAS: return str8_lit("SEARCH_ALIAS");
case COFF_WeakExt_NoLibrary: return str8_lit("NoLibrary");
case COFF_WeakExt_SearchLibrary: return str8_lit("SearchLibrary");
case COFF_WeakExt_SearchAlias: return str8_lit("SearchAlias");
}
return str8_zero();
}
internal String8
coff_string_from_selection(COFF_ComdatSelectType x)
coff_string_from_reloc_x86(COFF_Reloc_X86 x)
{
switch (x) {
case COFF_ComdatSelectType_NULL: break;
case COFF_ComdatSelectType_NODUPLICATES: return str8_lit("NODUPLICATES");
case COFF_ComdatSelectType_ANY: return str8_lit("ANY");
case COFF_ComdatSelectType_SAME_SIZE: return str8_lit("SIZE");
case COFF_ComdatSelectType_EXACT_MATCH: return str8_lit("MATCH");
case COFF_ComdatSelectType_ASSOCIATIVE: return str8_lit("ASSOCIATIVE");
case COFF_ComdatSelectType_LARGEST: return str8_lit("LARGEST");
case COFF_Reloc_X86_Abs: return str8_lit("Abs");
case COFF_Reloc_X86_Dir16: return str8_lit("Dir16");
case COFF_Reloc_X86_Rel16: return str8_lit("Rel16");
case COFF_Reloc_X86_Unknown0: return str8_lit("Unknown0");
case COFF_Reloc_X86_Unknown2: return str8_lit("Unknown2");
case COFF_Reloc_X86_Unknown3: return str8_lit("Unknown3");
case COFF_Reloc_X86_Dir32: return str8_lit("Dir32");
case COFF_Reloc_X86_Dir32Nb: return str8_lit("Dir32Nb");
case COFF_Reloc_X86_Seg12: return str8_lit("Seg12");
case COFF_Reloc_X86_Section: return str8_lit("Section");
case COFF_Reloc_X86_SecRel: return str8_lit("SecRel");
case COFF_Reloc_X86_Token: return str8_lit("Token");
case COFF_Reloc_X86_SecRel7: return str8_lit("SecRel7");
case COFF_Reloc_X86_Unknown4: return str8_lit("Unknown4");
case COFF_Reloc_X86_Unknown5: return str8_lit("Unknown5");
case COFF_Reloc_X86_Unknown6: return str8_lit("Unknown6");
case COFF_Reloc_X86_Unknown7: return str8_lit("Unknown7");
case COFF_Reloc_X86_Unknown8: return str8_lit("Unknown8");
case COFF_Reloc_X86_Unknown9: return str8_lit("Unknown9");
case COFF_Reloc_X86_Rel32: return str8_lit("Rel32");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_x86(COFF_RelocTypeX86 x)
coff_string_from_reloc_x64(COFF_Reloc_X64 x)
{
switch (x) {
case COFF_RelocTypeX86_ABS: return str8_lit("ABS");
case COFF_RelocTypeX86_DIR16: return str8_lit("DIR16");
case COFF_RelocTypeX86_REL16: return str8_lit("REL16");
case COFF_RelocTypeX86_UNKNOWN0: return str8_lit("UNKNOWN0");
case COFF_RelocTypeX86_UNKNOWN2: return str8_lit("UNKNOWN2");
case COFF_RelocTypeX86_UNKNOWN3: return str8_lit("UNKNOWN3");
case COFF_RelocTypeX86_DIR32: return str8_lit("DIR32");
case COFF_RelocTypeX86_DIR32NB: return str8_lit("DIR32NB");
case COFF_RelocTypeX86_SEG12: return str8_lit("SEG12");
case COFF_RelocTypeX86_SECTION: return str8_lit("SECTION");
case COFF_RelocTypeX86_SECREL: return str8_lit("SECREL");
case COFF_RelocTypeX86_TOKEN: return str8_lit("TOKEN");
case COFF_RelocTypeX86_SECREL7: return str8_lit("SECREL7");
case COFF_RelocTypeX86_UNKNOWN4: return str8_lit("UNKNOWN4");
case COFF_RelocTypeX86_UNKNOWN5: return str8_lit("UNKNOWN5");
case COFF_RelocTypeX86_UNKNOWN6: return str8_lit("UNKNOWN6");
case COFF_RelocTypeX86_UNKNOWN7: return str8_lit("UNKNOWN7");
case COFF_RelocTypeX86_UNKNOWN8: return str8_lit("UNKNOWN8");
case COFF_RelocTypeX86_UNKNOWN9: return str8_lit("UNKNOWN9");
case COFF_RelocTypeX86_REL32: return str8_lit("REL32");
case COFF_Reloc_X64_Abs: return str8_lit("Abs");
case COFF_Reloc_X64_Addr64: return str8_lit("Addr64");
case COFF_Reloc_X64_Addr32: return str8_lit("Addr32");
case COFF_Reloc_X64_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_X64_Rel32: return str8_lit("Rel32");
case COFF_Reloc_X64_Rel32_1: return str8_lit("Rel32_1");
case COFF_Reloc_X64_Rel32_2: return str8_lit("Rel32_2");
case COFF_Reloc_X64_Rel32_3: return str8_lit("Rel32_3");
case COFF_Reloc_X64_Rel32_4: return str8_lit("Rel32_4");
case COFF_Reloc_X64_Rel32_5: return str8_lit("Rel32_5");
case COFF_Reloc_X64_Section: return str8_lit("Section");
case COFF_Reloc_X64_SecRel: return str8_lit("SecRel");
case COFF_Reloc_X64_SecRel7: return str8_lit("SecRel7");
case COFF_Reloc_X64_Token: return str8_lit("Token");
case COFF_Reloc_X64_SRel32: return str8_lit("SRel32");
case COFF_Reloc_X64_Pair: return str8_lit("Pair");
case COFF_Reloc_X64_SSpan32: return str8_lit("SSpan32");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_x64(COFF_RelocTypeX64 x)
coff_string_from_reloc_arm(COFF_Reloc_Arm x)
{
switch (x) {
case COFF_RelocTypeX64_ABS: return str8_lit("ABS");
case COFF_RelocTypeX64_ADDR64: return str8_lit("ADDR64");
case COFF_RelocTypeX64_ADDR32: return str8_lit("ADDR32");
case COFF_RelocTypeX64_ADDR32NB: return str8_lit("ADDR32NB");
case COFF_RelocTypeX64_REL32: return str8_lit("REL32");
case COFF_RelocTypeX64_REL32_1: return str8_lit("REL32_1");
case COFF_RelocTypeX64_REL32_2: return str8_lit("REL32_2");
case COFF_RelocTypeX64_REL32_3: return str8_lit("REL32_3");
case COFF_RelocTypeX64_REL32_4: return str8_lit("REL32_4");
case COFF_RelocTypeX64_REL32_5: return str8_lit("REL32_5");
case COFF_RelocTypeX64_SECTION: return str8_lit("SECTION");
case COFF_RelocTypeX64_SECREL: return str8_lit("SECREL");
case COFF_RelocTypeX64_SECREL7: return str8_lit("SECREL7");
case COFF_RelocTypeX64_TOKEN: return str8_lit("TOKEN");
case COFF_RelocTypeX64_SREL32: return str8_lit("SREL32");
case COFF_RelocTypeX64_PAIR: return str8_lit("PAIR");
case COFF_RelocTypeX64_SSPAN32: return str8_lit("SSPAN32");
case COFF_Reloc_Arm_Abs: return str8_lit("Abs");
case COFF_Reloc_Arm_Addr32: return str8_lit("Addr32");
case COFF_Reloc_Arm_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_Arm_Branch24: return str8_lit("Branch24");
case COFF_Reloc_Arm_Branch11: return str8_lit("Branch11");
case COFF_Reloc_Arm_Unknown1: return str8_lit("Unknown1");
case COFF_Reloc_Arm_Unknown2: return str8_lit("Unknown2");
case COFF_Reloc_Arm_Unknown3: return str8_lit("Unknown3");
case COFF_Reloc_Arm_Unknown4: return str8_lit("Unknown4");
case COFF_Reloc_Arm_Unknown5: return str8_lit("Unknown5");
case COFF_Reloc_Arm_Rel32: return str8_lit("Rel32");
case COFF_Reloc_Arm_Section: return str8_lit("Section");
case COFF_Reloc_Arm_SecRel: return str8_lit("SecRel");
case COFF_Reloc_Arm_Mov32: return str8_lit("Mov32");
case COFF_Reloc_Arm_ThumbMov32: return str8_lit("ThumbMov32");
case COFF_Reloc_Arm_ThumbBranch20: return str8_lit("ThumbBranch20");
case COFF_Reloc_Arm_Unused: return str8_lit("Unused");
case COFF_Reloc_Arm_ThumbBranch24: return str8_lit("ThumbBranch24");
case COFF_Reloc_Arm_ThumbBlx23: return str8_lit("ThumbBlx23");
case COFF_Reloc_Arm_Pair: return str8_lit("Pair");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_arm(COFF_RelocTypeARM x)
coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x)
{
switch (x) {
case COFF_RelocTypeARM_ABS: return str8_lit("ABS");
case COFF_RelocTypeARM_ADDR32: return str8_lit("ADDR32");
case COFF_RelocTypeARM_ADDR32NB: return str8_lit("ADDR32NB");
case COFF_RelocTypeARM_BRANCH24: return str8_lit("BRANCH24");
case COFF_RelocTypeARM_BRANCH11: return str8_lit("BRANCH11");
case COFF_RelocTypeARM_UNKNOWN1: return str8_lit("UNKNOWN1");
case COFF_RelocTypeARM_UNKNOWN2: return str8_lit("UNKNOWN2");
case COFF_RelocTypeARM_UNKNOWN3: return str8_lit("UNKNOWN3");
case COFF_RelocTypeARM_UNKNOWN4: return str8_lit("UNKNOWN4");
case COFF_RelocTypeARM_UNKNOWN5: return str8_lit("UNKNOWN5");
case COFF_RelocTypeARM_REL32: return str8_lit("REL32");
case COFF_RelocTypeARM_SECTION: return str8_lit("SECTION");
case COFF_RelocTypeARM_SECREL: return str8_lit("SECREL");
case COFF_RelocTypeARM_MOV32: return str8_lit("MOV32");
case COFF_RelocTypeARM_THUMB_MOV32: return str8_lit("THUMB_MOV32");
case COFF_RelocTypeARM_THUMB_BRANCH20: return str8_lit("THUMB_BRANCH20");
case COFF_RelocTypeARM_UNUSED: return str8_lit("UNUSED");
case COFF_RelocTypeARM_THUMB_BRANCH24: return str8_lit("THUMB_BRANCH24");
case COFF_RelocTypeARM_THUMB_BLX23: return str8_lit("THUMB_BLX23");
case COFF_RelocTypeARM_PAIR: return str8_lit("PAIR");
}
return str8_zero();
}
internal String8
coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x)
{
switch (x) {
case COFF_RelocTypeARM64_ABS: return str8_lit("ABS");
case COFF_RelocTypeARM64_ADDR32: return str8_lit("ADDR32");
case COFF_RelocTypeARM64_ADDR32NB: return str8_lit("ADDR32NB");
case COFF_RelocTypeARM64_BRANCH26: return str8_lit("BRANCH26");
case COFF_RelocTypeARM64_PAGEBASE_REL21: return str8_lit("PAGEBASE_REL21");
case COFF_RelocTypeARM64_REL21: return str8_lit("REL21");
case COFF_RelocTypeARM64_PAGEOFFSET_12A: return str8_lit("PAGEOFFSET_12A");
case COFF_RelocTypeARM64_SECREL: return str8_lit("SECREL");
case COFF_RelocTypeARM64_SECREL_LOW12A: return str8_lit("SECREL_LOW12A");
case COFF_RelocTypeARM64_SECREL_HIGH12A: return str8_lit("SECREL_HIGH12A");
case COFF_RelocTypeARM64_SECREL_LOW12L: return str8_lit("SECREL_LOW12L");
case COFF_RelocTypeARM64_TOKEN: return str8_lit("TOKEN");
case COFF_RelocTypeARM64_SECTION: return str8_lit("SECTION");
case COFF_RelocTypeARM64_ADDR64: return str8_lit("ADDR64");
case COFF_RelocTypeARM64_BRANCH19: return str8_lit("BRANCH19");
case COFF_RelocTypeARM64_BRANCH14: return str8_lit("BRANCH14");
case COFF_RelocTypeARM64_REL32: return str8_lit("REL32");
case COFF_Reloc_Arm64_Abs: return str8_lit("Abs");
case COFF_Reloc_Arm64_Addr32: return str8_lit("Addr32");
case COFF_Reloc_Arm64_Addr32Nb: return str8_lit("Addr32Nb");
case COFF_Reloc_Arm64_Branch26: return str8_lit("Branch26");
case COFF_Reloc_Arm64_PageBaseRel21: return str8_lit("PageBaseRel21");
case COFF_Reloc_Arm64_Rel21: return str8_lit("Rel21");
case COFF_Reloc_Arm64_PageOffset12a: return str8_lit("PageOffset12a");
case COFF_Reloc_Arm64_SecRel: return str8_lit("SecRel");
case COFF_Reloc_Arm64_SecRelLow12a: return str8_lit("SecRelLow12a");
case COFF_Reloc_Arm64_SecRelHigh12a: return str8_lit("SecRelHigh12a");
case COFF_Reloc_Arm64_SecRelLow12l: return str8_lit("SecRelLow12l");
case COFF_Reloc_Arm64_Token: return str8_lit("Token");
case COFF_Reloc_Arm64_Section: return str8_lit("Section");
case COFF_Reloc_Arm64_Addr64: return str8_lit("Addr64");
case COFF_Reloc_Arm64_Branch19: return str8_lit("Branch19");
case COFF_Reloc_Arm64_Branch14: return str8_lit("Branch14");
case COFF_Reloc_Arm64_Rel32: return str8_lit("Rel32");
}
return str8_zero();
}
@@ -432,10 +417,10 @@ internal String8
coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x)
{
switch (machine) {
case COFF_MachineType_X86: return coff_string_from_reloc_x86(x);
case COFF_MachineType_X64: return coff_string_from_reloc_x64(x);
case COFF_MachineType_ARM: return coff_string_from_reloc_arm(x);
case COFF_MachineType_ARM64: return coff_string_from_reloc_arm64(x);
case COFF_Machine_X86: return coff_string_from_reloc_x86(x);
case COFF_Machine_X64: return coff_string_from_reloc_x64(x);
case COFF_Machine_Arm: return coff_string_from_reloc_arm(x);
case COFF_Machine_Arm64: return coff_string_from_reloc_arm64(x);
}
return str8_zero();
}
@@ -448,10 +433,10 @@ coff_machine_from_string(String8 string)
return g_coff_machine_map[i].machine;
}
}
return COFF_MachineType_UNKNOWN;
return COFF_Machine_Unknown;
}
internal COFF_ImportHeaderType
internal COFF_ImportType
coff_import_header_type_from_string(String8 name)
{
for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) {
@@ -459,7 +444,7 @@ coff_import_header_type_from_string(String8 name)
return g_coff_import_header_type_map[i].type;
}
}
return COFF_ImportHeaderType_COUNT;
return COFF_ImportType_Invalid;
}
+9 -10
View File
@@ -5,23 +5,22 @@
#define COFF_ENUM_H
internal String8 coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp);
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select);
internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType type);
internal String8 coff_string_from_machine_type(COFF_MachineType machine);
internal String8 coff_string_from_flags(Arena *arena, COFF_Flags flags);
internal String8 coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags);
internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags);
internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type);
internal String8 coff_string_from_import_header_type(COFF_ImportType type);
internal String8 coff_string_from_sym_dtype(COFF_SymDType x);
internal String8 coff_string_from_sym_type(COFF_SymType x);
internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x);
internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x);
internal String8 coff_string_from_selection(COFF_ComdatSelectType x);
internal String8 coff_string_from_reloc_x86(COFF_RelocTypeX86 x);
internal String8 coff_string_from_reloc_x64(COFF_RelocTypeX64 x);
internal String8 coff_string_from_reloc_arm(COFF_RelocTypeARM x);
internal String8 coff_string_from_reloc_arm64(COFF_RelocTypeARM64 x);
internal String8 coff_string_from_reloc_x86(COFF_Reloc_X86 x);
internal String8 coff_string_from_reloc_x64(COFF_Reloc_X64 x);
internal String8 coff_string_from_reloc_arm(COFF_Reloc_Arm x);
internal String8 coff_string_from_reloc_arm64(COFF_Reloc_Arm64 x);
internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x);
internal COFF_MachineType coff_machine_from_string(String8 string);
internal COFF_ImportHeaderType coff_import_header_type_from_string(String8 name);
internal COFF_MachineType coff_machine_from_string(String8 string);
internal COFF_ImportType coff_import_header_type_from_string(String8 name);
#endif // COFF_ENUM_H
+904
View File
@@ -0,0 +1,904 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
coff_is_big_obj(String8 raw_coff)
{
B32 is_big_obj = 0;
if (raw_coff.size >= sizeof(COFF_BigObjHeader)) {
COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str);
is_big_obj = file_header32->sig1 == COFF_Machine_Unknown &&
file_header32->sig2 == max_U16 &&
file_header32->version >= 2 &&
MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0;
}
return is_big_obj;
}
internal B32
coff_is_obj(String8 raw_coff)
{
B32 is_obj = 0;
if (raw_coff.size >= sizeof(COFF_FileHeader)) {
COFF_FileHeader *header = (COFF_FileHeader*)(raw_coff.str);
// validate machine
B32 is_machine_type_valid = 0;
switch (header->machine) {
case COFF_Machine_Unknown:
case COFF_Machine_X86: case COFF_Machine_X64:
case COFF_Machine_Am33: case COFF_Machine_Arm:
case COFF_Machine_Arm64: case COFF_Machine_ArmNt:
case COFF_Machine_Ebc: case COFF_Machine_Ia64:
case COFF_Machine_M32R: case COFF_Machine_Mips16:
case COFF_Machine_MipsFpu:case COFF_Machine_MipsFpu16:
case COFF_Machine_PowerPc:case COFF_Machine_PowerPcFp:
case COFF_Machine_R4000: case COFF_Machine_RiscV32:
case COFF_Machine_RiscV64:case COFF_Machine_RiscV128:
case COFF_Machine_Sh3: case COFF_Machine_Sh3Dsp:
case COFF_Machine_Sh4: case COFF_Machine_Sh5:
case COFF_Machine_Thumb: case COFF_Machine_WceMipsV2:
{
is_machine_type_valid = 1;
}break;
}
if (is_machine_type_valid) {
// validate section count
U64 section_count = header->section_count;
U64 section_hdr_opl_off = sizeof(*header) + section_count*sizeof(COFF_SectionHeader);
if (raw_coff.size >= section_hdr_opl_off) {
COFF_SectionHeader *section_hdrs = (COFF_SectionHeader*)(raw_coff.str + sizeof(*header));
COFF_SectionHeader *section_hdr_opl = section_hdrs + section_count;
// validate section ranges
B32 is_sect_range_valid = 1;
for (COFF_SectionHeader *sec_hdr = section_hdrs;
sec_hdr < section_hdr_opl;
sec_hdr += 1) {
if (!(sec_hdr->flags & COFF_SectionFlag_CntUninitializedData)) {
U64 min = sec_hdr->foff;
U64 max = min + sec_hdr->fsize;
if (sec_hdr->fsize > 0 && !(section_hdr_opl_off <= min && min <= max && max <= raw_coff.size)) {
is_sect_range_valid = 0;
break;
}
}
}
if (is_sect_range_valid) {
// validate symbol table
U64 symbol_table_off = header->symbol_table_foff;
U64 symbol_table_size = sizeof(COFF_Symbol16)*header->symbol_count;
U64 symbol_table_opl_off = symbol_table_off + symbol_table_size;
// don't validate symbol table when there is none
if (symbol_table_off == 0 && symbol_table_size == 0) {
symbol_table_off = section_hdr_opl_off;
symbol_table_opl_off = section_hdr_opl_off;
}
is_obj = (section_hdr_opl_off <= symbol_table_off &&
symbol_table_off <= symbol_table_opl_off &&
symbol_table_opl_off <= raw_coff.size);
}
}
}
}
return is_obj;
}
internal COFF_FileHeaderInfo
coff_file_header_info_from_data(String8 raw_coff)
{
COFF_FileHeaderInfo info = {0};
if (coff_is_big_obj(raw_coff)) {
COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str;
info.is_big_obj = 1;
info.machine = header32->machine;
info.header_size = sizeof(COFF_BigObjHeader);
info.section_array_off = sizeof(COFF_BigObjHeader);
info.section_count_no_null = header32->section_count;
info.string_table_off = header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count;
info.symbol_size = sizeof(COFF_Symbol32);
info.symbol_off = header32->symbol_table_foff;
info.symbol_count = header32->symbol_count;
} else if (coff_is_obj(raw_coff)) {
COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str;
info.is_big_obj = 0;
info.machine = header16->machine;
info.header_size = sizeof(COFF_FileHeader);
info.section_array_off = sizeof(COFF_FileHeader);
info.section_count_no_null = header16->section_count;
info.string_table_off = header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count;
info.symbol_size = sizeof(COFF_Symbol16);
info.symbol_off = header16->symbol_table_foff;
info.symbol_count = header16->symbol_count;
}
return info;
}
internal COFF_ParsedSymbol
coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name);
result.value = sym32->value;
result.section_number = sym32->section_number;
result.type = sym32->type;
result.storage_class = sym32->storage_class;
result.aux_symbol_count = sym32->aux_symbol_count;
return result;
}
internal COFF_ParsedSymbol
coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16)
{
COFF_ParsedSymbol result = {0};
result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name);
result.value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
result.section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
result.section_number = COFF_Symbol_AbsSection32;
} else {
result.section_number = (U32)sym16->section_number;
}
result.type = sym16->type;
result.storage_class = sym16->storage_class;
result.aux_symbol_count = sym16->aux_symbol_count;
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result = {0};
result.count = symbol_count;
result.v = push_array_no_zero_aligned(arena, COFF_Symbol32, result.count, 8);
Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count);
String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range);
COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str;
for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) {
COFF_Symbol16 *sym16 = &sym16_arr[isymbol];
COFF_Symbol32 *sym32 = &result.v[isymbol];
sym32->name = sym16->name;
sym32->value = sym16->value;
if (sym16->section_number == COFF_Symbol_DebugSection16) {
sym32->section_number = COFF_Symbol_DebugSection32;
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
sym32->section_number = COFF_Symbol_AbsSection32;
} else {
sym32->section_number = (U32)sym16->section_number;
}
sym32->type.v = sym16->type.v;
sym32->storage_class = sym16->storage_class;
sym32->aux_symbol_count = sym16->aux_symbol_count;
// copy aux symbols
for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) {
COFF_Symbol16 *aux16 = sym16_arr + iaux;
COFF_Symbol32 *aux32 = result.v + iaux;
// 32bit COFF uses 16bit aux symbols
MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16));
MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16));
}
// take into account aux symbols
isymbol += sym32->aux_symbol_count;
}
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count)
{
COFF_Symbol32Array result;
result.count = symbol_count;
result.v = (COFF_Symbol32 *)(data.str + symbol_array_off);
return result;
}
internal COFF_Symbol32Array
coff_symbol_array_from_data(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size)
{
COFF_Symbol32Array result = {0};
switch (symbol_size) {
case sizeof(COFF_Symbol16): result = coff_symbol_array_from_data_16(arena, data, symbol_array_off, symbol_count); break;
case sizeof(COFF_Symbol32): result = coff_symbol_array_from_data_32(arena, data, symbol_array_off, symbol_count); break;
}
return result;
}
internal COFF_Symbol16Node *
coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol)
{
COFF_Symbol16Node *node = push_array(arena, COFF_Symbol16Node, 1);
node->next = 0;
node->data = symbol;
SLLQueuePush(list->first, list->last, node);
list->count += 1;
return node;
}
internal COFF_SymbolValueInterpType
coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class)
{
if (storage_class == COFF_SymStorageClass_Section && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value == 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Undefined;
}
if (storage_class == COFF_SymStorageClass_External && value != 0 && section_number == COFF_Symbol_UndefinedSection) {
return COFF_SymbolValueInterp_Common;
}
if (section_number == COFF_Symbol_AbsSection32) {
return COFF_SymbolValueInterp_Abs;
}
if (section_number == COFF_Symbol_DebugSection32) {
return COFF_SymbolValueInterp_Debug;
}
if (storage_class == COFF_SymStorageClass_WeakExternal) {
return COFF_SymbolValueInterp_Weak;
}
return COFF_SymbolValueInterp_Regular;
}
internal COFF_RelocNode *
coff_reloc_list_push(Arena *arena, COFF_RelocList *list, COFF_Reloc reloc)
{
COFF_RelocNode *node = push_array(arena, COFF_RelocNode, 1);
node->data = reloc;
SLLQueuePush(list->first, list->last, node);
++list->count;
return node;
}
internal COFF_RelocInfo
coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header)
{
COFF_RelocInfo result = {0};
if (header->flags & COFF_SectionFlag_LnkNRelocOvfl && header->reloc_count == max_U16) {
COFF_Reloc counter;
U64 read_size = str8_deserial_read_struct(data, header->relocs_foff, &counter);
if (read_size == sizeof(counter) && counter.apply_off > 0) {
result.array_off = header->relocs_foff + sizeof(COFF_Reloc);
result.count = counter.apply_off - 1; // exclude counter entry
}
} else {
result.array_off = header->relocs_foff;
result.count = header->reloc_count;
}
return result;
}
internal String8
coff_resource_string_from_str16(Arena *arena, String16 string)
{
AssertAlways(string.size <= max_U16);
U16 size16 = (U16)string.size;
U16 *buffer = push_array_no_zero(arena, U16, size16 + 1);
MemoryCopy(buffer + 0, &size16, sizeof(size16));
MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0]));
return str8_array(buffer, size16 + 1);
}
internal String8
coff_resource_string_from_str8(Arena *arena, String8 string)
{
Temp scratch = scratch_begin(&arena, 1);
String16 string16 = str16_from_8(scratch.arena, string);
String8 result = coff_resource_string_from_str16(arena, string16);
scratch_end(scratch);
return result;
}
internal String8
coff_resource_number_from_u16(Arena *arena, U16 number)
{
U16 *buffer = push_array_no_zero(arena, U16, 2);
buffer[0] = max_U16;
buffer[1] = number;
return str8_array(buffer, 2);
}
internal COFF_ResourceID
coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16)
{
COFF_ResourceID id = {0};
id.type = id_16->type;
switch (id_16->type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
id.u.number = id_16->u.number;
} break;
case COFF_ResourceIDType_String: {
id.u.string = str8_from_16(arena, id_16->u.string);
} break;
default: InvalidPath;
}
return id;
}
internal U64
coff_read_resource_id_utf16(String8 raw_res, U64 off, COFF_ResourceID16 *id_out)
{
U64 cursor = off;
U16 flag = 0;
str8_deserial_read_struct(raw_res, cursor, &flag);
if (flag == max_U16) {
id_out->type = COFF_ResourceIDType_Number;
cursor += sizeof(flag);
cursor += str8_deserial_read_struct(raw_res, cursor, &id_out->u.number);
} else {
id_out->type = COFF_ResourceIDType_String;
cursor += str8_deserial_read_windows_utf16_string16(raw_res, cursor, &id_out->u.string);
}
U64 read_size = cursor - off;
read_size = AlignPow2(read_size, COFF_ResourceAlign);
return read_size;
}
internal U64
coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out)
{
String8 raw_header = str8_skip(raw_res, off);
U64 header_cursor = 0;
// prefix
COFF_ResourceHeaderPrefix prefix = {0};
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix);
Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix));
raw_header = str8_prefix(raw_header, prefix.header_size);
// header
COFF_ResourceID16 type_16 = {0};
COFF_ResourceID16 name_16 = {0};
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16);
header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version);
header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics);
Assert(prefix.header_size == header_cursor);
// convert utf-16 resource ids to utf-8
res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16);
res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16);
// read data
U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data);
Assert(prefix.data_size == data_read_size);
// compute read size
U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_ResourceAlign);
return read_size;
}
internal COFF_ParsedResourceList
coff_resource_list_from_data(Arena *arena, String8 data)
{
COFF_ParsedResourceList list = {0};
U64 cursor;
for (cursor = 0 ; cursor < data.size; ) {
COFF_ParsedResourceNode *node = push_array(arena, COFF_ParsedResourceNode, 1);
cursor += coff_read_resource(arena, data, cursor, &node->data);
SLLQueuePush(list.first, list.last, node);
++list.count;
}
Assert(cursor == data.size);
return list;
}
internal String8
coff_write_resource_id(Arena *arena, COFF_ResourceID id)
{
String8 result = str8_zero();
switch (id.type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: {
result = coff_resource_number_from_u16(arena, id.u.number);
} break;
case COFF_ResourceIDType_String: {
result = coff_resource_string_from_str8(arena, id.u.string);
} break;
default: InvalidPath;
}
return result;
}
internal String8
coff_write_resource(Arena *arena,
COFF_ResourceID type,
COFF_ResourceID name,
U32 data_version,
COFF_ResourceMemoryFlags memory_flags,
U16 language_id,
U32 version,
U32 characteristics,
String8 data)
{
Temp scratch = scratch_begin(&arena, 1);
String8List list = {0};
COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1);
String8 packed_type = coff_write_resource_id(scratch.arena, type);
String8 packed_name = coff_write_resource_id(scratch.arena, name);
// prefix + header
str8_list_push(scratch.arena, &list, str8_struct(prefix));
str8_list_push(scratch.arena, &list, packed_type);
str8_list_push(scratch.arena, &list, packed_name);
str8_list_push(scratch.arena, &list, str8_struct(&data_version));
str8_list_push(scratch.arena, &list, str8_struct(&memory_flags));
str8_list_push(scratch.arena, &list, str8_struct(&language_id));
str8_list_push(scratch.arena, &list, str8_struct(&version));
str8_list_push(scratch.arena, &list, str8_struct(&characteristics));
prefix->data_size = safe_cast_u32(data.size);
prefix->header_size = safe_cast_u32(list.total_size);
// data
str8_list_push(scratch.arena, &list, data);
// magic
str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic));
// align
U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size;
U8 *align = push_array(scratch.arena, U8, align_size);
str8_list_push(scratch.arena, &list, str8(align, align_size));
// join
String8 res = str8_list_join(arena, &list, 0);
scratch_end(scratch);
return res;
}
internal int
coff_resource_id_compar(void *raw_a, void *raw_b)
{
int cmp;
COFF_ResourceID *a = raw_b;
COFF_ResourceID *b = raw_b;
if (a->type == b->type) {
switch (a->type) {
case COFF_ResourceIDType_Null: break;
case COFF_ResourceIDType_Number: cmp = u16_compar(&a->u.number, &b->u.number); break;
case COFF_ResourceIDType_String: cmp = str8_compar_case_sensitive(&a->u.string, &b->u.string); break;
default: InvalidPath; break;
}
} else {
cmp = u32_compar(&a->type, &b->type);
}
return cmp;
}
internal B32
coff_is_import(String8 raw_archive_member)
{
B32 is_import = 0;
if (raw_archive_member.size >= sizeof(U16)*2) {
U16 *sig1 = (U16*)raw_archive_member.str;
U16 *sig2 = sig1 + 1;
is_import = *sig1 == COFF_Machine_Unknown && *sig2 == 0xffff;
}
return is_import;
}
internal COFF_DataType
coff_data_type_from_data(String8 raw_archive_member)
{
B32 is_big_obj = coff_is_big_obj(raw_archive_member);
if (is_big_obj) {
return COFF_DataType_BigObj;
}
B32 is_import = coff_is_import(raw_archive_member);
if (is_import) {
return COFF_DataType_Import;
}
return COFF_DataType_Obj;
}
internal B32
coff_is_regular_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_archive_sig[0], sizeof(g_coff_archive_sig)) == 0;
}
return is_archive;
}
internal B32
coff_is_thin_archive(String8 raw_archive)
{
B32 is_archive = 0;
U8 sig[sizeof(g_coff_thin_archive_sig)];
if (str8_deserial_read_struct(raw_archive, 0, &sig) == sizeof(sig)) {
is_archive = MemoryCompare(&sig[0], &g_coff_thin_archive_sig[0], sizeof(g_coff_thin_archive_sig)) == 0;
}
return is_archive;
}
internal COFF_ArchiveType
coff_archive_type_from_data(String8 raw_archive)
{
if (coff_is_regular_archive(raw_archive)) {
return COFF_Archive_Regular;
} else if (coff_is_thin_archive(raw_archive)) {
return COFF_Archive_Thin;
}
return COFF_Archive_Null;
}
internal U64
coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out)
{
COFF_ArchiveMemberHeader *header = str8_deserial_get_raw_ptr(raw_archive, offset, sizeof(*header));
if (header) {
String8 name = str8_skip_chop_whitespace(str8_cstring_capped(header->name, header->name + sizeof(header->name) ));
String8 date = str8_skip_chop_whitespace(str8_cstring_capped(header->date, header->date + sizeof(header->date) ));
String8 user_id = str8_skip_chop_whitespace(str8_cstring_capped(header->user_id, header->user_id + sizeof(header->user_id) ));
String8 group_id = str8_skip_chop_whitespace(str8_cstring_capped(header->group_id, header->group_id + sizeof(header->group_id)));
String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) ));
String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) ));
String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end));
U32 data_size = u32_from_str8(size, 10);
U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader);
header_out->name = name;
header_out->time_stamp = u32_from_str8(date, 10);
header_out->user_id = u32_from_str8(user_id, 10);
header_out->group_id = u32_from_str8(group_id, 10);
header_out->mode = mode;
header_out->is_end_correct = str8_match_lit("`\n", end, 0);
header_out->data_range = rng_1u64(data_off, data_off + data_size);
return sizeof(*header);
}
return 0;
}
internal COFF_ArchiveFirstMember
coff_parse_first_archive_member(COFF_ArchiveMember *member)
{
Assert(str8_match_lit("/", member->header.name, 0));
U64 cursor = 0;
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
symbol_count = from_be_u32(symbol_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
cursor += dim_1u64(string_table_range);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
COFF_ArchiveFirstMember result = {0};
result.symbol_count = symbol_count;
result.member_offset_count = member_offset_count;
result.member_offsets = member_offsets;
result.string_table = str8_substr(member->data, string_table_range);
return result;
}
internal COFF_ArchiveSecondMember
coff_parse_second_archive_member(COFF_ArchiveMember *member)
{
COFF_ArchiveSecondMember result = {0};
if (str8_match_lit("/", member->header.name, 0)) {
U64 cursor = 0;
U32 member_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &member_count);
Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32));
cursor += dim_1u64(member_offsets_range);
U32 symbol_count = 0;
cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count);
Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16));
cursor += dim_1u64(symbol_indices_range);
Rng1U64 string_table_range = rng_1u64(cursor, member->data.size);
String8 raw_member_offsets = str8_substr(member->data, member_offsets_range);
String8 raw_indices = str8_substr(member->data, symbol_indices_range);
U32 *member_offsets = (U32 *)raw_member_offsets.str;
U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]);
U16 *symbol_indices = (U16 *)raw_indices.str;
U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]);
result.member_count = member_count;
result.symbol_count = symbol_count;
result.member_offsets = member_offsets;
result.member_offset_count = member_offset_count;
result.symbol_indices = symbol_indices;
result.symbol_index_count = symbol_index_count;
result.string_table = str8_substr(member->data, string_table_range);
}
return result;
}
internal String8
coff_parse_long_name(String8 long_names, String8 name)
{
String8 result = name;
if (name.size > 0 && name.str[0] == '/') {
String8 offset_str = str8(name.str + 1, name.size - 1);
U64 offset = u64_from_str8(offset_str, 10);
if (offset < long_names.size) {
U8 *ptr = long_names.str + offset;
U8 *opl = long_names.str + long_names.size;
for (; ptr < opl; ++ptr) {
if (*ptr == '\0' || *ptr == '\n') {
break;
}
}
result = str8_range(long_names.str + offset, ptr);
}
}
return result;
}
internal U64
coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out)
{
COFF_ImportHeader *header = str8_deserial_get_raw_ptr(raw_archive_member, offset, sizeof(*header));
if (header) {
Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size);
String8 raw_data = str8_substr(raw_archive_member, data_range);
U64 data_cursor = 0;
header_out->version = header->version;
header_out->machine = header->machine;
header_out->time_stamp = header->time_stamp;
header_out->data_size = header->data_size;
header_out->hint_or_ordinal = header->hint_or_ordinal;
header_out->type = COFF_ImportHeader_ExtractType(header->flags);
header_out->import_by = COFF_ImportHeader_ExtractImportBy(header->flags);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->func_name);
data_cursor += str8_deserial_read_cstr(raw_data, data_cursor, &header_out->dll_name);
Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size);
U64 read_size = sizeof(*header) + header->data_size;
return read_size;
}
return 0;
}
internal COFF_ArchiveMember
coff_archive_member_from_offset(String8 raw_archive, U64 offset)
{
COFF_ArchiveMember member = {0};
coff_regular_archive_member_iter_next(raw_archive, &offset, &member);
return member;
}
internal COFF_ArchiveMember
coff_archive_member_from_data(String8 raw_archive_member)
{
return coff_archive_member_from_offset(raw_archive_member, 0);
}
internal COFF_ParsedArchiveImportHeader
coff_archive_import_from_data(String8 raw_archive_member)
{
COFF_ParsedArchiveImportHeader header = {0};
coff_parse_import(raw_archive_member, 0, &header);
return header;
}
internal U64
coff_regular_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_regular_archive(raw_archive)) {
cursor = sizeof(g_coff_archive_sig);
}
return cursor;
}
internal B32
coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, member_out->header.data_range);
U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal U64
coff_thin_archive_member_iter_init(String8 raw_archive)
{
U64 cursor = raw_archive.size;
if (coff_is_thin_archive(raw_archive)) {
cursor = sizeof(g_coff_thin_archive_sig);
}
return cursor;
}
internal B32
coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out)
{
B32 is_parsed = 0;
member_out->header.is_end_correct = 0;
U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header);
if (member_out->header.is_end_correct) {
Rng1U64 data_in_archive_range = {0};
if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) {
data_in_archive_range = member_out->header.data_range;
}
member_out->offset = *offset;
member_out->data = str8_substr(raw_archive, data_in_archive_range);
U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign);
*offset += read_size;
is_parsed = 1;
}
return is_parsed;
}
internal void
coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node)
{
SLLQueuePush(list->first, list->last, node);
list->count += 1;
}
internal COFF_ArchiveParse
coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list)
{
String8 error = str8_zero();
B32 has_second_header = 0;
B32 has_long_names = 0;
COFF_ArchiveMember first_header = {0};
COFF_ArchiveMember second_header = {0};
COFF_ArchiveMember long_names_member = {0};
COFF_ArchiveMemberNode *ptr = member_list.first;
if (ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
first_header = ptr->data;
ptr = ptr->next;
} else {
error = str8_lit("first header doesn't have correct end");
}
}
} else {
error = str8_lit("missing first header");
}
if (!error.size && ptr) {
if (str8_match_lit("/", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
second_header = ptr->data;
ptr = ptr->next;
has_second_header = 1;
} else {
error = str8_lit("second header doesn't have correct end");
}
}
}
if (!error.size && ptr) {
if (str8_match_lit("//", ptr->data.header.name, 0)) {
if (ptr->data.header.is_end_correct) {
long_names_member = ptr->data;
ptr = ptr->next;
has_long_names;
} else {
error = str8_lit("long names header doesn't have correct end");
}
}
}
COFF_ArchiveParse parse = {0};
parse.has_second_header = has_second_header;
parse.has_long_names = has_long_names;
parse.first_member = coff_parse_first_archive_member(&first_header);
parse.second_member = coff_parse_second_archive_member(&second_header);
parse.long_names = long_names_member.data;
parse.error = error;
return parse;
}
internal COFF_ArchiveParse
coff_regular_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_regular_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); ++i) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_regular_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_thin_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveMemberList list = {0};
COFF_ArchiveMemberNode node_arr[3] = {0};
U64 cursor = coff_thin_archive_member_iter_init(raw_archive);
for (U64 i = 0; i < ArrayCount(node_arr); i += 1) {
COFF_ArchiveMemberNode *node = &node_arr[i];
if (!coff_thin_archive_member_iter_next(raw_archive, &cursor, &node->data)) {
break;
}
coff_archive_member_list_push_node(&list, node);
}
return coff_archive_parse_from_member_list(list);
}
internal COFF_ArchiveParse
coff_archive_parse_from_data(String8 raw_archive)
{
COFF_ArchiveType type = coff_archive_type_from_data(raw_archive);
switch (type) {
case COFF_Archive_Null: break;
case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive);
case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive);
}
COFF_ArchiveParse null_parse = {0};
return null_parse;
}
+315
View File
@@ -0,0 +1,315 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef COFF_PARSE_H
#define COFF_PARSE_H
typedef struct COFF_FileHeaderInfo
{
B32 is_big_obj;
COFF_MachineType machine;
U64 header_size;
U64 section_array_off;
U64 section_count_no_null;
U64 string_table_off;
U64 symbol_size;
U64 symbol_off;
U64 symbol_count;
} COFF_FileHeaderInfo;
////////////////////////////////
typedef struct COFF_SectionHeaderArray
{
U64 count;
COFF_SectionHeader *v;
} COFF_SectionHeaderArray;
////////////////////////////////
typedef struct COFF_Symbol16Node
{
struct COFF_Symbol16Node *next;
COFF_Symbol16 data;
} COFF_Symbol16Node;
typedef struct COFF_Symbol16List
{
U64 count;
COFF_Symbol16Node *first;
COFF_Symbol16Node *last;
} COFF_Symbol16List;
typedef struct COFF_Symbol32Array
{
U64 count;
COFF_Symbol32 *v;
} COFF_Symbol32Array;
typedef struct COFF_ParsedSymbol
{
String8 name;
U32 value;
U32 section_number;
COFF_SymbolType type;
COFF_SymStorageClass storage_class;
U8 aux_symbol_count;
} COFF_ParsedSymbol;
typedef U32 COFF_SymbolValueInterpType;
enum
{
COFF_SymbolValueInterp_Regular, // symbol has section and offset.
COFF_SymbolValueInterp_Weak, // symbol is overridable.
COFF_SymbolValueInterp_Undefined, // symbol doesn't have a reference section.
COFF_SymbolValueInterp_Common, // symbol has no section but still has size.
COFF_SymbolValueInterp_Abs, // symbol has an absolute (non-relocatable) value and is not an address.
COFF_SymbolValueInterp_Debug // symbol is used to provide general type of debugging information.
};
////////////////////////////////
typedef struct COFF_RelocNode
{
struct COFF_RelocNode *next;
COFF_Reloc data;
} COFF_RelocNode;
typedef struct COFF_RelocList
{
U64 count;
COFF_RelocNode *first;
COFF_RelocNode *last;
} COFF_RelocList;
typedef struct COFF_RelocArray
{
U64 count;
COFF_Reloc *v;
} COFF_RelocArray;
typedef struct COFF_RelocInfo
{
U64 array_off;
U64 count;
} COFF_RelocInfo;
////////////////////////////////
typedef U32 COFF_ResourceIDType;
enum COFF_ResourceIDTypeEnum
{
COFF_ResourceIDType_Null,
COFF_ResourceIDType_Number,
COFF_ResourceIDType_String,
COFF_ResourceIDType_Count
};
typedef struct COFF_ResourceID16
{
COFF_ResourceIDType type;
union {
U16 number;
String16 string;
} u;
} COFF_ResourceID16;
typedef struct COFF_ResourceID
{
COFF_ResourceIDType type;
union {
U16 number;
String8 string;
} u;
} COFF_ResourceID;
typedef struct COFF_ParsedResource
{
COFF_ResourceID type;
COFF_ResourceID name;
U32 data_version;
COFF_ResourceMemoryFlags memory_flags;
U16 language_id;
U32 version;
U32 characteristics;
String8 data;
} COFF_ParsedResource;
typedef struct COFF_ParsedResourceNode
{
struct COFF_ParsedResourceNode *next;
COFF_ParsedResource data;
} COFF_ParsedResourceNode;
typedef struct COFF_ParsedResourceList
{
U64 count;
COFF_ParsedResourceNode *first;
COFF_ParsedResourceNode *last;
} COFF_ParsedResourceList;
////////////////////////////////
typedef enum
{
COFF_DataType_Null,
COFF_DataType_Obj,
COFF_DataType_BigObj,
COFF_DataType_Import
} COFF_DataType;
typedef enum
{
COFF_Archive_Null,
COFF_Archive_Regular,
COFF_Archive_Thin
} COFF_ArchiveType;
typedef struct COFF_ParsedArchiveMemberHeader
{
String8 name; // padded to 16 bytes with spaces
COFF_TimeStamp time_stamp;
U32 user_id; // unix artifact that does not have meaning on windows
U32 group_id; // unix artifact that does not have meaning on windows
String8 mode; // octal representation the members file mode
B32 is_end_correct; // set to true if found correct signature after header
Rng1U64 data_range;
} COFF_ParsedArchiveMemberHeader;
typedef struct COFF_ParsedArchiveImportHeader
{
B32 is_sig_correct;
U16 version;
COFF_MachineType machine;
COFF_TimeStamp time_stamp;
U32 data_size;
U16 hint_or_ordinal;
COFF_ImportType type;
COFF_ImportByType import_by;
String8 func_name;
String8 dll_name;
} COFF_ParsedArchiveImportHeader;
typedef struct COFF_ArchiveMember
{
COFF_ParsedArchiveMemberHeader header;
U64 offset;
String8 data;
} COFF_ArchiveMember;
typedef struct COFF_ArchiveFirstMember
{
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
String8 string_table;
} COFF_ArchiveFirstMember;
typedef struct COFF_ArchiveSecondMember
{
U32 member_count;
U32 symbol_count;
U64 member_offset_count;
U32 *member_offsets;
U64 symbol_index_count;
U16 *symbol_indices;
String8 string_table;
} COFF_ArchiveSecondMember;
typedef struct COFF_ArchiveMemberNode
{
struct COFF_ArchiveMemberNode *next;
COFF_ArchiveMember data;
} COFF_ArchiveMemberNode;
typedef struct COFF_ArchiveMemberList
{
U64 count;
COFF_ArchiveMemberNode *first;
COFF_ArchiveMemberNode *last;
} COFF_ArchiveMemberList;
typedef struct COFF_ArchiveParse
{
B32 has_second_header;
B32 has_long_names;
COFF_ArchiveFirstMember first_member;
COFF_ArchiveSecondMember second_member;
String8 long_names;
String8 error;
} COFF_ArchiveParse;
////////////////////////////////
// Obj Header
internal B32 coff_is_big_obj(String8 raw_coff);
internal B32 coff_is_obj (String8 raw_coff);
internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff);
////////////////////////////////
// Symbol
internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32);
internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16);
internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count);
internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count, U64 symbol_size);
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
////////////////////////////////
// Reloc
internal COFF_RelocInfo coff_reloc_info_from_section_header(String8 data, COFF_SectionHeader *header);
////////////////////////////////
// Resource
internal String8 coff_resource_string_from_str16 (Arena *arena, String16 string);
internal String8 coff_resource_string_from_str8 (Arena *arena, String8 string);
internal String8 coff_resource_number_from_u16 (Arena *arena, U16 number);
internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID16 *id_16);
internal U64 coff_read_resource_id_utf16 (String8 raw_res, U64 off, COFF_ResourceID16 *id_out);
internal U64 coff_read_resource (Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource *res_out);
internal COFF_ParsedResourceList coff_resource_list_from_data(Arena *arena, String8 data);
internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id);
internal String8 coff_write_resource (Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data);
internal int coff_resource_id_compar(void *raw_a, void *raw_b); // COFF_ResourceID
////////////////////////////////
// Archive
internal B32 coff_is_import (String8 raw_archive_member);
internal COFF_DataType coff_data_type_from_data (String8 raw_archive_member);
internal B32 coff_is_regular_archive (String8 raw_archive);
internal B32 coff_is_thin_archive (String8 raw_archive);
internal COFF_ArchiveType coff_archive_type_from_data(String8 raw_archive);
internal U64 coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArchiveMemberHeader *header_out);
internal COFF_ArchiveFirstMember coff_parse_first_archive_member (COFF_ArchiveMember *member);
internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member);
internal String8 coff_parse_long_name (String8 long_names, String8 name);
internal U64 coff_parse_import (String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImportHeader *header_out);
internal COFF_ArchiveMember coff_archive_member_from_offset(String8 raw_archive, U64 offset);
internal COFF_ArchiveMember coff_archive_member_from_data (String8 raw_archive_member);
internal COFF_ParsedArchiveImportHeader coff_archive_import_from_data (String8 raw_archive_member);
internal U64 coff_regular_archive_member_iter_init(String8 raw_archive);
internal B32 coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal U64 coff_thin_archive_member_iter_init(String8 raw_archive);
internal B32 coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_ArchiveMember *member_out);
internal COFF_ArchiveParse coff_regular_archive_parse_from_member_list(COFF_ArchiveMemberList list);
internal COFF_ArchiveParse coff_thin_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_regular_archive_parse_from_data (String8 raw_archive);
internal COFF_ArchiveParse coff_archive_parse_from_data (String8 raw_archive);
#endif // COFF_PARSE_H