use global symbol table to detect duplicate imports

This commit is contained in:
Nikita Smith
2025-09-06 16:15:25 -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);
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
-1
View File
@@ -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