diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 5bf7bb5b..f23c5eac 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -969,22 +969,11 @@ internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, - LNK_Symbol *member_symbol, + LNK_Lib *lib, + U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { - // lookup member in the lib where pull-in reference is declared - LNK_Symbol *best_match = member_symbol; - for (LNK_Symbol *s = member_symbol; s != 0; s = s->u.member.next) { - if (s->u.member.v.lib == pull_in_ref->u.defined.obj->lib) { - best_match = s; - break; - } - } - - LNK_Lib *lib = best_match->u.member.v.lib; - U32 member_idx = best_match->u.member.v.member_idx; - B32 was_member_queued = ins_atomic_u8_eval_assign(&lib->was_member_queued[member_idx], 1); if (!was_member_queued) { U64 member_offset = lib->member_offsets[member_idx]; @@ -992,7 +981,7 @@ lnk_queue_lib_member_for_input(Arena *arena, // compose input index so that members are laid out in the image // in the order of undefined symbols appearing in objs, // mimicking serial discovery - U64 input_idx = Compose64Bit(pull_in_ref->u.defined.obj->input_idx, pull_in_ref->u.defined.symbol_idx); + U64 input_idx = Compose64Bit(pull_in_ref->defined.obj->input_idx, pull_in_ref->defined.symbol_idx); // parse member COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); @@ -1067,20 +1056,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj String8List roots = str8_list_copy(scratch.arena, &config->include_symbol_list); // tls - LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); + LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME); if (tls_symbol) { str8_list_pushf(scratch.arena, &roots, MSCRT_TLS_SYMBOL_NAME); } // push tasks for each root symbol for (String8Node *root_n = roots.first; root_n != 0; root_n = root_n->next) { - LNK_Symbol *root = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, root_n->string); + LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->string); struct Task *t = push_array(scratch.arena, struct Task, 1); - t->obj = root->u.defined.obj; + t->obj = root->defined.obj; t->relocs.count = 1; t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1); - t->relocs.v[0].isymbol = root->u.defined.symbol_idx; + t->relocs.v[0].isymbol = root->defined.symbol_idx; SLLStackPush(task_stack, t); } @@ -1133,20 +1122,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj if (ref_interp == COFF_SymbolValueInterp_Regular) { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number); if (symlink) { - ref_symbol = symlink->u.defined; + ref_symbol = symlink->defined; } break; } else if (ref_interp == COFF_SymbolValueInterp_Undefined) { if (reloc_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - next_ref = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = defn->defined; } else { MemoryZeroStruct(&ref_symbol); break; } } else if (ref_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, ref_parsed.name); - next_ref = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name); + next_ref = defn->defined; } else { break; } @@ -1247,12 +1236,12 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp == COFF_SymbolValueInterp_Weak) { - LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->u.defined); + LNK_SymbolDefined resolve = lnk_resolve_weak_symbol(symtab, symbol->defined); COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx); COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed); if (resolve_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->u.defined.obj->header.is_big_obj); - if (symbol->u.defined.obj->header.is_big_obj) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->defined.obj->header.is_big_obj); + if (symbol->defined.obj->header.is_big_obj) { COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol; symbol32->section_number = COFF_Symbol_UndefinedSection; symbol32->value = 0; @@ -1264,7 +1253,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task) symbol16->storage_class = COFF_SymStorageClass_External; } } else { - symbol->u.defined = resolve; + symbol->defined = resolve; } } } @@ -1391,11 +1380,11 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) hash_table_push_string_raw(ht_arena, import_stub_ht, import_header.func_name, 0); // create import stubs (later replaced with acutal imports generated by linker) - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); - LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->u.defined.obj, import_stub->u.defined.symbol_idx); - lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, thunk_symbol); - lnk_symbol_table_push(symtab, LNK_SymbolScope_Defined, imp_symbol); + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); + LNK_Symbol *thunk_symbol = lnk_make_defined_symbol(symtab->arena->v[0], import_header.func_name, import_stub->defined.obj, import_stub->defined.symbol_idx); + LNK_Symbol *imp_symbol = lnk_make_defined_symbol(symtab->arena->v[0], push_str8f(scratch.arena, "__imp_%S", import_header.func_name), import_stub->defined.obj, import_stub->defined.symbol_idx); + lnk_symbol_table_push(symtab, thunk_symbol); + lnk_symbol_table_push(symtab, imp_symbol); // pick imports hash table HashTable *imports_ht = lnk_is_dll_delay_load(config, import_header.dll_name) ? delayed_imports : static_imports; @@ -1410,6 +1399,8 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // push symbol str8_list_push(scratch.arena, import_symbols, input->data.coff_import); } + + search_flags = SearchFlag_All; // reset input MemoryZeroStruct(&input_import_list); @@ -1528,7 +1519,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // replace undefined symbols that have an alternate name with a weak symbol for (LNK_AltNameNode *alt_name_n = config->alt_name_list.first; alt_name_n != 0; alt_name_n = alt_name_n->next) { - LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, LNK_SymbolScope_Defined, alt_name_n->data.from); + LNK_SymbolHashTrie *symbol_ht = lnk_symbol_table_search_(symtab, alt_name_n->data.from); if (symbol_ht) { COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(symbol_ht->symbol); if (interp == COFF_SymbolValueInterp_Undefined) { @@ -1631,8 +1622,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) ProfBegin("Lib Init"); LNK_LibNodeArray libs = lnk_lib_list_push_parallel(tp, tp_arena, &lib_index[input_source], datas, paths); ProfEnd(); - - lnk_input_lib_symbols(tp, symtab, libs); if (lnk_get_log_status(LNK_Log_InputLib)) { if (libs.count > 0) { @@ -1669,70 +1658,95 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) } break; case State_SearchUndefined: { ProfBegin("Search Undefined"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); - } - } - } - } - } - ProfEnd(); - } break; - case State_SearchWeak: { - ProfBegin("Search Weak"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol->name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); - } - } - } - } - } - } - ProfEnd(); - } break; - case State_SearchWeakAntiDep: { - ProfBegin("Search Weak AntiDep"); - for EachIndex(worker_id, symtab->arena->count) { - for (LNK_SymbolHashTrieChunk *c = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; c != 0; c = c->next) { - for EachIndex(i, c->count) { - LNK_Symbol *symbol = c->v[i].symbol; - COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); - if (symbol_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { - LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->u.defined); - COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); - COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); - if (dep_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *member_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, symbol_parsed.name); - if (member_symbol) { - lnk_queue_lib_member_for_input(scratch.arena, config, symbol, member_symbol, &input_import_list, &input_obj_list); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Undefined) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); } } } } } + if (input_import_list.count || input_obj_list.count) { + goto end_search_undefined; + } } } + end_search_undefined:; + ProfEnd(); + } break; + case State_SearchWeak: { + ProfBegin("Search Weak"); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + } + } + } + } + } + } + if (input_import_list.count || input_obj_list.count) { + goto end_search_weak; + } + } + } + end_search_weak:; + ProfEnd(); + } break; + case State_SearchWeakAntiDep: { + ProfBegin("Search Weak AntiDep"); + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + for EachIndex(worker_id, symtab->arena->count) { + for (LNK_SymbolHashTrieChunk *c = symtab->chunks[worker_id].first; c != 0; c = c->next) { + for EachIndex(i, c->count) { + LNK_Symbol *symbol = c->v[i].symbol; + COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); + COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); + if (symbol_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { + LNK_SymbolDefined dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->defined); + COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx); + COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed); + if (dep_interp == COFF_SymbolValueInterp_Weak) { + U32 member_idx; + if (lnk_search_lib(&lib_n->data, symbol_parsed.name, &member_idx)) { + lnk_queue_lib_member_for_input(scratch.arena, config, symbol, &lib_n->data, member_idx, &input_import_list, &input_obj_list); + } + } + } + } + } + } + } + + if (input_import_list.count || input_obj_list.count) { + goto end_search_antidep; + } + } + } + end_search_antidep:; ProfEnd(); } break; case State_SearchEntryPoint: { @@ -1748,23 +1762,28 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); + entry_point_symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); if (entry_point_symbol) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->entry_point_name = name_arr.v[entry_idx]; goto dbl_break; } } } // search for potential entry points in libs - if (!entry_point_symbol) { + if (config->entry_point_name.size) { for EachIndex(subsys_idx, PE_WindowsSubsystem_COUNT) { String8Array name_arr = pe_get_entry_point_names(config->machine, (PE_WindowsSubsystem)subsys_idx, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); - if (entry_point_symbol) { - config->subsystem = (PE_WindowsSubsystem)subsys_idx; - goto dbl_break; + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { + config->subsystem = (PE_WindowsSubsystem)subsys_idx; + config->entry_point_name = name_arr.v[entry_idx]; + goto dbl_break; + } + } } } } @@ -1776,42 +1795,44 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) // and see which is in the symbol table String8Array name_arr = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics); for EachIndex(entry_idx, name_arr.count) { - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, name_arr.v[entry_idx]); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name_arr.v[entry_idx]); if (symbol) { - if (entry_point_symbol) { + if (config->entry_point_name.size) { lnk_error(LNK_Error_EntryPoint, "multiple entry point symbols found: %S(%S) and %S(%S)", - entry_point_symbol->name, entry_point_symbol->u.defined.obj->path, - symbol->name, symbol->u.defined.obj->path); + entry_point_symbol->name, entry_point_symbol->defined.obj->path, + symbol->name, symbol->defined.obj->path); } else { - entry_point_symbol = symbol; + config->entry_point_name = name_arr.v[entry_idx]; } } } // search for entry point in libs - if (!entry_point_symbol) { + if (!config->entry_point_name.size) { for EachIndex(entry_idx, name_arr.count) { - entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Lib, name_arr.v[entry_idx]); - if (entry_point_symbol) { - break; + for EachIndex(i, ArrayCount(lib_index)) { + for (LNK_LibNode *lib_n = lib_index[i].first; lib_n != 0; lib_n = lib_n->next) { + if (lnk_search_lib(&lib_n->data, name_arr.v[entry_idx], 0)) { + config->entry_point_name = name_arr.v[entry_idx]; + goto dbl_break2; + } + } } } + dbl_break2:; } } // redirect user entry to appropriate CRT entry - if (entry_point_symbol) { - config->entry_point_name = entry_point_symbol->name; - if (str8_match_lit("wmain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wmainCRTStartup"); - } else if (str8_match_lit("main", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("mainCRTStartup"); - } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("WinMainCRTStartup"); - } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { - config->entry_point_name = str8_lit("wWinMainCRTStartup"); - } + if (str8_match_lit("wmain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("wmainCRTStartup"); + } else if (str8_match_lit("main", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("mainCRTStartup"); + } else if (str8_match_lit("WinMain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("WinMainCRTStartup"); + } else if (str8_match_lit("wWinMain", config->entry_point_name, 0)) { + config->entry_point_name = str8_lit("wWinMainCRTStartup"); } } @@ -1822,7 +1843,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) str8_list_push(scratch.arena, &value_strings, config->entry_point_name); lnk_apply_cmd_option_to_config(tp_arena->v[0], config, str8_lit("include"), value_strings, 0); } - // no entry point, error and exit + // no entry point, print out error and exit else { lnk_error(LNK_Error_EntryPoint, "unable to find entry point symbol"); } @@ -1968,7 +1989,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) if (!exp->is_forwarder) { // filter out unresolved exports - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, exp_n->data.name); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, exp_n->data.name); if (symbol == 0) { lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "unresolved export symbol %S\n", exp->name); continue; @@ -2170,7 +2191,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) { U64 chunks_count = 0; - LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count); + LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count); ProfBegin("Replace Unresolved Weak Symbols With Defualt Symbol"); { @@ -2220,7 +2241,7 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config) for EachIndex(i, count) { LNK_Symbol *symbol = unresolved[i]; - lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->u.defined.obj, "unresolved symbol %S", symbol->name); + lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->defined.obj, "unresolved symbol %S", symbol->name); } // TODO: /FORCE @@ -2289,34 +2310,34 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_Symbol switch (symbol_interp) { case COFF_SymbolValueInterp_Regular: { LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number); - *symbol_out = symlink ? symlink->u.defined : symbol; + *symbol_out = symlink ? symlink->defined : symbol; } break; case COFF_SymbolValueInterp_Weak: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->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_Undefined) { - *symbol_out = defn->u.defined; + *symbol_out = defn->defined; } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Undefined: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); if (defn) { - *symbol_out = defn->u.defined; + *symbol_out = defn->defined; } else { is_resolved = 0; } } break; case COFF_SymbolValueInterp_Common: { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - *symbol_out = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + *symbol_out = defn->defined; } break; case COFF_SymbolValueInterp_Abs: { if (symbol_parsed.storage_class == COFF_SymStorageClass_External) { - LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name); - *symbol_out = defn->u.defined; + LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name); + *symbol_out = defn->defined; } else { *symbol_out = symbol; } @@ -2442,7 +2463,7 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task) if (symlink == 0) { continue; } COFF_ParsedSymbol symlink_parsed = lnk_parsed_symbol_from_defined(symlink); - task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->u.defined.obj->input_idx][symlink_parsed.section_number - 1]; + task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->defined.obj->input_idx][symlink_parsed.section_number - 1]; } ProfEnd(); } @@ -2485,12 +2506,12 @@ 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 = lnk_obj_get_comdat_symlink(obj, symbol.section_number); - if (symlink && symlink->u.defined.obj != obj) { + if (symlink && symlink->defined.obj != obj) { U32 section_number; U32 value; if (symbol.storage_class == COFF_SymStorageClass_External) { // COMDAT leader may be at a different offset, so update this symbol with leader's offset - COFF_ParsedSymbol parsed_symlink = lnk_parsed_symbol_from_coff_symbol_idx(symlink->u.defined.obj, symlink->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symlink = lnk_parsed_symbol_from_coff_symbol_idx(symlink->defined.obj, symlink->defined.symbol_idx); section_number = symbol.section_number; value = parsed_symlink.value; } else { @@ -2548,10 +2569,10 @@ lnk_common_block_contrib_is_before(void *raw_a, void *raw_b) if (a->u.size == b->u.size) { LNK_Symbol *a_symbol = a->symbol; LNK_Symbol *b_symbol = b->symbol; - if (a_symbol->u.defined.obj->input_idx == b_symbol->u.defined.obj->input_idx) { - is_before = a_symbol->u.defined.symbol_idx < b_symbol->u.defined.symbol_idx; + if (a_symbol->defined.obj->input_idx == b_symbol->defined.obj->input_idx) { + is_before = a_symbol->defined.symbol_idx < b_symbol->defined.symbol_idx; } else { - is_before = a_symbol->u.defined.obj->input_idx < b_symbol->u.defined.obj->input_idx; + is_before = a_symbol->defined.obj->input_idx < b_symbol->defined.obj->input_idx; } } else { is_before = a->u.size > b->u.size; @@ -2571,8 +2592,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) { LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx]; LNK_Symbol *symbol = contrib->symbol; - LNK_Obj *obj = symbol->u.defined.obj; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->u.defined.symbol_idx); + LNK_Obj *obj = symbol->defined.obj; + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->defined.symbol_idx); U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1; if (obj->header.is_big_obj) { @@ -2585,7 +2606,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task) symbol16->section_number = safe_cast_u16(section_number); } - task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->u.defined.symbol_idx] = 1; + task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->defined.symbol_idx] = 1; } ProfEnd(); @@ -2605,8 +2626,8 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task) COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); if (interp == COFF_SymbolValueInterp_Common) { - LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name); - COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx); + LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->defined.obj, defn->defined.symbol_idx); Assert(coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class) == COFF_SymbolValueInterp_Regular); if (defn) { if (obj->header.is_big_obj) { @@ -2880,10 +2901,10 @@ THREAD_POOL_TASK_FUNC(lnk_count_common_block_contribs_task) LNK_BuildImageTask *task = raw_task; LNK_SymbolTable *symtab = task->symtab; - for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { + for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { task->u.common_block.counts[task_id] += 1; @@ -2899,10 +2920,10 @@ THREAD_POOL_TASK_FUNC(lnk_fill_out_common_block_contribs_task) LNK_SymbolTable *symtab = task->symtab; U64 cursor = task->u.common_block.offsets[task_id]; - for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][task_id].first; chunk != 0; chunk = chunk->next) { + for (LNK_SymbolHashTrieChunk *chunk = symtab->chunks[task_id].first; chunk != 0; chunk = chunk->next) { for EachIndex(i, chunk->count) { LNK_Symbol *symbol = chunk->v[i].symbol; - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); COFF_SymbolValueInterpType parsed_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class); if (parsed_interp == COFF_SymbolValueInterp_Common) { LNK_CommonBlockContrib *contrib = &task->u.common_block.contribs[cursor++]; @@ -3833,7 +3854,7 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config COFF_SectionHeader **section_table = push_array(arena, COFF_SectionHeader *, coff_section_table_count + 1); for (U64 i = 1; i <= coff_section_table_count; i += 1) { section_table[i] = &coff_section_table[i-1]; } - LNK_Symbol *entry_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, config->entry_point_name); + LNK_Symbol *entry_symbol = lnk_symbol_table_search(symtab, config->entry_point_name); if (entry_symbol) { *entry_point_va = safe_cast_u32(lnk_virt_off_from_symbol(section_table, entry_symbol)); } @@ -4272,7 +4293,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch load config { - LNK_Symbol *load_config_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); + LNK_Symbol *load_config_symbol = lnk_symbol_table_search(symtab, str8_lit(MSCRT_LOAD_CONFIG_SYMBOL_NAME)); if (load_config_symbol) { U64 load_config_foff = lnk_file_off_from_symbol(image_section_table, load_config_symbol); String8 load_config_data = str8_skip(image_data, load_config_foff); @@ -4326,16 +4347,16 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch import and import addr { LNK_Section *idata_sect = lnk_section_table_search(sectab, str8_lit(".idata"), PE_IDATA_SECTION_FLAGS); - LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "__NULL_IMPORT_DESCRIPTOR"); - LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); + LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, "__NULL_IMPORT_DESCRIPTOR"); + LNK_Symbol *null_thunk_data = lnk_symbol_table_searchf(symtab, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); if (idata_sect && null_import_desc && null_thunk_data) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_IMPORT); import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff + idata_first_contrib->u.off; import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; - COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_thunk_data->u.defined.obj, null_thunk_data->u.defined.symbol_idx); + COFF_ParsedSymbol null_thunk_data_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_thunk_data->defined.obj, null_thunk_data->defined.symbol_idx); U64 null_thunk_data_voff = image_section_table[null_thunk_data_parsed.section_number]->voff + null_thunk_data_parsed.value; U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff + idata_first_contrib->u.off; PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); @@ -4348,10 +4369,10 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch delay imports { LNK_Section *didat_sect = lnk_section_table_search(sectab, str8_lit(".didat"), PE_IDATA_SECTION_FLAGS); - LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); - LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); + LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); + LNK_Symbol *last_null_thunk = lnk_symbol_table_searchf(symtab,"\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); if (didat_sect && null_import_desc && last_null_thunk) { - COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->defined.obj, null_import_desc->defined.symbol_idx); LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); PE_DataDirectory *import_dir = pe_data_directory_from_idx(image_data, pe, PE_DataDirectoryIndex_DELAY_IMPORT); import_dir->virt_off = lnk_get_first_section_contrib_voff(image_section_table, didat_sect); @@ -4361,7 +4382,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // patch TLS { - LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, MSCRT_TLS_SYMBOL_NAME); + LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME); if (tls_used_symbol) { ProfBegin("Patch TLS"); @@ -4441,8 +4462,8 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT // compute image guid, and patch PDB and RDI guids { - LNK_Symbol *guid_pdb_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINK_PE_DEBUG_GUID_PDB")); - LNK_Symbol *guid_rdi_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINK_PE_DEBUG_GUID_RDI")); + LNK_Symbol *guid_pdb_symbol = lnk_symbol_table_search(symtab, str8_lit("RAD_LINK_PE_DEBUG_GUID_PDB")); + LNK_Symbol *guid_rdi_symbol = lnk_symbol_table_search(symtab, str8_lit("RAD_LINK_PE_DEBUG_GUID_RDI")); if (guid_pdb_symbol || guid_rdi_symbol) { switch (config->guid_type) { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 20fc27be..07491fe0 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -175,15 +175,6 @@ typedef struct U128 *hashes; } LNK_Blake3Hasher; -typedef struct -{ - LNK_SymbolTable *symtab; - union { - LNK_ObjNodeArray objs; - LNK_LibNodeArray libs; - } u; -} LNK_SymbolPusher; - // --- Config ----------------------------------------------------------------- internal LNK_Config * lnk_config_from_argcv(Arena *arena, int argc, char **argv); @@ -221,7 +212,7 @@ internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht, internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path); internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config); -internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Symbol *member_symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); +internal void lnk_queue_lib_member_for_input(Arena *arena, LNK_Config *config, LNK_Symbol *pull_in_ref, LNK_Lib *lib, U32 member_idx, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list); internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config); diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 0c163f4e..e940de6b 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -3023,7 +3023,7 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) LNK_Symbol *symbol = chunk->v[i].symbol; COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol); - if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->u.defined.obj)) { continue; } + if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->defined.obj)) { continue; } COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed); if (symbol_interp != COFF_SymbolValueInterp_Regular) { continue; } @@ -3072,8 +3072,8 @@ lnk_build_pdb_public_symbols(TP_Context *tp, ProfBegin("Defined"); LNK_BuildPublicSymbolsTask task = {0}; - task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count); - task.chunk_lists = symtab->chunk_lists[LNK_SymbolScope_Defined]; + task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count); + task.chunk_lists = symtab->chunks; tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task); ProfEnd(); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 3437c68b..c8270380 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -221,29 +221,18 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S return result; } -internal -THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task) +internal B32 +lnk_search_lib(LNK_Lib *lib, String8 symbol_name, U32 *member_idx_out) { - LNK_SymbolPusher *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - LNK_Lib *lib = &task->u.libs.v[task_id].data; + // TODO: symbol names are already sorted, replace with binary search for EachIndex(symbol_idx, lib->symbol_count) { - U32 member_offset_number = lib->symbol_indices[symbol_idx]; - if (member_offset_number > 0) { - LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, member_offset_number-1); - lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol); + if (str8_match(lib->symbol_names.v[symbol_idx], symbol_name, 0)) { + if (member_idx_out) { + *member_idx_out = lib->symbol_indices[symbol_idx] - 1; + } + return 1; } } -} - -internal void -lnk_input_lib_symbols(TP_Context *tp, LNK_SymbolTable *symtab, LNK_LibNodeArray libs) -{ - ProfBeginFunction(); - LNK_SymbolPusher task = {0}; - task.symtab = symtab; - task.u.libs = libs; - tp_for_parallel(tp, symtab->arena, libs.count, lnk_push_lib_symbols_task, &task); - ProfEnd(); + return 0; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 8b990655..bb15bcc2 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -345,27 +345,27 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) break; } LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Weak: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Undefined: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Common: { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } break; case COFF_SymbolValueInterp_Abs: { if (symbol.storage_class == COFF_SymStorageClass_External) { LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx); - lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn); + lnk_symbol_table_push_(task->symtab, arena, worker_id, defn); } } break; case COFF_SymbolValueInterp_Debug: { @@ -388,7 +388,7 @@ lnk_symlinks_from_obj(Arena *arena, LNK_SymbolTable *symtab, LNK_Obj *obj) 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); + symlinks[symbol.section_number] = lnk_symbol_table_search_(symtab, symbol.name); } } } diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 41cecd19..cfa7276e 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -6,18 +6,8 @@ lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 sym { LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); symbol->name = name; - symbol->u.defined.obj = obj; - symbol->u.defined.symbol_idx = symbol_idx; - return symbol; -} - -internal LNK_Symbol * -lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx) -{ - LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->u.member.v.lib = lib; - symbol->u.member.v.member_idx = member_idx; + symbol->defined.obj = obj; + symbol->defined.symbol_idx = symbol_idx; return symbol; } @@ -25,7 +15,7 @@ internal B32 lnk_symbol_defined_is_before(void *raw_a, void *raw_b) { LNK_Symbol *a = raw_a, *b = raw_b; - return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx; + return a->defined.obj->input_idx < b->defined.obj->input_idx; } internal B32 @@ -34,13 +24,6 @@ lnk_symbol_defined_ptr_is_before(void *raw_a, void *raw_b) return lnk_symbol_defined_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b); } -internal B32 -lnk_symbol_lib_is_before(void *raw_a, void *raw_b) -{ - LNK_Symbol *a = raw_a, *b = raw_b; - return a->u.member.v.lib->input_idx < b->u.member.v.lib->input_idx; -} - internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node) { @@ -125,281 +108,265 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * internal void lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->u.defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->u.defined.symbol_idx, src->u.defined.obj->path, src->u.defined.symbol_idx); + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->defined.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->defined.symbol_idx, src->defined.obj->path, src->defined.symbol_idx); } internal B32 -lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) +lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { B32 can_replace = 0; - switch (scope) { - case LNK_SymbolScope_Defined: { - LNK_Obj *dst_obj = dst->u.defined.obj; - LNK_Obj *src_obj = src->u.defined.obj; - 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_from_parsed_symbol(dst_parsed); - COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); - // undefined vs regular - if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { - can_replace = 1; - } - // (weak vs undefined) or (undefined vs weak) - else if ((dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Undefined) || (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak)) { - LNK_Symbol *weak, *undef; - COFF_ParsedSymbol weak_parsed; - if (dst_interp == COFF_SymbolValueInterp_Weak) { - weak = dst, undef = src; - weak_parsed = dst_parsed; - } else { - weak = src, undef = dst; - weak_parsed = src_parsed; - } + LNK_Obj *dst_obj = dst->defined.obj; + LNK_Obj *src_obj = src->defined.obj; + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->defined.symbol_idx); + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->defined.symbol_idx); + COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed); + COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed); - COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); - if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = lnk_symbol_defined_is_before(dst, src); - } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { - can_replace = dst_interp == COFF_SymbolValueInterp_Weak; - } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { - can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; - } else { - can_replace = lnk_symbol_defined_is_before(src, dst); - } + // undefined vs regular + if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) { + can_replace = 1; + } + // (weak vs undefined) or (undefined vs weak) + else if ((dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Undefined) || (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak)) { + LNK_Symbol *weak, *undef; + COFF_ParsedSymbol weak_parsed; + if (dst_interp == COFF_SymbolValueInterp_Weak) { + weak = dst, undef = src; + weak_parsed = dst_parsed; + } else { + weak = src, undef = dst; + weak_parsed = src_parsed; } - // undefined vs undefined - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + + COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->defined.obj->header.is_big_obj); + if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { + can_replace = lnk_symbol_defined_is_before(dst, src); + } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; + } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { + can_replace = dst_interp == COFF_SymbolValueInterp_Undefined; + } else { can_replace = lnk_symbol_defined_is_before(src, dst); } - // undefined vs common - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { + } + // undefined vs undefined + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = lnk_symbol_defined_is_before(src, dst); + } + // undefined vs common + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) { + can_replace = 1; + } + // undefined vs abs + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) { + can_replace = 1; + } + // undefined vs debug + else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { + can_replace = 1; + } + // regular/common/abs/debug vs undefined + else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { + can_replace = 0; + } + // regular vs abs + else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { + lnk_error_multiply_defined_symbol(dst, src); + } + // abs vs regular + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) { + lnk_error_multiply_defined_symbol(dst, src); + } + // abs vs common + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) { + if (lnk_symbol_defined_is_before(dst, src)) { can_replace = 1; - } - // undefined vs abs - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) { - can_replace = 1; - } - // undefined vs debug - else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) { - can_replace = 1; - } - // regular/common/abs/debug vs undefined - else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) { - can_replace = 0; - } - // regular vs abs - else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) { + } else { lnk_error_multiply_defined_symbol(dst, src); } - // abs vs regular - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) { + } + // common vs abs + else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) { + if (lnk_symbol_defined_is_before(dst, src)) { lnk_error_multiply_defined_symbol(dst, src); } - // abs vs common - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) { - if (lnk_symbol_defined_is_before(dst, src)) { - can_replace = 1; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } - // common vs abs - else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) { - if (lnk_symbol_defined_is_before(dst, src)) { - lnk_error_multiply_defined_symbol(dst, src); - } - } - // abs vs abs - else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Abs) { - lnk_error_multiply_defined_symbol(dst, src); - } - // weak vs weak - else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->u.defined.obj->header.is_big_obj); - COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->u.defined.obj->header.is_big_obj); - if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { - if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 0; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 1; - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - lnk_error_multiply_defined_symbol(dst, src); - } else { - can_replace = lnk_symbol_defined_is_before(src, dst); - } - } - // weak vs regular/abs/common - else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) { - can_replace = 1; - } - // regular/abs/common vs weak - else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Abs || dst_interp == COFF_SymbolValueInterp_Common) && src_interp == COFF_SymbolValueInterp_Weak) { - can_replace = 0; - } - // regular/common vs regular/common - else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { - // parse dst symbol properties - B32 dst_is_comdat = 0; - COFF_ComdatSelectType dst_select; - 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, 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; - dst_check_sum = 0; - dst_is_comdat = 1; - } - - // parse src symbol properties - B32 src_is_comdat = 0; - COFF_ComdatSelectType src_select; - 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, 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; - src_check_sum = 0; - src_is_comdat = 1; - } - - // regular non-comdat vs communal - if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat && src_interp == COFF_SymbolValueInterp_Common) { + } + // abs vs abs + else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Abs) { + lnk_error_multiply_defined_symbol(dst, src); + } + // weak vs weak + else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { + COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->defined.obj->header.is_big_obj); + COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->defined.obj->header.is_big_obj); + if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { + if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { can_replace = 0; - } - // communal vs regular non-comdat - else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) { - can_replace = 1; - } - // handle COMDATs - else if (dst_is_comdat && src_is_comdat) { - if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest)) { - src_select = COFF_ComdatSelect_Largest; - } - if (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any) { - dst_select = COFF_ComdatSelect_Largest; - } - - if (src_select == dst_select) { - switch (src_select) { - case COFF_ComdatSelect_Null: - case COFF_ComdatSelect_Any: { - if (src_section_length == dst_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - // both COMDATs are valid but to get smaller exe pick smallest - can_replace = src_section_length < dst_section_length; - } - } break; - case COFF_ComdatSelect_NoDuplicates: { - lnk_error_multiply_defined_symbol(dst, src); - } break; - case COFF_ComdatSelect_SameSize: { - if (dst_section_length == src_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } break; - case COFF_ComdatSelect_ExactMatch: { - COFF_SectionHeader *dst_sect_header = lnk_coff_section_header_from_section_number(dst_obj, dst_parsed.section_number); - COFF_SectionHeader *src_sect_header = lnk_coff_section_header_from_section_number(src_obj, src_parsed.section_number); - String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize)); - String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize)); - B32 is_exact_match = 0; - if (dst_check_sum != 0 && src_check_sum != 0) { - is_exact_match = dst_check_sum == src_check_sum && str8_match(dst_data, src_data, 0); - } else { - is_exact_match = str8_match(dst_data, src_data, 0); - } - - if (is_exact_match) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - lnk_error_multiply_defined_symbol(dst, src); - } - } break; - case COFF_ComdatSelect_Largest: { - if (dst_section_length == src_section_length) { - can_replace = lnk_obj_is_before(src_obj, dst_obj); - } else { - can_replace = dst_section_length < src_section_length; - } - } break; - case COFF_ComdatSelect_Associative: { /* ignore */ } break; - default: { InvalidPath; } break; - } - } else { - lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj, - "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", - src->name, coff_string_from_comdat_select_type(src_select), coff_string_from_comdat_select_type(dst_select), dst_obj); - } } else { lnk_error_multiply_defined_symbol(dst, src); } + } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 1; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + lnk_error_multiply_defined_symbol(dst, src); + } else { + can_replace = lnk_symbol_defined_is_before(src, dst); + } + } + // weak vs regular/abs/common + else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) { + can_replace = 1; + } + // regular/abs/common vs weak + else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Abs || dst_interp == COFF_SymbolValueInterp_Common) && src_interp == COFF_SymbolValueInterp_Weak) { + can_replace = 0; + } + // regular/common vs regular/common + else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { + // parse dst symbol properties + B32 dst_is_comdat = 0; + COFF_ComdatSelectType dst_select; + 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->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; + dst_check_sum = 0; + dst_is_comdat = 1; + } + + // parse src symbol properties + B32 src_is_comdat = 0; + COFF_ComdatSelectType src_select; + 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->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; + src_check_sum = 0; + src_is_comdat = 1; + } + + // regular non-comdat vs communal + if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat && src_interp == COFF_SymbolValueInterp_Common) { + can_replace = 0; + } + // communal vs regular non-comdat + else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) { + can_replace = 1; + } + // handle COMDATs + else if (dst_is_comdat && src_is_comdat) { + if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest)) { + src_select = COFF_ComdatSelect_Largest; + } + if (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any) { + dst_select = COFF_ComdatSelect_Largest; + } + + if (src_select == dst_select) { + switch (src_select) { + case COFF_ComdatSelect_Null: + case COFF_ComdatSelect_Any: { + if (src_section_length == dst_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + // both COMDATs are valid but to get smaller exe pick smallest + can_replace = src_section_length < dst_section_length; + } + } break; + case COFF_ComdatSelect_NoDuplicates: { + lnk_error_multiply_defined_symbol(dst, src); + } break; + case COFF_ComdatSelect_SameSize: { + if (dst_section_length == src_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } break; + case COFF_ComdatSelect_ExactMatch: { + COFF_SectionHeader *dst_sect_header = lnk_coff_section_header_from_section_number(dst_obj, dst_parsed.section_number); + COFF_SectionHeader *src_sect_header = lnk_coff_section_header_from_section_number(src_obj, src_parsed.section_number); + String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize)); + String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize)); + B32 is_exact_match = 0; + if (dst_check_sum != 0 && src_check_sum != 0) { + is_exact_match = dst_check_sum == src_check_sum && str8_match(dst_data, src_data, 0); + } else { + is_exact_match = str8_match(dst_data, src_data, 0); + } + + if (is_exact_match) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } break; + case COFF_ComdatSelect_Largest: { + if (dst_section_length == src_section_length) { + can_replace = lnk_obj_is_before(src_obj, dst_obj); + } else { + can_replace = dst_section_length < src_section_length; + } + } break; + case COFF_ComdatSelect_Associative: { /* ignore */ } break; + default: { InvalidPath; } break; + } + } else { + lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj, + "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", + src->name, coff_string_from_comdat_select_type(src_select), coff_string_from_comdat_select_type(dst_select), dst_obj); + } } else { - lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); + lnk_error_multiply_defined_symbol(dst, src); } - } break; - case LNK_SymbolScope_Lib: { - can_replace = lnk_symbol_lib_is_before(src, dst); - } break; - default: { InvalidPath; } + } else { + lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); } + return can_replace; } internal void -lnk_on_symbol_replace(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) +lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - 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; + COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->defined.obj, dst->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->defined.obj, dst_parsed.section_number); + dst_sect->flags |= COFF_SectionFlag_LnkRemove; - // 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; - } + // remove associated sections from the output + for (U32Node *associated_section = dst->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->defined.obj, associated_section->data); + section_header->flags |= COFF_SectionFlag_LnkRemove; } - - // assert leader section is live -#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_Lib: { - LNK_Symbol *last; - for (last = src; last->u.member.next != 0; last = last->u.member.next); - last->u.member.next = dst; - } break; - default: { InvalidPath; } } + + // assert leader section is live +#if BUILD_DEBUG + { + COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->defined.obj, src->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->defined.obj, src_parsed.section_number); + AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove); + } + } +#endif } internal void @@ -407,7 +374,6 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, - LNK_SymbolScope scope, LNK_Symbol *symbol) { LNK_SymbolHashTrie **curr_trie_ptr = trie; @@ -447,13 +413,13 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, // apply replacement if (leader) { - if (lnk_can_replace_symbol(scope, leader, src)) { + if (lnk_can_replace_symbol(leader, src)) { // discard leader - lnk_on_symbol_replace(scope, leader, src); + lnk_on_symbol_replace(leader, src); leader = src; } else { // discard source - lnk_on_symbol_replace(scope, src, leader); + lnk_on_symbol_replace(src, leader); src = leader; } } else { @@ -526,7 +492,7 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol) { - return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + return lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); } internal COFF_SymbolValueInterpType @@ -576,11 +542,11 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) SLLQueuePush(sf, sl, s); // 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); + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); + COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->defined.obj, defn_symbol->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; + current_symbol = defn_symbol->defined; break; } @@ -593,20 +559,20 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol) if (weak_ext->characteristics == COFF_WeakExt_AntiDependency) { if (tag_interp == COFF_SymbolValueInterp_Undefined || tag_interp == COFF_SymbolValueInterp_Weak) { - LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, tag_parsed.name); + LNK_Symbol *dep_symbol = lnk_symbol_table_search(symtab, tag_parsed.name); tag_interp = lnk_interp_from_symbol(dep_symbol); } if (tag_interp == COFF_SymbolValueInterp_Weak) { goto exit; } } } else if (current_interp == COFF_SymbolValueInterp_Undefined) { - LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name); + LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name); COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn_symbol); // unresolved undefined symbol if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; } // follow symbol definition - current_symbol = defn_symbol->u.defined; + current_symbol = defn_symbol->defined; } else { break; } } @@ -630,41 +596,39 @@ lnk_symbol_table_init(TP_Arena *arena) { LNK_SymbolTable *symtab = push_array(arena->v[0], LNK_SymbolTable, 1); symtab->arena = arena; - for (U64 i = 0; i < LNK_SymbolScope_Count; ++i) { - symtab->chunk_lists[i] = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); - } + symtab->chunks = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); return symtab; } internal void -lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_SymbolScope scope, LNK_Symbol *symbol) +lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, U64 worker_id, LNK_Symbol *symbol) { U64 hash = lnk_symbol_hash(symbol->name); - lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunk_lists[scope][worker_id], &symtab->scopes[scope], hash, scope, symbol); + lnk_symbol_hash_trie_insert_or_replace(arena, &symtab->chunks[worker_id], &symtab->root, hash, symbol); } internal void -lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol *symbol) +lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol) { - lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, scope, symbol); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, symbol); } internal LNK_SymbolHashTrie * -lnk_symbol_table_search_(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) +lnk_symbol_table_search_(LNK_SymbolTable *symtab, String8 name) { U64 hash = lnk_symbol_hash(name); - return lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name); + return lnk_symbol_hash_trie_search(symtab->root, hash, name); } internal LNK_Symbol * -lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name) +lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name) { - LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, scope, name); + LNK_SymbolHashTrie *trie = lnk_symbol_table_search_(symtab, name); return trie ? trie->symbol : 0; } internal LNK_Symbol * -lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...) +lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...) { Temp scratch = scratch_begin(0, 0); @@ -672,7 +636,7 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f String8 name = push_str8fv(scratch.arena, fmt, args); va_end(args); - LNK_Symbol *symbol = lnk_symbol_table_search(symtab, scope, name); + LNK_Symbol *symbol = lnk_symbol_table_search(symtab, name); scratch_end(scratch); return symbol; @@ -681,7 +645,7 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *f internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol) { - COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx); + COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->defined.obj, symbol->defined.symbol_idx); ISectOff sc = {0}; sc.isect = parsed_symbol.section_number; diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 5a90bcf2..b87fa44b 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -5,35 +5,16 @@ // --- Symbol ------------------------------------------------------------------ -typedef enum -{ - LNK_SymbolScope_Defined, - LNK_SymbolScope_Lib, - LNK_SymbolScope_Count -} LNK_SymbolScope; - typedef struct LNK_SymbolDefined { struct LNK_Obj *obj; U32 symbol_idx; } LNK_SymbolDefined; -typedef struct LNK_SymbolLib -{ - struct LNK_Lib *lib; - U32 member_idx; -} LNK_SymbolLib; - typedef struct LNK_Symbol { - String8 name; - union { - LNK_SymbolDefined defined; - struct { - struct LNK_Symbol *next; - LNK_SymbolLib v; - } member; - } u; + String8 name; + LNK_SymbolDefined defined; } LNK_Symbol; // --- Symbol Containers ------------------------------------------------------- @@ -92,14 +73,13 @@ typedef struct LNK_SymbolHashTrieChunkList typedef struct LNK_SymbolTable { TP_Arena *arena; - LNK_SymbolHashTrie *scopes[LNK_SymbolScope_Count]; - LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScope_Count]; + LNK_SymbolHashTrie *root; + LNK_SymbolHashTrieChunkList *chunks; } LNK_SymbolTable; // --- Symbol Make ------------------------------------------------------------- internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); -internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U32 member_idx); // --- Symbol Containers ------------------------------------------------------ @@ -113,7 +93,7 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol // --- Symbol Hash Trie -------------------------------------------------------- -internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol); +internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *symbol); internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name); internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie); internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out); @@ -129,9 +109,9 @@ internal LNK_SymbolDefined lnk_resolve_weak_symbol(LNK_SymbolTable *sym internal U64 lnk_symbol_hash(String8 string); internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena); -internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_SymbolScope scope, LNK_Symbol *symbol); -internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name); -internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...); +internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); +internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, String8 name); +internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, char *fmt, ...); // --- Symbol Contrib Helpers --------------------------------------------------