diff --git a/src/base/base_core.h b/src/base/base_core.h index 3455562a..8eeb9ab1 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -266,6 +266,7 @@ # define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((LONG *)(x),(k),(c)) # define ins_atomic_u32_add_eval(x,c) InterlockedAdd((LONG *)(x), (c)) # define ins_atomic_u8_eval_assign(x,c) InterlockedExchange8((CHAR *)(x), (c)) +# define ins_atomic_u8_or(x,c) InterlockedOr8((char *)(x), (char)c) # else # error Atomic intrinsics not defined for this compiler / architecture combination. # endif @@ -284,6 +285,7 @@ # define ins_atomic_u32_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) # define ins_atomic_u32_eval_cond_assign(x,k,c) ({ U32 _new = (c); __atomic_compare_exchange_n((U32 *)(x),&_new,(k),0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); _new; }) # define ins_atomic_u8_eval_assign(x,c) __atomic_exchange_n((x), (c), __ATOMIC_SEQ_CST) +# define ins_atomic_u8_or(x,c) __atomic_fetch_or((U8 *)(x), (U8)(c), __ATOMIC_SEQ_CST) #else # error Atomic intrinsics not defined for this compiler / architecture. #endif diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 65534ce8..81bfbbfc 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1486,8 +1486,9 @@ lnk_queue_lib_member(Arena *arena, LNK_LibMemberRefList *queued_members, LNK_Sym B32 was_linked = lnk_lib_set_link_symbol(lib, member_idx, link_symbol); if (was_linked) { LNK_LibMemberRef *member_ref = push_array(arena, LNK_LibMemberRef, 1); - member_ref->lib = lib; - member_ref->member_idx = member_idx; + member_ref->lib = lib; + member_ref->member_idx = member_idx; + member_ref->link_symbol = link_symbol; lnk_lib_member_ref_list_push_node(queued_members, member_ref); } } @@ -1583,7 +1584,7 @@ lnk_link_inputs(TP_Context *tp, LNK_LibMemberRef *member_ref = member_refs[i]; LNK_Lib *lib = member_ref->lib; - LNK_Symbol *link_symbol = lib->member_links[member_ref->member_idx]; + LNK_Symbol *link_symbol = member_ref->link_symbol; 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); @@ -1612,35 +1613,21 @@ lnk_link_inputs(TP_Context *tp, switch (member_type) { case COFF_DataType_Import: { - LNK_Symbol *link_symbol = lib->member_links[member_idx]; + // find import stub + LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - LNK_Symbol *import_symbols[2] = {0}; - if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) { - import_symbols[0] = link_symbol; - import_symbols[1] = lnk_symbol_table_search(symtab, str8_skip(link_symbol->name, str8_lit("__imp_").size)); - } else { - Temp temp = temp_begin(scratch.arena); - String8 imp_name = push_str8f(temp.arena, "__imp_%S", link_symbol->name); - import_symbols[0] = lnk_symbol_table_search(symtab, imp_name); - import_symbols[1] = link_symbol; - temp_end(temp); - } + // same import symbol must never be queued more than once, if it is, there is a bug in the link set logic + AssertAlways(member_ref->link_symbol->refs != import_stub->refs); - for EachIndex(i, ArrayCount(import_symbols)) { - LNK_Symbol *import_symbol = import_symbols[i]; - if (import_symbol == 0) { continue; } - - LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB)); - - // same import symbol must never be queued more than once, if it is, there is a bug in the link set logic - AssertAlways(import_symbol->refs != import_stub->refs); - - // replace the import symbol with a stub, which is later replaced with the real import symbol once import obj is ready - import_symbol->refs = import_stub->refs; - } + // replace the import symbol with a stub, which is later replaced with the real import symbol once import obj is ready + member_ref->link_symbol->refs = import_stub->refs; // push import member for import obj generation - lnk_lib_member_ref_list_push_node(&link->imports, member_ref); + LNK_LibMemberFlags member_flags = lib->member_flags[member_ref->member_idx]; + B32 is_first_link = member_flags != (LNK_LibMemberFlag_LinkedRegular | LNK_LibMemberFlag_LinkedImp); + if (is_first_link) { + lnk_lib_member_ref_list_push_node(&link->imports, member_ref); + } } break; case COFF_DataType_BigObj: case COFF_DataType_Obj: { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index fd96e826..4f8f9cbe 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -7,8 +7,9 @@ typedef struct LNK_LibMemberRef { - LNK_Lib *lib; - U32 member_idx; + LNK_Lib *lib; + U32 member_idx; + LNK_Symbol *link_symbol; struct LNK_LibMemberRef *next; } LNK_LibMemberRef; @@ -183,6 +184,7 @@ typedef struct { B32 search_anti_deps; LNK_SymbolTable *symtab; + LNK_Symbol *import_stub; LNK_Lib *lib; LNK_LibMemberRefList *member_ref_lists; } LNK_SearchLibTask; diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index 28ab3673..cd00876a 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -142,6 +142,7 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path, U64 input_idx, LNK_L lib_out->member_offsets = member_offsets; lib_out->symbol_indices = symbol_indices; lib_out->member_links = push_array(arena, LNK_Symbol *, member_count); + lib_out->member_flags = push_array(arena, LNK_LibMemberFlags, member_count); lib_out->symbol_names = symbol_names; lib_out->long_names = parse.long_names; lib_out->input_idx = input_idx; @@ -224,15 +225,21 @@ lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, U internal B32 lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) { - local_persist LNK_Symbol null_symbol; - - LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol); - - B32 was_linked = (slot == 0); + B32 was_linked; + if (str8_starts_with(link_symbol->name, str8_lit("__imp_"))) { + U8 member_flags = ins_atomic_u8_or(&lib->member_flags[member_idx], LNK_LibMemberFlag_LinkedImp); + was_linked = !!(~member_flags & LNK_LibMemberFlag_LinkedImp); + } else { + U8 flag = LNK_LibMemberFlag_LinkedRegular; + U8 member_flags = ins_atomic_u8_or(&lib->member_flags[member_idx], LNK_LibMemberFlag_LinkedRegular); + was_linked = !!(~member_flags & LNK_LibMemberFlag_LinkedRegular); + } for (LNK_Symbol *leader = link_symbol;;) { + LNK_Symbol *slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], 0); + // update slot symbol if it is empty or link symbol comes before symbol in the slot - if (slot && slot != &null_symbol) { + if (slot) { if (lnk_symbol_is_before(slot, leader)) { leader = slot; } @@ -241,15 +248,12 @@ lnk_lib_set_link_symbol(LNK_Lib *lib, U32 member_idx, LNK_Symbol *link_symbol) } // try to insert back updated slot symbol - LNK_Symbol *swap = ins_atomic_ptr_eval_cond_assign(&lib->member_links[member_idx], leader, &null_symbol); + LNK_Symbol *swap = ins_atomic_ptr_eval_cond_assign(&lib->member_links[member_idx], leader, 0); // exit if slot symbol was null - if (swap == &null_symbol) { + if (swap == 0) { break; } - - // reload slot symbol - slot = ins_atomic_ptr_eval_assign(&lib->member_links[member_idx], &null_symbol); } return was_linked; diff --git a/src/linker/lnk_lib.h b/src/linker/lnk_lib.h index 0cbdd673..adaf0487 100644 --- a/src/linker/lnk_lib.h +++ b/src/linker/lnk_lib.h @@ -3,6 +3,13 @@ #pragma once +typedef U8 LNK_LibMemberFlags; +enum +{ + LNK_LibMemberFlag_LinkedRegular = (1 << 0), + LNK_LibMemberFlag_LinkedImp = (1 << 1), +}; + typedef struct LNK_Lib { String8 path; @@ -13,6 +20,7 @@ typedef struct LNK_Lib U32 *member_offsets; U16 *symbol_indices; LNK_Symbol **member_links; + LNK_LibMemberFlags *member_flags; String8Array symbol_names; String8 long_names; U64 input_idx;