diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 7fec2c93..6cefa2b7 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -912,9 +912,11 @@ lnk_push_export(Arena *arena, HashTable *export_ht, PE_ExportParseList *export_l } } -internal LNK_InputObjList -lnk_push_linker_symbols(Arena *arena, LNK_Config *config) +internal String8 +lnk_make_linker_obj(Arena *arena, LNK_Config *config) { + ProfBeginFunction(); + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, config->machine); // Emit __ImageBase symbol. @@ -924,8 +926,7 @@ lnk_push_linker_symbols(Arena *arena, LNK_Config *config) // passing it around as a function argument. // // 100h: lea rax, [rip + ffffff00h] ; -100h - U64 base_addr = lnk_get_base_addr(config); - coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("__ImageBase"), base_addr, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("__ImageBase"), 0, COFF_SymStorageClass_External); { // load config symbols if (config->machine == COFF_MachineType_X86) { @@ -950,13 +951,8 @@ lnk_push_linker_symbols(Arena *arena, LNK_Config *config) String8 obj = coff_obj_writer_serialize(arena, obj_writer); coff_obj_writer_release(&obj_writer); - LNK_InputObjList result = {0}; - LNK_InputObj *input = lnk_input_obj_list_push(arena, &result); - input->path = str8_lit("* Linker Symbols *"); - input->dedup_id = input->path; - input->data = obj; - - return result; + ProfEnd(); + return obj; } internal void @@ -976,9 +972,9 @@ lnk_queue_lib_member_input(Arena *arena, switch (member_type) { case COFF_DataType_Null: break; case COFF_DataType_Import: { - LNK_InputImport *input = lnk_input_import_list_push(arena, input_import_list); - input->coff_import = member_info.data; - input->input_idx = input_idx; + LNK_InputImportNode *input = lnk_input_import_list_push(arena, input_import_list); + input->data.coff_import = member_info.data; + input->data.input_idx = input_idx; } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { @@ -2088,11 +2084,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S for (U64 obj_idx = 0; obj_idx < objs_count; obj_idx += 1) { LNK_Obj *obj = objs[obj_idx]; COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str; - String8 string_table = str8_substr(obj->data, obj->header.string_table_range); - - U32 obj_features = lnk_obj_get_features (obj); - B32 discards_guards = (obj_features & MSCRT_FeatFlag_GUARD_CF) || - (obj_features & MSCRT_FeatFlag_GUARD_EH_CONT); + String8 string_table = str8_substr(obj->data, obj->header.string_table_range); for (U64 sect_idx = 0; sect_idx < obj->header.section_count_no_null; sect_idx += 1) { COFF_SectionHeader *sect_header = §ion_table[sect_idx]; @@ -2984,46 +2976,40 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S // patch import and import addr { - LNK_Symbol *dll_table_begin_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER_IMPORT_TABLE_DLL_BEGIN")); - LNK_Symbol *dll_table_end_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER_IMPORT_TABLE_DLL_END")); - if (dll_table_begin_symbol && dll_table_end_symbol) { - COFF_ParsedSymbol dll_table_begin_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dll_table_begin_symbol->u.defined.obj, dll_table_begin_symbol->u.defined.symbol_idx); - COFF_ParsedSymbol dll_table_end_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dll_table_end_symbol->u.defined.obj, dll_table_end_symbol->u.defined.symbol_idx); - U64 dll_table_voff = image_section_table[dll_table_begin_parsed.section_number]->voff + dll_table_begin_parsed.value; - U64 dll_table_vsize = dll_table_end_parsed.value - dll_table_begin_parsed.value; + LNK_Section *idata_sect = lnk_section_table_search(sectab, str8_lit(".idata"), PE_IDATA_SECTION_FLAGS); + LNK_Symbol *null_import_desc = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "__NULL_IMPORT_DESCRIPTOR"); + LNK_Symbol *last_import_desc = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA", lnk_get_image_name(config)); + if (idata_sect && null_import_desc && last_import_desc) { + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + LNK_SectionContrib *idata_first_contrib = lnk_get_first_section_contrib(idata_sect); PE_DataDirectory *import_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_IMPORT, sizeof(PE_DataDirectory)); - import_dir->virt_off = dll_table_voff; - import_dir->virt_size = dll_table_vsize; - } + import_dir->virt_off = image_section_table[idata_first_contrib->u.sect_idx + 1]->voff; + import_dir->virt_size = null_import_desc_parsed.value - idata_first_contrib->u.off; - LNK_Symbol *iat_begin_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER IMPORT_ADDRESS_TABLE_BEGIN")); - LNK_Symbol *iat_end_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER_IMPORT_ADDRESS_TABLE_END")); - if (iat_begin_symbol && iat_end_symbol) { - COFF_ParsedSymbol iat_begin_parsed = lnk_parsed_symbol_from_coff_symbol_idx(iat_begin_symbol->u.defined.obj, iat_begin_symbol->u.defined.symbol_idx); - COFF_ParsedSymbol iat_end_parsed = lnk_parsed_symbol_from_coff_symbol_idx(iat_end_symbol->u.defined.obj, iat_end_symbol->u.defined.symbol_idx); - U64 iat_voff = image_section_table[iat_begin_parsed.section_number]->voff + iat_begin_parsed.value; - U64 iat_vsize = iat_end_parsed.value - iat_begin_parsed.value; + COFF_ParsedSymbol last_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(last_import_desc->u.defined.obj, last_import_desc->u.defined.symbol_idx); + U64 last_import_desc_voff = image_section_table[last_import_desc_parsed.section_number]->voff + last_import_desc_parsed.value; + + U64 first_import_foff = image_section_table[idata_first_contrib->u.sect_idx+1]->foff; + PE_ImportEntry *first_import = str8_deserial_get_raw_ptr(image_data, first_import_foff, sizeof(*first_import)); PE_DataDirectory *import_addr_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_IMPORT_ADDR, sizeof(PE_DataDirectory)); - import_addr_dir->virt_off = iat_voff; - import_addr_dir->virt_size = iat_vsize; + import_addr_dir->virt_off = first_import->import_addr_table_voff; + import_addr_dir->virt_size = last_import_desc_voff - first_import->import_addr_table_voff /* null */ + coff_word_size_from_machine(config->machine); } } - // patch delay import + // patch delay imports { - LNK_Symbol *dll_table_begin_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER_IMPORT_TABLE_DLL_DELAY_BEGIN")); - LNK_Symbol *dll_table_end_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("RAD_LINKER_IMPORT_TABLE_DLL_DELAY_END")); - if (dll_table_begin_symbol && dll_table_end_symbol) { - COFF_ParsedSymbol dll_table_begin_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dll_table_begin_symbol->u.defined.obj, dll_table_begin_symbol->u.defined.symbol_idx); - COFF_ParsedSymbol dll_table_end_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dll_table_end_symbol->u.defined.obj, dll_table_end_symbol->u.defined.symbol_idx); - U64 dll_table_voff = image_section_table[dll_table_begin_parsed.section_number]->voff + dll_table_begin_parsed.value; - U64 dll_table_vsize = dll_table_end_parsed.value - dll_table_begin_parsed.value; - - PE_DataDirectory *delay_import_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DELAY_IMPORT, sizeof(PE_DataDirectory)); - delay_import_dir->virt_off = dll_table_voff; - delay_import_dir->virt_size = dll_table_vsize; + LNK_Section *didat_sect = lnk_section_table_search(sectab, str8_lit(".didat"), PE_IDATA_SECTION_FLAGS); + LNK_Symbol *null_import_desc = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, str8_lit("__NULL_DELAY_IMPORT_DESCRIPTOR")); + LNK_Symbol *last_import_desc = lnk_symbol_table_searchf(symtab, LNK_SymbolScope_Defined, "\x7f%S_NULL_THUNK_DATA_DLA", lnk_get_image_name(config)); + if (didat_sect && null_import_desc && last_import_desc) { + COFF_ParsedSymbol null_import_desc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(null_import_desc->u.defined.obj, null_import_desc->u.defined.symbol_idx); + LNK_SectionContrib *didat_first_contrib = lnk_get_first_section_contrib(didat_sect); + PE_DataDirectory *import_dir = str8_deserial_get_raw_ptr(image_data, pe.data_dir_range.min + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DELAY_IMPORT, sizeof(PE_DataDirectory)); + import_dir->virt_off = image_section_table[didat_first_contrib->u.sect_idx]->voff; + import_dir->virt_size = null_import_desc_parsed.value - didat_first_contrib->u.off; } } @@ -3173,6 +3159,10 @@ THREAD_POOL_TASK_FUNC(lnk_undef_symbol_finder) if (has_defn) { continue; } + LNK_Symbol *has_import = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Import, symbol->name); + if (has_import) { + continue; + } LNK_Symbol *member_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Lib, symbol->name); if (member_symbol) { @@ -3198,6 +3188,10 @@ THREAD_POOL_TASK_FUNC(lnk_weak_symbol_finder) if (has_strong_defn) { continue; } + LNK_Symbol *has_import = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Import, symbol->name); + if (has_import) { + continue; + } LNK_Symbol *member_symbol = 0; { @@ -3289,9 +3283,9 @@ lnk_run_symbol_finder(TP_Context *tp, ProfEnd(); ProfBegin("Sort Imports [Count %llu]", result.input_import_list.count); - LNK_InputImport **input_imp_ptr_arr = lnk_input_import_arr_from_list(scratch.arena, result.input_import_list); + LNK_InputImportNode **input_imp_ptr_arr = lnk_input_import_arr_from_list(scratch.arena, result.input_import_list); //radsort(input_imp_ptr_arr, result.input_import_list.count, lnk_input_import_is_before); - qsort(input_imp_ptr_arr, result.input_import_list.count, sizeof(input_obj_ptr_arr[0]), lnk_input_import_compar); + qsort(input_imp_ptr_arr, result.input_import_list.count, sizeof(input_imp_ptr_arr[0]), lnk_input_import_node_compar); result.input_import_list = lnk_list_from_input_import_arr(input_imp_ptr_arr, result.input_import_list.count); ProfEnd(); @@ -3488,17 +3482,12 @@ lnk_run(int argc, char **argv) State_InputObjs, State_InputLibs, State_PushDllHelperUndefSymbol, - State_PushLinkerSymbols, + State_InputLinkerObjs, State_PushLoadConfigUndefSymbol, State_LookupUndef, State_LookupWeak, State_LookupEntryPoint, State_ReportUnresolvedSymbols, - State_InputImportObjs, - State_InputExportObjs, - State_InputResObj, - State_InputLinkerObj, - State_InputDebugDirObj, State_BuildImage, State_BuildImpLib, State_BuildRadChunkMap, @@ -3576,11 +3565,7 @@ lnk_run(int argc, char **argv) LNK_SymbolList unresolved_weak_list = {0}; U64 entry_point_lookup_attempts = 0; B32 report_unresolved_symbols = 1; - B32 input_import_objs = 1; - B32 input_export_objs = 1; - B32 input_res_obj = 1; - B32 input_linker_obj = lnk_do_debug_info(config); - B32 input_debug_dir_obj = lnk_do_debug_info(config); + B32 input_linker_objs = 1; B32 build_imp_lib = config->build_imp_lib; B32 build_rad_chunk_map = (config->rad_chunk_map == LNK_SwitchState_Yes); B32 build_debug_info = lnk_do_debug_info(config); @@ -3649,8 +3634,8 @@ lnk_run(int argc, char **argv) } break; case State_InputImports: { ProfBegin("Input Imports"); - for (LNK_InputImport *input = input_import_list.first; input != 0; input = input->next) { - COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(input->coff_import); + for (LNK_InputImportNode *input = input_import_list.first; input != 0; input = input->next) { + COFF_ParsedArchiveImportHeader import_header = coff_archive_import_from_data(input->data.coff_import); // import machine compat check if (import_header.machine != config->machine) { @@ -3661,23 +3646,17 @@ lnk_run(int argc, char **argv) continue; } - // create import stubs (later replaced with acutal imports generated by linker) - LNK_Symbol *thunk_symbol; - { - thunk_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1); - thunk_symbol->type = LNK_Symbol_Import; - thunk_symbol->name = import_header.func_name; - thunk_symbol->u.coff_import = input->coff_import; - - LNK_Symbol *iat_symbol = push_array(symtab->arena->v[0], LNK_Symbol, 1); - iat_symbol->type = LNK_Symbol_Import; - iat_symbol->name = push_str8f(symtab->arena->v[0], "__imp_%S", import_header.func_name); - iat_symbol->u.coff_import = input->coff_import; - - lnk_symbol_table_push(symtab, thunk_symbol); - lnk_symbol_table_push(symtab, iat_symbol); + // was import already created? + if (lnk_symbol_table_search(symtab, LNK_SymbolScope_Import, import_header.func_name)) { + continue; } - + + // create import stubs (later replaced with acutal imports generated by linker) + LNK_Symbol *thunk_symbol = lnk_make_import_symbol(scratch.arena, import_header.func_name, input->data.coff_import); + LNK_Symbol *imp_symbol = lnk_make_import_symbol(scratch.arena, push_str8f(scratch.arena, "__imp_%S", import_header.func_name), input->data.coff_import); + lnk_symbol_table_push(symtab, thunk_symbol); + lnk_symbol_table_push(symtab, imp_symbol); + // pick imports hash table HashTable *imports_ht; { @@ -3690,18 +3669,14 @@ lnk_run(int argc, char **argv) } // search DLL symbol list - String8List *import_symbols; - { - import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); - if (import_symbols == 0) { - import_symbols = push_array(scratch.arena, String8List, 1); - hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols); - } + String8List *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + if (import_symbols == 0) { + import_symbols = push_array(scratch.arena, String8List, 1); hash_table_push_path_raw(scratch.arena, imports_ht, import_header.dll_name, import_symbols); } // push symbol - str8_list_push(scratch.arena, import_symbols, input->coff_import); + str8_list_push(scratch.arena, import_symbols, input->data.coff_import); } // reset input @@ -3915,8 +3890,12 @@ lnk_run(int argc, char **argv) LNK_SymbolInputResult input_result = lnk_input_obj_symbols(tp, tp_arena, symtab, obj_node_arr); // schedule symbol input - lnk_symbol_list_concat_in_place(&input_weak_list, &input_result.weak_symbols); + lnk_symbol_list_concat_in_place(&input_weak_list, &input_result.weak_symbols); lnk_symbol_list_concat_in_place(&lookup_undef_list, &input_result.undef_symbols); + + // give another chance to unresolved symbols + lnk_symbol_list_concat_in_place(&lookup_undef_list, &unresolved_undef_list); + lnk_symbol_list_concat_in_place(&input_weak_list, &unresolved_weak_list); // reset input objs MemoryZeroStruct(&input_obj_list); @@ -4033,12 +4012,6 @@ lnk_run(int argc, char **argv) str8_list_push(scratch.arena, &include_symbol_list, delay_load_helper_name); ProfEnd(); } break; - case State_PushLinkerSymbols: { - ProfBegin("Push Linker Symbols"); - LNK_InputObjList linker_objs = lnk_push_linker_symbols(scratch.arena, config); - lnk_input_obj_list_concat_in_place(&input_obj_list, &linker_objs); - ProfEnd(); - } break; case State_PushLoadConfigUndefSymbol: { ProfBegin("Push Load Config Undef Symbol"); String8 load_config_name = str8_lit(LNK_LOAD_CONFIG_SYMBOL_NAME); @@ -4207,8 +4180,15 @@ lnk_run(int argc, char **argv) goto exit; } } break; - case State_InputImportObjs: { - ProfBegin("Build Import Table"); + case State_InputLinkerObjs: { + { + ProfBegin("Push Linker Symbols"); + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = str8_lit("* Linker Symbols *"); + input->dedup_id = input->path; + input->data = lnk_make_linker_obj(scratch.arena, config); + ProfEnd(); + } // warn about unused delayloads if (config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll) { @@ -4221,76 +4201,72 @@ lnk_run(int argc, char **argv) // make and input delayed imports if (delayed_imports->count) { + ProfBegin("Build Delay Import Table"); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; B32 emit_biat = config->import_table_emit_biat == LNK_SwitchState_Yes; B32 emit_uiat = config->import_table_emit_uiat == LNK_SwitchState_Yes; String8 *dll_names = keys_from_hash_table_string(scratch.arena, delayed_imports); - String8List *dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, delayed_imports); for (U64 dll_idx = 0; dll_idx < delayed_imports->count; dll_idx += 1) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; - input->data = pe_make_import_dll_obj_delayed(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, dll_import_headers[dll_idx], emit_biat, emit_uiat); + input->data = pe_make_import_dll_obj_delayed(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], delay_load_helper_name, import_debug_symbols, *dll_import_headers[dll_idx], emit_biat, emit_uiat); input->path = dll_names[dll_idx]; } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; - input->data = pe_make_import_entry_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Delayed Import Entry Obj *"); - } - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_null_import_descriptor_obj(scratch.arena, time_stamp, config->machine, linker_debug_symbols); + input->data = pe_make_null_import_descriptor_delayed(scratch.arena, time_stamp, config->machine, linker_debug_symbols); input->path = str8_lit("* Delayed Null Import Descriptor *"); } { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; - input->data = pe_make_null_thunk_data_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols); + input->data = pe_make_null_thunk_data_obj_delayed(scratch.arena, lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); input->path = str8_lit("* Delayed Null Thunk Data *"); } + + ProfEnd(); } // make and input static imports if (static_imports->count) { + ProfBegin("Build Static Import Table"); + COFF_TimeStamp time_stamp = COFF_TimeStamp_Max; String8 *dll_names = keys_from_hash_table_string(scratch.arena, static_imports); - String8List *dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); + String8List **dll_import_headers = values_from_hash_table_raw(scratch.arena, static_imports); for (U64 dll_idx = 0; dll_idx < static_imports->count; dll_idx += 1) { String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_names[dll_idx]); LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; - input->data = pe_make_import_dll_obj_static(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, dll_import_headers[dll_idx]); + input->data = pe_make_import_dll_obj_static(scratch.arena, time_stamp, config->machine, dll_names[dll_idx], import_debug_symbols, *dll_import_headers[dll_idx]); input->path = dll_names[dll_idx]; + input->dedup_id = dll_names[dll_idx]; } String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine); - { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->input_idx = input_obj_list.count; - input->data = pe_make_import_entry_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols); - input->path = str8_lit("* Import Entry Obj *"); - } { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; input->data = pe_make_null_import_descriptor_obj(scratch.arena, time_stamp, config->machine, linker_debug_symbols); input->path = str8_lit("* Null Import Descriptor *"); + input->dedup_id = input->path; } { LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); input->input_idx = input_obj_list.count; - input->data = pe_make_null_thunk_data_obj(scratch.arena, config->image_name, time_stamp, config->machine, linker_debug_symbols); + input->data = pe_make_null_thunk_data_obj(scratch.arena, lnk_get_image_name(config), time_stamp, config->machine, linker_debug_symbols); input->path = str8_lit("* Null Thunk Data *"); + input->dedup_id = input->path; } + + ProfEnd(); } - ProfEnd(); - } break; - case State_InputExportObjs: { if (export_symbol_list.count) { ProfBegin("Build Export Table"); @@ -4344,122 +4320,121 @@ lnk_run(int argc, char **argv) ProfEnd(); } - } break; - case State_InputResObj: { - String8List res_data_list = {0}; - String8List res_path_list = {0}; - - // do we have manifest deps passed through pragma alone? - LNK_ManifestOpt manifest_opt = config->manifest_opt; - if (manifest_dep_list.node_count > 0 && manifest_opt == LNK_ManifestOpt_Null) { - manifest_opt = LNK_ManifestOpt_Embed; - } - - switch (manifest_opt) { - case LNK_ManifestOpt_Embed: { - ProfBegin("Embed Manifest"); - // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest - // resource to the tree directly - String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); - String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data); - str8_list_push(scratch.arena, &res_data_list, manifest_res); - str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); - ProfEnd(); - } break; - case LNK_ManifestOpt_WriteToFile: { - ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); - Temp temp = temp_begin(scratch.arena); - String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); - lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data); - temp_end(temp); - ProfEnd(); - } break; - case LNK_ManifestOpt_Null: { - Assert(input_manifest_path_list.node_count == 0); - Assert(manifest_dep_list.node_count == 0); - } break; - case LNK_ManifestOpt_No: { - // omit manifest generation - } break; - } - - ProfBegin("Load .res files from disk"); - for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { - String8 res_data = lnk_read_data_from_file_path(scratch.arena, node->string); - if (res_data.size > 0) { - if (pe_is_res(res_data)) { - str8_list_push(scratch.arena, &res_data_list, res_data); - String8 stable_res_path = lnk_make_full_path(scratch.arena, config->path_style, config->work_dir, node->string); - str8_list_push(scratch.arena, &res_path_list, stable_res_path); - } else { - lnk_error(LNK_Error_LoadRes, "file is not of RES format: %S", node->string); - } - } else { - lnk_error(LNK_Error_LoadRes, "unable to open res file: %S", node->string); - } - } - ProfEnd(); - - if (res_data_list.node_count > 0) { - ProfBegin("Build * Resources *"); - - String8 obj_name = str8_lit("* Resources *"); - String8 obj_data = lnk_make_res_obj(scratch.arena, - res_data_list, - res_path_list, - config->machine, - config->time_stamp, - config->work_dir, - config->path_style, - obj_name); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->dedup_id = obj_name; - input->path = obj_name; - input->data = obj_data; - - ProfEnd(); - } - } break; - case State_InputLinkerObj: { - ProfBegin("Build * Linker * Obj"); - - String8 obj_name = str8_lit("* Linker *"); - String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }); - String8 obj_data = lnk_make_linker_coff_obj(scratch.arena, config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name); - - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->dedup_id = obj_name; - input->path = obj_name; - input->data = obj_data; - - ProfEnd(); - } break; - case State_InputDebugDirObj: { - ProfBegin("Build Debug Directory"); { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Debug Directory *"); - input->dedup_id = input->path; - input->data = lnk_make_debug_directory_obj(scratch.arena, config); + String8List res_data_list = {0}; + String8List res_path_list = {0}; + + // do we have manifest deps passed through pragma alone? + LNK_ManifestOpt manifest_opt = config->manifest_opt; + if (manifest_dep_list.node_count > 0 && manifest_opt == LNK_ManifestOpt_Null) { + manifest_opt = LNK_ManifestOpt_Embed; + } + + switch (manifest_opt) { + case LNK_ManifestOpt_Embed: { + ProfBegin("Embed Manifest"); + // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest + // resource to the tree directly + String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); + String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data); + str8_list_push(scratch.arena, &res_data_list, manifest_res); + str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); + ProfEnd(); + } break; + case LNK_ManifestOpt_WriteToFile: { + ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); + Temp temp = temp_begin(scratch.arena); + String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); + lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data); + temp_end(temp); + ProfEnd(); + } break; + case LNK_ManifestOpt_Null: { + Assert(input_manifest_path_list.node_count == 0); + Assert(manifest_dep_list.node_count == 0); + } break; + case LNK_ManifestOpt_No: { + // omit manifest generation + } break; + } + + ProfBegin("Load .res files from disk"); + for (String8Node *node = config->input_list[LNK_Input_Res].first; node != 0; node = node->next) { + String8 res_data = lnk_read_data_from_file_path(scratch.arena, node->string); + if (res_data.size > 0) { + if (pe_is_res(res_data)) { + str8_list_push(scratch.arena, &res_data_list, res_data); + String8 stable_res_path = lnk_make_full_path(scratch.arena, config->path_style, config->work_dir, node->string); + str8_list_push(scratch.arena, &res_path_list, stable_res_path); + } else { + lnk_error(LNK_Error_LoadRes, "file is not of RES format: %S", node->string); + } + } else { + lnk_error(LNK_Error_LoadRes, "unable to open res file: %S", node->string); + } + } + ProfEnd(); + + if (res_data_list.node_count > 0) { + ProfBegin("Build * Resources *"); + + String8 obj_name = str8_lit("* Resources *"); + String8 obj_data = lnk_make_res_obj(scratch.arena, + res_data_list, + res_path_list, + config->machine, + config->time_stamp, + config->work_dir, + config->path_style, + obj_name); + + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->dedup_id = obj_name; + input->path = obj_name; + input->data = obj_data; + + ProfEnd(); + } } - if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Debug Directory PDB *"); - input->dedup_id = input->path; - input->data = lnk_make_debug_directory_pdb_obj(scratch.arena, config); - } + if (build_debug_info) { + { + ProfBegin("Build * Linker * Obj"); - if (config->rad_debug == LNK_SwitchState_Yes) { - LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); - input->path = str8_lit("* Debug Directory RDI *"); - input->dedup_id = input->path; - input->data = lnk_make_debug_directory_rdi_obj(scratch.arena, config); - } + String8 obj_name = str8_lit("* Linker *"); + String8 raw_cmd_line = str8_list_join(scratch.arena, &config->raw_cmd_line, &(StringJoin){ str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") }); + String8 obj_data = lnk_make_linker_coff_obj(scratch.arena, config->time_stamp, config->machine, config->work_dir, config->image_name, config->pdb_name, raw_cmd_line, obj_name); + + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->dedup_id = obj_name; + input->path = obj_name; + input->data = obj_data; - ProfEnd(); + ProfEnd(); + } + + ProfBegin("Build Debug Directory"); + { + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = str8_lit("* Debug Directory *"); + input->dedup_id = input->path; + input->data = lnk_make_debug_directory_obj(scratch.arena, config); + } + if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = str8_lit("* Debug Directory PDB *"); + input->dedup_id = input->path; + input->data = lnk_make_debug_directory_pdb_obj(scratch.arena, config); + } + if (config->rad_debug == LNK_SwitchState_Yes) { + LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list); + input->path = str8_lit("* Debug Directory RDI *"); + input->dedup_id = input->path; + input->data = lnk_make_debug_directory_rdi_obj(scratch.arena, config); + } + ProfEnd(); + } } break; case State_BuildImage: { // build image @@ -4623,6 +4598,11 @@ lnk_run(int argc, char **argv) entry_point_lookup_attempts += 1; continue; } + if (input_linker_objs) { + input_linker_objs = 0; + state_list_push(scratch.arena, state_list, State_InputLinkerObjs); + continue; + } if (unresolved_undef_list.count) { if (report_unresolved_symbols) { report_unresolved_symbols = 0; @@ -4630,35 +4610,6 @@ lnk_run(int argc, char **argv) continue; } } - - - if (input_import_objs) { - input_import_objs = 0; - state_list_push(scratch.arena, state_list, State_InputImportObjs); - continue; - } - if (input_export_objs) { - input_export_objs = 0; - state_list_push(scratch.arena, state_list, State_InputExportObjs); - continue; - } - if (input_res_obj) { - input_res_obj = 0; - state_list_push(scratch.arena, state_list, State_InputResObj); - continue; - } - if (input_linker_obj) { - input_linker_obj = 0; - state_list_push(scratch.arena, state_list, State_InputLinkerObj); - continue; - } - if (input_debug_dir_obj) { - input_debug_dir_obj = 0; - state_list_push(scratch.arena, state_list, State_InputDebugDirObj); - continue; - } - - if (image_data.size == 0) { state_list_push(scratch.arena, state_list, State_BuildImage); continue; diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 89842710..af76f03e 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -83,6 +83,8 @@ typedef struct typedef struct { LNK_InputObjList input_obj_list; + U64 input_imports_count; + LNK_InputImport *input_imports; LNK_InputImportList input_import_list; LNK_SymbolList unresolved_symbol_list; } LNK_SymbolFinderResult; diff --git a/src/linker/lnk_input.c b/src/linker/lnk_input.c index 5669a84b..919b1cce 100644 --- a/src/linker/lnk_input.c +++ b/src/linker/lnk_input.c @@ -90,10 +90,10 @@ lnk_input_obj_list_from_string_list(Arena *arena, String8List list) return input_list; } -internal LNK_InputImport * +internal LNK_InputImportNode * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list) { - LNK_InputImport *node = push_array(arena, LNK_InputImport, 1); + LNK_InputImportNode *node = push_array(arena, LNK_InputImportNode, 1); SLLQueuePush(list->first, list->last, node); list->count += 1; return node; @@ -105,12 +105,12 @@ lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImport SLLConcatInPlace(list, to_concat); } -internal LNK_InputImport ** +internal LNK_InputImportNode ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list) { - LNK_InputImport **result = push_array_no_zero(arena, LNK_InputImport *, list.count); + LNK_InputImportNode **result = push_array_no_zero(arena, LNK_InputImportNode *, list.count); U64 idx = 0; - for (LNK_InputImport *node = list.first; node != 0; node = node->next) { + for (LNK_InputImportNode *node = list.first; node != 0; node = node->next) { Assert(idx < list.count); result[idx++] = node; } @@ -118,7 +118,7 @@ lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list) } internal LNK_InputImportList -lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count) +lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count) { LNK_InputImportList list = {0}; for (U64 i = 0; i < count; i += 1) { @@ -137,10 +137,10 @@ lnk_input_import_is_before(void *raw_a, void *raw_b) } int -lnk_input_import_compar(const void *raw_a, const void *raw_b) +lnk_input_import_node_compar(const void *raw_a, const void *raw_b) { - LNK_InputImport * const *a = raw_a; - LNK_InputImport * const *b = raw_b; - return u64_compar(&(*a)->input_idx, &(*b)->input_idx); + LNK_InputImportNode * const *a = raw_a; + LNK_InputImportNode * const *b = raw_b; + return u64_compar(&(*a)->data.input_idx, &(*b)->data.input_idx); } diff --git a/src/linker/lnk_input.h b/src/linker/lnk_input.h index bbd351eb..6760bddb 100644 --- a/src/linker/lnk_input.h +++ b/src/linker/lnk_input.h @@ -16,16 +16,22 @@ typedef String8List LNK_InputLibList; typedef struct LNK_InputImport { - struct LNK_InputImport *next; - String8 coff_import; - U64 input_idx; + String8 coff_import; + U64 input_idx; + struct LNK_Lib *lib; } LNK_InputImport; +typedef struct LNK_InputImportNode +{ + struct LNK_InputImportNode *next; + LNK_InputImport data; +} LNK_InputImportNode; + typedef struct LNK_InputImportList { - U64 count; - LNK_InputImport *first; - LNK_InputImport *last; + U64 count; + LNK_InputImportNode *first; + LNK_InputImportNode *last; } LNK_InputImportList; typedef struct LNK_InputObj @@ -59,8 +65,8 @@ internal LNK_InputObj ** lnk_array_from_input_obj_list(Arena *arena, LNK_InputO internal LNK_InputObjList lnk_list_from_input_obj_arr(LNK_InputObj **arr, U64 count); internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, String8List list); -internal LNK_InputImport * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list); -internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat); -internal LNK_InputImport ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list); -internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count); +internal LNK_InputImportNode * lnk_input_import_list_push(Arena *arena, LNK_InputImportList *list); +internal void lnk_input_import_list_concat_in_place(LNK_InputImportList *list, LNK_InputImportList *to_concat); +internal LNK_InputImportNode ** lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list); +internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImportNode **arr, U64 count); diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 1e09f419..027e631e 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -7,9 +7,9 @@ internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx) { LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->type = LNK_Symbol_Defined; - symbol->u.defined.obj = obj; + symbol->name = name; + symbol->type = LNK_Symbol_Defined; + symbol->u.defined.obj = obj; symbol->u.defined.symbol_idx = symbol_idx; return symbol; } @@ -18,9 +18,9 @@ internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset) { LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->type = LNK_Symbol_Lib; - symbol->u.lib.lib = lib; + symbol->name = name; + symbol->type = LNK_Symbol_Lib; + symbol->u.lib.lib = lib; symbol->u.lib.member_offset = member_offset; return symbol; } @@ -29,12 +29,22 @@ internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj) { LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); - symbol->name = name; - symbol->type = LNK_Symbol_Undefined; + symbol->name = name; + symbol->type = LNK_Symbol_Undefined; symbol->u.undef.obj = obj; return symbol; } +internal LNK_Symbol * +lnk_make_import_symbol(Arena *arena, String8 name, String8 import_header) +{ + LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1); + symbol->name = name; + symbol->type = LNK_Symbol_Import; + symbol->u.import.import_header = import_header; + return symbol; +} + //////////////////////////////// internal void @@ -491,9 +501,9 @@ lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol { switch (symbol->type) { case LNK_Symbol_Null: break; - case LNK_Symbol_Defined: - case LNK_Symbol_Import: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Defined, hash, symbol); } break; - case LNK_Symbol_Lib: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Lib, hash, symbol); } break; + case LNK_Symbol_Defined: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Defined, hash, symbol); } break; + case LNK_Symbol_Import: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Import, hash, symbol); } break; + case LNK_Symbol_Lib: { lnk_symbol_table_push_(symtab, symtab->arena->v[0], 0, LNK_SymbolScope_Lib, hash, symbol); } break; default: { InvalidPath; } break; } } diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index d3cbd10c..6a355727 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -31,6 +31,11 @@ typedef struct LNK_SymbolUndefined struct LNK_Obj *obj; } LNK_SymbolUndefined; +typedef struct LNK_SymbolImport +{ + String8 import_header; +} LNK_SymbolImport; + typedef struct LNK_Symbol { String8 name; @@ -38,13 +43,11 @@ typedef struct LNK_Symbol union { LNK_SymbolDefined defined; LNK_SymbolLib lib; - String8 coff_import; + LNK_SymbolImport import; LNK_SymbolUndefined undef; } u; } LNK_Symbol; -//////////////////////////////// - typedef struct LNK_SymbolNode { struct LNK_SymbolNode *next; @@ -70,11 +73,10 @@ typedef struct LNK_SymbolArray LNK_Symbol *v; } LNK_SymbolArray; -//////////////////////////////// - typedef enum { LNK_SymbolScope_Defined, + LNK_SymbolScope_Import, LNK_SymbolScope_Lib, LNK_SymbolScope_Count } LNK_SymbolScope; @@ -120,14 +122,10 @@ typedef struct //////////////////////////////// -global read_only LNK_Symbol g_null_symbol = { str8_lit_comp("NULL"), LNK_Symbol_Null }; -global read_only LNK_Symbol *g_null_symbol_ptr = &g_null_symbol; - -//////////////////////////////// - internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx); internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset); internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj); +internal LNK_Symbol * lnk_make_import_symbol(Arena *arena, String8 name, String8 import_header); ////////////////////////////////