From a6b2cf64ba6c34a563dd8cb3f428e9e0a80ad6a9 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Wed, 16 Jul 2025 15:37:52 -0700 Subject: [PATCH] WIP collect sections associations --- src/base/base_core.h | 3 +- src/coff/coff_parse.c | 2 +- src/linker/base_ext/base_arrays.h | 6 ++ src/linker/lnk.c | 2 - src/linker/lnk_obj.c | 44 ++++++++++++--- src/linker/lnk_obj.h | 3 +- src/linker/lnk_symbol_table.c | 94 ++++++++++++++++++++----------- 7 files changed, 107 insertions(+), 47 deletions(-) diff --git a/src/base/base_core.h b/src/base/base_core.h index 26e08d64..319837ba 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -348,7 +348,8 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s #endif #define PtrFromInt(i) (void*)(i) -#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b)); +#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b)) +#define Compose32Bit(a,b) ((((U32)a) << 16) | ((U32)b)) #define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1))) #define AlignDownPow2(x,b) ((x)&(~((b) - 1))) #define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1)) diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c index 9d734c48..f8b2a3a4 100644 --- a/src/coff/coff_parse.c +++ b/src/coff/coff_parse.c @@ -296,7 +296,7 @@ coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectTyp if (selection_out) *selection_out = sd->selection; if (length_out) *length_out = sd->length; if (check_sum_out) *check_sum_out = sd->check_sum; - if (number_out) *number_out = sd->number_lo | ((U32)sd->number_hi << 16); + if (number_out) *number_out = Compose32Bit(sd->number_hi, sd->number_lo); } else { COFF_SymbolSecDef *sd = (COFF_SymbolSecDef *)((COFF_Symbol16 *)symbol.raw_symbol + 1); if (selection_out) *selection_out = sd->selection; diff --git a/src/linker/base_ext/base_arrays.h b/src/linker/base_ext/base_arrays.h index b2c45bd5..1c6f6f4d 100644 --- a/src/linker/base_ext/base_arrays.h +++ b/src/linker/base_ext/base_arrays.h @@ -3,6 +3,12 @@ #pragma once +typedef struct U32Node +{ + struct U32Node *next; + U32 data; +} U32Node; + typedef struct U64Node { struct U64Node *next; diff --git a/src/linker/lnk.c b/src/linker/lnk.c index a62701c4..6ac30d13 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -4053,8 +4053,6 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT .null_sc = push_array(arena->v[0], LNK_SectionContrib, 1), }; - tp_for_parallel(tp, 0, objs_count, lnk_remove_associative_sections_task, &task); - { ProfBegin("Define And Count Sections"); TP_Temp temp = tp_temp_begin(arena); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 0d161af7..8ce4827e 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -224,6 +224,31 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) scratch_end(scratch); } + + // + // collect sections associations + // + U32Node **associated_sections = push_array(arena, U32Node *, header.section_count_no_null + 1); + { + String8 string_table = str8_substr(input->data, header.string_table_range); + String8 symbol_table = str8_substr(input->data, header.symbol_table_range); + + COFF_ParsedSymbol symbol; + for (U32 symbol_idx = 0; symbol_idx < header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = coff_parse_symbol(header, string_table, symbol_table, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); + if (interp == COFF_SymbolValueInterp_Regular && symbol.storage_class == COFF_SymStorageClass_Static && symbol.aux_symbol_count > 0) { + COFF_ComdatSelectType selection = COFF_ComdatSelect_Null; + U32 section_number = 0; + coff_parse_secdef(symbol, header.is_big_obj, &selection, §ion_number, 0, 0); + if (selection != COFF_ComdatSelect_Associative) { continue; } + + U32Node *associated_node = push_array(arena, U32Node, 1); + associated_node->data = symbol.section_number; + SLLStackPush(associated_sections[section_number], associated_node); + } + } + } // // extract obj features from compile symbol in .debug$S @@ -267,13 +292,14 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) } // fill out obj - obj->data = input->data; - obj->path = push_str8_copy(arena, input->path); - obj->lib_path = push_str8_copy(arena, input->lib_path); - obj->input_idx = obj_idx; - obj->header = header; - obj->comdats = comdats; - obj->hotpatch = hotpatch; + obj->data = input->data; + obj->path = push_str8_copy(arena, input->path); + obj->lib_path = push_str8_copy(arena, input->lib_path); + obj->input_idx = obj_idx; + obj->header = header; + obj->comdats = comdats; + obj->hotpatch = hotpatch; + obj->associated_sections = associated_sections; ProfEnd(); } @@ -466,13 +492,13 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number) } internal B32 -lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_length_out, U32 *check_sum_out) +lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out) { Assert(section_number > 0); U32 symbol_idx = obj->comdats[section_number-1]; if (symbol_idx != max_U32) { COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx); - coff_parse_secdef(secdef, obj->header.is_big_obj, select_out, 0, section_length_out, check_sum_out); + coff_parse_secdef(secdef, obj->header.is_big_obj, select_out, section_number_out, section_length_out, check_sum_out); return 1; } return 0; diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 5a844569..1f0d08f3 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -14,6 +14,7 @@ typedef struct LNK_Obj COFF_FileHeaderInfo header; U32 *comdats; B8 hotpatch; + U32Node **associated_sections; } LNK_Obj; typedef struct LNK_ObjNode @@ -109,7 +110,7 @@ internal U32 lnk_obj_get_vol_md(LNK_Obj *obj); internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff(LNK_Obj *obj, void *coff_symbol); internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx); internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number); -internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_length_out, U32 *check_sum_out); +internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out); internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx); // --- Helpers ----------------------------------------------------------------- diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 9c732876..89c5f66e 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -193,7 +193,7 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) U32 dst_section_length; U32 dst_check_sum; if (dst_interp == COFF_SymbolValueInterp_Regular) { - dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->u.defined.obj, dst_parsed.section_number, &dst_select, &dst_section_length, &dst_check_sum); + dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->u.defined.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum); } else if (dst_interp == COFF_SymbolValueInterp_Common) { dst_select = COFF_ComdatSelect_Largest; dst_section_length = dst_parsed.value; @@ -207,7 +207,7 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) U32 src_section_length, src_checks; U32 src_check_sum; if (src_interp == COFF_SymbolValueInterp_Regular) { - src_is_comdat = lnk_try_comdat_props_from_section_number(src->u.defined.obj, src_parsed.section_number, &src_select, &src_section_length, &src_check_sum); + src_is_comdat = lnk_try_comdat_props_from_section_number(src->u.defined.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum); } else if (src_interp == COFF_SymbolValueInterp_Common) { src_select = COFF_ComdatSelect_Largest; src_section_length = src_parsed.value; @@ -308,23 +308,44 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) internal void lnk_on_symbol_replace(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) { - Assert(dst != src); - if (scope == LNK_SymbolScope_Lib) { - dst->u.lib = src->u.lib; - } else if (scope == LNK_SymbolScope_Defined) { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); - COFF_SymbolValueInterpType dst_interp = coff_interp_symbol(dst_parsed.section_number, dst_parsed.value, dst_parsed.storage_class); - COFF_SymbolValueInterpType src_interp = coff_interp_symbol(src_parsed.section_number, src_parsed.value, src_parsed.storage_class); + switch (scope) { + case LNK_SymbolScope_Defined: { + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx); + COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); if (dst_interp == COFF_SymbolValueInterp_Regular) { + // remove replaced section from the output COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->u.defined.obj, dst_parsed.section_number); dst_sect->flags |= COFF_SectionFlag_LnkRemove; - dst->u.defined = src->u.defined; + + // remove associated sections from the output + for (U32Node *associated_section = dst->u.defined.obj->associated_sections[dst_parsed.section_number]; + associated_section != 0; + associated_section = associated_section->next) { + COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->u.defined.obj, associated_section->data); + section_header->flags |= COFF_SectionFlag_LnkRemove; + } } - if (src_interp == COFF_SymbolValueInterp_Regular) { - COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->u.defined.obj, src_parsed.section_number); - AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); + + // make sure leader section is not removed from the output +#if BUILD_DEBUG + { + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx); + COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); + if (src_interp == COFF_SymbolValueInterp_Regular) { + COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->u.defined.obj, src_parsed.section_number); + AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); + } } +#endif + } break; + case LNK_SymbolScope_Import: { + // illegal to replace imports + InvalidPath; + } break; + case LNK_SymbolScope_Lib: { + // nothing to replace + } break; + default: { InvalidPath; } } } @@ -551,31 +572,38 @@ THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task) break; } - // record visited symbol - struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1); - loc->symbol = current_symbol; - SLLQueuePush(lookup_first, lookup_last, loc); - COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx); COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class); - if (current_interp != COFF_SymbolValueInterp_Weak && current_interp != COFF_SymbolValueInterp_Undefined) { - break; - } + if (current_interp == COFF_SymbolValueInterp_Weak) { + // record visited symbol + struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1); + loc->symbol = current_symbol; + SLLQueuePush(lookup_first, lookup_last, loc); - // does weak symbol have the strong definition? - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx); - COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); - if (defn_interp != COFF_SymbolValueInterp_Weak) { + // does weak symbol have a definition? + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx); + COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class); + if (defn_interp != COFF_SymbolValueInterp_Weak) { + current_symbol = defn_symbol->u.defined; + break; + } + + // no definition fallback to the tag + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); + COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); + COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); + current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; + } else if (current_interp == COFF_SymbolValueInterp_Undefined) { + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + if (defn_symbol == 0) { + MemoryZeroStruct(¤t_symbol); + break; + } current_symbol = defn_symbol->u.defined; + } else { break; } - - // no strong definition fallback to the tag - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj); - COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index); - COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class); - current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index }; } // replace weak symbol with it's tag