mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 09:18:09 +00:00
replace single-hop associative section walk to multi-hop
This commit is contained in:
@@ -267,6 +267,7 @@
|
||||
# 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)
|
||||
# define ins_atomic_u32_or(x,c) InterlockedOr((LONG *)(x), (LONG)c)
|
||||
# else
|
||||
# error Atomic intrinsics not defined for this compiler / architecture combination.
|
||||
# endif
|
||||
@@ -286,6 +287,7 @@
|
||||
# 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)
|
||||
# define ins_atomic_u32_or(x,c) __atomic_fetch_or((U32 *)(x), (U32)(c), __ATOMIC_SEQ_CST)
|
||||
#else
|
||||
# error Atomic intrinsics not defined for this compiler / architecture.
|
||||
#endif
|
||||
|
||||
@@ -725,6 +725,18 @@ hash_map_push_u64_u64(Arena *arena, HashMap *hm, U64 key, U64 value)
|
||||
return hash_map_push(arena, hm, hash_map_hasher(str8_struct(&key)), (HashMapKeyValue){ .key = { .key_u64 = key }, .value = { .value_u64 = value } }, hash_map_match_u64);
|
||||
}
|
||||
|
||||
internal HashMapNode *
|
||||
hash_map_push_raw_raw(Arena *arena, HashMap *hm, void *key, void *value)
|
||||
{
|
||||
return hash_map_push(arena, hm, hash_map_hasher(str8_struct(&key)), (HashMapKeyValue){ .key = { .key_raw = key }, .value = { .value_raw = value } }, hash_map_match_raw);
|
||||
}
|
||||
|
||||
internal HashMapNode *
|
||||
hash_map_push_raw_u64(Arena *arena, HashMap *hm, void *key, U64 value)
|
||||
{
|
||||
return hash_map_push(arena, hm, hash_map_hasher(str8_struct(&key)), (HashMapKeyValue){ .key = { .key_raw = key }, .value = { .value_u64 = value } }, hash_map_match_u64);
|
||||
}
|
||||
|
||||
internal HashMapNode *
|
||||
hash_map_push_path_u64(Arena *arena, HashMap *hm, String8 path, U64 value)
|
||||
{
|
||||
@@ -794,6 +806,13 @@ hash_map_search_raw_raw(HashMap *hm, void *key)
|
||||
return n ? n->v.value.value_raw : 0;
|
||||
}
|
||||
|
||||
internal U64 *
|
||||
hash_map_search_raw_u64(HashMap *hm, void *key)
|
||||
{
|
||||
HashMapNode *n = hash_map_search(hm, hash_map_hasher(str8_struct(&key)), (HashMapKey){ .key_raw = key }, hash_map_match_raw);
|
||||
return n ? &n->v.value.value_u64 : 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal B32 hash_map_purge_u32(HashMap *hm, U32 key) { return hash_map_purge_item(hm, hash_map_hasher(str8_struct(&key)), (HashMapKey){ .key_u32 = key }, hash_map_match_u32); }
|
||||
|
||||
@@ -169,6 +169,8 @@ internal HashMapNode * hash_map_push_u32_string (Arena *arena, HashMap *hm, U3
|
||||
internal HashMapNode * hash_map_push_u64_raw (Arena *arena, HashMap *hm, U64 key, void *value);
|
||||
internal HashMapNode * hash_map_push_u64_string (Arena *arena, HashMap *hm, U64 key, String8 value);
|
||||
internal HashMapNode * hash_map_push_u64_u64 (Arena *arena, HashMap *hm, U64 key, U64 value);
|
||||
internal HashMapNode * hash_map_push_raw_raw (Arena *arena, HashMap *hm, void *key, void *value);
|
||||
internal HashMapNode * hash_map_push_raw_u64 (Arena *arena, HashMap *hm, void *key, U64 value);
|
||||
internal HashMapNode * hash_map_push_path_u64 (Arena *arena, HashMap *hm, String8 path, U64 value);
|
||||
internal HashMapNode * hash_map_push_path_string (Arena *arena, HashMap *hm, String8 path, String8 value);
|
||||
internal HashMapNode * hash_map_push_path_raw (Arena *arena, HashMap *hm, String8 path, void *value);
|
||||
@@ -180,6 +182,7 @@ internal void * hash_map_search_path_raw (HashMap *hm, String8 key);
|
||||
internal void * hash_map_search_u64_raw (HashMap *hm, U64 key);
|
||||
internal U64 * hash_map_search_u64_u64 (HashMap *hm, U64 key);
|
||||
internal void * hash_map_search_raw_raw (HashMap *hm, void *key);
|
||||
internal U64 * hash_map_search_raw_u64 (HashMap *hm, void *key);
|
||||
|
||||
internal HashMapKeyValue * key_value_from_hash_map (Arena *arena, HashMap *hm);
|
||||
internal U32 * keys_from_hash_map_u32 (Arena *arena, HashMap *hm);
|
||||
|
||||
+245
-211
@@ -1968,7 +1968,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
PE_MakeImportList *imports = hash_table_search_path_raw(delayed_imports_ht, dll_name_n->string);
|
||||
String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_name_n->string);
|
||||
String8 import_obj = pe_make_import_dll_obj_delayed(arena->v[0], time_stamp, config->machine, dll_name_n->string, config->delay_load_helper_name, import_debug_symbols, *imports, emit_biat, emit_uiat);
|
||||
lnk_inputer_push_obj(inputer, 0, dll_name_n->string, import_obj);
|
||||
lnk_inputer_push_obj(inputer, 0, str8f(inputer->arena, "Import:%S", dll_name_n->string), import_obj);
|
||||
}
|
||||
|
||||
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(arena->v[0], config->machine);
|
||||
@@ -1990,7 +1990,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
PE_MakeImportList *imports = hash_table_search_path_raw(static_imports_ht, dll_name_n->string);
|
||||
String8 import_debug_symbols = lnk_make_dll_import_debug_symbols(scratch.arena, config->machine, dll_name_n->string);
|
||||
String8 import_obj = pe_make_import_dll_obj_static(arena->v[0], time_stamp, config->machine, dll_name_n->string, import_debug_symbols, *imports);
|
||||
lnk_inputer_push_obj(inputer, 0, dll_name_n->string, import_obj);
|
||||
lnk_inputer_push_obj(inputer, 0, str8f(inputer->arena, "Import:%S", dll_name_n->string), import_obj);
|
||||
}
|
||||
|
||||
String8 linker_debug_symbols = lnk_make_linker_debug_symbols(scratch.arena, config->machine);
|
||||
@@ -2395,158 +2395,41 @@ internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
Temp scratch2 = scratch_begin(&scratch.arena, 1);
|
||||
|
||||
LNK_OptRefTask *task = raw_task;
|
||||
LNK_SymbolTable *symtab = task->symtab;
|
||||
LNK_Config *config = task->config;
|
||||
LNK_ObjList objs = task->objs;
|
||||
|
||||
U8 **is_live = 0;
|
||||
U64 *active_thread_count = 0;
|
||||
LNK_RelocRefsList *ref_queue = 0;
|
||||
LNK_RelocRefsList free_list = {0};
|
||||
for (;;) {
|
||||
// update active thread count
|
||||
ins_atomic_u32_inc_eval(&task->active_thread_count);
|
||||
if (task_id == 0) {
|
||||
active_thread_count = push_array(scratch.arena, U64, 1);
|
||||
ref_queue = push_array(scratch.arena, LNK_RelocRefsList, 1);
|
||||
|
||||
for (;;) {
|
||||
// pop head node
|
||||
LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(task->reloc_refs);
|
||||
if (!node) { break; }
|
||||
|
||||
LNK_RelocRefs *reloc_refs = node->v;
|
||||
|
||||
LNK_RelocRefsNode *first_node = 0, *last_node = 0;
|
||||
for EachIndex(reloc_idx, reloc_refs->relocs.count) {
|
||||
COFF_Reloc *reloc = &reloc_refs->relocs.v[reloc_idx];
|
||||
LNK_ObjSymbolRef reloc_defn = (LNK_ObjSymbolRef){ .obj = reloc_refs->obj, .symbol_idx = reloc->isymbol };
|
||||
COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_defn.obj, reloc_defn.symbol_idx);
|
||||
COFF_SymbolValueInterpType reloc_interp = coff_interp_from_parsed_symbol(reloc_parsed);
|
||||
|
||||
LNK_ObjSymbolRef ref_symbol = reloc_defn;
|
||||
for (;;) {
|
||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||
|
||||
LNK_ObjSymbolRef next_ref = {0};
|
||||
if (ref_interp == COFF_SymbolValueInterp_Regular) {
|
||||
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(ref_symbol.obj, ref_parsed.section_number);
|
||||
if (symlink) {
|
||||
ref_symbol = lnk_ref_from_symbol(symlink);
|
||||
}
|
||||
break;
|
||||
} else if (ref_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
if (reloc_parsed.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name);
|
||||
next_ref = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
MemoryZeroStruct(&ref_symbol);
|
||||
break;
|
||||
}
|
||||
} else if (ref_interp == COFF_SymbolValueInterp_Weak) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, ref_parsed.name);
|
||||
next_ref = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (MemoryMatchStruct(&next_ref, &ref_symbol)) {
|
||||
MemoryZeroStruct(&ref_symbol);
|
||||
break;
|
||||
}
|
||||
ref_symbol = next_ref;
|
||||
}
|
||||
|
||||
// skip unresolved symbol
|
||||
if (ref_symbol.obj == 0) { continue; }
|
||||
|
||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||
LNK_Obj *ref_obj = ref_symbol.obj;
|
||||
|
||||
if (ref_interp == COFF_SymbolValueInterp_Regular) {
|
||||
// make section number list (reloc section + associates)
|
||||
U32Node *section_number_list = push_array(scratch.arena, U32Node, 1);
|
||||
section_number_list->data = ref_parsed.section_number;
|
||||
section_number_list->next = ref_obj->associated_sections[ref_parsed.section_number];
|
||||
|
||||
// push section headers relocations to the task stack
|
||||
for EachNode(section_number_n, U32Node, section_number_list) {
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_obj, section_number_n->data);
|
||||
|
||||
// is section eligible for walking?
|
||||
if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
||||
if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; }
|
||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||
if (section_header->flags & LNK_SECTION_FLAG_LIVE) { continue; }
|
||||
|
||||
// mark section live
|
||||
section_header->flags |= LNK_SECTION_FLAG_LIVE;
|
||||
|
||||
LNK_RelocRefsNode *node;
|
||||
if (free_list.head.node) {
|
||||
node = lnk_reloc_refs_list_pop_node(&free_list);
|
||||
} else {
|
||||
node = push_array(scratch.arena, LNK_RelocRefsNode, 1);
|
||||
node->v = push_array(scratch.arena, LNK_RelocRefs, 1);
|
||||
}
|
||||
|
||||
node->v->obj = ref_obj;
|
||||
node->v->relocs = lnk_coff_reloc_info_from_section_number(ref_obj, section_number_n->data);
|
||||
|
||||
if (first_node == 0) {
|
||||
first_node = node;
|
||||
last_node = node;
|
||||
} else {
|
||||
node->next = first_node;
|
||||
first_node = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lnk_reloc_refs_list_push_node(&free_list, node);
|
||||
|
||||
if (first_node && last_node) {
|
||||
lnk_reloc_refs_list_concat_in_place(task->reloc_refs, first_node, last_node);
|
||||
}
|
||||
}
|
||||
|
||||
// are all threads done walking?
|
||||
U32 active_thread_count = ins_atomic_u32_dec_eval(&task->active_thread_count);
|
||||
if (active_thread_count == 0 && ins_atomic_ptr_eval(&task->reloc_refs->head.node) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// comprehensive solution to the waiting problem
|
||||
for (; ins_atomic_ptr_eval(&task->reloc_refs->head.node) == 0; ) {
|
||||
// was signaled to exit?
|
||||
if (ins_atomic_u64_eval(&task->active_thread_count) == 0) { goto exit; }
|
||||
}
|
||||
}
|
||||
exit:;
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs)
|
||||
// alloc live flags for each section
|
||||
is_live = push_array_no_zero(scratch.arena, U8 *, objs.count);
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
U64 obj_idx = 0;
|
||||
for EachNode(n, LNK_ObjNode, task->objs.first) {
|
||||
is_live[obj_idx] = push_array(scratch.arena, U8, n->data.header.section_count_no_null + 1);
|
||||
|
||||
LNK_RelocRefsList reloc_refs = {0};
|
||||
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(&n->data);
|
||||
for EachIndex(sect_idx, n->data.header.section_count_no_null) {
|
||||
COFF_SectionHeader *header = §ion_table[sect_idx];
|
||||
is_live[obj_idx][sect_idx + 1] = !(header->flags & COFF_SectionFlag_LnkCOMDAT);
|
||||
}
|
||||
|
||||
//
|
||||
// reset live flag on sections
|
||||
//
|
||||
for EachNode(obj_n, LNK_ObjNode, objs.first) {
|
||||
for EachIndex(sect_idx, obj_n->data.header.section_count_no_null) {
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(&obj_n->data, sect_idx+1);
|
||||
section_header->flags &= ~LNK_SECTION_FLAG_LIVE;
|
||||
obj_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// define roots
|
||||
//
|
||||
{
|
||||
// tls
|
||||
LNK_Symbol *tls_symbol = lnk_symbol_table_searchf(symtab, MSCRT_TLS_SYMBOL_NAME);
|
||||
@@ -2565,7 +2448,7 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj
|
||||
r->relocs.v = push_array(scratch.arena, COFF_Reloc, 1);
|
||||
r->relocs.v[0].isymbol = root_ref.symbol_idx;
|
||||
|
||||
lnk_reloc_refs_list_push(scratch.arena, &reloc_refs, r);
|
||||
lnk_reloc_refs_list_push(scratch.arena, ref_queue, r);
|
||||
}
|
||||
|
||||
// push task for every non-COMDAT section
|
||||
@@ -2591,99 +2474,206 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj
|
||||
r->relocs.count = Min(LNK_RELOCS_PER_TASK, relocs.count - (new_task_idx * LNK_RELOCS_PER_TASK));
|
||||
r->relocs.v = relocs.v + (new_task_idx * LNK_RELOCS_PER_TASK);
|
||||
|
||||
lnk_reloc_refs_list_push(scratch.arena, &reloc_refs, r);
|
||||
lnk_reloc_refs_list_push(scratch.arena, ref_queue, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tp_broadcast(&is_live);
|
||||
tp_broadcast(&ref_queue);
|
||||
tp_broadcast(&active_thread_count);
|
||||
|
||||
for (;;) {
|
||||
// update active thread count
|
||||
ins_atomic_u32_inc_eval(active_thread_count);
|
||||
|
||||
for (;;) {
|
||||
// pop head node
|
||||
LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(ref_queue);
|
||||
if (!node) { break; }
|
||||
|
||||
LNK_RelocRefs *reloc_refs = node->v;
|
||||
LNK_RelocRefsNode *first_node = 0, *last_node = 0;
|
||||
|
||||
for EachIndex(reloc_idx, reloc_refs->relocs.count) {
|
||||
COFF_Reloc *reloc = &reloc_refs->relocs.v[reloc_idx];
|
||||
|
||||
// reloc -> symbol
|
||||
LNK_ObjSymbolRef ref_symbol = (LNK_ObjSymbolRef){ .obj = reloc_refs->obj, .symbol_idx = reloc->isymbol };
|
||||
{
|
||||
Temp temp = temp_begin(scratch2.arena);
|
||||
HashMap seen_hm = {0};
|
||||
B32 keep_walking = 1;
|
||||
do {
|
||||
// detect cyclic chains
|
||||
U64 symbol_key = ((U64)ref_symbol.obj->input_idx << 32ull) | (U64)ref_symbol.symbol_idx;
|
||||
if (hash_map_search_u64_u64(&seen_hm, symbol_key) == 0) {
|
||||
hash_map_push_u64_u64(temp.arena, &seen_hm, symbol_key, 1);
|
||||
} else {
|
||||
COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_refs->obj, reloc->isymbol);
|
||||
lnk_error_obj(LNK_Warning_CyclicSymbol, reloc_refs->obj, "symbol %S forms a cyclic chain (/OPT:REF)", reloc_parsed.name);
|
||||
MemoryZeroStruct(&ref_symbol);
|
||||
break;
|
||||
}
|
||||
|
||||
// unpack symbol
|
||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||
|
||||
// resolve symbol
|
||||
LNK_ObjSymbolRef next_ref = {0};
|
||||
if (lnk_resolve_symbol(symtab, ref_symbol, &next_ref)) {
|
||||
keep_walking = (ref_interp == COFF_SymbolValueInterp_Weak || ref_interp == COFF_SymbolValueInterp_Undefined);
|
||||
ref_symbol = next_ref;
|
||||
} else {
|
||||
keep_walking = 0;
|
||||
}
|
||||
} while (keep_walking);
|
||||
temp_end(temp);
|
||||
}
|
||||
|
||||
// skip unresolved symbol
|
||||
if (ref_symbol.obj == 0) { continue; }
|
||||
|
||||
// unpack resolved symbol
|
||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||
|
||||
if (ref_interp == COFF_SymbolValueInterp_Regular) {
|
||||
Temp temp = temp_begin(scratch2.arena);
|
||||
|
||||
HashMap visited_sections_hm = {0};
|
||||
U32Node *stack = push_array(temp.arena, U32Node, 1);
|
||||
stack->data = ref_parsed.section_number;
|
||||
do {
|
||||
U32 section_number = stack->data;
|
||||
SLLStackPop(stack);
|
||||
|
||||
// is section number valid?
|
||||
if (section_number == 0 || section_number > ref_symbol.obj->header.section_count_no_null) { continue; }
|
||||
|
||||
// detect cyclic associative sections
|
||||
if (hash_map_search_u64_u64(&visited_sections_hm, section_number)) { continue; }
|
||||
hash_map_push_u64_u64(temp.arena, &visited_sections_hm, section_number, 1);
|
||||
|
||||
// push associated section
|
||||
for EachNode(associated_n, U32Node, ref_symbol.obj->associated_sections[section_number]) {
|
||||
if (hash_map_search_u64_u64(&visited_sections_hm, associated_n->data)) { continue; }
|
||||
U32Node *stack_n = push_array(temp.arena, U32Node, 1);
|
||||
stack_n->data = associated_n->data;
|
||||
SLLStackPush(stack, stack_n);
|
||||
}
|
||||
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_symbol.obj, section_number);
|
||||
|
||||
// is section eligible for walking?
|
||||
if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
||||
if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; }
|
||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||
|
||||
// on first section visit set live flag and queue new section to walk
|
||||
U8 was_visited = ins_atomic_u8_eval_assign(&is_live[ref_symbol.obj->input_idx][section_number], 1);
|
||||
if (was_visited) { continue; }
|
||||
|
||||
LNK_RelocRefsNode *node;
|
||||
if (free_list.head.node) {
|
||||
node = lnk_reloc_refs_list_pop_node(&free_list);
|
||||
} else {
|
||||
node = push_array(scratch.arena, LNK_RelocRefsNode, 1);
|
||||
node->v = push_array(scratch.arena, LNK_RelocRefs, 1);
|
||||
}
|
||||
|
||||
node->v->obj = ref_symbol.obj;
|
||||
node->v->relocs = lnk_coff_reloc_info_from_section_number(ref_symbol.obj, section_number);
|
||||
|
||||
if (first_node == 0) {
|
||||
first_node = node, last_node = node;
|
||||
} else {
|
||||
node->next = first_node;
|
||||
first_node = node;
|
||||
}
|
||||
} while (stack);
|
||||
|
||||
temp_end(temp);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// walk relocations and mark referenced sections with live flag
|
||||
//
|
||||
LNK_OptRefTask task = {0};
|
||||
task.symtab = symtab;
|
||||
task.reloc_refs = &reloc_refs;
|
||||
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_walk_relocs_and_mark_ref_sections_task, &task, "Mark Live Sections");
|
||||
// free walk node
|
||||
lnk_reloc_refs_list_push_node(&free_list, node);
|
||||
|
||||
// queue new walks
|
||||
if (first_node && last_node) {
|
||||
lnk_reloc_refs_list_concat_in_place(ref_queue, first_node, last_node);
|
||||
}
|
||||
}
|
||||
|
||||
// are all threads done walking?
|
||||
{
|
||||
U32 c = ins_atomic_u32_dec_eval(active_thread_count);
|
||||
if (c == 0 && ins_atomic_ptr_eval(&ref_queue->head.node) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// comprehensive solution to the waiting problem
|
||||
for (; ins_atomic_ptr_eval(&ref_queue->head.node) == 0; ) {
|
||||
// was signaled to exit?
|
||||
if (ins_atomic_u32_eval(active_thread_count) == 0) { goto exit; }
|
||||
}
|
||||
}
|
||||
exit:;
|
||||
barrier_wait(tp->barrier);
|
||||
|
||||
// TODO: thread
|
||||
if (task_id == 0) {
|
||||
ProfBegin("Remove Unreachable Sections");
|
||||
|
||||
U64 discard_vsize = 0;
|
||||
U64 discard_fsize = 0;
|
||||
U64 discard_count = 0;
|
||||
|
||||
for EachNode(obj_n, LNK_ObjNode, objs.first) {
|
||||
LNK_Obj *obj = &obj_n->data;
|
||||
|
||||
for EachIndex(sect_idx, obj->header.section_count_no_null) {
|
||||
U32 section_number = sect_idx+1;
|
||||
if (is_live[obj->input_idx][section_number]) { continue; }
|
||||
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number);
|
||||
|
||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||
|
||||
// remove unreferenced sections
|
||||
if (~section_header->flags & LNK_SECTION_FLAG_LIVE && section_header->flags & COFF_SectionFlag_LnkCOMDAT) {
|
||||
section_header->flags |= COFF_SectionFlag_LnkRemove;
|
||||
}
|
||||
|
||||
// remove associated sections
|
||||
if (section_header->flags & COFF_SectionFlag_LnkRemove) {
|
||||
for EachNode(section_number_n, U32Node, obj->associated_sections[section_number]) {
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number_n->data);
|
||||
section_header->flags |= COFF_SectionFlag_LnkRemove;
|
||||
if (section_header->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
discard_vsize += section_header->vsize;
|
||||
} else {
|
||||
discard_fsize += section_header->fsize;
|
||||
}
|
||||
discard_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Reset reserved flag so it does not get propagated to the image sections.
|
||||
// We need to mask out reserved flags when gathering section definitions to actually
|
||||
// prevent propagation.
|
||||
section_header->flags &= ~LNK_SECTION_FLAG_LIVE;
|
||||
}
|
||||
}
|
||||
lnk_log(LNK_Log_Debug, "/OPT:REF total virt size discard: %M", (unsigned long long)discard_vsize);
|
||||
lnk_log(LNK_Log_Debug, "/OPT:REF total file size discard: %M", (unsigned long long)discard_fsize);
|
||||
lnk_log(LNK_Log_Debug, "/OPT:REF total section discard : %llu", (unsigned long long)discard_count);
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
barrier_wait(tp->barrier);
|
||||
|
||||
scratch_end(scratch2);
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out)
|
||||
internal void
|
||||
lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_ObjList objs)
|
||||
{
|
||||
B32 is_resolved = 1;
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class);
|
||||
switch (symbol_interp) {
|
||||
case COFF_SymbolValueInterp_Regular: {
|
||||
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number);
|
||||
*symbol_out = symlink ? lnk_ref_from_symbol(symlink) : symbol;
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Weak: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn);
|
||||
COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn);
|
||||
if (defn_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Undefined: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
if (defn) {
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Abs: {
|
||||
if (symbol_parsed.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
*symbol_out = symbol;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Debug: { *symbol_out = symbol; } break;
|
||||
}
|
||||
return is_resolved;
|
||||
ProfScope("Mark Live Sections")
|
||||
tp_for_parallel(tp,
|
||||
0,
|
||||
tp->worker_count,
|
||||
lnk_walk_relocs_and_mark_ref_sections_task,
|
||||
&(LNK_OptRefTask){ .symtab = symtab, .config = config, .objs = objs });
|
||||
}
|
||||
|
||||
internal
|
||||
@@ -3728,8 +3718,26 @@ THREAD_POOL_TASK_FUNC(lnk_patch_section_symbols_task)
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Undefined) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_Section) {
|
||||
B32 is_referenced = 0;
|
||||
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
|
||||
for EachIndex(sect_idx, obj->header.section_count_no_null) {
|
||||
COFF_SectionHeader *section_header = §ion_table[sect_idx];
|
||||
if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
||||
if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; }
|
||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||
COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header);
|
||||
for EachIndex(reloc_idx, relocs.count) {
|
||||
if (relocs.v[reloc_idx].isymbol == symbol_idx) {
|
||||
is_referenced = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_referenced) { break; }
|
||||
}
|
||||
if (!is_referenced) { continue; }
|
||||
|
||||
LNK_Section *sect = lnk_section_table_search(task->sectab, symbol.name, symbol.value);
|
||||
if (sect) {
|
||||
if (sect && (~sect->flags & COFF_SectionFlag_LnkRemove)) {
|
||||
if (~sect->flags & COFF_SectionFlag_MemDiscardable) {
|
||||
LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect);
|
||||
if (obj->header.is_big_obj) {
|
||||
@@ -3747,7 +3755,32 @@ THREAD_POOL_TASK_FUNC(lnk_patch_section_symbols_task)
|
||||
lnk_error_obj(LNK_Error_SectRefsDiscardedMemory, obj, "symbol %S (No. 0x%llx) references section with discard flag", symbol.name, symbol_idx);
|
||||
}
|
||||
} else {
|
||||
lnk_error_obj(LNK_Error_UnresolvedSymbol, obj, "undefined section symbol %S (No 0x%llx) refers to an image section that doesn't exist", symbol.name, symbol_idx);
|
||||
U64 fallback_voff = 0;
|
||||
U64 fallback_align = Max(task->sect_align, KB(4));
|
||||
for EachIndex(sect_idx, task->image_sects.count) {
|
||||
LNK_Section *image_sect = task->image_sects.v[sect_idx];
|
||||
U64 image_sect_size = AlignPow2(Max(image_sect->vsize, image_sect->fsize), fallback_align);
|
||||
if (image_sect_size == 0) { image_sect_size = fallback_align; }
|
||||
fallback_voff = Max(fallback_voff, image_sect->voff + image_sect_size);
|
||||
}
|
||||
fallback_voff = AlignPow2(fallback_voff, fallback_align);
|
||||
|
||||
LNK_Section *fallback_sect = task->image_sects.v[task->image_sects.count-1];
|
||||
U32 fallback_section_number = safe_cast_u32(fallback_sect->sect_idx + 1);
|
||||
U32 fallback_section_offset = safe_cast_u32(fallback_voff - fallback_sect->voff);
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
symbol32->section_number = fallback_section_number;
|
||||
symbol32->value = fallback_section_offset;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
|
||||
symbol16->section_number = safe_cast_u16(fallback_section_number);
|
||||
symbol16->value = fallback_section_offset;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
|
||||
lnk_error_obj(LNK_Warning_UndefinedSectionSymbol, obj, "undefined section symbol %S (No. 0x%llx) refers to an image section that doesn't exist; patching to %#llx", symbol.name, symbol_idx, fallback_voff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4275,6 +4308,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
.objs = objs,
|
||||
.function_pad_min = config->function_pad_min,
|
||||
.default_align = coff_default_align_from_machine(config->machine),
|
||||
.sect_align = config->sect_align,
|
||||
.null_sc = push_array(arena->v[0], LNK_SectionContrib, 1),
|
||||
};
|
||||
|
||||
|
||||
+4
-4
@@ -73,8 +73,7 @@ typedef struct LNK_Inputer
|
||||
#define LNK_IMPORT_STUB "*** RAD_IMPORT_STUB ***"
|
||||
#define LNK_NULL_SYMBOL "*** RAD_NULL_SYMBOL ***"
|
||||
|
||||
#define LNK_SECTION_FLAG_LIVE (1 << 0)
|
||||
#define LNK_SECTION_FLAG_DEBUG (1 << 1)
|
||||
#define LNK_SECTION_FLAG_DEBUG (1 << 0)
|
||||
|
||||
typedef U8 LNK_LibMemberFlags;
|
||||
enum
|
||||
@@ -215,8 +214,8 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
U32 active_thread_count;
|
||||
LNK_RelocRefsList *reloc_refs;
|
||||
LNK_Config *config;
|
||||
LNK_ObjList objs;
|
||||
} LNK_OptRefTask;
|
||||
|
||||
typedef struct
|
||||
@@ -263,6 +262,7 @@ typedef struct
|
||||
LNK_Obj **objs;
|
||||
U64 function_pad_min;
|
||||
U64 default_align;
|
||||
U64 sect_align;
|
||||
LNK_SectionContrib *null_sc;
|
||||
LNK_SectionContrib ***sect_map;
|
||||
HashTable *contribs_ht;
|
||||
|
||||
@@ -2407,14 +2407,16 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
if (obj_sect_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
||||
if (obj_sect_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||
|
||||
String8 header_name = str8_cstring_capped(obj_sect_header->name, obj_sect_header->name + sizeof(obj_sect_header->name));
|
||||
if (str8_match(header_name, str8_lit(".pdata"), 0)) { continue; }
|
||||
|
||||
U64 sect_number;
|
||||
String8 sect_data;
|
||||
U32 sect_off;
|
||||
U32 data_crc;
|
||||
if (obj_sect_header->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
if (obj_sect_header->vsize == 0) {
|
||||
continue;
|
||||
}
|
||||
if (obj_sect_header->vsize == 0) { continue; }
|
||||
|
||||
U64 sect_num = rng1u64_array_num_from_value__binary_search(&task->image_section_virt_ranges, obj_sect_header->voff);
|
||||
sect_number = sect_num-1;
|
||||
Assert(sect_number < task->image_section_virt_ranges.count);
|
||||
@@ -2422,9 +2424,8 @@ THREAD_POOL_TASK_FUNC(lnk_push_dbi_sec_contrib_task)
|
||||
sect_off = obj_sect_header->voff - task->image_section_virt_ranges.v[sect_number].min;
|
||||
data_crc = 0;
|
||||
} else {
|
||||
if (obj_sect_header->fsize == 0) {
|
||||
continue;
|
||||
}
|
||||
if (obj_sect_header->fsize == 0) { continue; }
|
||||
|
||||
U64 sect_num = rng1u64_array_num_from_value__binary_search(&task->image_section_file_ranges, obj_sect_header->foff);
|
||||
sect_number = sect_num-1;
|
||||
Assert(sect_number < task->image_section_file_ranges.count);
|
||||
|
||||
@@ -109,6 +109,8 @@ typedef enum
|
||||
LNK_Warning_TryingToExportEntryPoint,
|
||||
LNK_Warning_InferAsanFail,
|
||||
LNK_Warning_GHash,
|
||||
LNK_Warning_UndefinedSectionSymbol,
|
||||
LNK_Warning_CyclicSymbol,
|
||||
LNK_Warning_Last,
|
||||
|
||||
LNK_Error_Count
|
||||
|
||||
@@ -708,6 +708,52 @@ exit:;
|
||||
return is_resolved;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out)
|
||||
{
|
||||
B32 is_resolved = 1;
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class);
|
||||
switch (symbol_interp) {
|
||||
case COFF_SymbolValueInterp_Regular: {
|
||||
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number);
|
||||
*symbol_out = symlink ? lnk_ref_from_symbol(symlink) : symbol;
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Weak: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_from_symbol(defn);
|
||||
COFF_SymbolValueInterpType defn_interp = lnk_interp_from_symbol(defn);
|
||||
if (defn_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Undefined: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
if (defn) {
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Abs: {
|
||||
if (symbol_parsed.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
*symbol_out = lnk_ref_from_symbol(defn);
|
||||
} else {
|
||||
*symbol_out = symbol;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Debug: { *symbol_out = symbol; } break;
|
||||
}
|
||||
return is_resolved;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
|
||||
{
|
||||
|
||||
@@ -134,6 +134,7 @@ internal U64 lnk_foff_from_symbol(COFF_SectionHeader **image_section_table,
|
||||
// --- Weak Symbol -------------------------------------------------------------
|
||||
|
||||
internal B32 lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *resolved_symbol_out);
|
||||
internal B32 lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymbolRef *symbol_out);
|
||||
|
||||
internal void lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab);
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ pe_make_import_dll_obj_static(Arena *arena, COFF_TimeStamp time_stamp, COFF_Mach
|
||||
COFF_ObjSection *int_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
|
||||
COFF_ObjSection *dll_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$7"), PE_IDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
|
||||
COFF_ObjSection *code_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text$zz"), PE_TEXT_SECTION_FLAGS |COFF_SectionFlag_Align1Bytes, str8_zero());
|
||||
COFF_ObjSection *debug_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), PE_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
|
||||
|
||||
COFF_ObjSymbol *ilt_symbol = coff_obj_writer_push_symbol_static(obj_writer, ilt_sect->name, 0, ilt_sect);
|
||||
COFF_ObjSymbol *iat_symbol = coff_obj_writer_push_symbol_static(obj_writer, iat_sect->name, 0, iat_sect);
|
||||
|
||||
Reference in New Issue
Block a user