// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags) { U32 align = 0; U32 align_index = COFF_SectionFlags_ExtractAlign(flags); switch (align_index) { default: break; case COFF_SectionAlign_1Bytes: align = 1; break; case COFF_SectionAlign_2Bytes: align = 2; break; case COFF_SectionAlign_4Bytes: align = 4; break; case COFF_SectionAlign_8Bytes: align = 8; break; case COFF_SectionAlign_16Bytes: align = 16; break; case COFF_SectionAlign_32Bytes: align = 32; break; case COFF_SectionAlign_64Bytes: align = 64; break; case COFF_SectionAlign_128Bytes: align = 128; break; case COFF_SectionAlign_256Bytes: align = 256; break; case COFF_SectionAlign_512Bytes: align = 512; break; case COFF_SectionAlign_1024Bytes: align = 1024; break; case COFF_SectionAlign_2048Bytes: align = 2048; break; case COFF_SectionAlign_4096Bytes: align = 4096; break; case COFF_SectionAlign_8192Bytes: align = 8192; break; } return align; } internal COFF_SectionFlags coff_section_flag_from_align_size(U64 align) { COFF_SectionFlags flags = 0; switch (align) { case 0: flags = COFF_SectionAlign_None; break; case 1: flags = COFF_SectionAlign_1Bytes; break; case 2: flags = COFF_SectionAlign_2Bytes; break; case 4: flags = COFF_SectionAlign_4Bytes; break; case 8: flags = COFF_SectionAlign_8Bytes; break; case 16: flags = COFF_SectionAlign_16Bytes; break; case 32: flags = COFF_SectionAlign_32Bytes; break; case 64: flags = COFF_SectionAlign_64Bytes; break; case 128: flags = COFF_SectionAlign_128Bytes; break; case 256: flags = COFF_SectionAlign_256Bytes; break; case 512: flags = COFF_SectionAlign_512Bytes; break; case 1024: flags = COFF_SectionAlign_1024Bytes; break; case 2048: flags = COFF_SectionAlign_2048Bytes; break; case 4096: flags = COFF_SectionAlign_4096Bytes; break; case 8192: flags = COFF_SectionAlign_8192Bytes; break; } flags <<= COFF_SectionFlag_AlignShift; return flags; } internal String8 coff_name_from_section_header(String8 string_table, COFF_SectionHeader *header) { String8 name = str8_cstring_capped(header->name, header->name + sizeof(header->name)); if (name.str[0] == '/') { String8 name_off_str = str8_skip(name, 1); U64 name_off = u64_from_str8(name_off_str, 10); name = str8_cstring_capped(string_table.str + name_off, string_table.str+string_table.size); } return name; } internal void coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out) { // dollar sign has multiple interpretations that depend on the type of the section. // 1. when section contains code/data it indicates section precedence // 2. when section starts with .debug it indicates type of data inside the section // T: Types // S: Symbols // P: Precompiled types // F: FPO data // H: Clang extension produced with /debug:ghash, array of type hashes *name_out = full_name; *postfix_out = str8_lit(""); for (U64 i = 0; i < full_name.size; ++i) { if (full_name.str[i] == '$') { *name_out = str8(full_name.str, i); *postfix_out = str8(full_name.str + i, full_name.size - i); break; } } } internal String8 coff_read_symbol_name(String8 string_table, COFF_SymbolName *name) { String8 name_str = str8_lit(""); if (name->long_name.zeroes == 0) { str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str); } else { U32 i; for (i = 0; i < sizeof(name->short_name); ++i) { if (name->short_name[i] == '\0') { break; } } name_str = str8(name->short_name, i); } return name_str; } internal U64 coff_apply_size_from_reloc_x64(COFF_Reloc_X64 x) { switch (x) { case COFF_Reloc_X64_Abs: return 4; case COFF_Reloc_X64_Addr64: return 8; case COFF_Reloc_X64_Addr32: return 4; case COFF_Reloc_X64_Addr32Nb: return 4; case COFF_Reloc_X64_Rel32: return 4; case COFF_Reloc_X64_Rel32_1: return 4; case COFF_Reloc_X64_Rel32_2: return 4; case COFF_Reloc_X64_Rel32_3: return 4; case COFF_Reloc_X64_Rel32_4: return 4; case COFF_Reloc_X64_Rel32_5: return 4; case COFF_Reloc_X64_Section: return 2; case COFF_Reloc_X64_SecRel: return 4; case COFF_Reloc_X64_SRel32: return 4; case COFF_Reloc_X64_SecRel7: case COFF_Reloc_X64_Token: case COFF_Reloc_X64_Pair: case COFF_Reloc_X64_SSpan32: NotImplemented; break; } return 0; } internal U64 coff_apply_size_from_reloc_x86(COFF_Reloc_X86 x) { switch (x) { case COFF_Reloc_X86_Abs: return 4; case COFF_Reloc_X86_Dir16: return 2; case COFF_Reloc_X86_Rel16: return 2; case COFF_Reloc_X86_Dir32: return 4; case COFF_Reloc_X86_Dir32Nb: return 4; case COFF_Reloc_X86_Seg12: return 0; case COFF_Reloc_X86_Section: return 2; case COFF_Reloc_X86_SecRel: return 4; case COFF_Reloc_X86_Token: return 4; case COFF_Reloc_X86_SecRel7: return 1; case COFF_Reloc_X86_Rel32: return 4; case COFF_Reloc_X86_Unknown0: case COFF_Reloc_X86_Unknown2: case COFF_Reloc_X86_Unknown3: case COFF_Reloc_X86_Unknown4: case COFF_Reloc_X86_Unknown6: case COFF_Reloc_X86_Unknown7: case COFF_Reloc_X86_Unknown8: case COFF_Reloc_X86_Unknown9: NotImplemented; break; } return 0; } internal U64 coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x) { switch (machine) { case COFF_MachineType_X64: return coff_apply_size_from_reloc_x64(x); case COFF_MachineType_X86: return coff_apply_size_from_reloc_x86(x); default: NotImplemented; } return 0; } internal COFF_RelocValue coff_pick_reloc_value_x64(COFF_Reloc_X64 type, U64 image_base, U64 reloc_virtual_offset, U32 symbol_section_number, U32 symbol_section_offset, S64 symbol_virtual_offset) { U64 reloc_value_size = 0; S64 reloc_value = 0; switch (type) { case COFF_Reloc_X64_Abs: {} break; case COFF_Reloc_X64_Addr64: { reloc_value_size = 8; reloc_value = symbol_virtual_offset + (S64)image_base; } break; case COFF_Reloc_X64_Addr32: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset + (S64)image_base); } break; case COFF_Reloc_X64_Addr32Nb: { reloc_value_size = 4; reloc_value = symbol_virtual_offset; } break; case COFF_Reloc_X64_Rel32: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 0)); } break; case COFF_Reloc_X64_Rel32_1: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 1)); } break; case COFF_Reloc_X64_Rel32_2: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 2)); } break; case COFF_Reloc_X64_Rel32_3: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 3)); } break; case COFF_Reloc_X64_Rel32_4: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 4)); } break; case COFF_Reloc_X64_Rel32_5: { reloc_value_size = 4; reloc_value = safe_cast_s32(symbol_virtual_offset - reloc_virtual_offset - (4 + 5)); } break; case COFF_Reloc_X64_Section: { reloc_value_size = 4; reloc_value = symbol_section_number; } break; case COFF_Reloc_X64_SecRel: { reloc_value_size = 4; reloc_value = symbol_section_offset; } break; case COFF_Reloc_X64_SecRel7: case COFF_Reloc_X64_Token: case COFF_Reloc_X64_SRel32: case COFF_Reloc_X64_Pair: case COFF_Reloc_X64_SSpan32: case COFF_Reloc_X64_Unknown_11: { NotImplemented; } break; } COFF_RelocValue result = {0}; result.size = reloc_value_size; result.value = reloc_value; return result; } internal String8 coff_make_import_lookup(Arena *arena, U16 hint, String8 name) { U64 buffer_size = sizeof(hint) + (name.size + 1); U8 *buffer = push_array(arena, U8, buffer_size); *(U16*)buffer = hint; MemoryCopy(buffer + sizeof(hint), name.str, name.size); buffer[buffer_size - 1] = 0; String8 result = str8(buffer, buffer_size); return result; } internal U32 coff_make_ordinal32(U16 hint) { U32 ordinal = (1 << 31) | hint; return ordinal; } internal U64 coff_make_ordinal64(U16 hint) { U64 ordinal = (1ULL << 63) | hint; return ordinal; } internal String8 coff_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) { String8 ordinal_data = {0}; switch (machine) { case COFF_MachineType_Unknown: break; case COFF_MachineType_X64: { U64 *ordinal = push_array(arena, U64, 1); *ordinal = coff_make_ordinal64(hint); ordinal_data = str8_struct(ordinal); } break; case COFF_MachineType_X86: { U32 *ordinal = push_array(arena, U32, 1); *ordinal = coff_make_ordinal32(hint); ordinal_data = str8_struct(ordinal); } break; default: { NotImplemented; } break; } return ordinal_data; } internal String8 coff_make_import_header(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType type) { COFF_ImportHeaderFlags flags = 0; flags |= (type & COFF_ImportHeader_TypeMask) << COFF_ImportHeader_TypeShift; flags |= import_by << COFF_ImportHeader_ImportByShift; COFF_ImportHeader header = {0}; header.sig1 = COFF_MachineType_Unknown; header.sig2 = max_U16; header.version = 0; header.machine = machine; header.time_stamp = time_stamp; header.data_size = safe_cast_u32(name.size + dll_name.size + 2); header.flags = flags; // alloc memory U64 buffer_size = sizeof(header) + header.data_size; U8 *buffer = push_array_no_zero(arena, U8, buffer_size); // copy header MemoryCopy(buffer, &header, sizeof(header)); // copy function name U8 *func_name = buffer + sizeof(header); MemoryCopy(func_name, name.str, name.size); func_name[name.size] = 0; // copy dll name U8 *dll_name_buffer = buffer + sizeof(header) + name.size + 1; MemoryCopy(dll_name_buffer, dll_name.str, dll_name.size); dll_name_buffer[dll_name.size] = 0; String8 import_data = str8(buffer, buffer_size); return import_data; } internal U64 coff_word_size_from_machine(COFF_MachineType machine) { U64 result = 0; switch (machine) { case COFF_MachineType_X64: result = 8; break; case COFF_MachineType_X86: result = 4; break; } return result; } internal U64 coff_default_exe_base_from_machine(COFF_MachineType machine) { U64 exe_base = 0; switch (coff_word_size_from_machine(machine)) { case 4: exe_base = 0x400000; break; case 8: exe_base = 0x140000000; break; } return exe_base; } internal U64 coff_default_dll_base_from_machine(COFF_MachineType machine) { U64 dll_base = 0; switch (coff_word_size_from_machine(machine)) { case 4: dll_base = 0x10000000; break; case 8: dll_base = 0x180000000; break; } return dll_base; } internal Arch arch_from_coff_machine(COFF_MachineType machine) { Arch result = Arch_Null; switch (machine) { case COFF_MachineType_Unknown: break; case COFF_MachineType_X86: result = Arch_x86; break; case COFF_MachineType_X64: result = Arch_x64; break; case COFF_MachineType_Arm: result = Arch_arm32; break; case COFF_MachineType_Arm64: result = Arch_arm64; break; } return result; } internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff) { U64 foff = 0; for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) { COFF_SectionHeader *sect = §ions[sect_idx]; if(sect->voff <= voff && voff < sect->voff+sect->vsize) { if(!(sect->flags & COFF_SectionFlag_CntUninitializedData)) { foff = sect->foff + (voff - sect->voff); } break; } } return foff; } //////////////////////////////// //~ rjf: Enum -> String internal String8 coff_string_from_time_stamp(Arena *arena, COFF_TimeStamp time_stamp) { String8 result; if (time_stamp == 0) { result = str8_lit("0"); } else if (time_stamp >= max_U32) { result = str8_lit("-1"); } else { DateTime dt = date_time_from_unix_time(time_stamp); result = push_date_time_string(arena, &dt); } return result; } 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 }, }; read_only static struct { char * name; COFF_ImportType type; } g_coff_import_header_type_map[] = { { "Code", COFF_ImportHeader_Code }, { "Data", COFF_ImportHeader_Data }, { "Const", COFF_ImportHeader_Const }, }; internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType type) { 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; } internal String8 coff_string_from_machine_type(COFF_MachineType machine) { for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { if (g_coff_machine_map[i].machine == machine) { return g_coff_machine_map[i].string; } } return str8_zero(); } internal String8 coff_string_from_flags(Arena *arena, COFF_FileHeaderFlags flags) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; if (flags & COFF_FileHeaderFlag_RelocStripped) { str8_list_pushf(scratch.arena, &list, "Relocs Stripped"); } if (flags & COFF_FileHeaderFlag_ExecutableImage) { str8_list_pushf(scratch.arena, &list, "Executable"); } if (flags & COFF_FileHeaderFlag_LineNumbersStripped) { str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped"); } if (flags & COFF_FileHeaderFlag_SymbolsStripped) { str8_list_pushf(scratch.arena, &list, "Symbols Stripped"); } if (flags & COFF_FileHeaderFlag_LargeAddressAware) { str8_list_pushf(scratch.arena, &list, "Large Address Aware"); } if (flags & COFF_FileHeaderFlag_32BitMachine) { str8_list_pushf(scratch.arena, &list, "32-Bit Machine"); } if (flags & COFF_FileHeaderFlag_DebugStripped) { str8_list_pushf(scratch.arena, &list, "Debug Stripped"); } if (flags & COFF_FileHeaderFlag_RemovableRunFromSwap) { str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap"); } if (flags & COFF_FileHeaderFlag_NetRunFromSwap) { str8_list_pushf(scratch.arena, &list, "Net Run From Swap"); } if (flags & COFF_FileHeaderFlag_System) { str8_list_pushf(scratch.arena, &list, "System"); } if (flags & COFF_FileHeaderFlag_Dll) { str8_list_pushf(scratch.arena, &list, "DLL"); } if (flags & COFF_FileHeaderFlag_UpSystemOnly) { str8_list_pushf(scratch.arena, &list, "Up System Only"); } String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); return result; } internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; if (flags & COFF_SectionFlag_TypeNoPad) { str8_list_pushf(scratch.arena, &list, "TypeNoPad"); } if (flags & COFF_SectionFlag_CntCode) { str8_list_pushf(scratch.arena, &list, "CntCode"); } if (flags & COFF_SectionFlag_CntInitializedData) { str8_list_pushf(scratch.arena, &list, "CntInitializedData"); } if (flags & COFF_SectionFlag_CntUninitializedData) { str8_list_pushf(scratch.arena, &list, "CntUninitializedData"); } if (flags & COFF_SectionFlag_LnkOther) { str8_list_pushf(scratch.arena, &list, "LnkOther"); } if (flags & COFF_SectionFlag_LnkInfo) { str8_list_pushf(scratch.arena, &list, "LnkInfo"); } 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_Mem16Bit) { str8_list_pushf(scratch.arena, &list, "Mem16Bit"); } if (flags & COFF_SectionFlag_MemLocked) { str8_list_pushf(scratch.arena, &list, "MemLocked"); } if (flags & COFF_SectionFlag_MemPreload) { str8_list_pushf(scratch.arena, &list, "MemPreload"); } if (flags & COFF_SectionFlag_LnkNRelocOvfl) { str8_list_pushf(scratch.arena, &list, "LnkNRelocOvfl"); } if (flags & COFF_SectionFlag_MemDiscardable) { str8_list_pushf(scratch.arena, &list, "MemDiscardable"); } if (flags & COFF_SectionFlag_MemNotCached) { str8_list_pushf(scratch.arena, &list, "MemNotCached"); } if (flags & COFF_SectionFlag_MemNotPaged) { str8_list_pushf(scratch.arena, &list, "MemNotPaged"); } if (flags & COFF_SectionFlag_MemShared) { str8_list_pushf(scratch.arena, &list, "MemShared"); } if (flags & COFF_SectionFlag_MemExecute) { str8_list_pushf(scratch.arena, &list, "MemExecute"); } if (flags & COFF_SectionFlag_MemRead) { str8_list_pushf(scratch.arena, &list, "MemRead"); } if (flags & COFF_SectionFlag_MemWrite) { str8_list_pushf(scratch.arena, &list, "MemWrite"); } U64 align = coff_align_size_from_section_flags(flags); if (align) { str8_list_pushf(scratch.arena, &list, "Align=%u", align); } if (!list.node_count) { str8_list_pushf(scratch.arena, &list, "None"); } StringJoin join = {0}; join.sep = str8_lit(", "); String8 result = str8_list_join(arena, &list, &join); scratch_end(scratch); return result; } internal String8 coff_string_from_resource_memory_flags(Arena *arena, COFF_ResourceMemoryFlags flags) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; if (flags & COFF_ResourceMemoryFlag_Moveable) { flags &= COFF_ResourceMemoryFlag_Moveable; str8_list_pushf(scratch.arena, &list, "Moveable"); } if (flags & COFF_ResourceMemoryFlag_Pure) { flags &= COFF_ResourceMemoryFlag_Pure; str8_list_pushf(scratch.arena, &list, "Pure"); } if (flags & COFF_ResourceMemoryFlag_Discardable) { flags &= COFF_ResourceMemoryFlag_Discardable; str8_list_pushf(scratch.arena, &list, "Discardable"); } if (flags != 0) { str8_list_pushf(scratch.arena, &list, "%#x", flags); } String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); return result; } internal String8 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) { return str8_cstring(g_coff_import_header_type_map[i].name); } } return str8(0,0); } 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"); } return str8_zero(); } 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_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(); } internal String8 coff_string_from_sym_storage_class(COFF_SymStorageClass x) { switch (x) { 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(); } internal String8 coff_string_from_weak_ext_type(COFF_WeakExtType x) { switch (x) { 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_reloc_x86(COFF_Reloc_X86 x) { switch (x) { 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_x64(COFF_Reloc_X64 x) { switch (x) { 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_arm(COFF_Reloc_Arm x) { switch (x) { 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_arm64(COFF_Reloc_Arm64 x) { switch (x) { 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(); } 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); } return str8_zero(); } internal COFF_MachineType coff_machine_from_string(String8 string) { for (U64 i = 0; i < ArrayCount(g_coff_machine_map); ++i) { if (str8_match(g_coff_machine_map[i].string, string, StringMatchFlag_CaseInsensitive)) { return g_coff_machine_map[i].machine; } } return COFF_MachineType_Unknown; } internal COFF_ImportType coff_import_header_type_from_string(String8 name) { for (U64 i = 0; i < ArrayCount(g_coff_import_header_type_map); ++i) { if (str8_match(str8_cstring(g_coff_import_header_type_map[i].name), name, StringMatchFlag_CaseInsensitive)) { return g_coff_import_header_type_map[i].type; } } return COFF_ImportType_Invalid; } internal String8 coff_make_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size) { Assert(name.size < 16); Assert(user_id < 10000); Assert(group_id < 10000); Assert(mode < 10000); Assert(size < 1000000000); Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; str8_list_pushf(scratch.arena, &list, "%-16.*s", str8_varg(name)); str8_list_pushf(scratch.arena, &list, "%-12u", time_stamp); str8_list_pushf(scratch.arena, &list, "%-6u", user_id); str8_list_pushf(scratch.arena, &list, "%-6u", group_id); str8_list_pushf(scratch.arena, &list, "%-8u", mode); str8_list_pushf(scratch.arena, &list, "%-10u", size); str8_list_pushf(scratch.arena, &list, "`\n"); String8 result = str8_list_join(arena, &list, 0); Assert(result.size == sizeof(COFF_ArchiveMemberHeader)); scratch_end(scratch); return result; }