From dd715dacf75dd1f3236a3bb02c56e2045a8a10be Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Fri, 1 Aug 2025 11:41:20 -0700 Subject: [PATCH] assign COMDAT symlinks as soon as the symbol table is processed --- src/linker/lnk.c | 43 +++++++-------------- src/linker/lnk.h | 1 - src/linker/lnk_obj.c | 73 ++++++++++++++++++----------------- src/linker/lnk_obj.h | 28 +++++++------- src/linker/lnk_symbol_table.c | 10 ++++- 5 files changed, 74 insertions(+), 81 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7ed2f76a..ce3cc0de 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1021,10 +1021,6 @@ THREAD_POOL_TASK_FUNC(lnk_undef_symbol_finder) for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { LNK_SymbolNode *symbol_n = task->lookup_node_arr.v[symbol_idx]; LNK_Symbol *symbol = symbol_n->data; - - if (str8_match(symbol->name, str8_lit("return_1"), 0)) { - int x = 0; - } LNK_Symbol *has_defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol->name); if (has_defn) { @@ -2110,15 +2106,14 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } internal B32 -lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol **symlinks, LNK_SymbolDefined symbol, LNK_SymbolDefined *symbol_out) +lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_SymbolDefined *symbol_out) { B32 is_resolved = 1; COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx); COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class); switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { - COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(symbol.obj, symbol_parsed.section_number); - LNK_Symbol *symlink = section_header->flags & COFF_SectionFlag_LnkCOMDAT ? symlinks[symbol_parsed.section_number] : 0; + LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); *symbol_out = symlink ? symlink->u.defined : symbol; } break; case COFF_SymbolValueInterp_Weak: { @@ -2157,12 +2152,7 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol **symlinks, LNK_SymbolDef } internal void -lnk_gc_comdats(TP_Context *tp, - LNK_SymbolTable *symtab, - U64 objs_count, - LNK_Obj **objs, - LNK_Symbol ***symlinks, - LNK_Config *config) +lnk_gc_comdats(TP_Context *tp, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, LNK_Config *config) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); @@ -2252,7 +2242,7 @@ lnk_gc_comdats(TP_Context *tp, for EachIndex(reloc_idx, t->relocs.count) { COFF_Reloc *reloc = &t->relocs.v[reloc_idx]; LNK_SymbolDefined reloc_symbol = {0}; - B32 is_reloc_symbol_resolved = lnk_resolve_symbol(symtab, symlinks[t->obj->input_idx], (LNK_SymbolDefined){ .obj = t->obj, .symbol_idx = reloc->isymbol }, &reloc_symbol); + B32 is_reloc_symbol_resolved = lnk_resolve_symbol(symtab, (LNK_SymbolDefined){ .obj = t->obj, .symbol_idx = reloc->isymbol }, &reloc_symbol); if (is_reloc_symbol_resolved) { // parse and interp reloc symbol LNK_Obj *reloc_obj = reloc_symbol.obj; @@ -2452,7 +2442,7 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number); if (~section_header->flags & COFF_SectionFlag_LnkCOMDAT) { continue; } - LNK_Symbol *symlink = task->symlinks[obj_idx][section_number]; + LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, section_number); if (symlink == 0) { continue; } COFF_ParsedSymbol symlink_parsed = lnk_parsed_symbol_from_defined(symlink); @@ -2479,7 +2469,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Regular) { - LNK_Symbol *symlink = task->symlinks[obj_idx][symbol.section_number]; + LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number); if (symlink && symlink->u.defined.obj != obj) { U32 section_number; U32 value; @@ -2667,7 +2657,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_regular_symbols_task) } internal void -lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Symbol **symlinks, LNK_Obj *obj, B8 *was_symbol_patched, COFF_SymbolValueInterpType fixup_type) +lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patched, COFF_SymbolValueInterpType fixup_type) { ProfBeginV("%S\n", obj->path); @@ -2681,7 +2671,7 @@ lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Symbol **symlinks, LNK_Obj *ob LNK_SymbolDefined symbol_to_resolve = { .obj = obj, .symbol_idx = symbol_idx }; LNK_SymbolDefined fixup_symbol = {0}; - B32 is_resolved = lnk_resolve_symbol(symtab, symlinks, symbol_to_resolve, &fixup_symbol); + B32 is_resolved = lnk_resolve_symbol(symtab, symbol_to_resolve, &fixup_symbol); if (is_resolved) { COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx); COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class); @@ -2714,28 +2704,28 @@ internal THREAD_POOL_TASK_FUNC(lnk_patch_common_symbols_task) { LNK_BuildImageTask *task = raw_task; - lnk_patch_obj_symtab(task->symtab, task->symlinks[task_id], task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Common); + lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Common); } internal THREAD_POOL_TASK_FUNC(lnk_patch_abs_symbols_task) { LNK_BuildImageTask *task = raw_task; - lnk_patch_obj_symtab(task->symtab, task->symlinks[task_id], task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Abs); + lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Abs); } internal THREAD_POOL_TASK_FUNC(lnk_patch_undefined_symbols_task) { LNK_BuildImageTask *task = raw_task; - lnk_patch_obj_symtab(task->symtab, task->symlinks[task_id], task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Undefined); + lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Undefined); } internal THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_task) { LNK_BuildImageTask *task = raw_task; - lnk_patch_obj_symtab(task->symtab, task->symlinks[task_id], task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Weak); + lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Weak); } internal U64 @@ -3849,17 +3839,11 @@ lnk_build_image(TP_Arena *arena, Temp scratch = scratch_begin(arena->v, arena->count); - // - // gather symbol links to COMDAT sections - // - LNK_Symbol ***symlinks = push_array(arena->v[0], LNK_Symbol **, objs_count); - for EachIndex(obj_idx, objs_count) { symlinks[obj_idx] = lnk_symlinks_from_obj(scratch.arena, symtab, objs[obj_idx]); } - // // remove unreachable COMDAT sections // if (config->opt_ref == LNK_SwitchState_Yes) { - lnk_gc_comdats(tp, symtab, objs_count, objs, symlinks, config); + lnk_gc_comdats(tp, symtab, objs_count, objs, config); } // @@ -3880,7 +3864,6 @@ lnk_build_image(TP_Arena *arena, .function_pad_min = config->function_pad_min, .default_align = coff_default_align_from_machine(config->machine), .null_sc = push_array(arena->v[0], LNK_SectionContrib, 1), - .symlinks = symlinks, }; { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 2f579854..a9e72113 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -81,7 +81,6 @@ typedef struct U64 function_pad_min; U64 default_align; LNK_SectionContrib *null_sc; - LNK_Symbol ***symlinks; LNK_SectionContrib ***sect_map; HashTable *contribs_ht; LNK_SectionArray image_sects; diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 557620cb..38cbce44 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -346,24 +346,11 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) LNK_InputCoffSymbolTable *task = raw_task; LNK_Obj *obj = &task->objs.v[task_id].data; - // - // parse obj header - // - COFF_FileHeaderInfo header = coff_file_header_info_from_data(obj->data); - - // - // extract COFF info - // - String8 raw_coff_section_table = str8_substr(obj->data, header.section_table_range); - String8 raw_coff_symbol_table = str8_substr(obj->data, header.symbol_table_range); - String8 raw_coff_string_table = str8_substr(obj->data, header.string_table_range); - COFF_ParsedSymbol symbol = {0}; - for (U64 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - // read symbol + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); switch (interp) { case COFF_SymbolValueInterp_Regular: { if (symbol.storage_class == COFF_SymStorageClass_External) { @@ -411,6 +398,34 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) } } +internal LNK_SymbolHashTrie ** +lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj) +{ + LNK_SymbolHashTrie **symlinks = push_array(arena, LNK_SymbolHashTrie *, obj->header.section_count_no_null+1); + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); + if (interp == COFF_SymbolValueInterp_Regular && symbol.aux_symbol_count == 0 && symbol.storage_class == COFF_SymStorageClass_External) { + COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); + if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { + if (symlinks[symbol.section_number] == 0 || symbol.value == 0) { + symlinks[symbol.section_number] = lnk_symbol_table_search_(symtab, LNK_SymbolScope_Defined, symbol.name); + } + } + } + } + return symlinks; +} + +internal +THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task) +{ + LNK_InputCoffSymbolTable *task = raw_task; + LNK_Obj *obj = &task->objs.v[task_id].data; + obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj); +} + internal LNK_SymbolInputResult lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs) { @@ -423,6 +438,7 @@ lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, task.weak_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count); task.undef_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count); tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task); + tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task); LNK_SymbolInputResult result = {0}; SLLConcatInPlaceArray(&result.weak_symbols, task.weak_lists, tp->worker_count); @@ -499,6 +515,13 @@ lnk_obj_get_removed_section_number(LNK_Obj *obj) return obj->header.is_big_obj ? LNK_REMOVED_SECTION_NUMBER_32 : LNK_REMOVED_SECTION_NUMBER_16; } +internal LNK_Symbol * +lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number) +{ + LNK_SymbolHashTrie *symlink = obj->symlinks[section_number]; + return symlink ? symlink->symbol : 0; +} + internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number) { @@ -513,26 +536,6 @@ lnk_coff_section_table_from_obj(LNK_Obj *obj) return (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; } -internal LNK_Symbol ** -lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj) -{ - LNK_Symbol **symlinks = push_array(arena, LNK_Symbol *, obj->header.section_count_no_null+1); - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular && symbol.aux_symbol_count == 0 && symbol.storage_class == COFF_SymStorageClass_External) { - COFF_SectionHeader *sect_header = lnk_coff_section_header_from_section_number(obj, symbol.section_number); - if (sect_header->flags & COFF_SectionFlag_LnkCOMDAT) { - if (symlinks[symbol.section_number] == 0 || symbol.value == 0) { - symlinks[symbol.section_number] = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol.name); - } - } - } - } - return symlinks; -} - internal COFF_RelocArray lnk_coff_reloc_info_from_section_number(LNK_Obj *obj, U64 section_number) { diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index e3f44fda..78510b80 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -7,14 +7,15 @@ typedef struct LNK_Obj { - String8 data; - String8 path; - struct LNK_Lib *lib; - U32 input_idx; - COFF_FileHeaderInfo header; - U32 *comdats; - B8 hotpatch; - U32Node **associated_sections; + String8 data; + String8 path; + struct LNK_Lib *lib; + U32 input_idx; + COFF_FileHeaderInfo header; + U32 *comdats; + B8 hotpatch; + U32Node **associated_sections; + LNK_SymbolHashTrie **symlinks; } LNK_Obj; typedef struct LNK_ObjNode @@ -101,11 +102,12 @@ internal LNK_SymbolInputResult lnk_input_obj_symbols(TP_Context *tp, TP_Arena *a // --- Metadata ---------------------------------------------------------------- -internal U32 lnk_obj_get_features(LNK_Obj *obj); -internal U32 lnk_obj_get_comp_id(LNK_Obj *obj); -internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); -internal String8 lnk_obj_get_lib_path(LNK_Obj *obj); -internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj); +internal U32 lnk_obj_get_features(LNK_Obj *obj); +internal U32 lnk_obj_get_comp_id(LNK_Obj *obj); +internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); +internal String8 lnk_obj_get_lib_path(LNK_Obj *obj); +internal U32 lnk_obj_get_removed_section_number(LNK_Obj *obj); +internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_number); // --- Symbol & Section Helpers ------------------------------------------------ diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index babde339..e34046da 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -489,11 +489,17 @@ lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, scope, symbol); } +internal LNK_SymbolHashTrie * +lnk_symbol_table_search_(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) +{ + U64 hash = lnk_symbol_hash(name); + return lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name); +} + internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) { - U64 hash = lnk_symbol_hash(name); - LNK_SymbolHashTrie *trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name); + LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, scope, name); return trie ? trie->symbol : 0; }