mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-06 13:58:40 +00:00
progress on /opt:ref
Link the debugger and strip unreferenced sections TODO: Mark referenced undefined symbols for unresolved symbol reporting
This commit is contained in:
+433
-492
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -19,6 +19,8 @@ typedef struct LNK_LinkContext
|
|||||||
#define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3
|
#define LNK_REMOVED_SECTION_NUMBER_32 (U32)-3
|
||||||
#define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3
|
#define LNK_REMOVED_SECTION_NUMBER_16 (U16)-3
|
||||||
|
|
||||||
|
#define LNK_SECTION_FLAG_IS_LIVE (1 << 0)
|
||||||
|
|
||||||
typedef struct LNK_ImageContext
|
typedef struct LNK_ImageContext
|
||||||
{
|
{
|
||||||
String8 image_data;
|
String8 image_data;
|
||||||
@@ -212,7 +214,7 @@ internal void lnk_push_disallow_lib(Arena *arena, HashTable *disallow_lib_ht,
|
|||||||
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
|
internal void lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path);
|
||||||
|
|
||||||
internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config);
|
internal LNK_InputObjList lnk_push_linker_symbols(Arena *arena, LNK_Config *config);
|
||||||
internal void lnk_queue_lib_member_input(Arena *arena, PathStyle path_style, LNK_SymbolLib *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list);
|
internal void lnk_queue_lib_member_input(Arena *arena, LNK_Config *config, LNK_Symbol *symbol, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list);
|
||||||
|
|
||||||
internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config);
|
internal LNK_LinkContext lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config);
|
||||||
|
|
||||||
|
|||||||
+5
-24
@@ -365,7 +365,6 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
|
|||||||
case COFF_SymbolValueInterp_Weak: {
|
case COFF_SymbolValueInterp_Weak: {
|
||||||
LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx);
|
LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx);
|
||||||
lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn);
|
lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn);
|
||||||
lnk_symbol_list_push(arena, &task->weak_lists[worker_id], defn);
|
|
||||||
} break;
|
} break;
|
||||||
case COFF_SymbolValueInterp_Common: {
|
case COFF_SymbolValueInterp_Common: {
|
||||||
LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx);
|
LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx);
|
||||||
@@ -378,16 +377,9 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case COFF_SymbolValueInterp_Undefined: {
|
case COFF_SymbolValueInterp_Undefined: {
|
||||||
LNK_Symbol *s = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name);
|
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||||
if (s == 0) {
|
LNK_Symbol *defn = lnk_make_defined_symbol(arena, symbol.name, obj, symbol_idx);
|
||||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
lnk_symbol_table_push_(task->symtab, arena, worker_id, LNK_SymbolScope_Defined, defn);
|
||||||
LNK_Symbol *undef = lnk_make_undefined_symbol(arena, symbol.name, obj);
|
|
||||||
lnk_symbol_list_push(arena, &task->undef_lists[worker_id], undef);
|
|
||||||
} else if (symbol.storage_class == COFF_SymStorageClass_Section) {
|
|
||||||
// lookup is performed during image patching step
|
|
||||||
} else {
|
|
||||||
Assert(!"unexpected storage class on undefined symbol");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case COFF_SymbolValueInterp_Debug: {
|
case COFF_SymbolValueInterp_Debug: {
|
||||||
@@ -426,27 +418,16 @@ THREAD_POOL_TASK_FUNC(lnk_assign_comdat_symlinks_task)
|
|||||||
obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj);
|
obj->symlinks = lnk_symlinks_from_obj(arena, task->symtab, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LNK_SymbolInputResult
|
internal void
|
||||||
lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs)
|
lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
ProfBeginFunction();
|
||||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
|
||||||
|
|
||||||
LNK_InputCoffSymbolTable task = {0};
|
LNK_InputCoffSymbolTable task = { .symtab = symtab, .objs = objs };
|
||||||
task.symtab = symtab;
|
|
||||||
task.objs = objs;
|
|
||||||
task.weak_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count);
|
|
||||||
task.undef_lists = push_array(scratch.arena, LNK_SymbolList, tp->worker_count);
|
|
||||||
tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task);
|
tp_for_parallel(tp, arena, objs.count, lnk_input_coff_symbol_table, &task);
|
||||||
tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task);
|
tp_for_parallel(tp, arena, objs.count, lnk_assign_comdat_symlinks_task, &task);
|
||||||
|
|
||||||
LNK_SymbolInputResult result = {0};
|
|
||||||
SLLConcatInPlaceArray(&result.weak_symbols, task.weak_lists, tp->worker_count);
|
|
||||||
SLLConcatInPlaceArray(&result.undef_symbols, task.undef_lists, tp->worker_count);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal COFF_ParsedSymbol
|
internal COFF_ParsedSymbol
|
||||||
|
|||||||
+3
-11
@@ -37,12 +37,6 @@ typedef struct LNK_ObjNodeArray
|
|||||||
LNK_ObjNode *v;
|
LNK_ObjNode *v;
|
||||||
} LNK_ObjNodeArray;
|
} LNK_ObjNodeArray;
|
||||||
|
|
||||||
typedef struct LNK_SymbolInputResult
|
|
||||||
{
|
|
||||||
LNK_SymbolList weak_symbols;
|
|
||||||
LNK_SymbolList undef_symbols;
|
|
||||||
} LNK_SymbolInputResult;
|
|
||||||
|
|
||||||
// --- Directive Parser --------------------------------------------------------
|
// --- Directive Parser --------------------------------------------------------
|
||||||
|
|
||||||
typedef struct LNK_Directive
|
typedef struct LNK_Directive
|
||||||
@@ -78,8 +72,6 @@ typedef struct
|
|||||||
{
|
{
|
||||||
LNK_SymbolTable *symtab;
|
LNK_SymbolTable *symtab;
|
||||||
LNK_ObjNodeArray objs;
|
LNK_ObjNodeArray objs;
|
||||||
LNK_SymbolList *weak_lists;
|
|
||||||
LNK_SymbolList *undef_lists;
|
|
||||||
} LNK_InputCoffSymbolTable;
|
} LNK_InputCoffSymbolTable;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -96,9 +88,9 @@ internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...);
|
|||||||
|
|
||||||
// --- Input -------------------------------------------------------------------
|
// --- Input -------------------------------------------------------------------
|
||||||
|
|
||||||
internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list);
|
internal LNK_Obj ** lnk_array_from_obj_list(Arena *arena, LNK_ObjList list);
|
||||||
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs);
|
internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, COFF_MachineType machine, U64 input_count, LNK_InputObj **inputs);
|
||||||
internal LNK_SymbolInputResult lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs);
|
internal void lnk_input_obj_symbols(TP_Context *tp, TP_Arena *arena, LNK_SymbolTable *symtab, LNK_ObjNodeArray objs);
|
||||||
|
|
||||||
// --- Metadata ----------------------------------------------------------------
|
// --- Metadata ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
+165
-120
@@ -21,15 +21,6 @@ lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_
|
|||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LNK_Symbol *
|
|
||||||
lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj)
|
|
||||||
{
|
|
||||||
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
|
|
||||||
symbol->name = name;
|
|
||||||
symbol->u.undef.obj = obj;
|
|
||||||
return symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
lnk_symbol_defined_is_before(void *raw_a, void *raw_b)
|
lnk_symbol_defined_is_before(void *raw_a, void *raw_b)
|
||||||
{
|
{
|
||||||
@@ -37,6 +28,12 @@ lnk_symbol_defined_is_before(void *raw_a, void *raw_b)
|
|||||||
return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx;
|
return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
lnk_symbol_defined_ptr_is_before(void *raw_a, void *raw_b)
|
||||||
|
{
|
||||||
|
return lnk_symbol_defined_is_before(*(LNK_Symbol **)raw_a, *(LNK_Symbol **)raw_b);
|
||||||
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
lnk_symbol_lib_is_before(void *raw_a, void *raw_b)
|
lnk_symbol_lib_is_before(void *raw_a, void *raw_b)
|
||||||
{
|
{
|
||||||
@@ -144,8 +141,36 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
|||||||
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
|
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
|
||||||
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
|
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
|
||||||
|
|
||||||
|
// undefined vs regular
|
||||||
|
if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) {
|
||||||
|
can_replace = 1;
|
||||||
|
}
|
||||||
|
// undefined vs weak
|
||||||
|
else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||||
|
can_replace = 1;
|
||||||
|
}
|
||||||
|
// undefined vs undefined
|
||||||
|
else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) {
|
||||||
|
can_replace = lnk_symbol_defined_is_before(src, dst);
|
||||||
|
}
|
||||||
|
// undefined vs common
|
||||||
|
else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Common) {
|
||||||
|
can_replace = 1;
|
||||||
|
}
|
||||||
|
// undefined vs abs
|
||||||
|
else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||||
|
can_replace = 1;
|
||||||
|
}
|
||||||
|
// undefined vs debug
|
||||||
|
else if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Debug) {
|
||||||
|
can_replace = 1;
|
||||||
|
}
|
||||||
|
// regular/weak/common/abs/debug vs undefined
|
||||||
|
else if (dst_interp != COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Undefined) {
|
||||||
|
can_replace = 0;
|
||||||
|
}
|
||||||
// regular vs abs
|
// regular vs abs
|
||||||
if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) {
|
else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||||
lnk_error_multiply_defined_symbol(dst, src);
|
lnk_error_multiply_defined_symbol(dst, src);
|
||||||
}
|
}
|
||||||
// abs vs regular
|
// abs vs regular
|
||||||
@@ -439,6 +464,129 @@ lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie)
|
|||||||
ins_atomic_ptr_eval_assign(&trie->symbol, 0);
|
ins_atomic_ptr_eval_assign(&trie->symbol, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal LNK_SymbolHashTrieChunk **
|
||||||
|
lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out)
|
||||||
|
{
|
||||||
|
U64 chunks_count = 0;
|
||||||
|
for EachIndex(i, lists_count) { chunks_count += lists[i].count; }
|
||||||
|
|
||||||
|
LNK_SymbolHashTrieChunk **chunks = push_array(arena, LNK_SymbolHashTrieChunk *, chunks_count);
|
||||||
|
U64 chunks_cursor = 0;
|
||||||
|
for EachIndex(i, lists_count) {
|
||||||
|
for (LNK_SymbolHashTrieChunk *chunk = lists[i].first; chunk != 0; chunk = chunk->next) {
|
||||||
|
chunks[chunks_cursor++] = chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count_out) {
|
||||||
|
*count_out = chunks_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal COFF_ParsedSymbol
|
||||||
|
lnk_parsed_symbol_from_defined(LNK_Symbol *symbol)
|
||||||
|
{
|
||||||
|
return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
lnk_mark_symbol_live(LNK_Symbol *symbol)
|
||||||
|
{
|
||||||
|
B32 was_live = ins_atomic_u32_eval_assign(&symbol->is_live, 1);
|
||||||
|
return was_live;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LNK_SymbolDefined
|
||||||
|
lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(0,0);
|
||||||
|
|
||||||
|
struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dep; };
|
||||||
|
struct LookupLocation *lookup_first = 0, *lookup_last = 0;
|
||||||
|
|
||||||
|
COFF_ParsedSymbol head_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
|
||||||
|
COFF_SymbolWeakExt *head_weak_ext = coff_parse_weak_tag(head_parsed, symbol.obj->header.is_big_obj);
|
||||||
|
LNK_SymbolDefined current_symbol = (LNK_SymbolDefined){ .obj = symbol.obj, .symbol_idx = head_weak_ext->tag_index };
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// guard against self-referencing weak symbols
|
||||||
|
struct LookupLocation *was_visited = 0;
|
||||||
|
for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) {
|
||||||
|
if (MemoryCompare(&l->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = l; break; }
|
||||||
|
}
|
||||||
|
if (was_visited) {
|
||||||
|
Temp temp = temp_begin(scratch.arena);
|
||||||
|
|
||||||
|
String8List ref_list = {0};
|
||||||
|
for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) {
|
||||||
|
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(l->symbol.obj, l->symbol.symbol_idx);
|
||||||
|
str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x) =>", l->symbol.obj->path, loc_symbol.name, l->symbol.symbol_idx);
|
||||||
|
}
|
||||||
|
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(lookup_first->symbol.obj, lookup_first->symbol.symbol_idx);
|
||||||
|
str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x)", lookup_first->symbol.obj->path, loc_symbol.name, lookup_first->symbol.symbol_idx);
|
||||||
|
|
||||||
|
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol.obj, symbol.symbol_idx);
|
||||||
|
String8 loc_string = str8_list_join(temp.arena, &ref_list, &(StringJoin){ .sep = str8_lit("\n") });
|
||||||
|
lnk_error_obj(LNK_Error_WeakCycle, symbol.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", parsed_symbol.name, loc_string);
|
||||||
|
|
||||||
|
MemoryZeroStruct(¤t_symbol);
|
||||||
|
|
||||||
|
temp_end(temp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx);
|
||||||
|
COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class);
|
||||||
|
if (current_interp == COFF_SymbolValueInterp_Weak) {
|
||||||
|
// check for anti dependency
|
||||||
|
for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) {
|
||||||
|
if (l->is_anti_dep) {
|
||||||
|
lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol.obj, "unresolved symbol %S", head_parsed.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// does weak symbol have a definition?
|
||||||
|
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name);
|
||||||
|
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx);
|
||||||
|
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class);
|
||||||
|
if (defn_interp != COFF_SymbolValueInterp_Weak) {
|
||||||
|
current_symbol = defn_symbol->u.defined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no definition fallback to default symbol
|
||||||
|
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj);
|
||||||
|
COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index);
|
||||||
|
COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class);
|
||||||
|
current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index };
|
||||||
|
|
||||||
|
// record visited symbol
|
||||||
|
struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1);
|
||||||
|
loc->symbol = current_symbol;
|
||||||
|
loc->is_anti_dep = weak_ext->characteristics == COFF_WeakExt_AntiDependency;
|
||||||
|
SLLQueuePush(lookup_first, lookup_last, loc);
|
||||||
|
} else if (current_interp == COFF_SymbolValueInterp_Undefined) {
|
||||||
|
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name);
|
||||||
|
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn_symbol);
|
||||||
|
COFF_SymbolValueInterpType defn_interp = coff_interp_from_parsed_symbol(defn_parsed);
|
||||||
|
|
||||||
|
current_symbol = defn_symbol->u.defined;
|
||||||
|
|
||||||
|
if (defn_interp == COFF_SymbolValueInterp_Undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
return current_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
lnk_symbol_hash(String8 string)
|
lnk_symbol_hash(String8 string)
|
||||||
{
|
{
|
||||||
@@ -539,10 +687,8 @@ THREAD_POOL_TASK_FUNC(lnk_check_anti_dependecy_task)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task)
|
THREAD_POOL_TASK_FUNC(lnk_replace_weak_symbols_with_default_symbols_task)
|
||||||
{
|
{
|
||||||
Temp scratch = scratch_begin(&arena,1);
|
|
||||||
|
|
||||||
LNK_FinalizeWeakSymbolsTask *task = raw_task;
|
LNK_FinalizeWeakSymbolsTask *task = raw_task;
|
||||||
LNK_SymbolTable *symtab = task->symtab;
|
LNK_SymbolTable *symtab = task->symtab;
|
||||||
LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id];
|
LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id];
|
||||||
@@ -552,117 +698,22 @@ THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task)
|
|||||||
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol);
|
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_defined(symbol);
|
||||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
|
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
|
||||||
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
|
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
|
||||||
struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; B32 is_anti_dependency; };
|
symbol->u.defined = lnk_default_symbol_from_weak(symtab, symbol->u.defined);
|
||||||
struct LookupLocation *lookup_first = 0, *lookup_last = 0;
|
|
||||||
|
|
||||||
LNK_SymbolDefined current_symbol = symbol->u.defined;
|
|
||||||
for (;;) {
|
|
||||||
// guard against self-referencing weak symbols
|
|
||||||
struct LookupLocation *was_visited = 0;
|
|
||||||
for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) {
|
|
||||||
if (MemoryCompare(&l->symbol, ¤t_symbol, sizeof(LNK_SymbolDefined)) == 0) { was_visited = l; break; }
|
|
||||||
}
|
|
||||||
if (was_visited) {
|
|
||||||
Temp temp = temp_begin(scratch.arena);
|
|
||||||
|
|
||||||
String8List ref_list = {0};
|
|
||||||
for (struct LookupLocation *l = lookup_first; l != 0; l = l->next) {
|
|
||||||
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(l->symbol.obj, l->symbol.symbol_idx);
|
|
||||||
str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x) =>", l->symbol.obj->path, loc_symbol.name, l->symbol.symbol_idx);
|
|
||||||
}
|
|
||||||
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(lookup_first->symbol.obj, lookup_first->symbol.symbol_idx);
|
|
||||||
str8_list_pushf(temp.arena, &ref_list, "\t%S Symbol %S (No. %#x)", lookup_first->symbol.obj->path, loc_symbol.name, lookup_first->symbol.symbol_idx);
|
|
||||||
|
|
||||||
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
|
||||||
String8 loc_string = str8_list_join(temp.arena, &ref_list, &(StringJoin){ .sep = str8_lit("\n") });
|
|
||||||
lnk_error_obj(LNK_Error_WeakCycle, symbol->u.defined.obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", parsed_symbol.name, loc_string);
|
|
||||||
|
|
||||||
MemoryZeroStruct(¤t_symbol);
|
|
||||||
|
|
||||||
temp_end(temp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_ParsedSymbol current_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, current_symbol.symbol_idx);
|
|
||||||
COFF_SymbolValueInterpType current_interp = coff_interp_symbol(current_parsed.section_number, current_parsed.value, current_parsed.storage_class);
|
|
||||||
if (current_interp == COFF_SymbolValueInterp_Weak) {
|
|
||||||
// record visited symbol
|
|
||||||
struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1);
|
|
||||||
loc->symbol = current_symbol;
|
|
||||||
SLLQueuePush(lookup_first, lookup_last, loc);
|
|
||||||
|
|
||||||
// does weak symbol have a definition?
|
|
||||||
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name);
|
|
||||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, defn_symbol->u.defined.symbol_idx);
|
|
||||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class);
|
|
||||||
if (defn_interp != COFF_SymbolValueInterp_Weak) {
|
|
||||||
current_symbol = defn_symbol->u.defined;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no definition fallback to the tag
|
|
||||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(current_parsed, current_symbol.obj->header.is_big_obj);
|
|
||||||
COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(current_symbol.obj, weak_ext->tag_index);
|
|
||||||
COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class);
|
|
||||||
current_symbol = (LNK_SymbolDefined){ .obj = current_symbol.obj, .symbol_idx = weak_ext->tag_index };
|
|
||||||
} else if (current_interp == COFF_SymbolValueInterp_Undefined) {
|
|
||||||
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, current_parsed.name);
|
|
||||||
if (defn_symbol == 0) {
|
|
||||||
MemoryZeroStruct(¤t_symbol);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current_symbol = defn_symbol->u.defined;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace weak symbol with it's tag
|
|
||||||
symbol->u.defined = current_symbol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab)
|
lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
ProfBeginFunction();
|
||||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
Temp scratch = scratch_begin(0,0);
|
||||||
|
|
||||||
U64 chunks_count = 0;
|
U64 chunks_count = 0;
|
||||||
for EachIndex(worker_id, tp->worker_count) { chunks_count += symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].count; }
|
LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunk_lists[LNK_SymbolScope_Defined], symtab->arena->count, &chunks_count);
|
||||||
|
|
||||||
LNK_SymbolHashTrieChunk **chunks = push_array(scratch.arena, LNK_SymbolHashTrieChunk *, chunks_count);
|
|
||||||
U64 chunks_cursor = 0;
|
|
||||||
for EachIndex(worker_id, tp->worker_count) {
|
|
||||||
for (LNK_SymbolHashTrieChunk *chunk = symtab->chunk_lists[LNK_SymbolScope_Defined][worker_id].first; chunk != 0; chunk = chunk->next) {
|
|
||||||
chunks[chunks_cursor++] = chunk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LNK_FinalizeWeakSymbolsTask task = { .symtab = symtab, .chunks = chunks };
|
LNK_FinalizeWeakSymbolsTask task = { .symtab = symtab, .chunks = chunks };
|
||||||
|
tp_for_parallel(tp, 0, chunks_count, lnk_replace_weak_symbols_with_default_symbols_task, &task);
|
||||||
{
|
|
||||||
TP_Temp temp = tp_temp_begin(arena);
|
|
||||||
task.anti_dependency_symbols = push_array(scratch.arena, LNK_SymbolList, tp->worker_count);
|
|
||||||
tp_for_parallel(tp, arena, chunks_count, lnk_check_anti_dependecy_task, &task);
|
|
||||||
|
|
||||||
LNK_SymbolList anti_dependency_symbol_list = {0};
|
|
||||||
lnk_symbol_concat_in_place_array(&anti_dependency_symbol_list, task.anti_dependency_symbols, tp->worker_count);
|
|
||||||
LNK_SymbolArray anti_dependency_symbols = lnk_symbol_array_from_list(scratch.arena, anti_dependency_symbol_list);
|
|
||||||
radsort(anti_dependency_symbols.v, anti_dependency_symbols.count, lnk_symbol_defined_is_before);
|
|
||||||
|
|
||||||
for EachIndex(symbol_idx, anti_dependency_symbols.count) {
|
|
||||||
LNK_Symbol *s = &anti_dependency_symbols.v[symbol_idx];
|
|
||||||
lnk_error_obj(LNK_Error_UnresolvedSymbol, s->u.defined.obj, "unresolved symbol %S", s->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp_temp_end(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp_for_parallel(tp, 0, chunks_count, lnk_finalize_weak_symbols_task, &task);
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
@@ -708,9 +759,3 @@ lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol)
|
|||||||
return foff;
|
return foff;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal COFF_ParsedSymbol
|
|
||||||
lnk_parsed_symbol_from_defined(LNK_Symbol *symbol)
|
|
||||||
{
|
|
||||||
return lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ typedef struct LNK_SymbolUndefined
|
|||||||
typedef struct LNK_Symbol
|
typedef struct LNK_Symbol
|
||||||
{
|
{
|
||||||
String8 name;
|
String8 name;
|
||||||
|
B32 is_live;
|
||||||
union {
|
union {
|
||||||
LNK_SymbolDefined defined;
|
LNK_SymbolDefined defined;
|
||||||
LNK_SymbolLib lib;
|
LNK_SymbolLib lib;
|
||||||
LNK_SymbolUndefined undef;
|
|
||||||
} u;
|
} u;
|
||||||
} LNK_Symbol;
|
} LNK_Symbol;
|
||||||
|
|
||||||
@@ -112,7 +112,6 @@ typedef struct
|
|||||||
|
|
||||||
internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx);
|
internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx);
|
||||||
internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
|
internal LNK_Symbol * lnk_make_lib_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
|
||||||
internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj);
|
|
||||||
|
|
||||||
// --- Symbol Containers ------------------------------------------------------
|
// --- Symbol Containers ------------------------------------------------------
|
||||||
|
|
||||||
@@ -126,9 +125,16 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol
|
|||||||
|
|
||||||
// --- Symbol Hash Trie --------------------------------------------------------
|
// --- Symbol Hash Trie --------------------------------------------------------
|
||||||
|
|
||||||
internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol);
|
internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_SymbolScope scope, LNK_Symbol *symbol);
|
||||||
internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
|
internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
|
||||||
internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
|
internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
|
||||||
|
internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunkList *lists, U64 lists_count, U64 *count_out);
|
||||||
|
|
||||||
|
// --- Symbol Helpers ----------------------------------------------------------
|
||||||
|
|
||||||
|
internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol);
|
||||||
|
internal B32 lnk_mark_symbol_live(LNK_Symbol *symbol);
|
||||||
|
internal LNK_SymbolDefined lnk_default_symbol_from_weak(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol);
|
||||||
|
|
||||||
// --- Symbol Table ------------------------------------------------------------
|
// --- Symbol Table ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -139,7 +145,7 @@ internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Sy
|
|||||||
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
|
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScope scope, String8 name);
|
||||||
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...);
|
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScope scope, char *fmt, ...);
|
||||||
|
|
||||||
internal void lnk_finalize_weak_symbols(TP_Arena *arena, TP_Context *tp, LNK_SymbolTable *symtab);
|
internal void lnk_replace_weak_symbols_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab);
|
||||||
|
|
||||||
// --- Symbol Contrib Helpers --------------------------------------------------
|
// --- Symbol Contrib Helpers --------------------------------------------------
|
||||||
|
|
||||||
@@ -149,5 +155,3 @@ internal U64 lnk_sect_off_from_symbol(LNK_Symbol *symbol);
|
|||||||
internal U64 lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
internal U64 lnk_virt_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
||||||
internal U64 lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
internal U64 lnk_file_off_from_symbol(COFF_SectionHeader **section_table, LNK_Symbol *symbol);
|
||||||
|
|
||||||
internal COFF_ParsedSymbol lnk_parsed_symbol_from_defined(LNK_Symbol *symbol);
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user