From 482a61aaf797d35d28b4800fa52ba105d6f21f32 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 9 Feb 2026 23:41:19 -0800 Subject: [PATCH] obj -> COFF serializer --- src/coff/coff_obj_writer.c | 100 ++++++++++++++++++++++++++++++++++++- src/coff/coff_obj_writer.h | 7 +++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c index f6a421f1..02fb5f1f 100644 --- a/src/coff/coff_obj_writer.c +++ b/src/coff/coff_obj_writer.c @@ -1,3 +1,6 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine) { @@ -5,7 +8,7 @@ coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine) COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1); obj_writer->arena = arena; obj_writer->time_stamp = time_stamp; - obj_writer->machine = machine; + obj_writer->machine = machine; return obj_writer; } @@ -508,5 +511,100 @@ coff_obj_section_is_before(void *raw_a, void *raw_b) return (*a)->section_number < (*b)->section_number; } +#ifdef OBJ_H +internal String8 +coff_from_obj(Arena *arena, OBJ *obj) +{ + Temp scratch = scratch_begin(&arena, 1); + COFF_MachineType machine = coff_machine_from_arch(obj->arch); + COFF_TimeStamp time_stamp = (COFF_TimeStamp)obj->time_stamp; + COFF_ObjWriter *cow = coff_obj_writer_alloc(time_stamp, machine); + + // push sections + HashTable *section_remap = hash_table_init(scratch.arena, obj->symbols.count * 2); + for EachNode(section_n, OBJ_SectionNode, obj->sections.first) { + OBJ_Section *section = §ion_n->v; + + COFF_SectionFlags flags = 0; + if (section->flags & OBJ_SectionFlag_Read) { flags |= COFF_SectionFlag_MemRead; } + if (section->flags & OBJ_SectionFlag_Write) { flags |= COFF_SectionFlag_MemWrite; } + if (section->flags & OBJ_SectionFlag_Exec) { flags |= COFF_SectionFlag_MemExecute|COFF_SectionFlag_CntCode; } + if ( ! (section->flags & OBJ_SectionFlag_Exec)) { flags |= COFF_SectionFlag_CntInitializedData; } + if ( ! (section->flags & OBJ_SectionFlag_Load)) { flags |= COFF_SectionFlag_MemDiscardable; } + + COFF_ObjSection *section_coff = coff_obj_writer_push_section(cow, section->name, flags, str8_zero()); + section_coff->data = section->data; + + // obj -> coff section + hash_table_push_raw_raw(scratch.arena, section_remap, section, section_coff); + } + + // push symbols + HashTable *symbol_remap = hash_table_init(scratch.arena, obj->symbols.count * 2); + for EachNode(symbol_n, OBJ_SymbolNode, obj->symbols.first) { + OBJ_Symbol *symbol = &symbol_n->v; + switch (symbol->ref_kind) { + case OBJ_RefKind_Null: break; + case OBJ_RefKind_Section: { + OBJ_Section *section = symbol->ref; + COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section); + COFF_SymbolLocation location = (COFF_SymbolLocation){ .type = COFF_SymbolLocation_Section, .u.section = section_coff }; + + COFF_SymStorageClass storage_class = COFF_SymStorageClass_Null; + switch (symbol->scope) { + case OBJ_SymbolScope_Null: break; + case OBJ_SymbolScope_Local: storage_class = COFF_SymStorageClass_Static; break; + case OBJ_SymbolScope_Global: storage_class = COFF_SymStorageClass_External; break; + } + + COFF_ObjSymbol *symbol_coff = coff_obj_writer_push_symbol(cow, + symbol->name, + 0, + location, + (COFF_SymbolType){0}, + storage_class); + hash_table_push_raw_raw(scratch.arena, symbol_remap, symbol, symbol_coff); + } break; + } + } + + // push relocations + for EachNode(section_n, OBJ_SectionNode, obj->sections.first) { + OBJ_Section *section = §ion_n->v; + COFF_ObjSection *section_coff = hash_table_search_raw_raw(section_remap, section); + + for EachNode(reloc_n, OBJ_RelocNode, section->relocs.first) { + OBJ_Reloc *reloc = &reloc_n->v; + + // obj -> coff reloc type + COFF_RelocType reloc_type_coff = 0; + switch (cow->machine) { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { + switch (reloc->kind) { + case OBJ_RelocKind_Null: break; + case OBJ_RelocKind_SecRel: reloc_type_coff = COFF_Reloc_X64_SecRel; break; + default: InvalidPath; break; + } + } break; + default: InvalidPath; break; + } + + // push reloc entry + COFF_ObjSymbol *symbol_coff = hash_table_search_raw_raw(symbol_remap, reloc->symbol); + AssertAlways(symbol_coff); + coff_obj_writer_section_push_reloc(cow, section_coff, reloc->offset, symbol_coff, reloc_type_coff); + } + } + + String8 raw_obj = coff_obj_writer_serialize(arena, cow); + + coff_obj_writer_release(&cow); + + scratch_end(scratch); + return raw_obj; +} + +#endif diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h index 0f68aabc..8c4d83d7 100644 --- a/src/coff/coff_obj_writer.h +++ b/src/coff/coff_obj_writer.h @@ -1,3 +1,6 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + #ifndef COFF_OBJ_WRITER_H #define COFF_OBJ_WRITER_H @@ -125,5 +128,9 @@ internal COFF_ObjReloc * coff_obj_writer_section_push_reloc_voff (COFF_ObjWrite internal void coff_obj_writer_push_directive(COFF_ObjWriter *obj_writer, String8 directive); +#ifdef OBJ_H +internal String8 coff_from_obj(Arena *arena, OBJ *obj); +#endif + #endif // COFF_OBJ_WRITER_H