diff --git a/src/base/base_core.h b/src/base/base_core.h index 511020f8..758a5b34 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -148,6 +148,7 @@ #define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d))) #define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d)) #define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c)) +#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size) #define MemoryZero(s,z) memset((s),0,(z)) #define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s))) diff --git a/src/base/base_strings.c b/src/base/base_strings.c index bbd485c9..3aa6019b 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -971,6 +971,15 @@ str8_list_push(Arena *arena, String8List *list, String8 string){ return(node); } +internal String8Node * +str8_list_push_cstr(Arena *arena, String8List *list, String8 string) +{ + String8Node *node = str8_list_push(arena, list, string); + local_persist String8 null = str8_lit_comp("\0"); + str8_list_push(arena, list, null); + return node; +} + internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string){ String8Node *node = push_array_no_zero(arena, String8Node, 1); diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 022676f3..7b9b3d20 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -446,6 +446,7 @@ internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x); internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x); internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str); internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str); +internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str); #define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count)) #define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1) diff --git a/src/coff/coff.h b/src/coff/coff.h index 92328f66..6c0c8828 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -144,6 +144,7 @@ enum COFF_SectionFlag_MemRead = (1 << 30), COFF_SectionFlag_MemWrite = (1 << 31) }; +#define COFF_SectionFlags_PackAlign(f) ((f) << COFF_SectionFlag_AlignShift) #define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask) #define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl) diff --git a/src/coff/coff_obj_writer.c b/src/coff/coff_obj_writer.c new file mode 100644 index 00000000..20caa69d --- /dev/null +++ b/src/coff/coff_obj_writer.c @@ -0,0 +1,273 @@ +internal COFF_ObjWriter* +coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type) +{ + Arena *arena = arena_alloc(); + COFF_ObjWriter *obj_writer = push_array(arena, COFF_ObjWriter, 1); + obj_writer->arena = arena; + obj_writer->time_stamp = time_stamp; + obj_writer->machine_type = machine_type; + return obj_writer; +} + +internal void +coff_obj_writer_release(COFF_ObjWriter **obj_writer) +{ + arena_release((*obj_writer)->arena); + *obj_writer = 0; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class) +{ + COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1); + SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n); + obj_writer->symbol_count += 1; + + COFF_ObjSymbol *s = &n->v; + s->name = name; + s->value = value; + s->section = section; + s->type = type; + s->storage_class = storage_class; + s->idx = obj_writer->symbol_count-1; + + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section) +{ + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, section, (COFF_SymbolType){0}, COFF_SymStorageClass_Static); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, COFF_SymStorageClass storage_class, U32 value) +{ + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, 0, (COFF_SymbolType){0}, storage_class); + return s; +} + +internal COFF_ObjSymbol * +coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name) +{ + COFF_SymbolType type = {0}; + type.u.msb = COFF_SymDType_Func; + COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, 0, type, COFF_SymStorageClass_External); + return s; +} + +internal COFF_ObjSection * +coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data) +{ + COFF_ObjSectionNode *sect_n = push_array(obj_writer->arena, COFF_ObjSectionNode, 1); + SLLQueuePush(obj_writer->sect_first, obj_writer->sect_last, sect_n); + obj_writer->sect_count += 1; + + COFF_ObjSection *sect = §_n->v; + sect->name = name; + sect->flags = flags; + sect->symbol = coff_obj_writer_push_symbol_static(obj_writer, name, 0, sect); + + str8_list_push(obj_writer->arena, §->data, data); + + return sect; +} + +internal COFF_ObjReloc* +coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType type) +{ + COFF_ObjRelocNode *reloc_n = push_array(obj_writer->arena, COFF_ObjRelocNode, 1); + SLLQueuePush(sect->reloc_first, sect->reloc_last, reloc_n); + sect->reloc_count += 1; + + COFF_ObjReloc *reloc = &reloc_n->v; + reloc->apply_off = apply_off; + reloc->symbol = symbol; + reloc->type = type; + + return reloc; +} + +internal int +coff_obj_section_is_before(void *raw_a, void *raw_b) +{ + COFF_ObjSection **a = raw_a; + COFF_ObjSection **b = raw_b; + return (*a)->section_number < (*b)->section_number; +} + +internal String8 +coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List srl = {0}; + + String8List string_table = {0}; + U32 *string_table_size = push_array(scratch.arena, U32, 1); + *string_table_size = sizeof(*string_table_size); + str8_list_push(scratch.arena, &string_table, str8_struct(string_table_size)); + + // + // + // + U64 obj_sections_count; + COFF_ObjSection **obj_sections; + { + obj_sections_count = obj_writer->sect_count; + obj_sections = push_array(scratch.arena, COFF_ObjSection *, obj_writer->sect_count); + U64 sect_idx = 0; + for (COFF_ObjSectionNode *sect_n = obj_writer->sect_first; sect_n != 0; sect_n = sect_n->next, sect_idx += 1) { + COFF_ObjSection *sect = §_n->v; + sect->section_number = sect_idx+1; + obj_sections[sect_idx] = sect; + + } + } + AssertAlways(obj_sections_count <= max_U16); + + // + // file header + // + COFF_FileHeader *file_header = push_array(scratch.arena, COFF_FileHeader, 1); + file_header->machine = obj_writer->machine_type; + file_header->section_count = obj_sections_count; + file_header->time_stamp = obj_writer->time_stamp; + file_header->symbol_table_foff = 0; + file_header->symbol_count = safe_cast_u32(obj_writer->symbol_count); + file_header->optional_header_size = 0; + file_header->flags = 0; + str8_list_push(scratch.arena, &srl, str8_struct(file_header)); + + // + // section table + // + + COFF_SectionHeader *sectab = push_array(scratch.arena, COFF_SectionHeader, obj_sections_count); + str8_list_push(scratch.arena, &srl, str8_array(sectab, obj_sections_count)); + { + for (U64 sect_idx = 0; sect_idx < obj_sections_count; sect_idx += 1) { + COFF_ObjSection *s = obj_sections[sect_idx]; + COFF_SectionHeader *d = §ab[sect_idx]; + + // section name + String8 sect_name = s->name; + if (sect_name.size > sizeof(d->name)) { + U64 sect_name_off = string_table.total_size; + str8_list_push_cstr(scratch.arena, &string_table, sect_name); + + sect_name = push_str8f(scratch.arena, "/%u", sect_name_off); + AssertAlways(sect_name.size <= sizeof(d->name)); + } + + // section data + U64 data_foff = 0; + U64 data_size = 0; + if (s->data.total_size > 0) { + data_foff = srl.total_size; + data_size = s->data.total_size; + str8_list_concat_in_place(&srl, &s->data); + } + + // section relocs + U64 relocs_foff = 0; + if (s->reloc_count) { + AssertAlways(s->reloc_count <= max_U16); + COFF_Reloc *relocs = push_array(scratch.arena, COFF_Reloc, s->reloc_count); + U64 reloc_idx = 0; + for (COFF_ObjRelocNode *reloc_n = s->reloc_first; reloc_n != 0; reloc_n = reloc_n->next, reloc_idx += 1) { + COFF_ObjReloc *rs = &reloc_n->v; + COFF_Reloc *rd = &relocs[reloc_idx]; + rd->apply_off = rs->apply_off; + rd->isymbol = rs->symbol->idx; + rd->type = rs->type; + } + relocs_foff = srl.total_size; + str8_list_push(scratch.arena, &srl, str8_array(relocs, s->reloc_count)); + } + + // section header + MemoryCopyStr8(d->name, sect_name); + MemoryZeroTyped(d->name + sect_name.size, sizeof(d->name) - sect_name.size); + d->vsize = 0; + d->voff = 0; + d->fsize = data_size; + d->foff = data_foff; + d->relocs_foff = relocs_foff; + d->lines_foff = 0; + d->reloc_count = safe_cast_u32(s->reloc_count); + d->line_count = 0; + d->flags = s->flags; + } + } + + // + // symbol table + // + if (obj_writer->symbol_count) { + file_header->symbol_table_foff = srl.total_size; + COFF_Symbol16 *symtab = push_array(scratch.arena, COFF_Symbol16, obj_writer->symbol_count); + str8_list_push(scratch.arena, &srl, str8_array(symtab, obj_writer->symbol_count)); + { + U64 symbol_idx = 0; + for (COFF_ObjSymbolNode *symbol_n = obj_writer->symbol_first; symbol_n != 0; symbol_n = symbol_n->next) { + COFF_ObjSymbol *s = &symbol_n->v; + COFF_Symbol16 *d = &symtab[symbol_idx]; + + COFF_SymbolName name = {0}; + // long name + if (s->name.size > sizeof(name.short_name)) { + U64 string_table_offset = string_table.total_size; + str8_list_push_cstr(scratch.arena, &string_table, s->name); + + name.long_name.zeroes = 0; + name.long_name.string_table_offset = safe_cast_u32(string_table_offset); + } + // short name + else { + MemoryCopyStr8(name.short_name, s->name); + MemoryZeroTyped(name.short_name + s->name.size, sizeof(name.short_name) - s->name.size); + } + + // symbol header + AssertAlways(s->aux_symbols.node_count <= max_U8); + d->name = name; + d->value = s->value; + if (s->section == 0) { + d->section_number = COFF_Symbol_AbsSection16; + } else { + d->section_number = safe_cast_u16(s->section->section_number); + } + d->type = s->type; + d->storage_class = s->storage_class; + d->aux_symbol_count = (U8)s->aux_symbols.node_count; + + // aux symbols + symbol_idx += 1; + for (String8Node *aux_n = s->aux_symbols.first; aux_n != 0; aux_n = aux_n->next, symbol_idx += 1) { + AssertAlways(aux_n->string.size <= sizeof(COFF_Symbol16)); + COFF_Symbol16 *a = &symtab[symbol_idx]; + MemoryZeroStruct(a); + MemoryCopyStr8(a, aux_n->string); + } + } + } + } + + // + // string table + // + *string_table_size = safe_cast_u32(string_table.total_size); + str8_list_concat_in_place(&srl, &string_table); + + // + // join + // + String8 obj = str8_list_join(arena, &srl, 0); + + scratch_end(scratch); + return obj; +} + + diff --git a/src/coff/coff_obj_writer.h b/src/coff/coff_obj_writer.h new file mode 100644 index 00000000..67297401 --- /dev/null +++ b/src/coff/coff_obj_writer.h @@ -0,0 +1,78 @@ +#ifndef COFF_OBJ_WRITER_H +#define COFF_OBJ_WRITER_H + +typedef struct COFF_ObjSymbol +{ + String8 name; + U32 value; + struct COFF_ObjSection *section; + COFF_SymbolType type; + COFF_SymStorageClass storage_class; + String8List aux_symbols; + U32 idx; +} COFF_ObjSymbol; + +typedef struct COFF_ObjSymbolNode +{ + struct COFF_ObjSymbolNode *next; + COFF_ObjSymbol v; +} COFF_ObjSymbolNode; + +typedef struct COFF_ObjReloc +{ + U32 apply_off; + COFF_ObjSymbol *symbol; + COFF_RelocType type; +} COFF_ObjReloc; + +typedef struct COFF_ObjRelocNode +{ + struct COFF_ObjRelocNode *next; + COFF_ObjReloc v; +} COFF_ObjRelocNode; + +typedef struct COFF_ObjSection +{ + String8 name; + String8List data; + COFF_SectionFlags flags; + COFF_ObjSymbol *symbol; + + U64 reloc_count; + COFF_ObjRelocNode *reloc_first; + COFF_ObjRelocNode *reloc_last; + + U32 section_number; +} COFF_ObjSection; + +typedef struct COFF_ObjSectionNode +{ + struct COFF_ObjSectionNode *next; + COFF_ObjSection v; +} COFF_ObjSectionNode; + +typedef struct COFF_ObjWriter +{ + Arena *arena; + COFF_TimeStamp time_stamp; + COFF_MachineType machine_type; + + U64 symbol_count; + COFF_ObjSymbolNode *symbol_first; + COFF_ObjSymbolNode *symbol_last; + + U64 sect_count; + COFF_ObjSectionNode *sect_first; + COFF_ObjSectionNode *sect_last; +} COFF_ObjWriter; + +//////////////////////////////// + +internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type); +internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer); +internal COFF_ObjSection* coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data); +internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class); +internal COFF_ObjReloc* coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type); + +#endif // COFF_OBJ_WRITER_H + diff --git a/src/linker/base_ext/base_strings.h b/src/linker/base_ext/base_strings.h index 5b9ac947..fd1c66db 100644 --- a/src/linker/base_ext/base_strings.h +++ b/src/linker/base_ext/base_strings.h @@ -3,8 +3,6 @@ #pragma once -#define MemoryCopyStr8(dst, s) MemoryCopy(dst, (s).str, (s).size) - internal int str8_compar(String8 a, String8 b, B32 ignore_case); internal int str8_compar_ignore_case(const void *a, const void *b); internal int str8_compar_case_sensitive(const void *a, const void *b); diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index c38e224f..29da28d3 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -270,6 +270,19 @@ hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) return 0; } +internal B32 +hash_table_search_string_raw(HashTable *ht, String8 key, void **value_out) +{ + KeyValuePair *result = hash_table_search_string(ht, key); + if (result) { + if (value_out) { + *value_out = result->value_raw; + } + return 1; + } + return 0; +} + //////////////////////////////// internal int @@ -327,6 +340,18 @@ key_value_pairs_from_hash_table(Arena *arena, HashTable *ht) return pairs; } +internal void * +values_from_hash_table_raw(Arena *arena, HashTable *ht) +{ + void **result = push_array(arena, void *, ht->count); + for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) { + for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) { + Assert(cursor < ht->count); + result[cursor++] = n->v.value_raw; + } + } + return result; +} #include "third_party/radsort/radsort.h" internal void diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index b35c9fcf..4ea808ff 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -81,6 +81,8 @@ internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); +internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht); + internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 235881fd..9e4850c5 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -33,11 +33,16 @@ #include "base/base_inc.h" #include "os/os_inc.h" +#include "path/path.h" +#include "hash_table.h" #include "coff/coff.h" +#include "coff/coff_enum.h" #include "coff/coff_parse.h" +#include "coff/coff_obj_writer.h" #include "pe/pe.h" #include "codeview/codeview.h" #include "codeview/codeview_parse.h" +#include "codeview/codeview_enum.h" #include "msf/msf.h" #include "msf/msf_parse.h" #include "pdb/pdb.h" @@ -45,10 +50,15 @@ #include "base/base_inc.c" #include "os/os_inc.c" +#include "path/path.c" +#include "hash_table.c" #include "coff/coff.c" +#include "coff/coff_enum.c" #include "coff/coff_parse.c" +#include "coff/coff_obj_writer.c" #include "pe/pe.c" #include "codeview/codeview.c" +#include "codeview/codeview_enum.c" #include "codeview/codeview_parse.c" #include "msf/msf.c" #include "msf/msf_parse.c" @@ -63,14 +73,15 @@ // RDI #include "rdi/rdi_overrides.h" -#include "lib_rdi/rdi.h" -#include "lib_rdi/rdi.c" +#include "lib_rdi_format/rdi_format.h" +#include "rdi/rdi.h" +#include "lib_rdi_format/rdi_format.c" +#include "rdi/rdi.c" //////////////////////////////// // Code Base Extensions #include "base_ext/base_inc.h" -#include "hash_table.h" #include "thread_pool/thread_pool.h" #include "codeview_ext/codeview.h" #include "pdb_ext/msf_builder.h" @@ -79,7 +90,6 @@ #include "pdb_ext/pdb_builder.h" #include "base_ext/base_inc.c" -#include "hash_table.c" #include "thread_pool/thread_pool.c" #include "codeview_ext/codeview.c" #include "pdb_ext/msf_builder.c" @@ -406,87 +416,61 @@ lnk_res_number_id_is_before(void *raw_a, void *raw_b) } internal void -lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir) +lnk_serialize_pe_resource_tree(COFF_ObjWriter *obj_writer, PE_ResourceDir *root_dir) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_Section *dir_sect = lnk_section_table_push(sectab, str8_lit(".rsrc$01"), LNK_RSRC_SECTION_FLAGS); - LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".rsrc$02"), LNK_RSRC_SECTION_FLAGS); - - LNK_Chunk *dir_tree_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); - LNK_Chunk *dir_data_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); - LNK_Chunk *dir_string_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); - - dir_tree_chunk->sort_idx = str8_lit("a"); - dir_string_chunk->sort_idx = str8_lit("b"); - dir_data_chunk->sort_idx = str8_lit("c"); - - PE_Resource root_wrapper = {0}; - root_wrapper.id.type = COFF_ResourceIDType_Number; - root_wrapper.id.u.number = 0; - root_wrapper.kind = PE_ResDataKind_DIR; - root_wrapper.u.dir = root_dir; - struct Stack { - struct Stack *next; - U64 arr_idx; - U64 res_idx[2]; - PE_ResourceArray res_arr[2]; - LNK_Chunk *coff_entry_array_chunk; - LNK_Chunk *coff_entry_chunk; + struct Stack *next; + U64 arr_idx; + U64 res_idx[2]; + PE_ResourceArray res_arr[2]; + COFF_ResourceDirEntry *coff_entry_arr[2]; }; - struct Stack *stack = push_array(scratch.arena, struct Stack, 1); - stack->res_arr[0].count = 1; - stack->res_arr[0].v = &root_wrapper; + struct Stack *stack = push_array(scratch.arena, struct Stack, 1); + // init stack + { + PE_Resource root_wrapper = {0}; + root_wrapper.id.type = COFF_ResourceIDType_Number; + root_wrapper.id.u.number = 0; + root_wrapper.kind = PE_ResDataKind_DIR; + root_wrapper.u.dir = root_dir; + + COFF_ResourceDirEntry root_dir = {0}; + + stack->res_arr[0].count = 1; + stack->res_arr[0].v = &root_wrapper; + + stack->coff_entry_arr[0] = &root_dir; + stack->coff_entry_arr[1] = 0; + } + + COFF_ObjSection *rsrc1 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$01"), LNK_RSRC1_SECTION_FLAGS, str8_zero()); + COFF_ObjSection *rsrc2 = coff_obj_writer_push_section(obj_writer, str8_lit(".rsrc$02"), LNK_RSRC2_SECTION_FLAGS, str8_zero()); - U64 total_res_count = 0; - - while (stack) { - while (stack->arr_idx < ArrayCount(stack->res_arr)) { - while (stack->res_idx[stack->arr_idx] < stack->res_arr[stack->arr_idx].count) { - PE_Resource *res = &stack->res_arr[stack->arr_idx].v[stack->res_idx[stack->arr_idx]]; - ++stack->res_idx[stack->arr_idx]; - - String8 flag_name = push_str8f(symtab->arena->v[0], "flag_%u", total_res_count); - String8 offset_name = push_str8f(symtab->arena->v[0], "offset_%u", total_res_count); - ++total_res_count; - - if (stack->coff_entry_array_chunk) { - COFF_ResourceDirEntry *entry = push_array(dir_sect->arena, COFF_ResourceDirEntry, 1); - stack->coff_entry_chunk = lnk_section_push_chunk_data(dir_sect, stack->coff_entry_array_chunk, str8_struct(entry), str8_zero()); - - switch (res->id.type) { - case COFF_ResourceIDType_Number: { - entry->name.id = res->id.u.number; - } break; + for (; stack; ) { + for (; stack->arr_idx < ArrayCount(stack->res_arr); stack->arr_idx += 1) { + for (; stack->res_idx[stack->arr_idx] < stack->res_arr[stack->arr_idx].count; ) { + U64 res_idx = stack->res_idx[stack->arr_idx]++; + PE_Resource *res = &stack->res_arr[stack->arr_idx].v[res_idx]; - case COFF_ResourceIDType_String: { - // TODO: we can make string table smaller by reusing offsets for same strings - - // not sure why high bit has to be turned on here since number id and string id entries are - // in separate arrays but windows doesn't treat name offset like string without this bit. - entry->name.offset |= (1 << 31); - - // make chunk and symbol - String8 res_name = coff_resource_string_from_str8(dir_sect->arena, res->id.u.string); - LNK_Chunk *name_chunk = lnk_section_push_chunk_data(dir_sect, dir_string_chunk, res_name, str8_zero()); - LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit("COFF_RESOURCE_ID_STRING"), LNK_DefinedSymbolVisibility_Static, 0, name_chunk, 0, 0, 0); + { + COFF_ResourceDirEntry *coff_entry = &stack->coff_entry_arr[stack->arr_idx][res_idx]; - // patch COFF_ResourceDirEntry.name.offset - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol); - } break; + // assign entry data offset + coff_entry->id.data_entry_offset = safe_cast_u32(rsrc1->data.total_size); - case COFF_ResourceIDType_Null: break; - - default: InvalidPath; + // set directory flag + if (res->kind == PE_ResDataKind_DIR) { + coff_entry->id.data_entry_offset |= COFF_Resource_SubDirFlag; } } - + switch (res->kind) { case PE_ResDataKind_DIR: { - // initialize directory header - COFF_ResourceDirTable *dir_header = push_array(dir_sect->arena, COFF_ResourceDirTable, 1); + // fill out directory header + COFF_ResourceDirTable *dir_header = push_array(obj_writer->arena, COFF_ResourceDirTable, 1); dir_header->characteristics = res->u.dir->characteristics; dir_header->time_stamp = res->u.dir->time_stamp; dir_header->major_version = res->u.dir->major_version; @@ -494,65 +478,71 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab dir_header->name_entry_count = res->u.dir->named_list.count; dir_header->id_entry_count = res->u.dir->id_list.count; - // push sub directory chunk layout - LNK_Chunk *dir_node_chunk = lnk_section_push_chunk_list(dir_sect, dir_tree_chunk, str8_zero()); - dir_node_chunk->align = COFF_ResourceAlign; - LNK_Chunk *dir_header_chunk = lnk_section_push_chunk_data(dir_sect, dir_node_chunk, str8_struct(dir_header), str8_zero()); - LNK_Chunk *entry_array_chunk = lnk_section_push_chunk_list(dir_sect, dir_node_chunk, str8_zero()); - lnk_chunk_set_debugf(dir_sect->arena, dir_header_chunk, "DIR_HEADER_CHUNK"); - lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK"); - - // push symbols to patch coff entry - LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_Resource_SubDirFlag); - LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory - lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory - - // patch resource dir header - if (stack->coff_entry_chunk) { - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), flag_symbol); - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), offset_symbol); - } - - // sort entries by id + // sort input resources PE_ResourceArray named_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->named_list); PE_ResourceArray id_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->id_list); radsort(named_array.v, named_array.count, lnk_res_string_id_is_before); - radsort(id_array.v, id_array.count, lnk_res_number_id_is_before); + radsort(id_array.v, id_array.count, lnk_res_number_id_is_before); - // frame for sub directory - struct Stack *frame = push_array(scratch.arena, struct Stack, 1); - frame->coff_entry_array_chunk = entry_array_chunk; - frame->res_arr[0] = named_array; - frame->res_arr[1] = id_array; + // allocate COFF entries + COFF_ResourceDirEntry *named_entries = push_array(obj_writer->arena, COFF_ResourceDirEntry, named_array.count); + COFF_ResourceDirEntry *id_entries = push_array(obj_writer->arena, COFF_ResourceDirEntry, id_array.count); + + // push header and entries + str8_list_push(obj_writer->arena, &rsrc1->data, str8_struct(dir_header)); + str8_list_push(obj_writer->arena, &rsrc1->data, str8_array(named_entries, named_array.count)); + str8_list_push(obj_writer->arena, &rsrc1->data, str8_array(id_entries, id_array.count)); + + // fill out named ids + for (U64 i = 0; i < named_array.count; i += 1) { + PE_Resource src = named_array.v[i]; + COFF_ResourceDirEntry *dst = &named_entries[i]; + + // append resource name + U32 res_name_off = safe_cast_u32(rsrc1->data.total_size); + String8 res_name = coff_resource_string_from_str8(obj_writer->arena, res->id.u.string); + str8_list_push(obj_writer->arena, &rsrc1->data, res_name); + + // not sure why high bit has to be turned on here since number id and string id entries are + // in separate arrays but windows doesn't treat name offset like string without this bit. + dst->name.offset = (1 << 31) | res_name_off; + } + + // fill out number ids + for (U64 i = 0; i < id_array.count; i += 1) { + PE_Resource src = id_array.v[i]; + COFF_ResourceDirEntry *dst = &id_entries[i]; + dst->name.id = src.id.u.number; + } + + // fill out sub directory stack frame + struct Stack *frame = push_array(scratch.arena, struct Stack, 1); + frame->res_arr[0] = named_array; + frame->res_arr[1] = id_array; + frame->coff_entry_arr[0] = named_entries; + frame->coff_entry_arr[1] = id_entries; SLLStackPush(stack, frame); - } goto yeild; // recurse to sub directory + } goto yield; // recurse to sub directory case PE_ResDataKind_COFF_RESOURCE: { - COFF_ResourceDataEntry *coff_resource_data_entry = push_array(dir_sect->arena, COFF_ResourceDataEntry, 1); - coff_resource_data_entry->data_size = res->u.coff_res.data.size; - coff_resource_data_entry->data_voff = 0; // relocated - coff_resource_data_entry->code_page = 0; // TODO: whats this for? (lld-link writes zero) + // fill out resource header + COFF_ResourceDataEntry *coff_res = push_array(obj_writer->arena, COFF_ResourceDataEntry, 1); + coff_res->data_size = res->u.coff_res.data.size; + coff_res->data_voff = 0; // relocated + coff_res->code_page = 0; // TODO: whats this for? (lld-link writes zero) - // push layout chunks - LNK_Chunk *coff_resource_data_entry_chunk = lnk_section_push_chunk_data(dir_sect, dir_data_chunk, str8_struct(coff_resource_data_entry), str8_zero()); - LNK_Chunk *resource_data_chunk = lnk_section_push_chunk_data(data_sect, data_sect->root, res->u.coff_res.data, str8_zero()); + // emit symbol for resource data + U32 resdat_off = safe_cast_u32(rsrc2->data.total_size); + COFF_ObjSymbol *resdat = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("resdat"), resdat_off, rsrc2); - // windows errors out on unaligned data - coff_resource_data_entry_chunk->align = COFF_ResourceAlign; - resource_data_chunk->align = COFF_ResourceAlign; + // emit reloc for 'data_voff' + U64 apply_off = rsrc1->data.total_size + OffsetOf(COFF_ResourceDataEntry, data_voff); + U32 apply_off32 = safe_cast_u32(apply_off); + coff_obj_writer_section_push_reloc(obj_writer, rsrc1, apply_off32, resdat, COFF_Reloc_X64_Addr32Nb); - // relocate data - String8 resource_data_symbol_name = push_str8f(symtab->arena->v[0], "$R%06X", total_res_count); - LNK_Symbol *resource_data_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], resource_data_symbol_name, LNK_DefinedSymbolVisibility_Static, 0, resource_data_chunk, 0, 0, 0); - lnk_section_push_reloc(dir_sect, coff_resource_data_entry_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_ResourceDataEntry, data_voff), resource_data_symbol); - - // push symbol for data offset relocation - LNK_Symbol *coff_data_offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_resource_data_entry_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, coff_data_offset_symbol); - - Assert(stack->coff_entry_chunk); - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), coff_data_offset_symbol); + // push resource entry & data + str8_list_push(obj_writer->arena, &rsrc1->data, str8_struct(coff_res)); + str8_list_push(obj_writer->arena, &rsrc2->data, res->u.coff_res.data); } break; case PE_ResDataKind_NULL: break; @@ -561,10 +551,9 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab case PE_ResDataKind_COFF_LEAF: InvalidPath; } } - ++stack->arr_idx; } SLLStackPop(stack); - yeild:; + yield:; } scratch_end(scratch); @@ -572,20 +561,20 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab } internal void -lnk_add_resource_debug_s(LNK_SectionTable *sectab, - LNK_SymbolTable *symtab, - String8 obj_path, - String8 cwd_path, - String8 exe_path, - CV_Arch arch, - String8List res_file_list, - MD5Hash *res_hash_array) +lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, + String8 obj_path, + String8 cwd_path, + String8 exe_path, + CV_Arch arch, + String8List res_file_list, + MD5Hash *res_hash_array) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); // init serial for tables - String8List string_srl, file_srl; MemoryZeroStruct(&string_srl); MemoryZeroStruct(&file_srl); + String8List string_srl = {0}; + String8List file_srl = {0}; str8_serial_begin(scratch.arena, &string_srl); str8_serial_begin(scratch.arena, &file_srl); @@ -620,7 +609,7 @@ lnk_add_resource_debug_s(LNK_SectionTable *sectab, 1, 0, 1, 0, version_string); - String8List env_list; MemoryZeroStruct(&env_list); + String8List env_list = {0}; str8_list_push(scratch.arena, &env_list, str8_lit("cwd")); str8_list_push(scratch.arena, &env_list, cwd_path); str8_list_push(scratch.arena, &env_list, str8_lit("exe")); @@ -629,18 +618,18 @@ lnk_add_resource_debug_s(LNK_SectionTable *sectab, str8_list_push(scratch.arena, &env_list, str8_lit("")); String8 envblock_data = cv_make_envblock(scratch.arena, env_list); - String8 obj_symbol = cv_make_symbol(scratch.arena, CV_SymKind_OBJNAME, obj_data); - String8 comp_symbol = cv_make_symbol(scratch.arena, CV_SymKind_COMPILE3, comp_data); + String8 obj_symbol = cv_make_symbol(scratch.arena, CV_SymKind_OBJNAME, obj_data); + String8 comp_symbol = cv_make_symbol(scratch.arena, CV_SymKind_COMPILE3, comp_data); String8 envblock_symbol = cv_make_symbol(scratch.arena, CV_SymKind_ENVBLOCK, envblock_data); - String8List symbol_srl; MemoryZeroStruct(&symbol_srl); + String8List symbol_srl = {0}; str8_serial_begin(scratch.arena, &symbol_srl); str8_serial_push_string(scratch.arena, &symbol_srl, obj_symbol); str8_serial_push_string(scratch.arena, &symbol_srl, comp_symbol); str8_serial_push_string(scratch.arena, &symbol_srl, envblock_symbol); // build code view sub-sections - String8List sub_sect_srl; MemoryZeroStruct(&sub_sect_srl); + String8List sub_sect_srl = {0}; str8_serial_begin(scratch.arena, &sub_sect_srl); CV_Signature sig = CV_Signature_C13; str8_serial_push_struct(scratch.arena, &sub_sect_srl, &sig); @@ -666,20 +655,18 @@ lnk_add_resource_debug_s(LNK_SectionTable *sectab, str8_serial_push_data_list(scratch.arena, &sub_sect_srl, symbol_srl.first); str8_serial_push_align(scratch.arena, &sub_sect_srl, CV_C13SubSectionAlign); - LNK_Section *debug_s = lnk_section_table_push(sectab, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); - String8 sub_sect_data = str8_serial_end(debug_s->arena, &sub_sect_srl); - lnk_section_push_chunk_data(debug_s, debug_s->root, sub_sect_data, str8_zero()); + String8 sub_sect_data = str8_serial_end(obj_writer->arena, &sub_sect_srl); + coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, sub_sect_data); scratch_end(scratch); ProfEnd(); } internal String8 -lnk_make_res_obj(TP_Context *tp, - Arena *arena, +lnk_make_res_obj(Arena *arena, PE_ResourceDir *root_dir, - COFF_MachineType machine, COFF_TimeStamp time_stamp, + COFF_MachineType machine, String8 path, String8 cwd_path, String8 exe_path, @@ -687,262 +674,23 @@ lnk_make_res_obj(TP_Context *tp, MD5Hash *res_hash_array) { ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - static const U64 sect_virt_align = 1; - static const U64 sect_file_align = 1; - TP_Arena *temp_tp_arena = push_array(scratch.arena, TP_Arena, 1); - temp_tp_arena->v = push_array(scratch.arena, Arena *, 1); - temp_tp_arena->count = 1; - temp_tp_arena->v[0] = arena_alloc(); + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine); + + // obj features + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@feat.00"), COFF_SymStorageClass_Static, MSCRT_FeatFlag_HAS_SAFE_SEH|MSCRT_FeatFlag_UNKNOWN_4); - LNK_SymbolTable *symtab = lnk_symbol_table_init(temp_tp_arena); - LNK_SectionTable *sectab = lnk_section_table_alloc(0, sect_virt_align, sect_file_align); - LNK_Section *header_sect = lnk_section_table_push(sectab, str8_lit(".null"), 0); + // serialize resource tree + lnk_serialize_pe_resource_tree(obj_writer, root_dir); + + // push resource debug info + lnk_add_resource_debug_s(obj_writer, path, cwd_path, exe_path, cv_arch_from_coff_machine(machine), res_file_list, res_hash_array); + + // finalize obj + String8 res_obj = coff_obj_writer_serialize(arena, obj_writer); - lnk_serialize_pe_resource_tree(sectab, symtab, root_dir); - - CV_Arch cv_arch = cv_arch_from_coff_machine(machine); - lnk_add_resource_debug_s(sectab, symtab, path, cwd_path, exe_path, cv_arch, res_file_list, res_hash_array); - - // register section symbols (after this point don't push new sections) - for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { - LNK_Section *sect = §_node->data; - lnk_symbol_table_push_defined_chunk(symtab, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - } - sectab->null_sect = lnk_section_list_remove(§ab->list, str8_lit(".null")); - lnk_section_table_build_data(tp, sectab, machine); - lnk_section_table_push_null(sectab); - lnk_section_table_assign_indices(sectab); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); - - COFF_Symbol16List coff_symbol_list = {0}; - - COFF_Symbol16 coff_feat00 = {0}; - MemoryCopyStr8(&coff_feat00.name, str8_lit("@feat.00")); - coff_feat00.value = MSCRT_FeatFlag_HAS_SAFE_SEH|MSCRT_FeatFlag_UNKNOWN_4; - coff_feat00.section_number = COFF_Symbol_AbsSection16; - coff_feat00.storage_class = COFF_SymStorageClass_Static; - coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_feat00); - - // emit coff symbols for section definitions - for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { - LNK_Section *sect = §_node->data; - if (sect == header_sect) continue; - if (!sect->emit_header) continue; - - U64 reloc_count = 0; - LNK_Symbol *coff_reloc_count_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, "%S.coff_relocs[].count", sect->name); - if (coff_reloc_count_symbol) { - reloc_count = coff_reloc_count_symbol->u.defined.u.va; - } - - U64 sect_size = lnk_virt_size_from_chunk_ref(sect_id_map, sect->root->ref); - - COFF_Symbol16 coff_sect_symbol = {0}; - Assert(sect->name.size <= 8); - MemoryCopyStr8(&coff_sect_symbol.name, sect->name); - coff_sect_symbol.value = 0; - coff_sect_symbol.section_number = sect->isect; - coff_sect_symbol.aux_symbol_count = 1; - coff_sect_symbol.storage_class = COFF_SymStorageClass_Static; - - Assert(sect->isect <= max_U16); - COFF_SymbolSecDef secdef = {0}; - secdef.length = safe_cast_u32(sect_size); - secdef.number_lo = sect->isect; - secdef.number_of_relocations = safe_cast_u32(reloc_count); - - coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_sect_symbol); - coff_symbol16_list_push(scratch.arena, &coff_symbol_list, *((COFF_Symbol16*)&secdef)); - } - - // convert relocations and symbols to coff format - { - for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { - LNK_Section *sect = §_node->data; - - // filter out resource relocations - LNK_RelocList reloc_list = {0}; - LNK_RelocList res_data_reloc_list = {0}; - for (LNK_Reloc *reloc = sect->reloc_list.first; reloc != 0; reloc = reloc->next) { - B32 is_reloc_symbol = str8_match_lit("$R", reloc->symbol->name, StringMatchFlag_RightSideSloppy); - LNK_Reloc *dst; - if (is_reloc_symbol) { - dst = lnk_reloc_list_push(sect->arena, &res_data_reloc_list); - } else { - dst = lnk_reloc_list_push(sect->arena, &reloc_list); - } - dst->chunk = reloc->chunk; - dst->type = reloc->type; - dst->apply_off = reloc->apply_off; - dst->symbol = reloc->symbol; - } - sect->reloc_list = reloc_list; - - COFF_RelocList coff_reloc_list = {0}; - for (LNK_Reloc *reloc = res_data_reloc_list.first; reloc != 0; reloc = reloc->next) { - LNK_Symbol *symbol = reloc->symbol; - - Assert(LNK_Symbol_IsDefined(symbol->type)); - Assert(symbol->u.defined.value_type == LNK_DefinedSymbolValue_Chunk); - LNK_DefinedSymbol *def = &symbol->u.defined; - - // resolve symbol offset - LNK_Section *symbol_sect = lnk_sect_from_chunk_ref(sect_id_map, def->u.chunk->ref); - U64 chunk_off = lnk_off_from_chunk_ref(sect_id_map, def->u.chunk->ref); - U64 symbol_offset = chunk_off + def->u.chunk_offset; - U64 symbol_idx = coff_symbol_list.count; - - // push coff symbol - COFF_Symbol16 coff_symbol = {0}; - Assert(symbol->name.size <= 8); - String8 symbol_name = push_str8f(scratch.arena, "$R%06X", symbol_offset); - MemoryCopyStr8(&coff_symbol.name, symbol_name); - coff_symbol.value = symbol_offset; - coff_symbol.section_number = symbol_sect->isect; - coff_symbol.storage_class = COFF_SymStorageClass_Static; - coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_symbol); - - // push coff reloc - U64 reloc_off = lnk_off_from_chunk_ref(sect_id_map, reloc->chunk->ref); - reloc_off += reloc->apply_off; - - COFF_Reloc coff_reloc = {0}; - coff_reloc.apply_off = reloc_off; - coff_reloc.isymbol = safe_cast_u32(symbol_idx); - coff_reloc.type = lnk_ext_reloc_type_to_coff(machine, reloc->type); - coff_reloc_list_push(scratch.arena, &coff_reloc_list, coff_reloc); - } - - if (coff_reloc_list.count == 0) continue; - - // push section for relocation data - String8 sect_name = push_str8f(sectab->arena, "%S.relocs", sect->name); - LNK_Section *reloc_sect = lnk_section_table_push(sectab, sect_name, 0); - reloc_sect->emit_header = 0; - - // push chunk layout for relocations - LNK_Chunk *reloc_array_chunk = lnk_section_push_chunk_list(reloc_sect, reloc_sect->root, str8_zero()); - for (COFF_RelocNode *i = coff_reloc_list.first; i != 0; i = i->next) { - String8 reloc_data = push_str8_copy(reloc_sect->arena, str8_struct(&i->data)); - lnk_section_push_chunk_data(reloc_sect, reloc_array_chunk, reloc_data, str8_zero()); - } - - // emit symbols for coff section header patch - String8 coff_reloc_symbol_name = push_str8f(symtab->arena->v[0], "%S.coff_reloc[]", sect->name); - String8 coff_reloc_count_symbol_name = push_str8f(symtab->arena->v[0], "%S.coff_reloc[].count", sect->name); - LNK_Symbol *coff_reloc_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], coff_reloc_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, reloc_array_chunk, 0, 0, 0); - LNK_Symbol *coff_reloc_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], coff_reloc_count_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_reloc_list.count); - lnk_symbol_table_push(symtab, coff_reloc_symbol); - lnk_symbol_table_push(symtab, coff_reloc_count_symbol); - } - } - - LNK_Section *misc_sect = lnk_section_table_push(sectab, str8_lit(".misc"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove); - misc_sect->emit_header = 0; - - // serialize coff symbol list - String8List srl = {0}; - str8_serial_begin(scratch.arena, &srl); - for (COFF_Symbol16Node *i = coff_symbol_list.first; i != 0; i = i->next) { - str8_serial_push_struct(scratch.arena, &srl, &i->data); - } - String8 coff_symbol_table_data = str8_serial_end(scratch.arena, &srl); - LNK_Chunk *coff_symbol_table_chunk = lnk_section_push_chunk_data(misc_sect, misc_sect->root, coff_symbol_table_data, str8_zero()); - LNK_Symbol *coff_symbol_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit("COFF_SYMBOL_TABLE"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, coff_symbol_table_symbol); - - LNK_Symbol *coff_symbol_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], str8_lit("COFF_SYMBOL_COUNT"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_list.count); - lnk_symbol_table_push(symtab, coff_symbol_count_symbol); - - // build obj header - { - // init header - COFF_FileHeader *file_header = push_array(header_sect->arena, COFF_FileHeader, 1); - file_header->machine = machine; - file_header->section_count = 0; // relocated - file_header->time_stamp = time_stamp; - file_header->symbol_table_foff = 0; // relocated - file_header->symbol_count = 0; // relocated - file_header->optional_header_size = 0; // no PE header in obj - file_header->flags = COFF_FileHeaderFlag_32BitMachine; - - // push coff header chunk - String8 file_header_data = str8_struct(file_header); - LNK_Chunk *file_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, file_header_data, str8_zero()); - - // relocate coff header fields - lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); - lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_FileHeader, symbol_table_foff), coff_symbol_table_symbol); - lnk_section_push_reloc(header_sect, file_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_FileHeader, symbol_count), coff_symbol_count_symbol); - - // push coff header symbol - LNK_Symbol *file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, file_header_symbol); - } - - // build section headers - { - LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); - for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { - if (sect_node == sectab->null_sect) continue; - if (!sect_node->data.emit_header) continue; - LNK_Section *sect = §_node->data; - - // init section header - COFF_SectionHeader *coff_sect_header = push_array(header_sect->arena, COFF_SectionHeader, 1); - Assert(sect->name.size <= sizeof(coff_sect_header->name)); - MemoryCopyStr8(&coff_sect_header->name[0], sect->name); - coff_sect_header->flags = sect->flags; - coff_sect_header->vsize = 0; // ignored - coff_sect_header->voff = 0; // ignored - coff_sect_header->fsize = 0; // relocated - coff_sect_header->foff = 0; // relocated - coff_sect_header->relocs_foff = 0; // relocated - coff_sect_header->lines_foff = 0; // obsolete - coff_sect_header->line_count = 0; // obsolete - coff_sect_header->reloc_count = 0; // relocated - - // push section header chunk - String8 coff_sect_header_data = str8_struct(coff_sect_header); - String8 sort_index = lnk_make_section_sort_index(header_sect->arena, str8_zero(), 0, sect->isect); - LNK_Chunk *coff_sect_header_chunk = lnk_section_push_chunk_data(header_sect, coff_section_header_array_chunk, coff_sect_header_data, sort_index); - lnk_chunk_set_debugf(header_sect->arena, coff_sect_header_chunk, "%S", sect->name); - - // patch reloc fields - if (sect->reloc_list.count) { - String8 coff_reloc_symbol_name = push_str8f(scratch.arena, "%S.coff_reloc[]", sect->name); - String8 coff_reloc_count_symbol_name = push_str8f(scratch.arena, "%S.coff_reloc[].count", sect->name); - lnk_section_push_reloc_undefined(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, relocs_foff), coff_reloc_symbol_name, LNK_SymbolScopeFlag_Internal); - lnk_section_push_reloc_undefined(header_sect, coff_sect_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_SectionHeader, reloc_count), coff_reloc_count_symbol_name, LNK_SymbolScopeFlag_Internal); - } - - // patch file fields - if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { - LNK_Symbol *sect_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, sect->name); - lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect_symbol); - lnk_section_push_reloc(header_sect, coff_sect_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect_symbol); - } - } - - // push section header count symbol - U64 symbol_count = coff_section_header_array_chunk->u.list->count; - LNK_Symbol *coff_section_header_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, symbol_count); - lnk_symbol_table_push(symtab, coff_section_header_count_symbol); - } - - lnk_section_table_assign_indices(sectab); - lnk_section_table_build_data(tp, sectab, machine); - lnk_section_table_assign_file_offsets(sectab); - String8 res_obj = lnk_section_table_serialize(tp, arena, sectab, machine); - sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); - lnk_patch_relocs_linker(tp, symtab, sectab, sect_id_map, res_obj, 0); - lnk_section_table_release(§ab); - - arena_release(temp_tp_arena->v[0]); - scratch_end(scratch); + coff_obj_writer_release(&obj_writer); + ProfEnd(); return res_obj; } @@ -986,11 +734,10 @@ lnk_obj_from_res_file_list(TP_Context *tp, String8List exe_path_strs = {0}; str8_list_push(scratch.arena, &exe_path_strs, process_info->binary_path); String8 exe_path = str8_list_first(&exe_path_strs); - String8 res_obj = lnk_make_res_obj(tp, - arena, + String8 res_obj = lnk_make_res_obj(arena, root_dir, - machine, time_stamp, + machine, obj_name, work_dir, exe_path, diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 2790fa60..c7fc306d 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -89,6 +89,8 @@ #define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS #define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS +#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes)) +#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes)) #define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS #define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS @@ -262,9 +264,9 @@ internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, Str //////////////////////////////// // Resources -internal void lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir); -internal void lnk_add_resource_debug_s(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array); -internal String8 lnk_make_res_obj(TP_Context *tp, Arena *arena, PE_ResourceDir *root_dir, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array); +internal void lnk_serialize_pe_resource_tree(COFF_ObjWriter *obj_writer, PE_ResourceDir *root_dir); +internal void lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array); +internal String8 lnk_make_res_obj(Arena *arena, PE_ResourceDir *root_dir, COFF_TimeStamp time_stamp, COFF_MachineType machine, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array); internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); ////////////////////////////////