From 4a2e1dd8d0f280c505062acc03ec7ef73d6f0d02 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 28 Oct 2024 22:44:24 -0700 Subject: [PATCH] switch to thread safe hash trie map Initial implementation of the symbol table allowed us to push symbols from one thread at a time and required a wonky lock-step and spread out logic for replacing symbols. And because it was a externally chained hash table we had to guesstimate optimal capacity for small and big targets. We erred on the side of larger capacity to prevent degradation and rehashing, however this meant small targets had to spent unreasonable amount of time memory allocing slots. With hash trie we can dynamically scale up to 4 ^ 32 items and atomically replace symbols when needed. Neat! --- src/linker/lnk.c | 545 ++++++++++---------- src/linker/lnk.h | 17 +- src/linker/lnk_chunk.h | 2 + src/linker/lnk_debug_info.c | 57 ++- src/linker/lnk_debug_info.h | 12 +- src/linker/lnk_directive.c | 6 + src/linker/lnk_export_table.c | 23 +- src/linker/lnk_import_table.c | 165 +++--- src/linker/lnk_lib.c | 22 +- src/linker/lnk_lib.h | 8 +- src/linker/lnk_obj.c | 7 +- src/linker/lnk_obj.h | 3 +- src/linker/lnk_symbol_table.c | 929 +++++++++++++++------------------- src/linker/lnk_symbol_table.h | 130 ++--- 14 files changed, 877 insertions(+), 1049 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 16c81df0..8987158e 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -258,6 +258,7 @@ lnk_make_linker_manifest(Arena *arena, "\n")); if (manifest_uac) { +#if 1 String8 uac = push_str8f(scratch.arena, " \n" " \n" @@ -268,6 +269,17 @@ lnk_make_linker_manifest(Arena *arena, " \n", manifest_level, manifest_ui_access); +#else + String8 uac = push_str8f(scratch.arena, + "\n" + "" + "" + "" + "" + "" + "" + "", manifest_level, manifest_ui_access); +#endif str8_serial_push_string(scratch.arena, &srl, uac); } for (String8Node *node = manifest_dependency_list.first; node != 0; node = node->next) { @@ -448,8 +460,8 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE PE_Resource *res = &stack->res_arr[stack->arr_idx].v[stack->res_idx[stack->arr_idx]]; ++stack->res_idx[stack->arr_idx]; - String8 flag_name = push_str8f(symtab->arena, "flag_%u", total_res_count); - String8 offset_name = push_str8f(symtab->arena, "offset_%u", total_res_count); + String8 flag_name = push_str8f(symtab->arena->v[0], "flag_%u", total_res_count); + String8 offset_name = push_str8f(symtab->arena->v[0], "offset_%u", total_res_count); ++total_res_count; if (stack->coff_entry_array_chunk) { @@ -471,7 +483,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE // make chunk and symbol String8 res_name = coff_resource_string_from_str8(dir_sect->arena, res->id.u.string); LNK_Chunk *name_chunk = lnk_section_push_chunk_data(dir_sect, dir_string_chunk, res_name, str8_zero()); - LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("COFF_RESOURCE_ID_STRING"), LNK_DefinedSymbolVisibility_Static, 0, name_chunk, 0, 0, 0); + LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit("COFF_RESOURCE_ID_STRING"), LNK_DefinedSymbolVisibility_Static, 0, name_chunk, 0, 0, 0); // patch COFF_ResourceDirEntry.name.offset lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol); @@ -503,8 +515,8 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK"); // push symbols to patch coff entry - LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena, flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG); - LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); + LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG); + LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory @@ -543,12 +555,12 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE resource_data_chunk->align = COFF_RES_ALIGN; // relocate data - String8 resource_data_symbol_name = push_str8f(symtab->arena, "$R%06X", total_res_count); - LNK_Symbol *resource_data_symbol = lnk_make_defined_symbol_chunk(symtab->arena, resource_data_symbol_name, LNK_DefinedSymbolVisibility_Static, 0, resource_data_chunk, 0, 0, 0); + String8 resource_data_symbol_name = push_str8f(symtab->arena->v[0], "$R%06X", total_res_count); + LNK_Symbol *resource_data_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], resource_data_symbol_name, LNK_DefinedSymbolVisibility_Static, 0, resource_data_chunk, 0, 0, 0); lnk_section_push_reloc(dir_sect, coff_resource_data_entry_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_ResourceDataEntry, data_voff), resource_data_symbol); // push symbol for data offset relocation - LNK_Symbol *coff_data_offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_resource_data_entry_chunk, 0, 0, 0); + LNK_Symbol *coff_data_offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], offset_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_resource_data_entry_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, coff_data_offset_symbol); Assert(stack->coff_entry_chunk); @@ -691,8 +703,13 @@ lnk_make_res_obj(TP_Context *tp, static const U64 sect_virt_align = 1; static const U64 sect_file_align = 1; + + TP_Arena *temp_tp_arena = push_array(scratch.arena, TP_Arena, 1); + temp_tp_arena->v = push_array(scratch.arena, Arena *, 1); + temp_tp_arena->count = 1; + temp_tp_arena->v[0] = arena_alloc(); - LNK_SymbolTable *symtab = lnk_symbol_table_alloc(); + LNK_SymbolTable *symtab = lnk_symbol_table_init(temp_tp_arena); LNK_SectionTable *st = lnk_section_table_alloc(0, sect_virt_align, sect_file_align); LNK_Section *header_sect = lnk_section_table_push(st, str8_lit(".null"), 0); @@ -703,9 +720,8 @@ lnk_make_res_obj(TP_Context *tp, // register section symbols (after this point don't push new sections) for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { - LNK_Section *sect = §_node->data; - LNK_Symbol *sect_symbol = lnk_make_defined_symbol_chunk(symtab->arena, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, sect_symbol); + LNK_Section *sect = §_node->data; + lnk_symbol_table_push_defined_chunk(symtab, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } st->null_sect = lnk_section_list_remove(&st->list, str8_lit(".null")); lnk_section_table_build_data(tp, st, machine); @@ -826,10 +842,10 @@ lnk_make_res_obj(TP_Context *tp, } // emit symbols for coff section header patch - String8 coff_reloc_symbol_name = push_str8f(symtab->arena, "%S.coff_reloc[]", sect->name); - String8 coff_reloc_count_symbol_name = push_str8f(symtab->arena, "%S.coff_reloc[].count", sect->name); - LNK_Symbol *coff_reloc_symbol = lnk_make_defined_symbol_chunk(symtab->arena, coff_reloc_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, reloc_array_chunk, 0, 0, 0); - LNK_Symbol *coff_reloc_count_symbol = lnk_make_defined_symbol_va(symtab->arena, coff_reloc_count_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_reloc_list.count); + String8 coff_reloc_symbol_name = push_str8f(symtab->arena->v[0], "%S.coff_reloc[]", sect->name); + String8 coff_reloc_count_symbol_name = push_str8f(symtab->arena->v[0], "%S.coff_reloc[].count", sect->name); + LNK_Symbol *coff_reloc_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], coff_reloc_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, reloc_array_chunk, 0, 0, 0); + LNK_Symbol *coff_reloc_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], coff_reloc_count_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_reloc_list.count); lnk_symbol_table_push(symtab, coff_reloc_symbol); lnk_symbol_table_push(symtab, coff_reloc_count_symbol); } @@ -846,10 +862,10 @@ lnk_make_res_obj(TP_Context *tp, } String8 coff_symbol_table_data = str8_serial_end(scratch.arena, &srl); LNK_Chunk *coff_symbol_table_chunk = lnk_section_push_chunk_data(misc_sect, misc_sect->root, coff_symbol_table_data, str8_zero()); - LNK_Symbol *coff_symbol_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("COFF_SYMBOL_TABLE"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_table_chunk, 0, 0, 0); + LNK_Symbol *coff_symbol_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit("COFF_SYMBOL_TABLE"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_table_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, coff_symbol_table_symbol); - LNK_Symbol *coff_symbol_count_symbol = lnk_make_defined_symbol_va(symtab->arena, str8_lit("COFF_SYMBOL_COUNT"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_list.count); + LNK_Symbol *coff_symbol_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], str8_lit("COFF_SYMBOL_COUNT"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_list.count); lnk_symbol_table_push(symtab, coff_symbol_count_symbol); // build obj header @@ -874,7 +890,7 @@ lnk_make_res_obj(TP_Context *tp, lnk_section_push_reloc(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, symbol_count), coff_symbol_count_symbol); // push coff header symbol - LNK_Symbol *coff_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_chunk, 0, 0, 0); + LNK_Symbol *coff_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, coff_header_symbol); } @@ -882,7 +898,7 @@ lnk_make_res_obj(TP_Context *tp, { LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { - if (sect_node == st->null_sect) continue; + if (sect_node == st->null_sect) continue; if (!sect_node->data.emit_header) continue; LNK_Section *sect = §_node->data; @@ -924,7 +940,7 @@ lnk_make_res_obj(TP_Context *tp, // push section header count symbol U64 symbol_count = coff_section_header_array_chunk->u.list->count; - LNK_Symbol *coff_section_header_count_symbol = lnk_make_defined_symbol_va(symtab->arena, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, symbol_count); + LNK_Symbol *coff_section_header_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, symbol_count); lnk_symbol_table_push(symtab, coff_section_header_count_symbol); } @@ -936,8 +952,8 @@ lnk_make_res_obj(TP_Context *tp, String8 res_obj = lnk_section_table_serialize(arena, st); lnk_section_table_release(&st); - lnk_symbol_table_release(&symtab); + arena_release(temp_tp_arena->v[0]); scratch_end(scratch); ProfEnd(); return res_obj; @@ -1012,9 +1028,13 @@ lnk_make_linker_coff_obj(TP_Context *tp, String8 obj_name) { Temp scratch = scratch_begin(&arena, 1); + + TP_Arena *temp_tp_arena = push_array(scratch.arena, TP_Arena, 1); + temp_tp_arena->v = &scratch.arena; + temp_tp_arena->count = 1; - LNK_SymbolTable *symtab = lnk_symbol_table_alloc(); - LNK_SectionTable *st = lnk_section_table_alloc(0, 1, 1); + LNK_SymbolTable *symtab = lnk_symbol_table_init(temp_tp_arena); + LNK_SectionTable *st = lnk_section_table_alloc(0, 1, 1); LNK_Section *header_sect = lnk_section_table_push(st, str8_lit(".coffhdr"), 0); LNK_Section *debug_s_sect = lnk_section_table_push(st, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); @@ -1023,10 +1043,10 @@ lnk_make_linker_coff_obj(TP_Context *tp, header_sect->emit_header = 0; { - COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1); - coff_header->machine = machine; + COFF_Header *coff_header = push_array(header_sect->arena, COFF_Header, 1); + coff_header->machine = machine; coff_header->section_count = 0; - coff_header->time_stamp = time_stamp; + coff_header->time_stamp = time_stamp; LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, coff_header, sizeof(*coff_header), str8_zero()); lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -1045,13 +1065,13 @@ lnk_make_linker_coff_obj(TP_Context *tp, U64 ver_fe_major = 0; U64 ver_fe_minor = 0; U64 ver_fe_build = 0; - U64 ver_feqfe = 0; - U64 ver_major = 14; - U64 ver_minor = 36; - U64 ver_build = 32537; - U64 ver_qfe = 0; + U64 ver_feqfe = 0; + U64 ver_major = 14; + U64 ver_minor = 36; + U64 ver_build = 32537; + U64 ver_qfe = 0; String8 version_string = push_str8f(scratch.arena, "Epic Games Tools (R) RAD Linker"); - String8 comp3_data = cv_make_comp3(scratch.arena, 0, CV_Language_LINK, cv_arch, ver_fe_major, ver_fe_minor, ver_fe_build, ver_feqfe, ver_major, ver_minor, ver_build, ver_qfe, version_string); + String8 comp3_data = cv_make_comp3(scratch.arena, 0, CV_Language_LINK, cv_arch, ver_fe_major, ver_fe_minor, ver_fe_build, ver_feqfe, ver_major, ver_minor, ver_build, ver_qfe, version_string); cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data); // S_ENVBLOCK @@ -1091,13 +1111,12 @@ lnk_make_linker_coff_obj(TP_Context *tp, // register section symbols (after this point don't push new sections) for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; - LNK_Symbol *sect_symbol = lnk_make_defined_symbol_chunk(symtab->arena, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, sect_symbol); + lnk_symbol_table_push_defined_chunk(symtab, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { - if (sect_node == st->null_sect) continue; + if (sect_node == st->null_sect) continue; if (!sect_node->data.emit_header) continue; LNK_Section *sect = §_node->data; @@ -1138,7 +1157,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, // push section header count symbol U64 symbol_count = coff_section_header_array_chunk->u.list->count; - LNK_Symbol *coff_section_header_count_symbol = lnk_make_defined_symbol_va(symtab->arena, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, symbol_count); + LNK_Symbol *coff_section_header_count_symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, symbol_count); lnk_symbol_table_push(symtab, coff_section_header_count_symbol); } @@ -1228,21 +1247,6 @@ lnk_push_loaded_lib(Arena *arena, } } -internal -THREAD_POOL_TASK_FUNC(lnk_lazy_initer) -{ - LNK_LazyIniter *task = raw_task; - Rng1U64 range = task->range_arr[task_id]; - for (U64 lib_idx = range.min; lib_idx < range.max; lib_idx += 1) { - LNK_Lib *lib = &task->lib_arr[lib_idx].data; - String8Node *name_node = lib->symbol_name_list.first; - for (U64 symbol_idx = 0; symbol_idx < lib->symbol_count; symbol_idx += 1, name_node = name_node->next) { - LNK_Symbol *symbol = &task->symbol_arr_arr[lib_idx][symbol_idx]; - lnk_init_lazy_symbol(symbol, name_node->string, lib, lib->member_off_arr[symbol_idx]); - } - } -} - internal void lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *lazy, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { @@ -1298,40 +1302,26 @@ lnk_push_linker_symbols(LNK_SymbolTable *symtab, COFF_MachineType machine) // passing it around as a function argument. // // 100h: lea rax, [rip + ffffff00h] ; -100h - LNK_Symbol *image_base = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_ANY, 0); - lnk_symbol_table_push(symtab, image_base); + LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_ANY, 0); { // load config symbols if (machine == COFF_MachineType_X86) { - LNK_Symbol *safe_se_handler_table = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); - LNK_Symbol *safe_se_handler_count = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); - lnk_symbol_table_push(symtab, safe_se_handler_table); - lnk_symbol_table_push(symtab, safe_se_handler_count); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelectType_NODUPLICATES, 0); } // TODO: investigate IMAGE_ENCLAVE_CONFIG 32/64 - LNK_Symbol *enclave_config = lnk_make_defined_symbol_va(symtab->arena, str8_lit(LNK_ENCLAVE_CONFIG_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, 0); + lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_ENCLAVE_CONFIG_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, 0); - LNK_Symbol *guard_flags = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_FLAGS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_fids_table = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_FIDS_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_fids_count = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_FIDS_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_iat_table = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_IAT_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_iat_count = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_IAT_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_longjmp_table = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_LONGJMP_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_longjmp_count = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_LONGJMP_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_ehcont_table = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_EHCONT_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - LNK_Symbol *guard_ehcont_count = lnk_make_defined_symbol(symtab->arena, str8_lit(LNK_GUARD_EHCONT_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); - - lnk_symbol_table_push(symtab, enclave_config); - lnk_symbol_table_push(symtab, guard_flags); - lnk_symbol_table_push(symtab, guard_fids_table); - lnk_symbol_table_push(symtab, guard_fids_count); - lnk_symbol_table_push(symtab, guard_iat_table); - lnk_symbol_table_push(symtab, guard_iat_count); - lnk_symbol_table_push(symtab, guard_longjmp_table); - lnk_symbol_table_push(symtab, guard_longjmp_count); - lnk_symbol_table_push(symtab, guard_ehcont_table); - lnk_symbol_table_push(symtab, guard_ehcont_count); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_FLAGS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_FIDS_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_FIDS_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_IAT_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_IAT_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_LONGJMP_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_LONGJMP_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_EHCONT_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); + lnk_symbol_table_push_defined(symtab, str8_lit(LNK_GUARD_EHCONT_COUNT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Extern, 0); } } @@ -1422,11 +1412,8 @@ lnk_build_debug_pdb(LNK_SectionTable *st, lnk_chunk_set_debugf(sect->arena, debug_pdb_chunk, LNK_CV_HEADER_PDB70_SYMBOL_NAME); // push symbols - LNK_Symbol *debug_pdb_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_CV_HEADER_PDB70_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, debug_pdb_symbol); - - LNK_Symbol *guid_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, OffsetOf(PE_CvHeaderPDB70, guid), 0, 0); - lnk_symbol_table_push(symtab, guid_symbol); + LNK_Symbol *debug_pdb_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_PDB70_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, 0, 0, 0); + LNK_Symbol *guid_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_pdb_chunk, OffsetOf(PE_CvHeaderPDB70, guid), 0, 0); // push debug directory lnk_push_pe_debug_data_directory(sect, dir_array_chunk, debug_pdb_symbol, PE_DebugDirectoryType_CODEVIEW, time_stamp); @@ -1452,11 +1439,8 @@ lnk_build_debug_rdi(LNK_SectionTable *st, LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8_zero()); lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi, LNK_CV_HEADER_RDI_SYMBOL_NAME); // push symbols - LNK_Symbol *debug_rdi_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, debug_rdi_symbol); - - LNK_Symbol *guid_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, OffsetOf(PE_CvHeaderRDI, guid), 0, 0); - lnk_symbol_table_push(symtab, guid_symbol); + LNK_Symbol *debug_rdi_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0); + LNK_Symbol *guid_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_CV_HEADER_GUID_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, OffsetOf(PE_CvHeaderRDI, guid), 0, 0); // push debug directory lnk_push_pe_debug_data_directory(debug_sect, debug_dir_array_chunk, debug_rdi_symbol, PE_DebugDirectoryType_CODEVIEW, time_stamp); @@ -1566,6 +1550,8 @@ lnk_build_guard_tables(TP_Context *tp, // TODO: push noname exports + NotImplemented; +#if 0 // push thunks LNK_SymbolScopeIndex scope_array[] = { LNK_SymbolScopeIndex_Defined, LNK_SymbolScopeIndex_Internal }; for (U64 iscope = 0; iscope < ArrayCount(scope_array); ++iscope) { @@ -1582,6 +1568,7 @@ lnk_build_guard_tables(TP_Context *tp, } } } +#endif // build section data lnk_section_table_build_data(tp, st, machine); @@ -1628,8 +1615,7 @@ lnk_build_guard_tables(TP_Context *tp, }; for (U64 i = 0; i < ArrayCount(sect_layout); ++i) { LNK_Section *sect = lnk_section_table_push(st, str8_cstring(sect_layout[i].name), sect_layout[i].flags); - LNK_Symbol *symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(sect_layout[i].symbol), LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(sect_layout[i].symbol), LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } // TODO: emit table for SEH on X86 @@ -1768,6 +1754,13 @@ lnk_emit_base_reloc_info(Arena *arena, if (is_addr) { U64 reloc_voff = lnk_virt_off_from_reloc(sect_id_map, reloc); U64 page_voff = AlignDownPow2(reloc_voff, page_size); + + if (str8_match(reloc->symbol->name, str8_lit("_mi_heap_empty"), 0)) { + int x = 0; + } + if (page_voff == 0x21C7000) { + int x = 0; + } LNK_BaseRelocPageNode *page; { @@ -1945,8 +1938,7 @@ lnk_build_base_relocs(TP_Context *tp, if (main_page_list->count > 0) { LNK_Section *base_reloc_sect = lnk_section_table_push(st, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); - LNK_Symbol *base_reloc_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_BASE_RELOC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, base_reloc_sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, base_reloc_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_BASE_RELOC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, base_reloc_sect->root, 0, 0, 0); ProfBegin("Page List -> Array"); LNK_BaseRelocPageArray page_arr = lnk_base_reloc_page_array_from_list(base_reloc_sect->arena, *main_page_list); @@ -2046,10 +2038,8 @@ lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chun lnk_chunk_set_debugf(header_sect->arena, dos_header_chunk, LNK_DOS_HEADER_SYMBOL_NAME); lnk_chunk_set_debugf(header_sect->arena, dos_program_chunk, LNK_DOS_PROGRAM_SYMBOL_NAME); - LNK_Symbol *dos_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_DOS_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, dos_header_chunk, 0, 0, 0); - LNK_Symbol *dos_program_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_DOS_PROGRAM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, dos_program_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, dos_header_symbol); - lnk_symbol_table_push(symtab, dos_program_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_DOS_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, dos_header_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_DOS_PROGRAM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, dos_program_chunk, 0, 0, 0); // :coff_file_offset lnk_section_push_reloc_undefined(header_sect, dos_header_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(PE_DosHeader, coff_file_offset), str8_lit(LNK_NT_HEADERS_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -2066,8 +2056,7 @@ lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk LNK_Chunk *pe_magic_chunk = lnk_section_push_chunk_raw(header_sect, parent, pe_magic, sizeof(*pe_magic), str8_zero()); lnk_chunk_set_debugf(header_sect->arena, pe_magic_chunk, LNK_PE_MAGIC_SYMBOL_NAME); - LNK_Symbol *pe_magic_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_MAGIC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, pe_magic_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, pe_magic_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_MAGIC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, pe_magic_chunk, 0, 0, 0); return pe_magic_chunk; } @@ -2088,8 +2077,7 @@ lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LN LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, file_header, sizeof(*file_header), str8_zero()); lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_HEADER_SYMBOL_NAME); - LNK_Symbol *file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, file_header_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); // :section_count lnk_section_push_reloc_undefined(header_sect, file_header_chunk, LNK_Reloc_ADDR_16, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -2158,8 +2146,7 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, lnk_chunk_set_debugf(header_sect->arena, opt_header_chunk, LNK_PE_OPT_HEADER_SYMBOL_NAME); // define optional header symbol - LNK_Symbol *opt_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, opt_header_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, 0, 0, 0); // :entry_point_va lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_OptionalHeader32Plus, entry_point_va), entry_point_name, LNK_SymbolScopeFlag_Main); @@ -2202,8 +2189,7 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, lnk_section_push_reloc(header_sect, opt_header_chunk, LNK_Reloc_FILE_ALIGN_32, OffsetOf(PE_OptionalHeader32Plus, sizeof_headers), &g_null_symbol); // :check_sum - LNK_Symbol *checksum_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelectType_NODUPLICATES, 0); - lnk_symbol_table_push(symtab, checksum_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_CHECKSUM_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, opt_header_chunk, OffsetOf(PE_OptionalHeader32Plus, check_sum), COFF_ComdatSelectType_NODUPLICATES, 0); // :data_dir_count lnk_section_push_reloc_undefined(header_sect, opt_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(PE_OptionalHeader32Plus, data_dir_count), str8_lit(LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -2215,18 +2201,18 @@ internal LNK_Chunk * lnk_build_pe_directories(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent) { static struct { - char *name; - PE_DataDirectoryIndex index; - LNK_SymbolScopeFlags scope; + char *name; + PE_DataDirectoryIndex index; + LNK_SymbolScopeFlags scope; } directory_map[] = { - { LNK_LOAD_CONFIG_SYMBOL_NAME , PE_DataDirectoryIndex_LOAD_CONFIG , LNK_SymbolScopeFlag_Main }, + { LNK_LOAD_CONFIG_SYMBOL_NAME , PE_DataDirectoryIndex_LOAD_CONFIG , LNK_SymbolScopeFlag_Main }, { LNK_PDATA_SYMBOL_NAME , PE_DataDirectoryIndex_EXCEPTIONS , LNK_SymbolScopeFlag_Internal }, { LNK_EDATA_SYMBOL_NAME , PE_DataDirectoryIndex_EXPORT , LNK_SymbolScopeFlag_Internal }, { LNK_BASE_RELOC_SYMBOL_NAME , PE_DataDirectoryIndex_BASE_RELOC , LNK_SymbolScopeFlag_Internal }, { LNK_IMPORT_DLL_TABLE_SYMBOL_NAME , PE_DataDirectoryIndex_IMPORT , LNK_SymbolScopeFlag_Internal }, { LNK_IMPORT_IAT_SYMBOL_NAME , PE_DataDirectoryIndex_IMPORT_ADDR , LNK_SymbolScopeFlag_Internal }, { LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME, PE_DataDirectoryIndex_DELAY_IMPORT, LNK_SymbolScopeFlag_Internal }, - { LNK_TLS_SYMBOL_NAME , PE_DataDirectoryIndex_TLS , LNK_SymbolScopeFlag_Main }, + { LNK_TLS_SYMBOL_NAME , PE_DataDirectoryIndex_TLS , LNK_SymbolScopeFlag_Main }, { LNK_DEBUG_DIR_SYMBOL_NAME , PE_DataDirectoryIndex_DEBUG , LNK_SymbolScopeFlag_Internal }, { LNK_RSRC_SYMBOL_NAME , PE_DataDirectoryIndex_RESOURCES , LNK_SymbolScopeFlag_Internal }, }; @@ -2239,10 +2225,8 @@ lnk_build_pe_directories(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_ lnk_chunk_set_debugf(header_sect->arena, directory_array_chunk, LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME); // define PE directory symbols - LNK_Symbol *directory_array_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, directory_array_chunk, 0, 0, 0); - LNK_Symbol *directory_count_symbol = lnk_make_defined_symbol_va(symtab->arena, str8_lit(LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, directory_count); - lnk_symbol_table_push(symtab, directory_array_symbol); - lnk_symbol_table_push(symtab, directory_count_symbol); + LNK_Symbol *directory_array_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, directory_array_chunk, 0, 0, 0); + LNK_Symbol *directory_count_symbol = lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_PE_DIRECTORY_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, directory_count); for (U64 dir_idx = 0; dir_idx < ArrayCount(directory_map); dir_idx += 1) { String8 symbol_name = str8_cstring(directory_map[dir_idx].name); @@ -2270,9 +2254,8 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, Assert(!test_symbol); (void)test_symbol; // define symbol - String8 sect_symbol_name = push_str8_copy(symtab->arena, sect->name); - LNK_Symbol *sect_symbol = lnk_make_defined_symbol_chunk(symtab->arena, sect_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, sect_symbol); + String8 sect_symbol_name = push_str8_copy(symtab->arena->v[0], sect->name); + lnk_symbol_table_push_defined_chunk(symtab, sect_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } // push COFF header array chunk @@ -2280,8 +2263,7 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, lnk_chunk_set_debugf(header_sect->arena, coff_header_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); // define symbol for COFF header array - LNK_Symbol *coff_header_array_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_array_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, coff_header_array_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_header_array_chunk, 0, 0, 0); // push headers for (LNK_Section *sect = §_arr.v[0], *sect_opl = sect + sect_arr.count; sect < sect_opl; sect += 1) { @@ -2331,8 +2313,7 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, // push symbol for section header count U64 header_count = coff_header_array_chunk->u.list->count; - LNK_Symbol *header_symbol = lnk_make_defined_symbol_va(symtab->arena, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, header_count); - lnk_symbol_table_push(symtab, header_symbol); + lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, header_count); return coff_header_array_chunk; } @@ -2365,21 +2346,13 @@ lnk_build_win32_image_header(LNK_SymbolTable *symtab, lnk_chunk_set_debugf(header_sect->arena, pe_optional_chunk , "PE Optional Header Container" ); lnk_chunk_set_debugf(header_sect->arena, coff_sect_header_chunk, "COFF Section Headers Container"); - LNK_Symbol *win32_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_WIN32_HEADER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, win32_header_chunk , 0, 0, 0); - LNK_Symbol *dos_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_DOS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dos_chunk , 0, 0, 0); - LNK_Symbol *nt_headers_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_NT_HEADERS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, nt_chunk , 0, 0, 0); - LNK_Symbol *pe_magic_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_MAGIC_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, pe_magic_chunk , 0, 0, 0); - LNK_Symbol *coff_file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_FILE_HEADER_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, coff_file_header_chunk, 0, 0, 0); - LNK_Symbol *pe_optional_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_OPT_HEADER_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, pe_optional_chunk , 0, 0, 0); - LNK_Symbol *coff_sect_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_SECTION_HEADER_CONTAINER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_sect_header_chunk, 0, 0, 0); - - lnk_symbol_table_push(symtab, win32_header_symbol ); - lnk_symbol_table_push(symtab, dos_symbol ); - lnk_symbol_table_push(symtab, nt_headers_symbol ); - lnk_symbol_table_push(symtab, pe_magic_symbol ); - lnk_symbol_table_push(symtab, coff_file_header_symbol); - lnk_symbol_table_push(symtab, pe_optional_symbol ); - lnk_symbol_table_push(symtab, coff_sect_header_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_WIN32_HEADER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, win32_header_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_DOS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dos_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_NT_HEADERS_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, nt_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_MAGIC_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, pe_magic_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_FILE_HEADER_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, coff_file_header_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_PE_OPT_HEADER_CONTAINER_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, pe_optional_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECTION_HEADER_CONTAINER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_sect_header_chunk, 0, 0, 0); lnk_build_dos_header(symtab, header_sect, dos_chunk); lnk_build_pe_magic(symtab, header_sect, pe_magic_chunk); @@ -2432,15 +2405,15 @@ THREAD_POOL_TASK_FUNC(lnk_undef_symbol_finder) Assert(symbol->type == LNK_Symbol_Undefined); LNK_UndefinedSymbol *undef = &symbol->u.undefined; - LNK_SymbolNode *has_defn = lnk_symbol_table_search_node(task->symtab, undef->scope_flags, symbol->name); + LNK_Symbol *has_defn = lnk_symbol_table_search(task->symtab, undef->scope_flags, symbol->name); if (has_defn) { - Assert(LNK_Symbol_IsDefined(has_defn->data->type) || has_defn->data->type == LNK_Symbol_Weak); + Assert(LNK_Symbol_IsDefined(has_defn->type) || has_defn->type == LNK_Symbol_Weak); continue; } - LNK_SymbolNode *lazy = lnk_symbol_table_search_node(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); + LNK_Symbol *lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); if (lazy) { - lnk_push_input_from_lazy(arena, task->path_style, &lazy->data->u.lazy, &result->input_import_list, &result->input_obj_list); + lnk_push_input_from_lazy(arena, task->path_style, &lazy->u.lazy, &result->input_import_list, &result->input_obj_list); } else { lnk_symbol_list_push_node(&result->unresolved_symbol_list, symbol_node); } @@ -2461,22 +2434,22 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) LNK_WeakSymbol *weak = &symbol->u.weak; Assert((weak->scope_flags & ~(LNK_SymbolScopeFlag_Defined | LNK_SymbolScopeFlag_Internal)) == 0); - LNK_SymbolNode *has_strong_defn = lnk_symbol_table_search_node(task->symtab, weak->scope_flags, symbol->name); + LNK_Symbol *has_strong_defn = lnk_symbol_table_search(task->symtab, weak->scope_flags, symbol->name); if (has_strong_defn) { - Assert(LNK_Symbol_IsDefined(has_strong_defn->data->type)); + Assert(LNK_Symbol_IsDefined(has_strong_defn->type)); continue; } - LNK_SymbolNode *lazy = 0; + LNK_Symbol *lazy = 0; switch (weak->lookup_type) { case COFF_WeakExtType_NOLIBRARY: { // NOLIBRARY means weak symbol should be resolved in case where strong definition pulls in lib member. } break; case COFF_WeakExtType_SEARCH_LIBRARY: { - lazy = lnk_symbol_table_search_node(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); + lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); } break; case COFF_WeakExtType_SEARCH_ALIAS: { - lazy = lnk_symbol_table_search_node(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); + lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, symbol->name); if (!lazy) { if (str8_match(str8_lit(".weak."), symbol->name, StringMatchFlag_RightSideSloppy)) { // TODO: Clang and MingGW encode extra info in alias @@ -2495,14 +2468,14 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) // In this case linker needs to parse .weak.bar.default.foo and search for bar and foo as well. Assert("TODO: MinGW weak symbol"); } else { - lazy = lnk_symbol_table_search_node(task->symtab, LNK_SymbolScopeFlag_Lib, weak->fallback_symbol->name); + lazy = lnk_symbol_table_search(task->symtab, LNK_SymbolScopeFlag_Lib, weak->fallback_symbol->name); } } } break; } if (lazy) { - lnk_push_input_from_lazy(arena, task->path_style, &lazy->data->u.lazy, &result->input_import_list, &result->input_obj_list); + lnk_push_input_from_lazy(arena, task->path_style, &lazy->u.lazy, &result->input_import_list, &result->input_obj_list); } else { lnk_symbol_list_push_node(&result->unresolved_symbol_list, symbol_node); } @@ -2564,26 +2537,66 @@ lnk_run_symbol_finder(TP_Context *tp, } internal -THREAD_POOL_TASK_FUNC(lnk_defined_symbol_inserter) +THREAD_POOL_TASK_FUNC(lnk_defined_symbol_pusher_task) { - LNK_DefinedSymbolInserter *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - Rng1U64 range = task->range_arr[task_id]; - for (U64 bucket_idx = range.min; bucket_idx < range.max; bucket_idx += 1) { - LNK_SymbolList *bucket = &task->bucket_arr[bucket_idx]; - for (LNK_SymbolNode *curr = bucket->first, *next; curr != 0; curr = next) { - next = curr->next; - LNK_SymbolNode *extant_node = lnk_symbol_table_search_bucket(symtab, LNK_SymbolScopeIndex_Defined, bucket_idx, curr->data->name, curr->hash); - if (extant_node) { - LNK_SymbolList *symtab_bucket = lnk_symbol_table_bucket_from_hash(symtab, LNK_SymbolScopeIndex_Defined, curr->hash); - lnk_symbol_list_insert_after(symtab_bucket, extant_node, curr); - } else { - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Defined, curr, curr->hash); - } + LNK_SymbolPusher *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_Obj *obj = &task->u.objs.v[task_id].data; + + LNK_SymbolHashTrieChunkList **chunk_lists = symtab->chunk_lists; + + for (LNK_SymbolNode *symnode = obj->symbol_list.first; symnode != 0; symnode = symnode->next) { + if (symnode->data->type == LNK_Symbol_DefinedExtern) { + U64 hash = lnk_symbol_hash(symnode->data->name); + lnk_symbol_table_push_(symtab, arena, &chunk_lists[LNK_SymbolScopeIndex_Defined][worker_id], LNK_SymbolScopeIndex_Defined, hash, symnode->data); + } else if (symnode->data->type == LNK_Symbol_Weak) { + U64 hash = lnk_symbol_hash(symnode->data->name); + lnk_symbol_table_push_(symtab, arena, &chunk_lists[LNK_SymbolScopeIndex_Weak][worker_id], LNK_SymbolScopeIndex_Weak, hash, symnode->data); } } } +internal void +lnk_push_defined_symbols(TP_Context *tp, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs) +{ + ProfBeginFunction(); + LNK_SymbolPusher task = {0}; + task.symtab = symtab; + task.u.objs = objs; + tp_for_parallel(tp, symtab->arena, objs.count, lnk_defined_symbol_pusher_task, &task); + ProfEnd(); +} + +internal +THREAD_POOL_TASK_FUNC(lnk_lazy_symbol_pusher_task) +{ + LNK_SymbolPusher *task = raw_task; + LNK_SymbolTable *symtab = task->symtab; + LNK_Lib *lib = &task->u.libs.v[task_id].data; + String8Node *name_node = lib->symbol_name_list.first; + + LNK_Symbol *lazy_symbols = push_array_no_zero(arena, LNK_Symbol, lib->symbol_count); + + for (U64 symbol_idx = 0; symbol_idx < lib->symbol_count; ++symbol_idx, name_node = name_node->next) { + LNK_Symbol *symbol = &lazy_symbols[symbol_idx]; + lnk_init_lazy_symbol(symbol, name_node->string, lib, lib->member_off_arr[symbol_idx]); + + U64 hash = lnk_symbol_hash(symbol->name); + lnk_symbol_table_push_(symtab, arena, &symtab->chunk_lists[LNK_SymbolScopeIndex_Lib][worker_id], LNK_SymbolScopeIndex_Lib, hash, symbol); + } +} + +internal void +lnk_push_lazy_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_lazy_symbol_pusher_task, &task); + ProfEnd(); +} + //////////////////////////////// internal void @@ -2872,6 +2885,7 @@ lnk_init_section_table(LNK_SymbolTable *symtab, U64 section_virt_off, U64 sect_a { ".edata", LNK_EDATA_SYMBOL_NAME, LNK_EDATA_SECTION_FLAGS }, { ".rsrc", LNK_RSRC_SYMBOL_NAME, LNK_RSRC_SECTION_FLAGS }, { ".debug", LNK_DEBUG_SYMBOL_NAME, LNK_DEBUG_SECTION_FLAGS }, + { ".tls", LNK_TLS_SYMBOL_NAME, LNK_TLS_SECTION_FLAGS }, }; LNK_SectionTable *st = lnk_section_table_alloc(section_virt_off, sect_align, file_align); @@ -2880,8 +2894,7 @@ lnk_init_section_table(LNK_SymbolTable *symtab, U64 section_virt_off, U64 sect_a sect->symbol_name = str8_cstring(sect_layout[i].symbol); sect->symbol_name = push_str8_copy(sect->arena, sect->symbol_name); - LNK_Symbol *symbol = lnk_make_defined_symbol_chunk(symtab->arena, sect->symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); - lnk_symbol_table_push(symtab, symbol); + lnk_symbol_table_push_defined_chunk(symtab, sect->symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } st->null_sect = lnk_section_list_remove(&st->list, str8_lit(".null")); @@ -2903,6 +2916,7 @@ lnk_init_merge_directive_list(Arena *arena, LNK_ObjList obj_list) LNK_MergeDirectiveList result = {0}; lnk_merge_directive_list_push(arena, &result, (LNK_MergeDirective){ str8_lit_comp(".xdata") , str8_lit_comp(".rdata") }); + //lnk_merge_directive_list_push(arena, &result, (LNK_MergeDirective){ str8_lit_comp(".tls"), str8_lit_comp(".data") }); // collect merge directives from objs for (LNK_ObjNode *obj_node = obj_list.first; obj_node != 0; obj_node = obj_node->next) { @@ -3130,6 +3144,15 @@ lnk_blake3_hash_parallel(TP_Context *tp, U64 chunk_count, String8 data) return result; } +LNK_CHUNK_VISITOR_SIG(lnk_max_tls_align) +{ + if (chunk->type == LNK_Chunk_Leaf) { + U64 *max_align = ud; + *max_align = Max(*max_align, chunk->align); + } + return 0; +} + internal void lnk_run(int argc, char **argv) { @@ -3150,7 +3173,6 @@ lnk_run(int argc, char **argv) State_SearchEntryPoint, State_CheckUnusedDelayLoads, State_ReportUnresolvedSymbols, - State_RewireComdats, State_DiscardMetaDataSections, State_BuildDebugDirectory, State_BuildExportTable, @@ -3207,7 +3229,6 @@ l.count += 1; \ LNK_InputLibList input_libs[LNK_InputSource_Count] = {0}; LNK_InputObjList input_obj_list = {0}; LNK_InputImportList input_import_list = {0}; - LNK_SymbolList input_defn_list = {0}; LNK_SymbolList input_weak_list = {0}; // :null_obj @@ -3222,7 +3243,7 @@ l.count += 1; \ input_libs[LNK_InputSource_Default] = config->input_default_lib_list; // state - LNK_SymbolTable *symtab = lnk_symbol_table_alloc_ex(config->symbol_table_cap_defined, config->symbol_table_cap_internal, config->symbol_table_cap_weak, config->symbol_table_cap_lib); + LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); LNK_SectionTable *st = lnk_init_section_table(symtab, config->section_virt_off, config->sect_align, config->file_align); LNK_ImportTable *imptab_static = 0; LNK_ImportTable *imptab_delayed = 0; @@ -3249,11 +3270,10 @@ l.count += 1; \ B32 build_base_relocs = !(config->flags & LNK_ConfigFlag_Fixed); B32 report_unresolved_symbols = 1; B32 check_unused_delay_loads = !!(config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll); - B32 do_comdat_rewire = 1; B32 build_win32_header = 1; B32 patch_relocs = 1; B32 sort_exception_info = 1; - B32 build_imp_lib = config->build_imp_lib; + B32 build_imp_lib = 1; //config->build_imp_lib; LNK_ObjList obj_list = {0}; LNK_LibList lib_index[LNK_InputSource_Count] = {0}; String8 image_data = str8_zero(); @@ -3332,8 +3352,8 @@ l.count += 1; \ if (entry_point_symbol) { lnk_error(LNK_Error_EntryPoint, "multiple entry point symbols found: %S(%S) and %S(%S)", - entry_point_symbol->name, entry_point_symbol->debug, - symbol->name, symbol->debug); + entry_point_symbol->name, entry_point_symbol->obj->path, + symbol->name, symbol->obj->path); } else { entry_point_symbol = symbol; } @@ -3432,8 +3452,8 @@ l.count += 1; \ ProfBegin("Push /INCLUDE Symbols"); for (String8Node *include_node = include_symbol_list.first; include_node != 0; include_node = include_node->next) { - String8 name = push_str8_copy(symtab->arena, include_node->string); - LNK_Symbol *symbol = lnk_make_undefined_symbol(symtab->arena, name, LNK_SymbolScopeFlag_Main); + String8 name = push_str8_copy(symtab->arena->v[0], include_node->string); + LNK_Symbol *symbol = lnk_make_undefined_symbol(symtab->arena->v[0], name, LNK_SymbolScopeFlag_Main); lnk_symbol_list_push(scratch.arena, &lookup_undef_list, symbol); } ProfEnd(); @@ -3443,64 +3463,19 @@ l.count += 1; \ for (String8Node *from_node = alt_name_list.from_list.first, *to_node = alt_name_list.to_list.first; from_node != 0; from_node = from_node->next, to_node = to_node->next) { - String8 to_name = push_str8_copy(symtab->arena, to_node->string); - String8 from_name = push_str8_copy(symtab->arena, from_node->string); - LNK_Symbol *fallback = lnk_make_undefined_symbol(symtab->arena, to_name, LNK_SymbolScopeFlag_Main); - LNK_Symbol *weak = lnk_make_weak_symbol(symtab->arena, from_name, COFF_WeakExtType_SEARCH_ALIAS, fallback); + LNK_Symbol *weak = lnk_symbol_table_push_weak(symtab, from_node->string, COFF_WeakExtType_SEARCH_ALIAS, to_node->string); lnk_symbol_list_push(scratch.arena, &input_weak_list, weak); } ProfEnd(); - - ProfBegin("Push Defined Symbols"); - { - Temp temp = temp_begin(scratch.arena); - - ProfBegin("List -> Array"); - LNK_SymbolNodeArray symbol_arr = lnk_symbol_node_array_from_list(temp.arena, input_defn_list); - ProfEnd(); - - ProfBegin("Hash Symbol Names"); - lnk_symbol_node_ptr_array_hash(tp, symbol_arr.v, symbol_arr.count); - ProfEnd(); - - ProfBegin("Populate Buckets"); - LNK_SymbolList *bucket_arr = push_array(temp.arena, LNK_SymbolList, symtab->bucket_count[LNK_SymbolScopeIndex_Defined]); - for (U64 symbol_idx = 0; symbol_idx < symbol_arr.count; symbol_idx += 1) { - LNK_SymbolNode *symbol_node = symbol_arr.v[symbol_idx]; - U64 bucket_idx = symbol_node->hash % symtab->bucket_count[LNK_SymbolScopeIndex_Defined]; - lnk_symbol_list_push_node(&bucket_arr[bucket_idx], symbol_node); - } - ProfEnd(); - - ProfBegin("Insert Defined Symbols"); - LNK_DefinedSymbolInserter symbol_inserter = {0}; - symbol_inserter.symtab = symtab; - symbol_inserter.bucket_arr = bucket_arr; - symbol_inserter.range_arr = tp_divide_work(temp.arena, symtab->bucket_count[LNK_SymbolScopeIndex_Defined], tp->worker_count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_defined_symbol_inserter, &symbol_inserter); - ProfEnd(); - - temp_end(temp); - } - ProfEnd(); - - ProfBegin("Push Weak Symbols"); - for (LNK_SymbolNode *curr = input_weak_list.first; curr != 0; curr = curr->next) { - lnk_symbol_table_push(symtab, curr->data); - } - ProfEnd(); - - LNK_SymbolList new_weak_symbols = lnk_symbol_list_copy(scratch.arena, input_weak_list); - + // we defined new symbols, give unresolved symbols another chance to be resolved lnk_symbol_list_concat_in_place(&lookup_undef_list, &unresolved_undef_list); - lnk_symbol_list_concat_in_place(&lookup_weak_list, &new_weak_symbols); + lnk_symbol_list_concat_in_place(&lookup_weak_list, &input_weak_list); lnk_symbol_list_concat_in_place(&lookup_weak_list, &unresolved_weak_list); // reset inputs MemoryZeroStruct(&include_symbol_list); MemoryZeroStruct(&alt_name_list); - MemoryZeroStruct(&input_defn_list); MemoryZeroStruct(&input_weak_list); ProfEnd(); @@ -3612,16 +3587,15 @@ l.count += 1; \ // derive machine from obj if (config->machine == COFF_MachineType_UNKNOWN) { config->machine = obj->machine; - } - - // is obj machine compatible? - if (obj->machine != COFF_MachineType_UNKNOWN && // obj with unknown machine type is compatible with any other machine type - config->machine != obj->machine) { - lnk_error_obj(LNK_Error_IncompatibleObj, - obj, - "conflicting machine types expected %S but got %S", - coff_string_from_machine_type(config->machine), - coff_string_from_machine_type(obj->machine)); + } else { + // is obj machine compatible? + if (config->machine != obj->machine && + obj->machine != COFF_MachineType_UNKNOWN) { // obj with unknown machine type is compatible with any other machine type + lnk_error_obj(LNK_Error_IncompatibleObj, obj, + "conflicting machine types expected %S but got %S", + coff_string_from_machine_type(config->machine), + coff_string_from_machine_type(obj->machine)); + } } } ProfEnd(); @@ -3644,14 +3618,15 @@ l.count += 1; \ // collect libs for input LNK_InputLibList lib_list = lnk_collect_default_lib_obj_arr(tp, tp_arena, obj_node_arr); // TODO: put these on temp arena str8_list_concat_in_place(&input_libs[LNK_InputSource_Obj], &lib_list); + + // update symbol table + lnk_push_defined_symbols(tp, symtab, obj_node_arr); // collect symbols for input - LNK_SymbolList new_defn_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_DefinedExtern); LNK_SymbolList new_weak_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_Weak); LNK_SymbolList new_undef_list = lnk_run_symbol_collector(tp, tp_arena, obj_node_arr, LNK_Symbol_Undefined); // TODO: allocate these on temp arena // schedule symbol input - lnk_symbol_list_concat_in_place(&input_defn_list, &new_defn_list); lnk_symbol_list_concat_in_place(&input_weak_list, &new_weak_list); lnk_symbol_list_concat_in_place(&lookup_undef_list, &new_undef_list); @@ -3723,43 +3698,16 @@ l.count += 1; \ } ProfEnd(); - LNK_LibNodeArray lib_arr; - { - ProfBegin("Disk Read Libs"); - String8Array path_arr = str8_array_from_list(scratch.arena, &unique_input_lib_list); - String8Array data_arr = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], path_arr); - ProfEnd(); - - ProfBegin("Lib Init"); - lib_arr = lnk_lib_list_push_parallel(tp, tp_arena, &lib_index[input_source], data_arr, path_arr); - ProfEnd(); - - ProfBegin("Count Symbols"); - U64 total_symbol_count = 0; - for (U64 lib_idx = 0; lib_idx < lib_arr.count; lib_idx += 1) { - total_symbol_count += lib_arr.v[lib_idx].data.symbol_count; - } - ProfEnd(); - - ProfBegin("Setup Symbol Array Pointers"); - LNK_Symbol *symbol_arr = push_array_no_zero(symtab->arena, LNK_Symbol, total_symbol_count); - LNK_Symbol **symbol_arr_arr = push_array_no_zero(scratch.arena, LNK_Symbol *, lib_arr.count); - for (U64 lib_idx = 0, cursor = 0; lib_idx < lib_arr.count; lib_idx += 1) { - symbol_arr_arr[lib_idx] = &symbol_arr[cursor]; - cursor += lib_arr.v[lib_idx].data.symbol_count; - } - ProfEnd(); - - ProfBegin("Lazy Symbol Init"); - LNK_LazyIniter lazy_initer_ctx = {0}; - lazy_initer_ctx.range_arr = tp_divide_work(scratch.arena, lib_arr.count, tp->worker_count); - lazy_initer_ctx.lib_arr = lib_arr.v; - lazy_initer_ctx.symbol_arr_arr = symbol_arr_arr; - tp_for_parallel(tp, 0, tp->worker_count, lnk_lazy_initer, &lazy_initer_ctx); - ProfEnd(); - - lnk_symbol_table_push_lazy_arr(tp, symtab, symbol_arr, total_symbol_count); - } + ProfBegin("Disk Read Libs"); + String8Array path_arr = str8_array_from_list(scratch.arena, &unique_input_lib_list); + String8Array data_arr = lnk_read_data_from_file_path_parallel(tp, tp_arena->v[0], path_arr); + ProfEnd(); + + ProfBegin("Lib Init"); + LNK_LibNodeArray lib_arr = lnk_lib_list_push_parallel(tp, tp_arena, &lib_index[input_source], data_arr, path_arr); + ProfEnd(); + + lnk_push_lazy_symbols(tp, symtab, lib_arr); if (lnk_get_log_status(LNK_Log_InputLib)) { if (lib_arr.count > 0) { @@ -3925,12 +3873,7 @@ l.count += 1; \ goto exit; } } break; - case State_RewireComdats: { - ProfBegin("Fold COMDAT symbols"); - lnk_fold_comdat_chunks(tp, symtab); - ProfEnd(); - } break; - + case State_DiscardMetaDataSections: { ProfBegin("Discard Meta Data Sections"); lnk_discard_meta_data_sections(st); @@ -3945,8 +3888,7 @@ l.count += 1; \ LNK_Chunk *debug_dir_array_chunk = lnk_section_push_chunk_list(debug_sect, debug_chunk, str8_zero()); // push symbols for PE directory patch - LNK_Symbol *dir_array_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_DEBUG_DIR_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_dir_array_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, dir_array_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_DEBUG_DIR_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_dir_array_chunk, 0, 0, 0); // debug entry for PDB if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { @@ -4061,12 +4003,45 @@ l.count += 1; \ String8 size_string = str8_from_memory_size2(scratch.arena, total_input_size); lnk_log(LNK_Log_InputLib, "[Total Lib Input Size %S]", size_string); } + + //lnk_symbol_hash_trie_debug(symtab->scopes[LNK_SymbolScopeIndex_Lib]); ProfBegin("Image Serialize"); image_data = lnk_section_table_serialize(scratch.arena, st); ProfEnd(); - + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + + LNK_Symbol *tls_used_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Main, "_tls_used"); + if (tls_used_symbol) { + ProfBegin("Patch TLS Align"); + + // loop over .tls sections and extract max alignment + LNK_Symbol *tls_sect_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_TLS_SYMBOL_NAME); + LNK_Chunk *tls_root_chunk = tls_sect_symbol->u.defined.u.chunk; + U64 tls_align = 0; + lnk_visit_chunks(0, tls_root_chunk, lnk_max_tls_align, &tls_align); + + if (IsPow2(tls_align)) { + // compute TLS header offset + U64 tls_header_foff = lnk_file_off_from_symbol(sect_id_map, tls_used_symbol); + + // patch TLS header + if (coff_word_size_from_machine(config->machine) == 8) { + String8 raw_tls_used = str8_substr(image_data, rng_1u64(tls_header_foff, tls_header_foff + sizeof(PE_TLSHeader64))); + PE_TLSHeader64 *tls_header = (PE_TLSHeader64 *) raw_tls_used.str; + tls_header->characteristics |= coff_section_flag_from_align_size(tls_align); + } else { + String8 raw_tls_used = str8_substr(image_data, rng_1u64(tls_header_foff, tls_header_foff + sizeof(PE_TLSHeader32))); + PE_TLSHeader32 *tls_header = (PE_TLSHeader32 *) raw_tls_used.str; + tls_header->characteristics |= coff_section_flag_from_align_size(tls_align); + } + } else { + lnk_error(LNK_Warning_TLSAlign, "unable to patch TLS Header characteristics, alignment must be power of two, align inferred from section flags: %llu", tls_align); + } + + ProfEnd(); + } if (config->flags & LNK_ConfigFlag_WriteImageChecksum) { ProfBegin("Image Checksum"); @@ -4196,8 +4171,7 @@ l.count += 1; \ state_list_push(scratch.arena, state_list, State_InputImports); continue; } - if (input_defn_list.count || - input_weak_list.count || + if (input_weak_list.count || include_symbol_list.node_count || alt_name_list.from_list.node_count) { state_list_push(scratch.arena, state_list, State_InputSymbols); @@ -4264,11 +4238,6 @@ l.count += 1; \ state_list_push(scratch.arena, state_list, State_BuildAndInputLinkerObj); continue; } - if (do_comdat_rewire) { - do_comdat_rewire = 0; - state_list_push(scratch.arena, state_list, State_RewireComdats); - continue; - } if (check_unused_delay_loads) { check_unused_delay_loads = 0; state_list_push(scratch.arena, state_list, State_CheckUnusedDelayLoads); @@ -4359,7 +4328,6 @@ l.count += 1; \ // linker is done punt memory release to OS //lnk_section_table_release(&st); - //lnk_symbol_table_release(&symtab); //lnk_export_table_release(&export_table); //lnk_import_table_release(&imptab_static); //lnk_import_table_release(&imptab_delayed); @@ -4376,6 +4344,9 @@ internal void entry_point(CmdLine *cmdline) { Temp scratch = scratch_begin(0,0); + + int a = 123; + int asdasd = 2; #if PROFILE_TELEMETRY tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index d8e5c28d..b77ea5ca 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -172,13 +172,6 @@ typedef struct HashTable **page_ht_arr; } LNK_ObjBaseRelocTask; -typedef struct -{ - Rng1U64 *range_arr; - LNK_LibNode *lib_arr; - LNK_Symbol **symbol_arr_arr; -} LNK_LazyIniter; - typedef struct { LNK_InputObjList input_obj_list; @@ -195,6 +188,15 @@ typedef struct Rng1U64 *range_arr; } LNK_SymbolFinder; +typedef struct +{ + LNK_SymbolTable *symtab; + union { + LNK_ObjNodeArray objs; + LNK_LibNodeArray libs; + } u; +} LNK_SymbolPusher; + typedef struct { LNK_SymbolTable *symtab; @@ -214,7 +216,6 @@ typedef struct LNK_Obj **obj_arr; } LNK_ObjRelocPatcher; - typedef struct { String8 path; diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index 072fa85c..23d5dccb 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -43,6 +43,8 @@ typedef struct LNK_Chunk #if LNK_DEBUG_CHUNKS String8 debug; #endif + + int debug; } LNK_Chunk, * LNK_ChunkPtr; typedef struct LNK_ChunkNode diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index a9589880..e7a177d5 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2827,20 +2827,23 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task) //////////////////////////////// internal -THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task) +THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task) { - U64 bucket_idx = task_id; - LNK_BuildPublicSymbolsTaskData *task = raw_task; + ProfBeginFunction(); - LNK_Section **sect_id_map = task->sect_id_map; - LNK_SymbolScopeIndex scope_idx = task->scope_idx; - LNK_SymbolList bucket = task->bucket_arr[scope_idx][bucket_idx]; - CV_SymbolList *pub_list = &task->pub_list_arr[bucket_idx]; + LNK_BuildPublicSymbolsTask *task = raw_task; + LNK_Section **sect_id_map = task->sect_id_map; + CV_SymbolList *pub_list = &task->pub_list_arr[task_id]; + LNK_SymbolHashTrieChunkList chunk_list = task->chunk_lists[task_id]; - for (LNK_SymbolNode *symbol_node = bucket.first; symbol_node != 0; symbol_node = symbol_node->next) { - LNK_Symbol *symbol = symbol_node->data; + for (LNK_SymbolHashTrieChunk *chunk = chunk_list.first; chunk != 0; chunk = chunk->next) { + CV_SymbolNode *nodes = push_array_no_zero(arena, CV_SymbolNode, chunk->count); + + for (U64 i = 0, node_idx = 0; i < chunk->count; ++i) { + LNK_Symbol *symbol = chunk->v[i].symbol; + + Assert(LNK_Symbol_IsDefined(symbol->type)); - if (LNK_Symbol_IsDefined(symbol->type)) { LNK_DefinedSymbol *defined_symbol = &symbol->u.defined; if (defined_symbol->value_type == LNK_DefinedSymbolValue_Chunk) { CV_Pub32Flags flags = 0; @@ -2854,11 +2857,15 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_task) U32 symbol_off32 = safe_cast_u32(symbol_off); U16 symbol_isect16 = safe_cast_u16(symbol_isect); - CV_SymbolNode *pub_node = cv_symbol_list_push(arena, pub_list); - pub_node->data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name); + nodes[node_idx].data = cv_make_pub32(arena, flags, symbol_off32, symbol_isect16, symbol->name); + cv_symbol_list_push_node(pub_list, &nodes[node_idx]); + + ++node_idx; } } } + + ProfEnd(); } internal @@ -2866,8 +2873,8 @@ THREAD_POOL_TASK_FUNC(lnk_gsi_hash_cv_list_task) { ProfBeginFunction(); - LNK_BuildPublicSymbolsTaskData *task = raw_task; - Rng1U64 range = task->symbol_ranges[task_id]; + LNK_BuildPublicSymbolsTask *task = raw_task; + Rng1U64 range = task->symbol_ranges[task_id]; for (U64 symbol_idx = range.min; symbol_idx < range.max; ++symbol_idx) { CV_Symbol *symbol = &task->symbols.v[symbol_idx]->data; @@ -2883,22 +2890,20 @@ lnk_build_pdb_public_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_Section **sect_id_map, - PDB_PsiContext *psi, - LNK_SymbolScopeIndex scope_idx) + PDB_PsiContext *psi) { ProfBeginFunction(); Temp scratch = scratch_begin(arena->v, arena->count); - ProfBegin("Make Public Symbols"); - LNK_BuildPublicSymbolsTaskData task = {0}; - task.sect_id_map = sect_id_map; - task.scope_idx = scope_idx; - task.bucket_arr = symtab->buckets; - task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, symtab->bucket_count[scope_idx]); - tp_for_parallel(tp, arena, symtab->bucket_count[scope_idx], lnk_build_pdb_public_symbols_task, &task); + ProfBegin("Defined"); + LNK_BuildPublicSymbolsTask task = {0}; + task.sect_id_map = sect_id_map; + task.pub_list_arr = push_array(scratch.arena, CV_SymbolList, tp->worker_count); + task.chunk_lists = symtab->chunk_lists[LNK_SymbolScopeIndex_Defined]; + tp_for_parallel(tp, arena, tp->worker_count, lnk_build_pdb_public_symbols_defined_task, &task); ProfEnd(); - CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, symtab->bucket_count[scope_idx], task.pub_list_arr); + CV_SymbolPtrArray symbols = cv_symbol_ptr_array_from_list(scratch.arena, tp, tp->worker_count, task.pub_list_arr); ProfBegin("GSI Push"); gsi_push_many_arr(tp, psi->gsi, symbols.count, symbols.v); @@ -3070,7 +3075,7 @@ lnk_build_pdb(TP_Context *tp, ProfBegin("Build DBI Section Headers"); { LNK_Symbol *coff_sect_array_symbol = lnk_symbol_table_searchf(symtab, LNK_SymbolScopeFlag_Internal, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); - LNK_Chunk *coff_sect_chunk = lnk_defined_symbol_get_chunk(&coff_sect_array_symbol->u.defined); + LNK_Chunk *coff_sect_chunk = lnk_chunk_from_symbol(coff_sect_array_symbol); String8 coff_sect_chunk_data = lnk_data_from_chunk_ref(sect_id_map, coff_sect_chunk->ref); U64 coff_sect_count = coff_sect_chunk_data.size / sizeof(COFF_SectionHeader); COFF_SectionHeader *coff_sect_ptr = (COFF_SectionHeader*)coff_sect_chunk_data.str; @@ -3125,7 +3130,7 @@ lnk_build_pdb(TP_Context *tp, } ProfEnd(); - lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi, LNK_SymbolScopeIndex_Defined); + lnk_build_pdb_public_symbols(tp, tp_arena, symtab, sect_id_map, pdb->psi); pdb_build(tp, tp_arena, pdb, string_ht); diff --git a/src/linker/lnk_debug_info.h b/src/linker/lnk_debug_info.h index 979dcef0..55865019 100644 --- a/src/linker/lnk_debug_info.h +++ b/src/linker/lnk_debug_info.h @@ -333,16 +333,15 @@ typedef struct typedef struct { - LNK_Section **sect_id_map; - LNK_SymbolScopeIndex scope_idx; - LNK_SymbolList **bucket_arr; - CV_SymbolList *pub_list_arr; + LNK_Section **sect_id_map; + LNK_SymbolHashTrieChunkList *chunk_lists; + CV_SymbolList *pub_list_arr; Rng1U64 *symbol_ranges; PDB_GsiContext *gsi; CV_SymbolPtrArray symbols; U32 *hashes; -} LNK_BuildPublicSymbolsTaskData; +} LNK_BuildPublicSymbolsTask; typedef struct { @@ -566,8 +565,7 @@ internal void lnk_build_pdb_public_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_Section **sect_id_map, - PDB_PsiContext *psi, - LNK_SymbolScopeIndex scope_idx); + PDB_PsiContext *psi); internal String8List lnk_build_pdb(TP_Context *tp, TP_Arena *tp_arena, diff --git a/src/linker/lnk_directive.c b/src/linker/lnk_directive.c index 8857cc3a..6ce82983 100644 --- a/src/linker/lnk_directive.c +++ b/src/linker/lnk_directive.c @@ -70,6 +70,12 @@ lnk_parse_directives(Arena *arena, LNK_DirectiveInfo *directive_info, String8 bu for (U64 i = 0; i < ArrayCount(directive_table); ++i) { if (str8_match(directive_table[i].name, opt->string, StringMatchFlag_CaseInsensitive)) { kind = directive_table[i].kind; +<<<<<<< HEAD +======= + if (kind == LNK_Directive_Merge) { + String8 v = str8_list_join(scratch.arena, &opt->value_strings, &(StringJoin){ .sep = str8_lit_comp(" ")}); + } +>>>>>>> 9e2d09f (switch to thread safe hash trie map) break; } } diff --git a/src/linker/lnk_export_table.c b/src/linker/lnk_export_table.c index 4351d594..ecbe952b 100644 --- a/src/linker/lnk_export_table.c +++ b/src/linker/lnk_export_table.c @@ -218,20 +218,16 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable * lnk_chunk_set_debugf(edata->arena, string_buffer_chunk, "EXPORT_STRING_BUFFER"); lnk_chunk_set_debugf(edata->arena, image_name_chunk, "EXPORT_IMAGE_NAME"); - LNK_Symbol *image_name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0); - LNK_Symbol *address_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0); - LNK_Symbol *name_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0); - LNK_Symbol *ordinal_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, image_name_symbol); - lnk_symbol_table_push(symtab, address_table_symbol); - lnk_symbol_table_push(symtab, name_table_symbol); - lnk_symbol_table_push(symtab, ordinal_table_symbol); + LNK_Symbol *image_name_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_voff"), LNK_DefinedSymbolVisibility_Internal, 0, image_name_chunk, 0, 0, 0); + LNK_Symbol *address_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.export_address_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, voff_table_chunk, 0, 0, 0); + LNK_Symbol *name_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.name_pointer_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, name_voff_table_chunk, 0, 0, 0); + LNK_Symbol *ordinal_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("export_table.ordinal_table_voff"), LNK_DefinedSymbolVisibility_Internal, 0, ordinal_table_chunk, 0, 0, 0); // patch header fields - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol); + lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_voff), image_name_symbol); lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, export_address_table_voff), address_table_symbol); - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol); - lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol); + lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, name_pointer_table_voff), name_table_symbol); + lnk_section_push_reloc(edata, header_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_ExportTable, ordinal_table_voff), ordinal_table_symbol); // reserve virtual offset chunks LNK_Chunk **ordinal_voff_map = push_array(scratch.arena, LNK_Chunk *, exptab->max_ordinal); @@ -254,9 +250,8 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable * lnk_chunk_set_debugf(edata->arena, name_chunk, "export: %S", name_cstr); // push name symbol - String8 name_export_name = push_str8f(symtab->arena, "export.%S", name_cstr); - LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, name_symbol); + String8 name_export_name = push_str8f(symtab->arena->v[0], "export.%S", name_cstr); + LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_export_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); // name voff LNK_Chunk *voff_chunk = lnk_section_push_chunk_bss(edata, name_voff_table_chunk, exptab->voff_size, /* export table must be sorted lexically: */ name_cstr); diff --git a/src/linker/lnk_import_table.c b/src/linker/lnk_import_table.c index df6cc351..1cf40ff3 100644 --- a/src/linker/lnk_import_table.c +++ b/src/linker/lnk_import_table.c @@ -18,17 +18,11 @@ lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COF LNK_Chunk *null_dll_import = lnk_section_push_chunk_data(data_sect, dll_table_chunk, str8(0, sizeof(PE_ImportEntry)), str8_lit("zzzzz")); lnk_chunk_set_debugf(data_sect->arena, null_dll_import, "DLL_DIRECTORY_TERMINATOR"); - LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0); - LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); - LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); - LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); - LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); - - lnk_symbol_table_push(symtab, dll_table_symbol); - lnk_symbol_table_push(symtab, int_symbol); - lnk_symbol_table_push(symtab, iat_symbol); - lnk_symbol_table_push(symtab, ilt_symbol); - lnk_symbol_table_push(symtab, code_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_NAME_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_IMPORT_JMP_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); Arena *arena = arena_alloc(); LNK_ImportTable *imptab = push_array(arena, LNK_ImportTable, 1); @@ -79,23 +73,14 @@ lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, CO lnk_chunk_set_debugf(data_sect->arena, null_biat_chunk, "BIAT_TERMINATOR"); } - LNK_Symbol *dll_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0); - LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); - LNK_Symbol *handle_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0); - LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); - LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); - LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0); - LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0); - LNK_Symbol *code_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); - - lnk_symbol_table_push(symtab, dll_table_symbol); - lnk_symbol_table_push(symtab, int_symbol); - lnk_symbol_table_push(symtab, handle_table_symbol); - lnk_symbol_table_push(symtab, iat_symbol); - lnk_symbol_table_push(symtab, ilt_symbol); - lnk_symbol_table_push(symtab, biat_symbol); - lnk_symbol_table_push(symtab, uiat_symbol); - lnk_symbol_table_push(symtab, code_symbol); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_DLL_TABLE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, dll_table_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_INT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, int_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_HANDLE_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, handle_table_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_IAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, iat_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_ILT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_BIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_UIAT_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk , 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(LNK_DELAYED_IMPORT_CODE_SYMBOL_NAME) , LNK_DefinedSymbolVisibility_Internal, 0, code_chunk , 0, 0, 0); LNK_ImportTableFlags flags = 0; if (is_unloadable) { @@ -193,21 +178,18 @@ lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symta LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); LNK_Chunk *code_table_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero()); - String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.lookup_table_voff", dll_name); - LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, ilt_symbol); + String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.lookup_table_voff", dll_name); + LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_table_chunk, 0, 0, 0); - String8 iat_symbol_name = push_str8f(symtab->arena, "%S.import_addr_table_voff", dll_name); - LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, iat_symbol); + String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "%S.import_addr_table_voff", dll_name); + LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); - String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name); + String8 dll_name_cstr = push_cstr(data_sect->arena, dll_name); LNK_Chunk *dll_name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, dll_name_cstr, str8_zero()); lnk_chunk_set_debugf(data_sect->arena, dll_name_chunk, "DLL name chunk (%S)", dll_name); - String8 dll_name_voff_name = push_str8f(symtab->arena, "%S.name_voff", dll_name); - LNK_Symbol *dll_name_voff_symbol = lnk_make_defined_symbol_chunk(symtab->arena, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, dll_name_voff_symbol); + String8 dll_name_voff_name = push_str8f(symtab->arena->v[0], "%S.name_voff", dll_name); + LNK_Symbol *dll_name_voff_symbol = lnk_symbol_table_push_defined_chunk(symtab, dll_name_voff_name, LNK_DefinedSymbolVisibility_Internal, 0, dll_name_chunk, 0, 0, 0); // chunk for dll directory entry PE_ImportEntry *dir = push_array(imptab->arena, PE_ImportEntry, 1); @@ -272,32 +254,29 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt imp_desc->time_stamp = 0; // emit entry chunk - String8 imp_desc_data = str8_struct(imp_desc); + String8 imp_desc_data = str8_struct(imp_desc); LNK_Chunk *imp_desc_chunk = lnk_section_push_chunk_data(data_sect, imptab->dll_table_chunk, imp_desc_data, str8_zero()); // emit entry symbol - String8 imp_desc_name = push_str8f(symtab->arena, "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name); - LNK_Symbol *imp_desc_symbol = lnk_make_defined_symbol_chunk(symtab->arena, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, imp_desc_symbol); + String8 imp_desc_name = push_str8f(symtab->arena->v[0], "__DELAY_IMPORT_DESCRIPTOR_%S", dll_name); + LNK_Symbol *imp_desc_symbol = lnk_symbol_table_push_defined_chunk(symtab, imp_desc_name, LNK_DefinedSymbolVisibility_Extern, 0, imp_desc_chunk, 0, 0, 0); // emit string table chunk - String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name); - LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug); + String8 int_table_chunk_debug = push_str8f(data_sect->arena, "delayed.%S.int", dll_name); + LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, int_table_chunk_debug); - String8 int_table_symbol_name = push_str8f(symtab->arena, "delayed.%S.int", dll_name); - LNK_Symbol *int_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, int_table_symbol); + String8 int_table_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.int", dll_name); + LNK_Symbol *int_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_table_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_table_chunk, 0, 0, 0); LNK_Chunk *null_string_chunk = lnk_section_push_chunk_list(data_sect, int_table_chunk, str8_lit("zzzzz")); lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "string table null"); // emit DLL name chunk - String8 name_chunk_data = push_cstr(data_sect->arena, dll_name); - LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero()); + String8 name_chunk_data = push_cstr(data_sect->arena, dll_name); + LNK_Chunk *name_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, name_chunk_data, str8_zero()); - String8 name_symbol_name = push_str8f(symtab->arena, "delayed.%S.name", dll_name); - LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, name_symbol); + String8 name_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.name", dll_name); + LNK_Symbol *name_symbol = lnk_symbol_table_push_defined_chunk(symtab, name_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, name_chunk, 0, 0, 0); // patch DLL name voff lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, name_voff), name_symbol); @@ -305,9 +284,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt // emit DLL handle chunk LNK_Chunk *handle_chunk = lnk_section_push_chunk_bss(data_sect, imptab->handle_table_chunk, handle_size, str8_zero()); - String8 handle_name = push_str8f(symtab->arena, "delayed.%S.handle", dll_name); - LNK_Symbol *handle_symbol = lnk_make_defined_symbol_chunk(symtab->arena, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, handle_symbol); + String8 handle_name = push_str8f(symtab->arena->v[0], "delayed.%S.handle", dll_name); + LNK_Symbol *handle_symbol = lnk_symbol_table_push_defined_chunk(symtab, handle_name, LNK_DefinedSymbolVisibility_Internal, 0, handle_chunk, 0, 0, 0); // patch DLL handle voff lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, module_handle_voff), handle_symbol); @@ -315,9 +293,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt // emit IAT chunk LNK_Chunk *iat_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->iat_chunk, str8_zero()); - String8 iat_table_name = push_str8f(symtab->arena, "delayed.%S.iat", dll_name); - LNK_Symbol *iat_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, iat_table_symbol); + String8 iat_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.iat", dll_name); + LNK_Symbol *iat_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_table_name, LNK_DefinedSymbolVisibility_Internal, 0, iat_table_chunk, 0, 0, 0); LNK_Chunk *null_iat_chunk = lnk_section_push_chunk_bss(data_sect, iat_table_chunk, import_size, str8_lit("zzzzzz")); lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S: IAT terminator", dll_name); @@ -328,9 +305,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Chunk *null_ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, str8_lit("zzzzzz")); lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S: ILT terminator", dll_name); - String8 ilt_table_name = push_str8f(symtab->arena, "delayed.%S.ilt", dll_name); - LNK_Symbol *ilt_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, ilt_table_symbol); + String8 ilt_table_name = push_str8f(symtab->arena->v[0], "delayed.%S.ilt", dll_name); + LNK_Symbol *ilt_table_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_table_name, LNK_DefinedSymbolVisibility_Extern, 0, ilt_table_chunk, 0, 0, 0); // patch import address table voff lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, iat_voff), iat_table_symbol); @@ -343,9 +319,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt if (imptab->flags & LNK_ImportTableFlag_EmitBiat) { biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero()); - String8 biat_symbol_name = push_str8f(symtab->arena, "delayed.%S.BIAT", dll_name); - LNK_Symbol *biat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, biat_symbol); + String8 biat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.BIAT", dll_name); + LNK_Symbol *biat_symbol = lnk_symbol_table_push_defined_chunk(symtab, biat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, biat_chunk, 0, 0, 0); // patch BIAT field off lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, bound_table_voff), biat_symbol); @@ -356,9 +331,8 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt if (imptab->flags & LNK_ImportTableFlag_EmitUiat) { uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero()); - String8 uiat_symbol_name = push_str8f(symtab->arena, "delayed.%S.UIAT", dll_name); - LNK_Symbol *uiat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, uiat_symbol); + String8 uiat_symbol_name = push_str8f(symtab->arena->v[0], "delayed.%S.UIAT", dll_name); + LNK_Symbol *uiat_symbol = lnk_symbol_table_push_defined_chunk(symtab, uiat_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, uiat_chunk, 0, 0, 0); // patch UIAT field voff lnk_section_push_reloc(data_sect, imp_desc_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(PE_DelayedImportEntry, unload_table_voff), uiat_symbol); @@ -372,7 +346,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Chunk *tail_merge_chunk = 0; switch (machine) { case COFF_MachineType_X64: { - LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena, str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); + LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol); } break; default: { @@ -438,9 +412,8 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); // create symbol for lookup chunk - String8 int_symbol_name = push_str8f(symtab->arena, "static.%S.%S.name", dll->name, header->func_name); - LNK_Symbol *int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, int_symbol); + String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name); + LNK_Symbol *int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); // in the file IAT mirrors ILT, dynamic linker later overwrites it with imported function addresses. ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index); @@ -464,12 +437,10 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt } break; } - String8 ilt_symbol_name = push_str8f(symtab->arena, "static.%S.%S.ilt", dll->name, header->func_name); - String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); - LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); - LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, ilt_symbol); - lnk_symbol_table_push(symtab, iat_symbol); + String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.ilt", dll->name, header->func_name); + String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name); + LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); + LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); // generate thunks LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; @@ -481,9 +452,8 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk); // push jump thunk symbol - String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena, header->func_name); + String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name); jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, jmp_thunk_symbol_name); - lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk %S.%S", dll->name, header->func_name); } break; default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break; } @@ -538,19 +508,16 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym if (header->type == COFF_ImportHeaderType_CODE) { switch (dll->machine) { case COFF_MachineType_X64: { - String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); - LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena, iat_symbol_name, LNK_SymbolScopeFlag_Main); - lnk_symbol_set_debugf(symtab->arena, iat_symbol, "x64 IAT (delayed) %S.%S", dll->name, header->func_name); + String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name); + LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main); // emit jmp thunk chunk jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol); jmp_thunk_symbol = lnk_emit_jmp_thunk_symbol(symtab, jmp_thunk_chunk, header->func_name); - lnk_symbol_set_debugf(symtab->arena, jmp_thunk_symbol, "x64 jmp thunk (delayed) %S.%S", dll->name, header->func_name); // emit load thunk load_thunk_chunk = lnk_emit_load_thunk_x64(code_sect, code_table_chunk, iat_symbol, dll->tail_merge_symbol); load_thunk_symbol = lnk_emit_load_thunk_symbol(symtab, load_thunk_chunk, header->func_name); - lnk_symbol_set_debugf(symtab->arena, load_thunk_symbol, "x64 load thunk (delayed) %S.%S", dll->name, header->func_name); } break; default: lnk_not_implemented("TODO: support for machine 0x%X", dll->machine); break; } @@ -582,9 +549,8 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); // create symbol for lookup chunk - String8 int_symbol_name = push_str8f(symtab->arena, "%S.%S.name.delayed", dll->name, header->func_name); - int_symbol = lnk_make_defined_symbol_chunk(symtab->arena, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, int_symbol); + String8 int_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.name.delayed", dll->name, header->func_name); + int_symbol = lnk_symbol_table_push_defined_chunk(symtab, int_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, int_chunk, 0, 0, 0); // dynamic linker patches this voff on DLL load event ilt_chunk = lnk_section_push_chunk_bss(data_sect, ilt_table_chunk, import_size, sort_index); @@ -635,13 +601,11 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym lnk_section_associate_chunks(data_sect, iat_chunk, load_thunk_chunk); } - String8 iat_symbol_name = push_str8f(symtab->arena, "__imp_%S", header->func_name); - LNK_Symbol *iat_symbol = lnk_make_defined_symbol_chunk(symtab->arena, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, iat_symbol); + String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name); + LNK_Symbol *iat_symbol = lnk_symbol_table_push_defined_chunk(symtab, iat_symbol_name, LNK_DefinedSymbolVisibility_Extern, 0, iat_chunk, 0, 0, 0); - String8 ilt_symbol_name = push_str8f(symtab->arena, "%S.%S.ilt.delayed", dll->name, header->func_name); - LNK_Symbol *ilt_symbol = lnk_make_defined_symbol_chunk(symtab->arena, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, ilt_symbol); + String8 ilt_symbol_name = push_str8f(symtab->arena->v[0], "%S.%S.ilt.delayed", dll->name, header->func_name); + LNK_Symbol *ilt_symbol = lnk_symbol_table_push_defined_chunk(symtab, ilt_symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, ilt_chunk, 0, 0, 0); // fill out import LNK_ImportFunc *func = push_array(imptab->arena, LNK_ImportFunc, 1); @@ -771,9 +735,8 @@ lnk_emit_load_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 fu { ProfBeginFunction(); // emit load thunk symbol - String8 load_thunk_name = push_str8f(symtab->arena, "__imp_load_%S", func_name); - LNK_Symbol *load_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, load_thunk_symbol); + String8 load_thunk_name = push_str8f(symtab->arena->v[0], "__imp_load_%S", func_name); + LNK_Symbol *load_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, load_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); ProfEnd(); return load_thunk_symbol; } @@ -782,9 +745,8 @@ internal LNK_Symbol * lnk_emit_jmp_thunk_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) { ProfBeginFunction(); - String8 jmp_thunk_name = push_str8f(symtab->arena, "%S", func_name); - LNK_Symbol *jmp_thunk_symbol = lnk_make_defined_symbol_chunk(symtab->arena, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, jmp_thunk_symbol); + String8 jmp_thunk_name = push_str8f(symtab->arena->v[0], "%S", func_name); + LNK_Symbol *jmp_thunk_symbol = lnk_symbol_table_push_defined_chunk(symtab, jmp_thunk_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); ProfEnd(); return jmp_thunk_symbol; } @@ -793,9 +755,8 @@ internal LNK_Symbol * lnk_emit_tail_merge_symbol(LNK_SymbolTable *symtab, LNK_Chunk *chunk, String8 func_name) { ProfBeginFunction(); - String8 tail_merge_name = push_str8f(symtab->arena, "__tailMerge_%S", func_name); - LNK_Symbol *tail_merge_symbol = lnk_make_defined_symbol_chunk(symtab->arena, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, tail_merge_symbol); + String8 tail_merge_name = push_str8f(symtab->arena->v[0], "__tailMerge_%S", func_name); + LNK_Symbol *tail_merge_symbol = lnk_symbol_table_push_defined_chunk(symtab, tail_merge_name, LNK_DefinedSymbolVisibility_Extern, LNK_DefinedSymbolFlag_IsFunc|LNK_DefinedSymbolFlag_IsThunk, chunk, 0, 0, 0); ProfEnd(); return tail_merge_symbol; } diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index a2457166..193d53a2 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -97,6 +97,8 @@ lnk_lib_symbol_array_sort(LNK_LibSymbol *arr, U64 count) internal LNK_Lib lnk_lib_from_data(Arena *arena, String8 data, String8 path) { + ProfBeginFunction(); + U64 symbol_count; String8 string_table; U32 *member_off_arr; @@ -167,9 +169,11 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path) lib.symbol_name_list = symbol_name_list; lib.long_names = parse.long_names; + ProfEnd(); return lib; } +internal THREAD_POOL_TASK_FUNC(lnk_lib_initer) { LNK_LibIniter *task = raw_task; @@ -179,6 +183,7 @@ THREAD_POOL_TASK_FUNC(lnk_lib_initer) String8 path = task->path_arr[task_id]; *lib = lnk_lib_from_data(arena, data, path); + lib->input_idx = task->base_input_idx + task_id; } internal LNK_LibNodeArray @@ -187,15 +192,16 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, S Assert(data_arr.count == path_arr.count); U64 lib_count = data_arr.count; - LNK_LibIniter lib_initer = {0}; - lib_initer.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count); - lib_initer.data_arr = data_arr.v; - lib_initer.path_arr = path_arr.v; - tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &lib_initer); + LNK_LibIniter task = {0}; + task.node_arr = lnk_lib_list_reserve(arena->v[0], list, lib_count); + task.data_arr = data_arr.v; + task.path_arr = path_arr.v; + task.base_input_idx = list->count; + tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task); - LNK_LibNodeArray arr; - arr.count = lib_count; - arr.v = lib_initer.node_arr; + LNK_LibNodeArray arr = {0}; + arr.count = lib_count; + arr.v = task.node_arr; return arr; } diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 3801e9fd..af87ae84 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -12,6 +12,7 @@ typedef struct LNK_Lib U32 * member_off_arr; String8List symbol_name_list; String8 long_names; + U64 input_idx; } LNK_Lib; typedef struct LNK_LibNode @@ -92,9 +93,10 @@ typedef struct LNK_LibBuild typedef struct { - LNK_LibNode *node_arr; - String8 *data_arr; - String8 *path_arr; + LNK_LibNode *node_arr; + String8 *data_arr; + String8 *path_arr; + U64 base_input_idx; } LNK_LibIniter; //////////////////////////////// diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index d2270a2e..95113386 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -417,7 +417,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) lnk_chunk_set_debugf(arena, master_common_block, "%S: master common block", path); // convert from coff - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, cached_path, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block); + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_symbols, chunk_arr, master_common_block); LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_arr, symbol_arr); @@ -425,6 +425,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) obj->data = input->data; obj->path = cached_path; obj->lib_path = cached_lib_path; + obj->input_idx = obj_idx; obj->machine = coff_info.machine; obj->chunk_count = chunk_count; obj->sect_count = coff_info.section_count_no_null; @@ -712,6 +713,7 @@ lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_lis internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, + LNK_Obj *obj, String8 obj_path, U64 string_table_off, U64 sect_count, @@ -729,7 +731,8 @@ lnk_symbol_array_from_coff(Arena *arena, for (U64 symbol_idx = 0; symbol_idx < coff_symbols.count; symbol_idx += 1) { COFF_Symbol32 *coff_symbol = &coff_symbols.v[symbol_idx]; LNK_Symbol *symbol = &symbol_array.v[symbol_idx]; - lnk_symbol_set_debug(symbol, obj_path); + + symbol->obj = obj; String8 name = coff_read_symbol_name(coff_data, string_table_off, &coff_symbol->name); diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index 370059d1..6a6ee555 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -32,6 +32,7 @@ typedef struct LNK_Obj String8 data; String8 path; String8 lib_path; + U64 input_idx; U64 common_symbol_size; COFF_MachineType machine; U64 chunk_count; @@ -179,7 +180,7 @@ internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 input_count, LNK_InputObj **inputs); internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr); -internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, String8 obj_path, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block); +internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, COFF_Symbol32Array coff_symbols, LNK_Chunk *chunk_arr, LNK_Chunk *master_common_block); internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count); internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_Chunk *sect_chunk_arr, LNK_SymbolArray symbol_array); internal LNK_DirectiveInfo lnk_init_directives(Arena *arena, String8 obj_path, U64 chunk_count, String8 *sect_name_arr, LNK_Chunk *chunk_arr); diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index f6addf1f..26a31e55 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -118,18 +118,20 @@ lnk_make_lazy_symbol(Arena *arena, String8 name, LNK_Lib *lib, U64 member_offset } internal LNK_Chunk * -lnk_defined_symbol_get_chunk(LNK_DefinedSymbol *symbol) +lnk_chunk_from_symbol(LNK_Symbol *symbol) { - if (symbol->value_type == LNK_DefinedSymbolValue_Chunk) { - return symbol->u.chunk; + if (LNK_Symbol_IsDefined(symbol->type) && symbol->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) { + return symbol->u.defined.u.chunk; } return 0; } +//////////////////////////////// + internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node) { - DLLPushBack(list->first, list->last, node); + SLLQueuePush(list->first, list->last, node); list->count += 1; } @@ -137,85 +139,15 @@ internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol) { LNK_SymbolNode *node = push_array(arena, LNK_SymbolNode, 1); - node->data = symbol; + node->data = symbol; lnk_symbol_list_push_node(list, node); return node; } -internal void -lnk_symbol_list_push_list(LNK_SymbolList *list, LNK_SymbolList *to_push) -{ - if (to_push->count) { - if (list->count) { - list->last->next = to_push->first; - to_push->first->prev = list->last; - list->last = to_push->last; - list->count += to_push->count; - } else { - *list = *to_push; - } - MemoryZeroStruct(to_push); - } -} - -internal void -lnk_symbol_list_insert_after(LNK_SymbolList *list, LNK_SymbolNode *node, LNK_SymbolNode *insert) -{ - DLLInsert(list->first, list->last, node, insert); - list->count += 1; -} - -internal LNK_SymbolNode * -lnk_symbol_list_pop_node(LNK_SymbolList *list) -{ - LNK_SymbolNode *node = 0; - if (list->count) { - node = list->first; - DLLRemove(list->first, list->last, node); - node->next = 0; - node->prev = 0; - list->count -= 1; - } - return node; -} - -internal LNK_Symbol * -lnk_symbol_list_pop(LNK_SymbolList *list) -{ - LNK_SymbolNode *node = lnk_symbol_list_pop_node(list); - return node ? node->data : 0; -} - -internal void -lnk_symbol_list_remove(LNK_SymbolList *list, LNK_SymbolNode *node) -{ - Assert(list->count > 0); - - list->count -= 1; - DLLRemove(list->first, list->last, node); - - node->next = 0; - node->prev = 0; -} - internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat) { - DLLConcatInPlace(list, to_concat); -} - -internal LNK_SymbolList -lnk_symbol_list_copy(Arena *arena, LNK_SymbolList list) -{ - LNK_SymbolList result = {0}; - LNK_SymbolNode *node_arr = push_array_no_zero(arena, LNK_SymbolNode, list.count); - for (LNK_SymbolNode *i = list.first; i != 0; i = i->next) { - Assert(result.count < list.count); - LNK_SymbolNode *n = &node_arr[result.count++]; - n->data = i->data; - SLLQueuePush(result.first, result.last, n); - } - return result; + SLLConcatInPlace(list, to_concat); } internal LNK_SymbolNode * @@ -243,8 +175,8 @@ lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr) LNK_SymbolNode *node_arr = push_array_no_zero(arena, LNK_SymbolNode, arr.count); for (U64 i = 0; i < arr.count; i += 1) { LNK_SymbolNode *node = &node_arr[i]; - node->prev = node->next = 0; - node->data = &arr.v[i]; + node->next = 0; + node->data = &arr.v[i]; lnk_symbol_list_push_node(&list, node); } return list; @@ -262,50 +194,6 @@ lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list) return result; } -internal -THREAD_POOL_TASK_FUNC(lnk_symbol_node_ptr_hasher) -{ - LNK_SymbolNodePtrHasher *hasher = raw_task; - Rng1U64 range = hasher->range_arr[task_id]; - for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { - LNK_SymbolNode *symbol_node = hasher->input_arr[symbol_idx]; - symbol_node->hash = lnk_symbol_table_hash(symbol_node->data->name); - } -} - -internal void -lnk_symbol_node_ptr_array_hash(TP_Context *tp, LNK_SymbolNode **arr, U64 count) -{ - Temp scratch = scratch_begin(0, 0); - LNK_SymbolNodePtrHasher hasher = {0}; - hasher.input_arr = arr; - hasher.range_arr = tp_divide_work(scratch.arena, count, tp->worker_count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_symbol_node_ptr_hasher, &hasher); - scratch_end(scratch); -} - -internal -THREAD_POOL_TASK_FUNC(lnk_symbol_node_hasher) -{ - LNK_SymbolNodeHasher *hasher = raw_task; - Rng1U64 range = hasher->range_arr[task_id]; - for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { - LNK_SymbolNode *symbol_node = &hasher->input_arr[symbol_idx]; - symbol_node->hash = lnk_symbol_table_hash(symbol_node->data->name); - } -} - -internal void -lnk_symbol_node_array_hash(TP_Context *tp, LNK_SymbolNode *arr, U64 count) -{ - Temp scratch = scratch_begin(0, 0); - LNK_SymbolNodeHasher hasher = {0}; - hasher.input_arr = arr; - hasher.range_arr = tp_divide_work(scratch.arena, count, tp->worker_count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_symbol_node_hasher, &hasher); - scratch_end(scratch); -} - internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list) { @@ -318,127 +206,332 @@ lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list) return arr; } -internal LNK_Symbol * -lnk_symbol_array_search(LNK_SymbolArray symarr, String8 name, StringMatchFlags flags) +//////////////////////////////// + +internal LNK_SymbolHashTrie * +lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList *list, U64 cap) { - for (U64 isym = 0; isym < symarr.count; ++isym) { - LNK_Symbol *sym = &symarr.v[isym]; - if (str8_match(sym->name, name, flags)) { - return sym; + if (list->last == 0 || list->last->count >= list->last->cap) { + LNK_SymbolHashTrieChunk *chunk = push_array(arena, LNK_SymbolHashTrieChunk, 1); + chunk->cap = cap; + chunk->v = push_array_no_zero(arena, LNK_SymbolHashTrie, cap); + SLLQueuePush(list->first, list->last, chunk); + ++list->count; + } + + LNK_SymbolHashTrie *result = &list->last->v[list->last->count++]; + return result; +} + +internal B32 +lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) +{ + B32 can_replace = 0; + + Assert(dst != src); + Assert(str8_match(dst->name, src->name, 0)); + Assert(src->type != LNK_Symbol_Undefined); + + if (dst->type == LNK_Symbol_Lazy && src->type == LNK_Symbol_Lazy) { + // link.exe picks symbol from lib that is discovered first + LNK_Lib *dst_lib = dst->u.lazy.lib; + LNK_Lib *src_lib = src->u.lazy.lib; + + if (dst_lib->input_idx == src_lib->input_idx) { + //Assert(!"TODO: report duplicate symbols in lib"); } - } - return 0; -} -internal -THREAD_POOL_TASK_FUNC(lnk_symbol_name_hasher) -{ - LNK_SymbolNameHasher *task = raw_task; - Rng1U64 range = task->range_arr[task_id]; - for (U64 symbol_idx = range.min; symbol_idx < range.max; symbol_idx += 1) { - LNK_Symbol *symbol = &task->symbol_arr[symbol_idx]; - task->hash_arr[symbol_idx] = lnk_symbol_table_hash(symbol->name); - } -} + can_replace = dst_lib->input_idx > src_lib->input_idx; + } else if (dst->type == LNK_Symbol_Lazy && (LNK_Symbol_IsDefined(src->type) || src->type == LNK_Symbol_Weak)) { + can_replace = 1; + } else if (dst->type == LNK_Symbol_Weak && LNK_Symbol_IsDefined(src->type)) { + // strong definition found, replace weak symbol + can_replace = 1; + } else if (dst->type == LNK_Symbol_Weak && src->type == LNK_Symbol_Weak) { + B32 is_fallback_same = str8_match(dst->u.weak.fallback_symbol->name, src->u.weak.fallback_symbol->name, 0); + if (!is_fallback_same) { + lnk_error(LNK_Error_MultiplyDefinedSymbol, "multiply defined weak symbol %S, symbol defined in:", src->name); + lnk_supplement_error("%S", dst->obj->path); + lnk_supplement_error("%S", src->obj->path); + } -internal U64 * -lnk_symbol_array_hash(TP_Context *tp, Arena *arena, LNK_Symbol *arr, U64 count) -{ - Temp scratch = scratch_begin(&arena, 1); + if (src->obj && !dst->obj) { + can_replace = 1; + } else if (src->obj && dst->obj) { + can_replace = src->obj->input_idx < dst->obj->input_idx; + } + } else if (LNK_Symbol_IsDefined(dst->type) && LNK_Symbol_IsDefined(src->type)) { + const LNK_DefinedSymbol *dst_defn = &dst->u.defined; + const LNK_DefinedSymbol *src_defn = &src->u.defined; - U64 stride = CeilIntegerDiv(count, tp->worker_count); - Rng1U64 *range_arr = push_array_no_zero(scratch.arena, Rng1U64, tp->worker_count); - for (U64 thread_idx = 0; thread_idx < tp->worker_count; thread_idx += 1) { - Rng1U64 *range = &range_arr[thread_idx]; - range->min = Min(count, stride * thread_idx); - range->max = Min(count, range->min + stride); + if (dst_defn->value_type == LNK_DefinedSymbolValue_Chunk && + src_defn->value_type == LNK_DefinedSymbolValue_Chunk) { + Assert(dst_defn->u.chunk->is_discarded == 0); + Assert(dst_defn->u.chunk->type == LNK_Chunk_Leaf); + Assert(src_defn->u.chunk->type == LNK_Chunk_Leaf); + + // handle communal variable + // + // MSVC CRT relies on this behaviour (e.g. __src_ucrt_dll_is_in_use in ucrt_detection.c) + if (dst_defn->u.chunk->u.leaf.str == 0 && src_defn->u.chunk->u.leaf.size > 0) { + return 1; + } + + COFF_ComdatSelectType dst_select = dst_defn->u.selection; + COFF_ComdatSelectType src_select = src_defn->u.selection; + + // handle objs compiled with /GR- and /GR + if ((src_select == COFF_ComdatSelectType_ANY && dst_select == COFF_ComdatSelectType_LARGEST) || + (src_select == COFF_ComdatSelectType_LARGEST && dst_select == COFF_ComdatSelectType_ANY)) { + dst_select = COFF_ComdatSelectType_LARGEST; + src_select = COFF_ComdatSelectType_LARGEST; + } + + if (src_select == dst_select) { + switch (src_select) { + default: InvalidPath; + case COFF_ComdatSelectType_NULL: + case COFF_ComdatSelectType_ANY: { + LNK_Chunk *dst_chunk = dst_defn->u.chunk; + LNK_Chunk *src_chunk = src_defn->u.chunk; + U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); + U64 src_chunk_size = lnk_chunk_get_size(src_chunk); + if (src_chunk_size == dst_chunk_size) { + can_replace = src_chunk->input_idx < dst_chunk->input_idx; + } else { + // both COMDATs are valid but to get smaller exe pick smallest + can_replace = src_chunk_size < dst_chunk_size; + } + } break; + case COFF_ComdatSelectType_NODUPLICATES: { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } break; + case COFF_ComdatSelectType_SAME_SIZE: { + LNK_Chunk *dst_chunk = dst_defn->u.chunk; + LNK_Chunk *src_chunk = src_defn->u.chunk; + U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); + U64 src_chunk_size = lnk_chunk_get_size(src_chunk); + B32 is_same_size = (dst_chunk_size == src_chunk_size); + if (!is_same_size) { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } + } break; + case COFF_ComdatSelectType_EXACT_MATCH: { + B32 is_exact_match = (dst_defn->u.check_sum == src_defn->u.check_sum); + if (!is_exact_match) { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } + } break; + case COFF_ComdatSelectType_LARGEST: { + LNK_Chunk *dst_chunk = dst_defn->u.chunk; + LNK_Chunk *src_chunk = src_defn->u.chunk; + U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); + U64 src_chunk_size = lnk_chunk_get_size(src_chunk); + if (dst_chunk_size == src_chunk_size) { + can_replace = src_chunk->input_idx < dst_chunk->input_idx; + } else { + can_replace = dst_chunk_size < src_chunk_size; + } + } break; + case COFF_ComdatSelectType_ASSOCIATIVE: { + // ignore + } break; + } + } else { + String8 src_select_str = coff_string_from_comdat_select_type(src_defn->u.selection); + String8 dst_select_str = coff_string_from_comdat_select_type(dst_defn->u.selection); + lnk_error_obj(LNK_Warning_UnresolvedComdat, src->obj, + "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", + src->name, src_select_str, dst_select_str, dst->obj->path); + } + } else if (dst_defn->value_type == LNK_DefinedSymbolValue_VA && src_defn->value_type == LNK_DefinedSymbolValue_Chunk) { + can_replace = 1; + } else { + InvalidPath; + } + } else { + InvalidPath; } - LNK_SymbolNameHasher hasher_ctx = {0}; - hasher_ctx.symbol_arr = arr; - hasher_ctx.range_arr = range_arr; - hasher_ctx.hash_arr = push_array_no_zero(arena, U64, count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_symbol_name_hasher, &hasher_ctx); - - scratch_end(scratch); - return hasher_ctx.hash_arr; -} - -internal LNK_SymbolTable * -lnk_symbol_table_alloc(void) -{ - return lnk_symbol_table_alloc_ex(0x1000, 0x100, 0x500, 0x1000); -} - -internal LNK_SymbolTable * -lnk_symbol_table_alloc_ex(U64 defined_cap, U64 internal_cap, U64 weak_cap, U64 lib_cap) -{ - ProfBeginDynamic("Alloc Symbol Table [Defined: 0x%llx, Internal: 0x%llx, Weak: 0x%llx, Lib: 0x%llx]", defined_cap, internal_cap, weak_cap, lib_cap); - Arena *arena = arena_alloc(); - LNK_SymbolTable *symtab = push_array(arena, LNK_SymbolTable, 1); - symtab->arena = arena; - symtab->bucket_count[LNK_SymbolScopeIndex_Defined] = defined_cap; - symtab->bucket_count[LNK_SymbolScopeIndex_Internal] = internal_cap; - symtab->bucket_count[LNK_SymbolScopeIndex_Weak] = weak_cap; - symtab->bucket_count[LNK_SymbolScopeIndex_Lib] = lib_cap; - for (U64 iscope = 0; iscope < ArrayCount(symtab->buckets); ++iscope) { - symtab->buckets[iscope] = push_array(symtab->arena, LNK_SymbolList, symtab->bucket_count[iscope]); - } - ProfEnd(); - return symtab; + return can_replace; } internal void -lnk_symbol_table_release(LNK_SymbolTable **symtab) +lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) { - ProfBeginFunction(); - arena_release((*symtab)->arena); - *symtab = 0; - ProfEnd(); -} + Assert(dst != src); -internal U64 -lnk_symbol_table_hash(String8 string) -{ - return hash_from_str8(string); -} + if (dst->type == LNK_Symbol_Lazy && src->type == LNK_Symbol_Lazy) { + dst->u.lazy = src->u.lazy; + } else if (LNK_Symbol_IsDefined(dst->type)) { + LNK_DefinedSymbol *dst_defined = &dst->u.defined; -internal LNK_SymbolNode * -lnk_symbol_table_search_bucket(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 bucket_idx, String8 name, U64 hash) -{ - for (LNK_SymbolNode *node = symtab->buckets[scope_idx][bucket_idx].first; node != 0; node = node->next) { - if (hash == node->hash && str8_match(node->data->name, name, 0)) { - return node; + if (dst_defined->value_type == LNK_DefinedSymbolValue_Chunk) { + // discard chunk from output + dst_defined->u.chunk->is_discarded = 1; + + if (LNK_Symbol_IsDefined(src->type)) { + LNK_DefinedSymbol *src_defined = &src->u.defined; + + if (src_defined->value_type == LNK_DefinedSymbolValue_Chunk) { + // static symbols that are not part of obj's symbol table might point to discarded chunk + dst_defined->u.chunk->ref = src_defined->u.chunk->ref; + + // copy offset because after folding COMDATS we might end + // up with larger sized chunk and, for instance, a vftable + // might have a function pointer preceeding lead symbol + dst_defined->u.chunk = src_defined->u.chunk; + dst_defined->u.chunk_offset = src_defined->u.chunk_offset; + } + } else { + InvalidPath; + } } } - return 0; } -internal LNK_SymbolNode * -lnk_symbol_table_search_node_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name, U64 hash) +internal void +lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_symbol) { - while (scope_flags) { - LNK_SymbolScopeIndex scope_idx = ctz64(scope_flags); - scope_flags &= scope_flags - 1; - U64 bucket_idx = hash % symtab->bucket_count[scope_idx]; - LNK_SymbolNode *node = lnk_symbol_table_search_bucket(symtab, scope_idx, bucket_idx, name, hash); - if (node) return node; + LNK_SymbolHashTrie **curr_trie_ptr = trie; + + for (U64 h = hash; ; h <<= 2) { + // load current pointer + LNK_SymbolHashTrie *curr_trie = ins_atomic_ptr_eval(curr_trie_ptr); + + if (curr_trie == 0) { + // init node + LNK_SymbolHashTrie *new_trie = lnk_symbol_hash_trie_chunk_list_push(arena, chunk_list, 512); + new_trie->name = &new_symbol->name; + new_trie->symbol = new_symbol; + MemoryZeroArray(new_trie->child); + + // try to insert new node + LNK_SymbolHashTrie *cmp = ins_atomic_ptr_eval_cond_assign(curr_trie_ptr, new_trie, curr_trie); + + // was symbol inserted? + if (cmp == curr_trie) { + break; + } + + // rollback chunk list push + chunk_list->last->count -= 1; + + // retry insert with trie node from another thread + curr_trie = cmp; + } + + // load current symbol + String8 *curr_name = ins_atomic_ptr_eval(&curr_trie->name); + + if (curr_name) { + if (str8_match(*curr_name, new_symbol->name, 0)) { + for (LNK_Symbol *src = new_symbol, *dst;;) { + LNK_Symbol *dst = ins_atomic_ptr_eval_assign(&curr_trie->symbol, 0); + + if (dst) { + if (lnk_can_replace_symbol(dst, src)) { + // HACK: patch dst because relocations might point to it + lnk_on_symbol_replace(dst, src); + + // swap + dst = src; + } else { + // discard source + lnk_on_symbol_replace(src, dst); + } + } + + // try insert back symbol + dst = ins_atomic_ptr_eval_cond_assign(&curr_trie->symbol, src, 0); + + if (dst == 0) { + break; + } + } + + break; + } + } + + // descend + curr_trie_ptr = curr_trie->child + (h >> 62); } - return 0; } -internal LNK_SymbolNode * -lnk_symbol_table_search_node(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name) +internal LNK_SymbolHashTrie * +lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name) { - U64 hash = lnk_symbol_table_hash(name); - return lnk_symbol_table_search_node_hash(symtab, scope_flags, name, hash); + LNK_SymbolHashTrie *result = 0; + LNK_SymbolHashTrie **curr_ptr = ≜ + for (U64 h = hash; ; h <<= 2) { + LNK_SymbolHashTrie *curr = ins_atomic_ptr_eval(curr_ptr); + if (curr == 0) { + break; + } + if (curr->symbol) { + if (str8_match(curr->symbol->name, name, 0)) { + result = curr; + break; + } + } + curr_ptr = curr->child + (h >> 62); + } + return result; +} + +internal void +lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie) +{ + ins_atomic_ptr_eval_assign(&trie->name, 0); + ins_atomic_ptr_eval_assign(&trie->symbol, 0); +} + +//////////////////////////////// + +internal U64 +lnk_symbol_hash(String8 string) +{ + XXH3_state_t hasher; XXH3_64bits_reset(&hasher); + XXH3_64bits_update(&hasher, &string.size, sizeof(string.size)); + XXH3_64bits_update(&hasher, string.str, string.size); + XXH64_hash_t result = XXH3_64bits_digest(&hasher); + return result; +} + +internal LNK_SymbolTable * +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_SymbolScopeIndex_Count; ++i) { + symtab->chunk_lists[i] = push_array(arena->v[0], LNK_SymbolHashTrieChunkList, arena->count); + } + return symtab; } internal LNK_Symbol * -lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name) +lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, U64 hash, String8 name) { - LNK_SymbolNode *node = lnk_symbol_table_search_node(symtab, scope_flags, name); - return node ? node->data : 0; + LNK_Symbol *result = 0; + while (scope_flags) { + LNK_SymbolScopeIndex scope_idx = ctz64(scope_flags); + scope_flags &= scope_flags - 1; + + LNK_SymbolHashTrie *match = lnk_symbol_hash_trie_search(symtab->scopes[scope_idx], hash, name); + if (match) { + result = match->symbol; + break; + } + } + return result; +} + +internal LNK_Symbol * +lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name) +{ + U64 hash = lnk_symbol_hash(name); + return lnk_symbol_table_search_hash(symtab, scope, hash, name); } internal LNK_Symbol * @@ -452,75 +545,37 @@ lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_fla va_end(args); LNK_Symbol *symbol = lnk_symbol_table_search(symtab, scope_flags, name); + scratch_end(scratch); return symbol; } internal void -lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name) +lnk_symbol_table_push_(LNK_SymbolTable *symtab, Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolScopeIndex scope_idx, U64 hash, LNK_Symbol *symbol) { - U64 hash = lnk_symbol_table_hash(name); - U64 ibucket = hash % symtab->bucket_count[scope]; - for (;;) { - LNK_SymbolNode *node = lnk_symbol_table_search_bucket(symtab, scope, ibucket, name, hash); - if (!node) { - break; - } - LNK_SymbolList *bucket = &symtab->buckets[scope][ibucket]; - DLLRemove(bucket->first, bucket->last, node); - bucket->count -= 1; - } -} - -internal LNK_SymbolList * -lnk_symbol_table_bucket_from_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 hash) -{ - U64 bucket_idx = hash % symtab->bucket_count[scope_idx]; - LNK_SymbolList *bucket = &symtab->buckets[scope_idx][bucket_idx]; - return bucket; + lnk_symbol_hash_trie_insert_or_replace(arena, chunk_list, &symtab->scopes[scope_idx], hash, symbol); } internal void -lnk_symbol_table_push_(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, LNK_SymbolNode *node, U64 hash) +lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol) { - LNK_SymbolList *bucket = lnk_symbol_table_bucket_from_hash(symtab, scope_idx, hash); - node->hash = hash; - lnk_symbol_list_push_node(bucket, node); -} - -internal void -lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U64 hash) -{ - switch (node->data->type) { + switch (symbol->type) { case LNK_Symbol_Null: break; case LNK_Symbol_DefinedExtern: { - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Defined, node, hash); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Defined][0], LNK_SymbolScopeIndex_Defined, hash, symbol); } break; + case LNK_Symbol_DefinedInternal: { - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Internal, node, hash); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Internal][0], LNK_SymbolScopeIndex_Internal, hash, symbol); } break; + case LNK_Symbol_Weak: { - LNK_SymbolNode *is_strong_defn_present = lnk_symbol_table_search_node(symtab, LNK_SymbolScopeFlag_Defined, node->data->name); - if (is_strong_defn_present) { - break; - } - - LNK_SymbolNode *is_weak_present = lnk_symbol_table_search_node(symtab, LNK_SymbolScopeFlag_Weak, node->data->name); - if (is_weak_present) { - B32 is_fallback_same = str8_match(is_weak_present->data->u.weak.fallback_symbol->name, node->data->u.weak.fallback_symbol->name, 0); - if (!is_fallback_same) { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "Weak symbol %S conflict detected, symbol defined in:", node->data->name); - lnk_supplement_error("%S", node->data->debug); - lnk_supplement_error("%S", is_weak_present->data->debug); - } - break; - } - - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Weak, node, hash); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Weak][0], LNK_SymbolScopeIndex_Weak, hash, symbol); } break; + case LNK_Symbol_Lazy: { - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Lib, node, hash); + lnk_symbol_table_push_(symtab, symtab->arena->v[0], &symtab->chunk_lists[LNK_SymbolScopeIndex_Lib][0], LNK_SymbolScopeIndex_Lib, hash, symbol); } break; // symbols not supported @@ -532,80 +587,55 @@ lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U } internal void -lnk_symbol_table_push_node(LNK_SymbolTable *symtab, LNK_SymbolNode *node) -{ - U64 hash = lnk_symbol_table_hash(node->data->name); - lnk_symbol_table_push_node_hash(symtab, node, hash); -} - -internal LNK_SymbolNode * lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol) { - LNK_SymbolNode *node = push_array(symtab->arena, LNK_SymbolNode, 1); - node->data = symbol; - lnk_symbol_table_push_node(symtab, node); - return node; -} - -internal -THREAD_POOL_TASK_FUNC(lnk_lazy_symbol_inserter) -{ - LNK_LazySymbolInserter *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - Rng1U64 range = task->range_arr[task_id]; - for (U64 bucket_idx = range.min; bucket_idx < range.max; bucket_idx += 1) { - LNK_SymbolList *bucket = &task->bucket_arr[bucket_idx]; - for (LNK_SymbolNode *curr = bucket->first, *next; curr != 0; curr = next) { - next = curr->next; - lnk_symbol_table_push_(symtab, LNK_SymbolScopeIndex_Lib, curr, curr->hash); - } - } + U64 hash = lnk_symbol_hash(symbol->name); + lnk_symbol_table_push_hash(symtab, hash, symbol); } internal void -lnk_symbol_table_push_lazy_arr(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Symbol *arr, U64 count) +lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name) { - Temp scratch = scratch_begin(0,0); - - ProfBegin("Push Symbol Nodes"); - LNK_SymbolNode *node_arr = push_array_no_zero(symtab->arena, LNK_SymbolNode, count); - for (U64 symbol_idx = 0; symbol_idx < count; symbol_idx += 1) { - LNK_SymbolNode *node = &node_arr[symbol_idx]; - node->prev = node->next = 0; - node->data = &arr[symbol_idx]; + U64 hash = lnk_symbol_hash(name); + LNK_SymbolHashTrie *trie = lnk_symbol_hash_trie_search(symtab->scopes[scope], hash, name); + if (trie) { + lnk_symbol_hash_trie_remove(trie); } - ProfEnd(); - - ProfBegin("Hash Symbol Names"); - lnk_symbol_node_array_hash(tp, node_arr, count); - ProfEnd(); - - ProfBegin("Populate Buckets"); - LNK_SymbolList *bucket_arr = push_array(scratch.arena, LNK_SymbolList, symtab->bucket_count[LNK_SymbolScopeIndex_Lib]); - for (U64 symbol_idx = 0; symbol_idx < count; symbol_idx += 1) { - LNK_SymbolNode *symbol_node = &node_arr[symbol_idx]; - U64 bucket_idx = symbol_node->hash % symtab->bucket_count[LNK_SymbolScopeIndex_Lib]; - lnk_symbol_list_push_node(&bucket_arr[bucket_idx], symbol_node); - } - ProfEnd(); - - ProfBegin("Update Symbol Table"); - LNK_LazySymbolInserter symbol_inserter; - symbol_inserter.symtab = symtab; - symbol_inserter.bucket_arr = bucket_arr; - symbol_inserter.range_arr = tp_divide_work(scratch.arena, symtab->bucket_count[LNK_SymbolScopeIndex_Lib], tp->worker_count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_lazy_symbol_inserter, &symbol_inserter); - ProfEnd(); - - scratch_end(scratch); } -internal void -lnk_symbol_table_push_list(LNK_SymbolTable *symtab, LNK_SymbolList *list) +internal LNK_Symbol * +lnk_symbol_table_push_defined_chunk(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, LNK_Chunk *chunk, U64 offset, COFF_ComdatSelectType selection, U32 check_sum) { - ProfBeginFunction(); - MemoryZeroStruct(list); - ProfEnd(); + LNK_Symbol *symbol = lnk_make_defined_symbol_chunk(symtab->arena->v[0], name, visibility, flags, chunk, offset, selection, check_sum); + lnk_symbol_table_push(symtab, symbol); + return symbol; +} + +internal LNK_Symbol * +lnk_symbol_table_push_defined(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags) +{ + LNK_Symbol *symbol = lnk_make_defined_symbol(symtab->arena->v[0], name, visibility, flags); + lnk_symbol_table_push(symtab, symbol); + return symbol; +} + +internal LNK_Symbol * +lnk_symbol_table_push_defined_va(LNK_SymbolTable *symtab, String8 name, LNK_DefinedSymbolVisibility visibility, LNK_DefinedSymbolFlags flags, U64 va) +{ + LNK_Symbol *symbol = lnk_make_defined_symbol_va(symtab->arena->v[0], name, visibility, flags, va); + lnk_symbol_table_push(symtab, symbol); + return symbol; +} + +internal LNK_Symbol * +lnk_symbol_table_push_weak(LNK_SymbolTable *symtab, String8 weak_name, COFF_WeakExtType lookup, String8 strong_name) +{ + weak_name = push_str8_copy(symtab->arena->v[0], weak_name); + strong_name = push_str8_copy(symtab->arena->v[0], strong_name); + LNK_Symbol *strong_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], strong_name, LNK_SymbolScopeFlag_Main); + LNK_Symbol *weak_symbol = lnk_make_weak_symbol(symtab->arena->v[0], weak_name, COFF_WeakExtType_SEARCH_ALIAS, strong_symbol); + lnk_symbol_table_push(symtab, weak_symbol); + return weak_symbol; } internal LNK_Symbol * @@ -636,10 +666,15 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol) } run_resolver = 1; } break; + case LNK_Symbol_DefinedExtern: { + // search for defined symbol because we don't update symbol pointers in relocations + // whenver we replace them in the symbol table + symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Defined, symbol->name); + Assert(symbol); + } break; case LNK_Symbol_DefinedStatic: - case LNK_Symbol_DefinedExtern: case LNK_Symbol_DefinedInternal: { - /* resolved */ + // symbol resolved } break; default: NotImplemented; } @@ -647,186 +682,62 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol) return symbol; } -internal LNK_SymbolList -lnk_pop_comdat_chain(LNK_SymbolList *bucket, LNK_SymbolNode **cursor) -{ - LNK_SymbolList chain_list = {0}; - - LNK_SymbolNode *leader_node = *cursor; - *cursor = (*cursor)->next; - - lnk_symbol_list_remove(bucket, leader_node); - lnk_symbol_list_push_node(&chain_list, leader_node); - - while (*cursor) { - LNK_SymbolNode *next = (*cursor)->next; - - // symbols with identical names are stored in order - if (!str8_match(leader_node->data->name, (*cursor)->data->name, 0)) { - break; - } - - // move node to chain list - lnk_symbol_list_remove(bucket, *cursor); - lnk_symbol_list_push_node(&chain_list, *cursor); - - // advance - *cursor = next; - } - - return chain_list; -} - -internal LNK_SymbolNode * -lnk_fold_comdat_chain(LNK_SymbolList chain_list) -{ - LNK_SymbolNode *lead_node = chain_list.first; - - if (LNK_Symbol_IsDefined(lead_node->data->type)) { - LNK_Symbol *lead = lead_node->data; - if (lead->u.defined.value_type != LNK_DefinedSymbolValue_Chunk && chain_list.count > 1) { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "Unable to perfrom COMDAT fold on symbol %S, symbol must reference a section, defined in %S", - lead->name, lead->debug); - return 0; - } - } - - for (LNK_SymbolNode *curr_node = lead_node->next; curr_node != 0; curr_node = curr_node->next) { - Assert(LNK_Symbol_IsDefined(lead_node->data->type)); - Assert(LNK_Symbol_IsDefined(curr_node->data->type)); - - LNK_DefinedSymbol *lead_defined = &lead_node->data->u.defined; - LNK_DefinedSymbol *curr_defined = &curr_node->data->u.defined; - - if (curr_defined->value_type != LNK_DefinedSymbolValue_Chunk) { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "Unable to perfrom COMDAT fold on symbol %S, symbol must reference a section, defined in %S", - curr_node->data->name, curr_node->data->debug); - return 0; - } - - // There is no mentioning of this rule in PE spec, but according to comment from lld-link in 'handleComdatSelection': - // "cl.exe picks "any" for vftabels when building with /GR- and "largest" when building /GR.". However, - // chromium links '__src_ucrt_dll_is_in_use' from MSVCRT which is not a vftable but still requires selection override. - if ((curr_defined->u.selection == COFF_ComdatSelectType_ANY && lead_defined->u.selection == COFF_ComdatSelectType_LARGEST) || - (curr_defined->u.selection == COFF_ComdatSelectType_LARGEST && lead_defined->u.selection == COFF_ComdatSelectType_ANY)) { - lead_defined->u.selection = COFF_ComdatSelectType_LARGEST; - curr_defined->u.selection = COFF_ComdatSelectType_LARGEST; - } - - // COMDATs must have same selection rule - if (lead_defined->u.selection != curr_defined->u.selection) { - String8 curr_selection_str = coff_string_from_comdat_select_type(curr_defined->u.selection); - String8 lead_selection_str = coff_string_from_comdat_select_type(lead_defined->u.selection); - lnk_error(LNK_Warning_UnresolvedComdat, - "COMDAT selection conflict detected in symbol %S defined in %S (%S), leader selection %S from %S", - curr_node->data->name, curr_node->data->debug, curr_selection_str, lead_selection_str, lead_node->data->debug); - return 0; - } - - switch (curr_defined->u.selection) { - case COFF_ComdatSelectType_NULL: - case COFF_ComdatSelectType_ANY: { - // both COMDATs are valid but to get smaller exe pick smallest - LNK_Chunk *lead_chunk = lead_defined->u.chunk; - LNK_Chunk *curr_chunk = curr_defined->u.chunk; - U64 lead_chunk_size = lnk_chunk_get_size(lead_chunk); - U64 curr_chunk_size = lnk_chunk_get_size(curr_chunk); - if (curr_chunk_size < lead_chunk_size) { - lead_node = curr_node; - } - } break; - case COFF_ComdatSelectType_NODUPLICATES: { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "%S: error: multiply defined symbol %S in %S.", curr_node->data->debug, curr_node->data->name, lead_node->data->debug); - } break; - case COFF_ComdatSelectType_SAME_SIZE: { - LNK_Chunk *lead_chunk = lead_defined->u.chunk; - LNK_Chunk *curr_chunk = curr_defined->u.chunk; - U64 lead_chunk_size = lnk_chunk_get_size(lead_chunk); - U64 curr_chunk_size = lnk_chunk_get_size(curr_chunk); - B32 is_same_size = (lead_chunk_size == curr_chunk_size); - if (!is_same_size) { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "%S: error: multiply defined symbol %S in %S.", curr_node->data->debug, curr_node->data->name, lead_node->data->debug); - } - } break; - case COFF_ComdatSelectType_EXACT_MATCH: { - B32 is_exact_match = (lead_defined->u.check_sum == curr_defined->u.check_sum); - if (!is_exact_match) { - lnk_error(LNK_Error_MultiplyDefinedSymbol, "%S: error: multiply defined symbol %S in %S.", curr_node->data->debug, curr_node->data->name, lead_node->data->debug); - } - } break; - case COFF_ComdatSelectType_LARGEST: { - LNK_Chunk *lead_chunk = lead_defined->u.chunk; - LNK_Chunk *curr_chunk = curr_defined->u.chunk; - U64 lead_chunk_size = lnk_chunk_get_size(lead_chunk); - U64 curr_chunk_size = lnk_chunk_get_size(curr_chunk); - if (lead_chunk_size > curr_chunk_size) { - lead_node = curr_node; - } - } break; - case COFF_ComdatSelectType_ASSOCIATIVE: { - // ignore - } break; - } - } - - // rewire chunks so they point to COMDAT leader - for (LNK_SymbolNode *curr_node = chain_list.first; curr_node != 0; curr_node = curr_node->next) { - if (curr_node == lead_node) { - continue; - } - - LNK_DefinedSymbol *curr_defined = &curr_node->data->u.defined; - LNK_Chunk *curr_chunk = curr_defined->u.chunk; - - // copy offset because after folding COMDATS we might end - // up with larger sized chunk and, for instance, a vftable - // might have a function pointer preceeding lead symbol - curr_defined->u.chunk = lead_node->data->u.defined.u.chunk; - curr_defined->u.chunk_offset = lead_node->data->u.defined.u.chunk_offset; - - // discard chunk from output - curr_chunk->is_discarded = 1; - - // static symbols that are not part of obj's symbol table might point to discarded chunk - curr_chunk->ref = lead_node->data->u.defined.u.chunk->ref; - } - - return lead_node; -} - -internal -THREAD_POOL_TASK_FUNC(lnk_comdat_folder) -{ - LNK_ComdatFolder *task = raw_task; - LNK_SymbolTable *symtab = task->symtab; - Rng1U64 range = task->range_arr[task_id]; - for (U64 bucket_idx = range.min; bucket_idx < range.max; ++bucket_idx) { - LNK_SymbolList *bucket = &symtab->buckets[LNK_SymbolScopeIndex_Defined][bucket_idx]; - LNK_SymbolList leader_list = {0}; - LNK_SymbolNode *curr = bucket->first; - while (curr) { - LNK_SymbolList chain_list = lnk_pop_comdat_chain(bucket, &curr); - LNK_SymbolNode *leader_node = lnk_fold_comdat_chain(chain_list); - if (leader_node) { - lnk_symbol_list_push_node(&leader_list, leader_node); - } - } - Assert(bucket->count == 0); - *bucket = leader_list; - } -} +#if 0 internal void -lnk_fold_comdat_chunks(TP_Context *tp, LNK_SymbolTable *symtab) +lnk_symbol_hash_trie_debug(LNK_SymbolHashTrie *root) { - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(0,0); - LNK_ComdatFolder folder = {0}; - folder.symtab = symtab; - folder.range_arr = tp_divide_work(scratch.arena, symtab->bucket_count[LNK_SymbolScopeIndex_Defined], tp->worker_count); - tp_for_parallel(tp, 0, tp->worker_count, lnk_comdat_folder, &folder); + struct Stack { + struct Stack *next; + U64 i; + LNK_SymbolHashTrie *trie; + }; + + struct Stack *stack = push_array(scratch.arena, struct Stack, 1); + stack->i = 0; + stack->trie = root; + + U64 cur_depth = 1; + U64 max_depth = 0; + + char *dashes = "--------------------------------"; + + FILE *f = fopen("trie.txt", "w"); + + while (stack) { + for (; stack->i < ArrayCount(stack->trie->child); ++stack->i) { + + if (stack->i == 0 && stack->trie->symbol) { + fprintf(f, "%.*s%.*s\n", (int)cur_depth, dashes, str8_varg(stack->trie->symbol->name)); + } + + if (stack->trie->child[stack->i] != 0) { + struct Stack *frame = push_array(scratch.arena, struct Stack, 1); + frame->i = 0; + frame->trie = stack->trie->child[stack->i]; + + stack->i += 1; + SLLStackPush(stack, frame); + + cur_depth += 1; + max_depth = Max(cur_depth, max_depth); + + break; + } + } + + if (stack->i >= ArrayCount(stack->trie->child)) { + cur_depth -= 1; + SLLStackPop(stack); + } + } + + fprintf(f, "Max Depth: %llu\n", max_depth); + fclose(f); scratch_end(scratch); - ProfEnd(); } + +#endif diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 4c68996c..e91403df 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -90,27 +90,22 @@ typedef enum LNK_Symbol_Undefined, } LNK_SymbolType; -#define LNK_DEBUG_SYMBOLS 1 typedef struct LNK_Symbol { - String8 name; - LNK_SymbolType type; + String8 name; + LNK_SymbolType type; + struct LNK_Obj *obj; union { LNK_DefinedSymbol defined; LNK_WeakSymbol weak; LNK_UndefinedSymbol undefined; LNK_LazySymbol lazy; } u; -#if LNK_DEBUG_SYMBOLS - String8 debug; -#endif } LNK_Symbol; typedef struct LNK_SymbolNode { struct LNK_SymbolNode *next; - struct LNK_SymbolNode *prev; - U64 hash; LNK_Symbol *data; } LNK_SymbolNode; @@ -133,55 +128,45 @@ typedef struct LNK_SymbolArray LNK_Symbol *v; } LNK_SymbolArray; +typedef struct LNK_SymbolHashTrie +{ + String8 *name; + LNK_Symbol *symbol; + struct LNK_SymbolHashTrie *child[4]; +} LNK_SymbolHashTrie; + +typedef struct LNK_SymbolHashTrieChunk +{ + struct LNK_SymbolHashTrieChunk *next; + U64 count; + U64 cap; + LNK_SymbolHashTrie *v; +} LNK_SymbolHashTrieChunk; + +typedef struct LNK_SymbolHashTrieChunkList +{ + U64 count; + LNK_SymbolHashTrieChunk *first; + LNK_SymbolHashTrieChunk *last; +} LNK_SymbolHashTrieChunkList; + typedef struct LNK_SymbolTable { - Arena *arena; - U64 bucket_count[LNK_SymbolScopeIndex_Count]; - LNK_SymbolList *buckets[LNK_SymbolScopeIndex_Count]; + TP_Arena *arena; + LNK_SymbolHashTrie *scopes[LNK_SymbolScopeIndex_Count]; + LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScopeIndex_Count]; } LNK_SymbolTable; //////////////////////////////// // parallel for wrappers -typedef struct -{ - LNK_Symbol *symbol_arr; - Rng1U64 *range_arr; - U64 *hash_arr; -} LNK_SymbolNameHasher; - -typedef struct -{ - LNK_SymbolNode **input_arr; - Rng1U64 *range_arr; -} LNK_SymbolNodePtrHasher; - -typedef struct -{ - LNK_SymbolNode *input_arr; - Rng1U64 *range_arr; -} LNK_SymbolNodeHasher; - typedef struct { LNK_SymbolTable *symtab; - LNK_SymbolList *bucket_arr; - Rng1U64 *range_arr; -} LNK_DefinedSymbolInserter; - -typedef struct -{ - LNK_SymbolTable *symtab; - LNK_SymbolList *bucket_arr; - Rng1U64 *range_arr; + Rng1U64 *ranges; + LNK_Symbol *arr; } LNK_LazySymbolInserter; -typedef struct -{ - LNK_SymbolTable *symtab; - Rng1U64 *range_arr; -} LNK_ComdatFolder; - //////////////////////////////// extern LNK_Symbol g_null_symbol; @@ -201,53 +186,34 @@ internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_ internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback); internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset); -#if LNK_DEBUG_SYMBOLS -#define lnk_symbol_set_debugf(a, s, fmt, ...) do { (s)->debug = push_str8f((a), fmt, __VA_ARGS__); } while (0) -#define lnk_symbol_set_debug(s, str) do { (s)->debug = str; } while (0) -#else -#define lnk_symbol_set_debugf(...) -#define lnk_symbol_set_debug(...) -#endif +internal LNK_Chunk * lnk_chunk_from_symbol(LNK_Symbol *symbol); -internal LNK_Chunk * lnk_defined_symbol_get_chunk(LNK_DefinedSymbol *symbol); - -internal void lnk_symbol_update_chunk_ref(LNK_Symbol *symbol, U64 src_sect_id, U64 dst_sect_id, U64 *id_map, U64 id_count); +//////////////////////////////// internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node); internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol); -internal void lnk_symbol_list_push_list(LNK_SymbolList *list, LNK_SymbolList *to_push); -internal void lnk_symbol_list_insert_after(LNK_SymbolList *list, LNK_SymbolNode *node, LNK_SymbolNode *insert); -internal LNK_SymbolNode * lnk_symbol_list_pop_node(LNK_SymbolList *list); -internal LNK_Symbol * lnk_symbol_list_pop(LNK_SymbolList *list); -internal void lnk_symbol_list_remove(LNK_SymbolList *list, LNK_SymbolNode *node); internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat); -internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list); - internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr); internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list); internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list); -internal LNK_Symbol * lnk_symbol_array_search(LNK_SymbolArray symarr, String8 name, StringMatchFlags flags); -internal U64 * lnk_symbol_array_hash(TP_Context *tp, Arena *arena, LNK_Symbol *arr, U64 count); -internal LNK_SymbolTable * lnk_symbol_table_alloc(void); -internal LNK_SymbolTable * lnk_symbol_table_alloc_ex(U64 defined_cap, U64 internal_cap, U64 weak_cap, U64 lib_cap); -internal void lnk_symbol_table_release(LNK_SymbolTable **symtab); -internal U64 lnk_symbol_table_hash(String8 string); -internal LNK_SymbolNode * lnk_symbol_table_search_bucket(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 bucket_idx, String8 name, U64 hash); -internal LNK_SymbolNode * lnk_symbol_table_search_node_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name, U64 hash); -internal LNK_SymbolNode * lnk_symbol_table_search_node(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name); -internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name); -internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, char *fmt, ...); -internal void lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U64 hash); -internal void lnk_symbol_table_push_node(LNK_SymbolTable *symtab, LNK_SymbolNode *node); -internal LNK_SymbolNode * lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); -internal void lnk_symbol_table_push_lazy_arr(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Symbol *arr, U64 count); +//////////////////////////////// + +internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_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 U64 lnk_symbol_hash(String8 string); + +internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena); +internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, U64 hash, String8 name); +internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name); +internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, char *fmt, ...); +internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol); +internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol); internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name); -internal void lnk_symbol_table_replace(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex iscope, LNK_Symbol *symbol); internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol); -internal LNK_SymbolList lnk_pop_comdat_chain(LNK_SymbolList *bucket, LNK_SymbolNode **cursor); -internal LNK_SymbolNode * lnk_fold_comdat_chain(LNK_SymbolList chain_list); -internal void lnk_fold_comdat_chunks(TP_Context *tp, LNK_SymbolTable *symtab); -