diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 5233ea7a..a5e18edd 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1544,18 +1544,18 @@ lnk_link_inputs_(TP_Context *tp, } } + // sort library member refs to match the order of their appearance in the respective obj symbol tables LNK_LibMemberRef **member_refs = lnk_array_from_lib_member_list(scratch.arena, queued_members); radsort(member_refs, queued_members.count, lnk_lib_member_ref_is_before); - // load lib member refs + // push inputs for lib member refs for EachIndex(i, queued_members.count) { - LNK_LibMemberRef *member_ref = member_refs[i]; - LNK_Lib *lib = member_ref->lib; - U32 member_offset = lib->member_offsets[member_ref->member_idx]; - LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; + LNK_LibMemberRef *member_ref = member_refs[i]; + LNK_Lib *lib = member_ref->lib; + LNK_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx]; // parse member - COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, member_offset); + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lib->data, lib->member_offsets[member_ref->member_idx]); COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { @@ -1564,44 +1564,54 @@ lnk_link_inputs_(TP_Context *tp, // import machine compat check if (import_header.machine != config->machine) { - lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)", - import_header.func_name, - coff_string_from_machine_type(import_header.machine), - coff_string_from_machine_type(config->machine)); + LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol); + lnk_error_obj(LNK_Error_IncompatibleMachine, + ref.obj, + "symbol %S pulls-in import from %S for an incompatible machine %S (expected machine %S)", + link_symbol->name, + str8_chop_last_slash(lib->path), + coff_string_from_machine_type(import_header.machine), + coff_string_from_machine_type(config->machine)); break; } - // skip duplicate import inputer - if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name)) { break; } - hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); + // was import already created? + LNK_Symbol *is_import_loaded = lnk_symbol_table_search(symtab, link_symbol->name); + if (is_import_loaded) { + COFF_SymbolValueInterpType interp = lnk_interp_from_symbol(is_import_loaded); + if (interp != COFF_SymbolValueInterp_Undefined) { + break; + } + } - // create import stub (later replaced with acutal import generated by linker) + // create import stub symbol (later replaced with actual import) LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); LNK_ObjSymbolRef import_symbol_ref = lnk_ref_from_symbol(import_stub); LNK_Symbol *import_symbol = lnk_make_symbol(symtab->arena->v[0], link_symbol->name, import_symbol_ref.obj, import_symbol_ref.symbol_idx); lnk_symbol_table_push(symtab, import_symbol); - // search DLL symbol list - B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); - String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; - HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; + // find DLL with import symbols + B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); + String8List *dll_names = is_delay_load ? &imps->delayed_dll_names : &imps->static_dll_names; + HashTable *imports_ht = is_delay_load ? imps->delayed_imports : imps->static_imports; PE_MakeImportList *import_symbols = hash_table_search_path_raw(imports_ht, import_header.dll_name); + + // create record for a first time-DLL if (import_symbols == 0) { import_symbols = push_array(imps->arena, PE_MakeImportList, 1); str8_list_push(imps->arena, dll_names, import_header.dll_name); hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols); } - // push symbol - PE_MakeImport make_import = { .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }; - pe_make_import_header_list_push(imps->arena, import_symbols, make_import); + // push make import info + pe_make_import_header_list_push(imps->arena, import_symbols, (PE_MakeImport){ .header = member_info.data, .make_jump_thunk = !str8_starts_with(link_symbol->name, str8_lit("__imp_")) }); } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); // obj path in thin archive has slash appended which screws up - // file lookup on disk; it couble be there to enable paths to symbols + // file lookup on disk; it could be there to enable paths to symbols // but we don't use this feature String8 slash = str8_lit("/"); if (str8_ends_with(obj_path, slash, 0)) { @@ -1610,8 +1620,7 @@ lnk_link_inputs_(TP_Context *tp, B32 is_thin = lib->type == COFF_Archive_Thin; if (is_thin) { - - // obj path in thin archive is relative to directory with archive + // obj path in thin archive is relative to the directory with archive String8List obj_path_list = {0}; str8_list_push(scratch.arena, &obj_path_list, str8_chop_last_slash(lib->path)); str8_list_push(scratch.arena, &obj_path_list, obj_path); @@ -1714,7 +1723,6 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer imps->arena = imps_arena; imps->static_imports = hash_table_init(imps->arena, 0x1000); imps->delayed_imports = hash_table_init(imps->arena, 0x1000); - imps->import_stub_ht = hash_table_init(imps->arena, 0x10000); } // input :null_obj diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 3712a5d9..9f358a56 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -82,7 +82,6 @@ typedef struct LNK_ImportTables String8List static_dll_names; HashTable *static_imports; HashTable *delayed_imports; - HashTable *import_stub_ht; } LNK_ImportTables; typedef struct LNK_Link