use global symbol table to detect duplicate imports

This commit is contained in:
Nikita Smith
2025-09-08 16:07:31 -07:00
committed by Ryan Fleury
parent 7cea036bc1
commit 8f749f4239
2 changed files with 33 additions and 26 deletions
+33 -25
View File
@@ -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); 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); 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) { for EachIndex(i, queued_members.count) {
LNK_LibMemberRef *member_ref = member_refs[i]; LNK_LibMemberRef *member_ref = member_refs[i];
LNK_Lib *lib = member_ref->lib; 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_Symbol *link_symbol = lib->was_member_linked[member_ref->member_idx];
// parse member // 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); COFF_DataType member_type = coff_data_type_from_data(member_info.data);
switch (member_type) { switch (member_type) {
@@ -1564,44 +1564,54 @@ lnk_link_inputs_(TP_Context *tp,
// import machine compat check // import machine compat check
if (import_header.machine != config->machine) { if (import_header.machine != config->machine) {
lnk_error(LNK_Error_IncompatibleMachine, "symbol %S pulled in import with incompatible machine %S (expected %S)", LNK_ObjSymbolRef ref = lnk_ref_from_symbol(link_symbol);
import_header.func_name, lnk_error_obj(LNK_Error_IncompatibleMachine,
coff_string_from_machine_type(import_header.machine), ref.obj,
coff_string_from_machine_type(config->machine)); "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; break;
} }
// skip duplicate import inputer // was import already created?
if (hash_table_search_string_raw(imps->import_stub_ht, import_header.func_name)) { break; } LNK_Symbol *is_import_loaded = lnk_symbol_table_search(symtab, link_symbol->name);
hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0); 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_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_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 *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); lnk_symbol_table_push(symtab, import_symbol);
// search DLL symbol list // find DLL with import symbols
B32 is_delay_load = lnk_is_dll_delay_load(config, import_header.dll_name); 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; 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; 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); 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) { if (import_symbols == 0) {
import_symbols = push_array(imps->arena, PE_MakeImportList, 1); import_symbols = push_array(imps->arena, PE_MakeImportList, 1);
str8_list_push(imps->arena, dll_names, import_header.dll_name); 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); hash_table_push_path_raw(imps->arena, imports_ht, import_header.dll_name, import_symbols);
} }
// push symbol // push make import info
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, (PE_MakeImport){ .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);
} break; } break;
case COFF_DataType_BigObj: case COFF_DataType_BigObj:
case COFF_DataType_Obj: { case COFF_DataType_Obj: {
String8 obj_path = coff_parse_long_name(lib->long_names, member_info.header.name); 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 // 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 // but we don't use this feature
String8 slash = str8_lit("/"); String8 slash = str8_lit("/");
if (str8_ends_with(obj_path, slash, 0)) { 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; B32 is_thin = lib->type == COFF_Archive_Thin;
if (is_thin) { if (is_thin) {
// obj path in thin archive is relative to the directory with archive
// obj path in thin archive is relative to directory with archive
String8List obj_path_list = {0}; 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, str8_chop_last_slash(lib->path));
str8_list_push(scratch.arena, &obj_path_list, obj_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->arena = imps_arena;
imps->static_imports = hash_table_init(imps->arena, 0x1000); imps->static_imports = hash_table_init(imps->arena, 0x1000);
imps->delayed_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 // input :null_obj
-1
View File
@@ -82,7 +82,6 @@ typedef struct LNK_ImportTables
String8List static_dll_names; String8List static_dll_names;
HashTable *static_imports; HashTable *static_imports;
HashTable *delayed_imports; HashTable *delayed_imports;
HashTable *import_stub_ht;
} LNK_ImportTables; } LNK_ImportTables;
typedef struct LNK_Link typedef struct LNK_Link