mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
improve unresolved symbol errors
- collect symbol references and print out objs that reference unresolved symbol - print source file location of the references
This commit is contained in:
committed by
Ryan Fleury
parent
d92f45784d
commit
a6432cce8e
@@ -1606,6 +1606,12 @@ cv_c13_collect_source_file_names(Arena *arena, CV_ChecksumList checksum_list, St
|
||||
|
||||
// $$Lines
|
||||
|
||||
internal void
|
||||
cv_c13_lines_header_list_concat_in_place(CV_C13LinesHeaderList *list, CV_C13LinesHeaderList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal CV_C13LinesHeaderList
|
||||
cv_c13_lines_from_sub_sections(Arena *arena, String8 c13_data, Rng1U64 ss_range)
|
||||
{
|
||||
@@ -1840,7 +1846,64 @@ cv_c13_make_lines_accel(Arena *arena, U64 lines_count, CV_LineArray *lines)
|
||||
return accel;
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal CV_LinesAccel *
|
||||
cv_lines_accel_from_debug_s(Arena *arena, CV_DebugS debug_s)
|
||||
{
|
||||
// parse $$LINES
|
||||
U64 c13_lines_count = 0;
|
||||
CV_LineArray *c13_lines = 0;
|
||||
{
|
||||
String8List raw_lines_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_Lines);
|
||||
|
||||
for (String8Node *raw_lines_node = raw_lines_list.first; raw_lines_node != 0; raw_lines_node = raw_lines_node->next) {
|
||||
Temp temp = temp_begin(arena);
|
||||
CV_C13LinesHeaderList parsed_list = cv_c13_lines_from_sub_sections(temp.arena, raw_lines_node->string, rng_1u64(0, raw_lines_node->string.size));
|
||||
c13_lines_count += parsed_list.count;
|
||||
temp_end(temp);
|
||||
}
|
||||
|
||||
c13_lines = push_array_no_zero(arena, CV_LineArray, c13_lines_count);
|
||||
|
||||
U64 c13_lines_idx = 0;
|
||||
for (String8Node *raw_lines_node = raw_lines_list.first; raw_lines_node != 0; raw_lines_node = raw_lines_node->next) {
|
||||
String8 raw_lines = raw_lines_node->string;
|
||||
CV_C13LinesHeaderList parsed_list = cv_c13_lines_from_sub_sections(arena, raw_lines, rng_1u64(0, raw_lines.size));
|
||||
|
||||
for(CV_C13LinesHeaderNode *header_node = parsed_list.first; header_node != 0; header_node = header_node->next) {
|
||||
c13_lines[c13_lines_idx++] = cv_c13_line_array_from_data(arena, raw_lines, 0, header_node->v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cv_c13_make_lines_accel(arena, c13_lines_count, c13_lines);
|
||||
}
|
||||
|
||||
internal U64
|
||||
cv_nearest_line(CV_Line *arr, U64 count, U64 value)
|
||||
{
|
||||
if(count > 1 && arr[0].voff <= value && value < arr[count-1].voff)
|
||||
{
|
||||
U64 l = 0;
|
||||
U64 r = count - 1;
|
||||
for (; l <= r; ) {
|
||||
U64 m = l + (r - l) / 2;
|
||||
if (arr[m].voff == value) {
|
||||
return m;
|
||||
} else if (arr[m].voff < value) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m - 1;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
else if (count == 1 && arr[0].voff == value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
internal CV_Line *
|
||||
cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count)
|
||||
{
|
||||
@@ -1849,7 +1912,7 @@ cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count)
|
||||
U64 voff_line_count = 0;
|
||||
CV_Line *lines = 0;
|
||||
|
||||
U64 map_idx = bsearch_nearest_u64(accel->map, accel->map_count, voff, sizeof(accel->map[0]), OffsetOf(CV_Line, voff));
|
||||
U64 map_idx = cv_nearest_line(accel->map, accel->map_count, voff);
|
||||
if(map_idx < accel->map_count) {
|
||||
U64 near_voff = accel->map[map_idx].voff;
|
||||
|
||||
@@ -1874,7 +1937,6 @@ cv_line_from_voff(CV_LinesAccel *accel, U64 voff, U64 *out_line_count)
|
||||
ProfEnd();
|
||||
return lines;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// $$InlineeLines Accel
|
||||
|
||||
@@ -455,7 +455,7 @@ internal String8List cv_c13_collect_source_file_names(Arena *arena, CV_ChecksumL
|
||||
|
||||
// $$Lines
|
||||
internal CV_C13LinesHeaderList cv_c13_lines_from_sub_sections(Arena *arena, String8 c13_data, Rng1U64 ss_range);
|
||||
internal CV_LineArray cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13LinesHeader parsed_lines);
|
||||
internal CV_LineArray cv_c13_line_array_from_data(Arena *arena, String8 c13_data, U64 sec_base, CV_C13LinesHeader parsed_lines);
|
||||
|
||||
// $$InlineeLines
|
||||
internal CV_C13InlineeLinesParsedList cv_c13_inlinee_lines_from_sub_sections(Arena *arena, String8List raw_inlinee_lines);
|
||||
|
||||
+158
-78
@@ -194,6 +194,11 @@ lnk_config_from_argcv(Arena *arena, int argc, char **argv)
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gfids");
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_RemoveSection, ".gxfg");
|
||||
|
||||
// set limits on unresolved symbol errors
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, "");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, "1000");
|
||||
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, "10");
|
||||
|
||||
// set default max worker count
|
||||
if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Rad_SharedThreadPool)) {
|
||||
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, "");
|
||||
@@ -1507,22 +1512,24 @@ lnk_link_inputs_(TP_Context *tp,
|
||||
LNK_Symbol *symbol = c->v[i].symbol;
|
||||
if (symbol->is_lib_member_linked) { continue; }
|
||||
|
||||
LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol);
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol);
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
|
||||
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
U32 member_idx;
|
||||
if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) {
|
||||
lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx);
|
||||
}
|
||||
} else if (symbol_interp == COFF_SymbolValueInterp_Weak) {
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol->ref.obj->header.is_big_obj);
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol_parsed, symbol_ref.obj->header.is_big_obj);
|
||||
if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) {
|
||||
U32 member_idx;
|
||||
if (lnk_search_lib(&lib_n->data, symbol->name, &member_idx)) {
|
||||
lnk_queue_lib_member(arena->v[0], &queued_members, symbol, &lib_n->data, member_idx);
|
||||
}
|
||||
} else if (search_anti_deps && weak_ext->characteristics == COFF_WeakExt_AntiDependency) {
|
||||
LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol->ref);
|
||||
LNK_ObjSymbolRef dep_symbol = lnk_resolve_weak_symbol(symtab, symbol_ref);
|
||||
COFF_ParsedSymbol dep_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dep_symbol.obj, dep_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType dep_interp = coff_interp_from_parsed_symbol(dep_parsed);
|
||||
if (dep_interp == COFF_SymbolValueInterp_Weak) {
|
||||
@@ -1569,8 +1576,9 @@ lnk_link_inputs_(TP_Context *tp,
|
||||
hash_table_push_string_raw(imps->arena, imps->import_stub_ht, import_header.func_name, 0);
|
||||
|
||||
// create import stub (later replaced with acutal import generated by linker)
|
||||
LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB));
|
||||
LNK_Symbol *import_symbol = lnk_make_obj_ref_symbol(symtab->arena->v[0], link_symbol->name, import_stub->ref.obj, import_stub->ref.symbol_idx);
|
||||
LNK_Symbol *import_stub = lnk_symbol_table_search(symtab, str8_lit(LNK_IMPORT_STUB));
|
||||
LNK_ObjSymbolRef import_symbol_ref = lnk_get_obj_symbol_ref(import_stub);
|
||||
LNK_Symbol *import_symbol = lnk_make_obj_ref_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
|
||||
@@ -1936,45 +1944,116 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
//
|
||||
{
|
||||
ProfBegin("Report Unresolved Symbols");
|
||||
U64 chunks_count = 0;
|
||||
LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count);
|
||||
|
||||
U64 count = 0;
|
||||
for EachIndex(chunk_idx, chunks_count) {
|
||||
LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx];
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol);
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
count += 1;
|
||||
U64 unresolved_symbols_count = 0;
|
||||
LNK_Symbol **unresolved_symbols = 0;
|
||||
{
|
||||
U64 chunks_count = 0;
|
||||
LNK_SymbolHashTrieChunk **chunks = lnk_array_from_symbol_hash_trie_chunk_list(scratch.arena, symtab->chunks, symtab->arena->count, &chunks_count);
|
||||
|
||||
for EachIndex(chunk_idx, chunks_count) {
|
||||
LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx];
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol);
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
unresolved_symbols_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U64 cursor = 0;
|
||||
LNK_Symbol **unresolved = push_array(scratch.arena, LNK_Symbol *, count);
|
||||
for EachIndex(chunk_idx, chunks_count) {
|
||||
LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx];
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
COFF_SymbolValueInterpType symbol_interp = lnk_interp_symbol(symbol);
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
unresolved[cursor++] = chunk->v[i].symbol;
|
||||
unresolved_symbols = push_array(scratch.arena, LNK_Symbol *, unresolved_symbols_count);
|
||||
if (unresolved_symbols_count) {
|
||||
U64 cursor = 0;
|
||||
for EachIndex(chunk_idx, chunks_count) {
|
||||
LNK_SymbolHashTrieChunk *chunk = chunks[chunk_idx];
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
if (lnk_interp_symbol(symbol) == COFF_SymbolValueInterp_Undefined) {
|
||||
unresolved_symbols[cursor++] = chunk->v[i].symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radsort(unresolved_symbols, unresolved_symbols_count, lnk_symbol_ptr_is_before);
|
||||
}
|
||||
|
||||
radsort(unresolved, count, lnk_symbol_ptr_is_before);
|
||||
for EachIndex(i, unresolved_symbols_count) {
|
||||
LNK_Symbol *symbol = unresolved_symbols[i];
|
||||
|
||||
for EachIndex(i, count) {
|
||||
LNK_Symbol *symbol = unresolved[i];
|
||||
lnk_error_obj(LNK_Error_UnresolvedSymbol, symbol->ref.obj, "unresolved symbol %S", symbol->name);
|
||||
if (i > config->unresolved_symbol_limit) {
|
||||
lnk_error(LNK_Error_UnresolvedSymbol, "too many unresolved symbol errors, stopping now");
|
||||
break;
|
||||
}
|
||||
|
||||
String8List supp_info = {0};
|
||||
{
|
||||
U64 refs_count = 0;
|
||||
LNK_ObjSymbolRef **refs = lnk_get_obj_symbol_ref_many(scratch.arena, symbol, &refs_count);
|
||||
for EachIndex(ref_idx, refs_count) {
|
||||
LNK_ObjSymbolRef *ref = refs[ref_idx];
|
||||
LNK_Obj *obj = ref->obj;
|
||||
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
|
||||
String8 string_table = lnk_coff_string_table_from_obj(obj);
|
||||
|
||||
CV_DebugS debug_s = {0};
|
||||
CV_LinesAccel *debug_lines = 0;
|
||||
String8 debug_checksums = {0};
|
||||
String8 debug_strings = {0};
|
||||
|
||||
for EachIndex(sect_idx, obj->header.section_count_no_null) {
|
||||
COFF_SectionHeader *section_header = §ion_table[sect_idx];
|
||||
String8 section_name = coff_name_from_section_header(string_table, section_header);
|
||||
U64 section_number = sect_idx+1;
|
||||
COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header);
|
||||
for EachIndex(reloc_idx, relocs.count) {
|
||||
if (supp_info.node_count > config->unresolved_symbol_ref_limit) {
|
||||
str8_list_pushf(scratch.arena, &supp_info, "too many unresolved symbol references reported, stopping now");
|
||||
break;
|
||||
}
|
||||
COFF_Reloc *reloc = &relocs.v[reloc_idx];
|
||||
if (reloc->isymbol == ref->symbol_idx) {
|
||||
U64 line_matches_count = 0;
|
||||
CV_Line *line_matches = 0;
|
||||
if (config->map_lines_for_unresolved_symbols == LNK_SwitchState_Yes) {
|
||||
if (debug_lines == 0) {
|
||||
debug_s = lnk_debug_s_from_obj(scratch.arena, obj);
|
||||
debug_lines = cv_lines_accel_from_debug_s(scratch.arena, debug_s);
|
||||
debug_checksums = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms).first->string;
|
||||
debug_strings = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable).first->string;
|
||||
}
|
||||
line_matches_count = 0;
|
||||
line_matches = cv_line_from_voff(debug_lines, reloc->apply_off, &line_matches_count);
|
||||
}
|
||||
|
||||
if (line_matches) {
|
||||
for EachIndex(i, line_matches_count) {
|
||||
CV_Line line = line_matches[i];
|
||||
CV_C13Checksum checksum = {0};
|
||||
String8 file_name = {0};
|
||||
str8_deserial_read_struct(debug_checksums, line.file_off, &checksum);
|
||||
str8_deserial_read_cstr(debug_strings, checksum.name_off, &file_name);
|
||||
str8_list_pushf(scratch.arena, &supp_info, "%S: %S:%u", lnk_loc_from_obj(scratch.arena, obj), file_name, line.line_num);
|
||||
}
|
||||
} else {
|
||||
str8_list_pushf(scratch.arena, &supp_info, "%S: %S(%llx)+%x", lnk_loc_from_obj(scratch.arena, obj), section_name, section_number, reloc->apply_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lnk_error(LNK_Error_UnresolvedSymbol, "unresolved symbol %S", symbol->name);
|
||||
lnk_supplement_error_list(supp_info);
|
||||
}
|
||||
|
||||
// TODO: /FORCE
|
||||
if (count) {
|
||||
if (unresolved_symbols_count) {
|
||||
lnk_exit(LNK_Error_UnresolvedSymbol);
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
@@ -2054,13 +2133,14 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj
|
||||
|
||||
// push tasks for each root symbol
|
||||
for (LNK_IncludeSymbolNode *root_n = config->include_symbol_list.first; root_n != 0; root_n = root_n->next) {
|
||||
LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name);
|
||||
LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name);
|
||||
LNK_ObjSymbolRef root_ref = lnk_get_obj_symbol_ref(root);
|
||||
|
||||
struct Task *t = push_array(scratch.arena, struct Task, 1);
|
||||
t->obj = root->ref.obj;
|
||||
t->obj = root_ref.obj;
|
||||
t->relocs.count = 1;
|
||||
t->relocs.v = push_array(scratch.arena, COFF_Reloc, 1);
|
||||
t->relocs.v[0].isymbol = root->ref.symbol_idx;
|
||||
t->relocs.v[0].isymbol = root_ref.symbol_idx;
|
||||
|
||||
SLLStackPush(task_stack, t);
|
||||
}
|
||||
@@ -2113,20 +2193,20 @@ lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj
|
||||
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 = symlink->ref;
|
||||
ref_symbol = lnk_get_obj_symbol_ref(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 = defn->ref;
|
||||
next_ref = lnk_get_obj_symbol_ref(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 = defn->ref;
|
||||
next_ref = lnk_get_obj_symbol_ref(defn);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -2227,14 +2307,14 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb
|
||||
switch (symbol_interp) {
|
||||
case COFF_SymbolValueInterp_Regular: {
|
||||
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(symbol.obj, symbol_parsed.section_number);
|
||||
*symbol_out = symlink ? symlink->ref : symbol;
|
||||
*symbol_out = symlink ? lnk_get_obj_symbol_ref(symlink) : symbol;
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Weak: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx);
|
||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn);
|
||||
COFF_SymbolValueInterpType defn_interp = lnk_interp_symbol(defn);
|
||||
if (defn_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
*symbol_out = defn->ref;
|
||||
*symbol_out = lnk_get_obj_symbol_ref(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
@@ -2242,19 +2322,19 @@ lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol, LNK_ObjSymb
|
||||
case COFF_SymbolValueInterp_Undefined: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
if (defn) {
|
||||
*symbol_out = defn->ref;
|
||||
*symbol_out = lnk_get_obj_symbol_ref(defn);
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, symbol_parsed.name);
|
||||
*symbol_out = defn->ref;
|
||||
*symbol_out = lnk_get_obj_symbol_ref(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 = defn->ref;
|
||||
*symbol_out = lnk_get_obj_symbol_ref(defn);
|
||||
} else {
|
||||
*symbol_out = symbol;
|
||||
}
|
||||
@@ -2379,7 +2459,8 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task)
|
||||
if (symlink == 0) { continue; }
|
||||
|
||||
COFF_ParsedSymbol symlink_parsed = lnk_parse_symbol(symlink);
|
||||
task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink->ref.obj->input_idx][symlink_parsed.section_number - 1];
|
||||
LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink);
|
||||
task->sect_map[obj_idx][sect_idx] = task->sect_map[symlink_ref.obj->input_idx][symlink_parsed.section_number - 1];
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -2422,29 +2503,32 @@ THREAD_POOL_TASK_FUNC(lnk_patch_comdat_leaders_task)
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
if (interp == COFF_SymbolValueInterp_Regular) {
|
||||
LNK_Symbol *symlink = lnk_obj_get_comdat_symlink(obj, symbol.section_number);
|
||||
if (symlink && symlink->ref.obj != obj) {
|
||||
U32 section_number;
|
||||
U32 value;
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
// COMDAT leader may be at a different offset, so update this symbol with leader's offset
|
||||
COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink);
|
||||
section_number = symbol.section_number;
|
||||
value = parsed_symlink.value;
|
||||
} else {
|
||||
// COMDAT section may have static symbols which are now invalid to relocate against
|
||||
section_number = LNK_REMOVED_SECTION_NUMBER_32;
|
||||
value = max_U32;
|
||||
task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1;
|
||||
}
|
||||
if (symlink) {
|
||||
LNK_ObjSymbolRef symlink_ref = lnk_get_obj_symbol_ref(symlink);
|
||||
if (symlink_ref.obj != obj) {
|
||||
U32 section_number;
|
||||
U32 value;
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
// COMDAT leader may be at a different offset, so update this symbol with leader's offset
|
||||
COFF_ParsedSymbol parsed_symlink = lnk_parse_symbol(symlink);
|
||||
section_number = symbol.section_number;
|
||||
value = parsed_symlink.value;
|
||||
} else {
|
||||
// COMDAT section may have static symbols which are now invalid to relocate against
|
||||
section_number = LNK_REMOVED_SECTION_NUMBER_32;
|
||||
value = max_U32;
|
||||
task->u.patch_symtabs.was_symbol_patched[obj_idx][symbol_idx] = 1;
|
||||
}
|
||||
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
symbol32->section_number = section_number;
|
||||
symbol32->value = value;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
|
||||
symbol16->section_number = (U16)section_number;
|
||||
symbol16->value = value;
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
symbol32->section_number = section_number;
|
||||
symbol32->value = value;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
|
||||
symbol16->section_number = (U16)section_number;
|
||||
symbol16->value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2504,11 +2588,11 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task)
|
||||
for (U64 contrib_idx = contrib_range.min; contrib_idx < contrib_range.max; contrib_idx += 1) {
|
||||
LNK_CommonBlockContrib *contrib = &task->u.patch_symtabs.common_block_contribs[contrib_idx];
|
||||
LNK_Symbol *symbol = contrib->symbol;
|
||||
LNK_Obj *obj = symbol->ref.obj;
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol->ref.symbol_idx);
|
||||
LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol);
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol);
|
||||
U64 section_number = task->u.patch_symtabs.common_block_sect->sect_idx + 1;
|
||||
|
||||
if (obj->header.is_big_obj) {
|
||||
if (symbol_ref.obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = parsed_symbol.raw_symbol;
|
||||
symbol32->value = contrib->u.offset;
|
||||
symbol32->section_number = safe_cast_u32(section_number);
|
||||
@@ -2518,7 +2602,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task)
|
||||
symbol16->section_number = safe_cast_u16(section_number);
|
||||
}
|
||||
|
||||
task->u.patch_symtabs.was_symbol_patched[obj->input_idx][symbol->ref.symbol_idx] = 1;
|
||||
task->u.patch_symtabs.was_symbol_patched[symbol_ref.obj->input_idx][symbol_ref.symbol_idx] = 1;
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
@@ -2536,11 +2620,10 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_symbols_task)
|
||||
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) {
|
||||
symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx);
|
||||
COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
|
||||
if (interp == COFF_SymbolValueInterp_Common) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, symbol.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->ref.obj, defn->ref.symbol_idx);
|
||||
Assert(coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class) == COFF_SymbolValueInterp_Regular);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn);
|
||||
Assert(lnk_interp_symbol(defn) == COFF_SymbolValueInterp_Regular);
|
||||
if (defn) {
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
@@ -2720,13 +2803,10 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher)
|
||||
Rng1U64 section_frange = rng_1u64(section_header->foff, section_header->foff + section_header->fsize);
|
||||
String8 section_data = str8_substr(data, section_frange);
|
||||
|
||||
// find section relocs
|
||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header);
|
||||
COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off);
|
||||
|
||||
// apply relocs
|
||||
for EachIndex(reloc_idx, reloc_info.count) {
|
||||
COFF_Reloc *reloc = &relocs[reloc_idx];
|
||||
COFF_RelocArray relocs = lnk_coff_relocs_from_section_header(obj, section_header);
|
||||
for EachIndex(reloc_idx, relocs.count) {
|
||||
COFF_Reloc *reloc = &relocs.v[reloc_idx];
|
||||
|
||||
// error check relocation
|
||||
if (obj->header.machine == COFF_MachineType_X64) {
|
||||
|
||||
+47
-32
@@ -121,38 +121,41 @@ global read_only LNK_CmdSwitch g_cmd_switch_map[] =
|
||||
{ LNK_CmdSwitch_NotImplemented, 0, "WX", "", "" },
|
||||
|
||||
//- internal switches
|
||||
{ LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
|
||||
{ LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." },
|
||||
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." },
|
||||
{ LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." },
|
||||
{ LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" },
|
||||
{ LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
|
||||
{ LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
|
||||
{ LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
|
||||
{ LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME },
|
||||
{ LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
|
||||
{ LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
|
||||
{ LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." },
|
||||
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
|
||||
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." },
|
||||
{ LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" },
|
||||
{ LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
|
||||
{ LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." },
|
||||
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
|
||||
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
|
||||
{ LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." },
|
||||
{ LNK_CmdSwitch_Rad_Age, 0, "RAD_AGE", ":#", "Age embeded in EXE and PDB, used to validate incremental build. Default is 1." },
|
||||
{ LNK_CmdSwitch_Rad_BuildInfo, 0, "RAD_BUILD_INFO", "", "Print build info and exit." },
|
||||
{ LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, 0, "RAD_CHECK_UNUSED_DELAY_LOAD_DLL", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Map, 0, "RAD_MAP", ":FILENAME", "Emit file with the output image's layout description." },
|
||||
{ LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols, 0, "RAD_MAP_LINES_FOR_UNRESOLVED_SYMBOLS", "[:NO]", "Use debug info to print source file location for unresolved symbol" },
|
||||
{ LNK_CmdSwitch_Rad_MemoryMapFiles, 0, "RAD_MEMORY_MAP_FILES", "[:NO]", "When enabled, files are memory-mapped instead of being read entirely on request." },
|
||||
{ LNK_CmdSwitch_Rad_Debug, 0, "RAD_DEBUG", "[:NO]", "Emit RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DebugAltPath, 0, "RAD_DEBUGALTPATH", "", "" },
|
||||
{ LNK_CmdSwitch_Rad_DebugName, 0, "RAD_DEBUG_NAME", ":FILENAME", "Sets file name for RAD debug info file." },
|
||||
{ LNK_CmdSwitch_Rad_DelayBind, 0, "RAD_DELAY_BIND", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_DoMerge, 0, "RAD_DO_MERGE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_EnvLib, 0, "RAD_ENV_LIB", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Exe, 0, "RAD_EXE", "[:NO]", "" },
|
||||
{ LNK_CmdSwitch_Rad_Guid, 0, "RAD_GUID", ":{IMAGEBLAKE3|XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}", "" },
|
||||
{ LNK_CmdSwitch_Rad_LargePages, 0, "RAD_LARGE_PAGES", "[:NO]", "Disabled by default on Windows." },
|
||||
{ LNK_CmdSwitch_Rad_LinkVer, 0, "RAD_LINK_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_Log, 0, "RAD_LOG", ":{ALL,INPUT_OBJ,INPUT_LIB,IO,LINK_STATS,TIMERS}", "" },
|
||||
{ LNK_CmdSwitch_Rad_MtPath, 0, "RAD_MT_PATH", ":EXEPATH", "Exe path to manifest tool, default: " LNK_MANIFEST_MERGE_TOOL_NAME },
|
||||
{ LNK_CmdSwitch_Rad_OsVer, 0, "RAD_OS_VER", ":##,##", "" },
|
||||
{ LNK_CmdSwitch_Rad_PageSize, 0, "RAD_PAGE_SIZE", ":#", "Must be power of two." },
|
||||
{ LNK_CmdSwitch_Rad_PathStyle, 0, "RAD_PATH_STYLE", ":{WindowsAbsolute|UnixAbsolute}", "" },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameLength, 0, "RAD_PDB_HASH_TYPE_NAME_LENGTH", ":#", "Number of hash bytes to use to replace type name. Default 8 bytes (Max 16)." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, 0, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
|
||||
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, 0, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
|
||||
{ LNK_CmdSwitch_Rad_RemoveSection, 0, "RAD_REMOVE_SECTION", ":NAME", "Removes a section from output image." },
|
||||
{ LNK_CmdSwitch_Rad_SharedThreadPool, 0, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" },
|
||||
{ LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, 0, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." },
|
||||
{ LNK_CmdSwitch_Rad_SuppressError, 0, "RAD_SUPPRESS_ERROR", ":#", "" },
|
||||
{ LNK_CmdSwitch_Rad_TargetOs, 0, "RAD_TARGET_OS", ":{WINDOWS,LINUX,MAC}" },
|
||||
{ LNK_CmdSwitch_Rad_WriteTempFiles, 0, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." },
|
||||
{ LNK_CmdSwitch_Rad_TimeStamp, 0, "RAD_TIME_STAMP", ":#", "Time stamp embeded in EXE and PDB." },
|
||||
{ LNK_CmdSwitch_Rad_UnresolvedSymbolLimit, 0, "RAD_UNRESOLVED_SYMBOL_LIMIT", ":#", "Limits number of unresolved symbol errors linker reports." },
|
||||
{ LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit, 0, "RAD_UNRESOLVED_SYMBOL_REF_LIMIT", ":#", "Limit number of unresolved symbol references linker reports." },
|
||||
{ LNK_CmdSwitch_Rad_Version, 0, "RAD_VERSION", "", "Print version and exit." },
|
||||
{ LNK_CmdSwitch_Rad_Workers, 0, "RAD_WORKERS", ":#", "Sets number of workers created in the pool. Number is capped at 1024. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." },
|
||||
|
||||
{ LNK_CmdSwitch_Help, 0, "HELP", "", "" },
|
||||
{ LNK_CmdSwitch_Help, 0, "?", "", "" },
|
||||
@@ -1776,6 +1779,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
|
||||
config->rad_chunk_map = LNK_SwitchState_Yes;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols: {
|
||||
lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->map_lines_for_unresolved_symbols);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_MemoryMapFiles: {
|
||||
lnk_cmd_switch_set_flag_32(obj, cmd_switch, value_strings, &config->io_flags, LNK_IO_Flags_MemoryMapFiles);
|
||||
} break;
|
||||
@@ -2005,6 +2012,14 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
|
||||
lnk_cmd_switch_parse_u32(obj, cmd_switch, value_strings, &config->time_stamp, 0);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_UnresolvedSymbolLimit: {
|
||||
lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->unresolved_symbol_limit, 0);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit: {
|
||||
lnk_cmd_switch_parse_u64(obj, cmd_switch, value_strings, &config->unresolved_symbol_ref_limit, 0);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Rad_Version: {
|
||||
fprintf(stdout, "%s\n", BUILD_TITLE_STRING_LITERAL);
|
||||
os_abort(0);
|
||||
|
||||
@@ -164,6 +164,7 @@ typedef enum
|
||||
LNK_CmdSwitch_Rad_Log,
|
||||
LNK_CmdSwitch_Rad_Logo,
|
||||
LNK_CmdSwitch_Rad_Map,
|
||||
LNK_CmdSwitch_Rad_MapLinesForUnresolvedSymbols,
|
||||
LNK_CmdSwitch_Rad_MemoryMapFiles,
|
||||
LNK_CmdSwitch_Rad_MtPath,
|
||||
LNK_CmdSwitch_Rad_OsVer,
|
||||
@@ -178,6 +179,8 @@ typedef enum
|
||||
LNK_CmdSwitch_Rad_SuppressError,
|
||||
LNK_CmdSwitch_Rad_TargetOs,
|
||||
LNK_CmdSwitch_Rad_TimeStamp,
|
||||
LNK_CmdSwitch_Rad_UnresolvedSymbolLimit,
|
||||
LNK_CmdSwitch_Rad_UnresolvedSymbolRefLimit,
|
||||
LNK_CmdSwitch_Rad_Version,
|
||||
LNK_CmdSwitch_Rad_Workers,
|
||||
LNK_CmdSwitch_Rad_WriteTempFiles,
|
||||
@@ -409,6 +412,9 @@ typedef struct LNK_Config
|
||||
HashTable *include_symbol_ht;
|
||||
HashTable *delay_load_ht;
|
||||
HashTable *disallow_lib_ht;
|
||||
U64 unresolved_symbol_limit;
|
||||
U64 unresolved_symbol_ref_limit;
|
||||
LNK_SwitchState map_lines_for_unresolved_symbols;
|
||||
} LNK_Config;
|
||||
|
||||
// --- MSVC Error Codes --------------------------------------------------------
|
||||
|
||||
@@ -72,4 +72,3 @@ lnk_make_dll_import_debug_symbols(Arena *arena, COFF_MachineType machine, String
|
||||
return debug_symbols;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3021,9 +3021,10 @@ THREAD_POOL_TASK_FUNC(lnk_build_pdb_public_symbols_defined_task)
|
||||
U64 node_idx = 0;
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol);
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol);
|
||||
|
||||
if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol->ref.obj)) { continue; }
|
||||
if (symbol_parsed.section_number == lnk_obj_get_removed_section_number(symbol_ref.obj)) { continue; }
|
||||
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
|
||||
if (symbol_interp != COFF_SymbolValueInterp_Regular) { continue; }
|
||||
|
||||
@@ -37,7 +37,6 @@ typedef enum
|
||||
LNK_Error_IllegalSectionMerge,
|
||||
LNK_Error_IllegalRelocation,
|
||||
LNK_Error_CircularMerge,
|
||||
LNK_Error_UnresolvedSymbol,
|
||||
LNK_Error_AssociativeLoop,
|
||||
LNK_Error_AlternateNameConflict,
|
||||
LNK_Error_RelocationAgainstRemovedSection,
|
||||
@@ -55,6 +54,7 @@ typedef enum
|
||||
LNK_Error_UndefinedIsWeak,
|
||||
LNK_Error_WeakCycle,
|
||||
LNK_Error_InvalidLib,
|
||||
LNK_Error_UnresolvedSymbol,
|
||||
LNK_Error_Last,
|
||||
|
||||
LNK_Warning_First,
|
||||
|
||||
+74
-1
@@ -1,11 +1,25 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8
|
||||
lnk_loc_from_obj(Arena *arena, LNK_Obj *obj)
|
||||
{
|
||||
String8 obj_path = str8_skip_last_slash(obj ? obj->path : str8_lit("RADLINK"));
|
||||
String8 lib_path = str8_skip_last_slash(lnk_obj_get_lib_path(obj));
|
||||
String8 result;
|
||||
if (lib_path.size) {
|
||||
result = push_str8f(arena, "%S(%S)", lib_path, obj_path);
|
||||
} else {
|
||||
result = push_str8_copy(arena, obj_path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...)
|
||||
{
|
||||
va_list args; va_start(args, fmt);
|
||||
String8 obj_path = obj ? obj->path : str8_lit("RADLINK");
|
||||
String8 obj_path = obj ? obj->path : str8_zero();
|
||||
String8 lib_path = lnk_obj_get_lib_path(obj);
|
||||
lnk_error_with_loc_fv(code, obj_path, lib_path, fmt, args);
|
||||
va_end(args);
|
||||
@@ -494,12 +508,27 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
|
||||
return section_header;
|
||||
}
|
||||
|
||||
internal COFF_RelocArray
|
||||
lnk_coff_relocs_from_section_header(LNK_Obj *obj, COFF_SectionHeader *section_header)
|
||||
{
|
||||
COFF_RelocInfo reloc_info = coff_reloc_info_from_section_header(obj->data, section_header);
|
||||
COFF_Reloc *relocs = (COFF_Reloc *)(obj->data.str + reloc_info.array_off);
|
||||
COFF_RelocArray result = { .count = reloc_info.count, .v = relocs };
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_SectionHeader *
|
||||
lnk_coff_section_table_from_obj(LNK_Obj *obj)
|
||||
{
|
||||
return (COFF_SectionHeader *)str8_substr(obj->data, obj->header.section_table_range).str;
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_coff_string_table_from_obj(LNK_Obj *obj)
|
||||
{
|
||||
return str8_substr(obj->data, obj->header.string_table_range);
|
||||
}
|
||||
|
||||
internal COFF_RelocArray
|
||||
lnk_coff_reloc_info_from_section_number(LNK_Obj *obj, U64 section_number)
|
||||
{
|
||||
@@ -684,3 +713,47 @@ lnk_directive_info_from_raw_directives(Arena *arena, LNK_Obj *obj, String8List r
|
||||
return directive_info;
|
||||
}
|
||||
|
||||
internal CV_DebugS
|
||||
lnk_debug_s_from_obj(Arena *arena, LNK_Obj *obj)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List raw_debug_s = {0};
|
||||
{
|
||||
COFF_SectionHeader *section_table = lnk_coff_section_table_from_obj(obj);
|
||||
String8 string_table = lnk_coff_string_table_from_obj(obj);
|
||||
for EachIndex(sect_idx, obj->header.section_count_no_null) {
|
||||
COFF_SectionHeader *section_header = §ion_table[sect_idx];
|
||||
String8 section_name = coff_name_from_section_header(string_table, section_header);
|
||||
if (str8_match(section_name, str8_lit(".debug$S"), 0)) {
|
||||
String8 debug_s = str8_substr(obj->data, rng_1u64(section_header->foff, section_header->foff + section_header->fsize));
|
||||
str8_list_push(scratch.arena, &raw_debug_s, debug_s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CV_DebugS debug_s = {0};
|
||||
{
|
||||
for (String8Node *node = raw_debug_s.first; node != 0; node = node->next) {
|
||||
// parse & merge sub sections
|
||||
CV_DebugS ds = cv_parse_debug_s(scratch.arena, node->string);
|
||||
cv_debug_s_concat_in_place(&debug_s, &ds);
|
||||
|
||||
// make sure there is one string table
|
||||
String8List string_data_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_StringTable);
|
||||
if (string_data_list.node_count > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// make sure there is one file checksum table
|
||||
String8List checksum_data_list = cv_sub_section_from_debug_s(debug_s, CV_C13SubSectionKind_FileChksms);
|
||||
if (checksum_data_list.node_count > 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return debug_s;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ typedef struct
|
||||
|
||||
// --- Error -------------------------------------------------------------------
|
||||
|
||||
internal String8 lnk_loc_from_obj(Arena *arena, LNK_Obj *obj);
|
||||
internal void lnk_error_obj(LNK_ErrorCode code, LNK_Obj *obj, char *fmt, ...);
|
||||
internal void lnk_error_input_obj(LNK_ErrorCode code, struct LNK_Input *input, char *fmt, ...);
|
||||
|
||||
@@ -115,7 +116,9 @@ internal LNK_Symbol * lnk_obj_get_comdat_symlink(LNK_Obj *obj, U64 section_n
|
||||
internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff(LNK_Obj *obj, void *coff_symbol);
|
||||
internal COFF_ParsedSymbol lnk_parsed_symbol_from_coff_symbol_idx(LNK_Obj *obj, U64 symbol_idx);
|
||||
internal COFF_SectionHeader * lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number);
|
||||
internal COFF_RelocArray lnk_coff_relocs_from_section_header(LNK_Obj *obj, COFF_SectionHeader *section_header);
|
||||
internal COFF_SectionHeader * lnk_coff_section_table_from_obj(LNK_Obj *obj);
|
||||
internal String8 lnk_coff_string_table_from_obj(LNK_Obj *obj);
|
||||
internal B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_number_out, U32 *section_length_out, U32 *check_sum_out);
|
||||
internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx);
|
||||
|
||||
@@ -130,3 +133,7 @@ internal void lnk_parse_msvc_linker_directive(Arena *arena, LNK_Obj
|
||||
internal String8List lnk_raw_directives_from_obj(Arena *arena, LNK_Obj *obj);
|
||||
internal LNK_DirectiveInfo lnk_directive_info_from_raw_directives(Arena *arena, LNK_Obj *obj, String8List raw_directives);
|
||||
|
||||
// --- Debug Info --------------------------------------------------------------
|
||||
|
||||
internal CV_DebugS lnk_debug_s_from_obj(Arena *arena, LNK_Obj *obj);
|
||||
|
||||
|
||||
+112
-44
@@ -4,30 +4,51 @@
|
||||
internal LNK_Symbol *
|
||||
lnk_make_obj_ref_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx)
|
||||
{
|
||||
LNK_ObjSymbolRefNode *ref = push_array(arena, LNK_ObjSymbolRefNode, 1);
|
||||
ref->v.obj = obj;
|
||||
ref->v.symbol_idx = symbol_idx;
|
||||
|
||||
LNK_Symbol *symbol = push_array(arena, LNK_Symbol, 1);
|
||||
symbol->name = name;
|
||||
symbol->ref.obj = obj;
|
||||
symbol->ref.symbol_idx = symbol_idx;
|
||||
symbol->refs = ref;
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_obj_symbol_ref_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_ObjSymbolRef *a_ref = raw_a;
|
||||
LNK_ObjSymbolRef *b_ref = raw_b;
|
||||
LNK_Lib *a_lib = lnk_obj_get_lib(a_ref->obj);
|
||||
LNK_Lib *b_lib = lnk_obj_get_lib(b_ref->obj);
|
||||
U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0;
|
||||
U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0;
|
||||
|
||||
if (a_lib_input_idx == b_lib_input_idx) {
|
||||
if (a_ref->obj->input_idx == b_ref->obj->input_idx) {
|
||||
return a_ref->symbol_idx < b_ref->symbol_idx;
|
||||
}
|
||||
return a_ref->obj->input_idx < b_ref->obj->input_idx;
|
||||
}
|
||||
|
||||
return a_lib_input_idx < b_lib_input_idx;
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_obj_symbol_ref_ptr_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_ObjSymbolRef **a = raw_a, **b = raw_b;
|
||||
return lnk_obj_symbol_ref_is_before(*a, *b);
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_symbol_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_Symbol *a = raw_a, *b = raw_b;
|
||||
|
||||
LNK_Lib *a_lib = lnk_obj_get_lib(a->ref.obj);
|
||||
LNK_Lib *b_lib = lnk_obj_get_lib(b->ref.obj);
|
||||
U32 a_lib_input_idx = a_lib ? a_lib->input_idx : 0;
|
||||
U32 b_lib_input_idx = b_lib ? b_lib->input_idx : 0;
|
||||
|
||||
if (a_lib_input_idx == b_lib_input_idx) {
|
||||
if (a->ref.obj->input_idx == b->ref.obj->input_idx) {
|
||||
return a->ref.symbol_idx < b->ref.symbol_idx;
|
||||
}
|
||||
return a->ref.obj->input_idx < b->ref.obj->input_idx;
|
||||
}
|
||||
return a_lib_input_idx < b_lib_input_idx;
|
||||
LNK_ObjSymbolRef a_ref = lnk_get_obj_symbol_ref(a);
|
||||
LNK_ObjSymbolRef b_ref = lnk_get_obj_symbol_ref(b);
|
||||
return lnk_obj_symbol_ref_is_before(&a_ref, &b_ref);
|
||||
}
|
||||
|
||||
internal B32
|
||||
@@ -120,7 +141,9 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList *
|
||||
internal void
|
||||
lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
{
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst->ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst->ref.symbol_idx, src->ref.obj->path, src->ref.symbol_idx);
|
||||
LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst);
|
||||
LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src);
|
||||
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, dst_ref.obj, "symbol \"%S\" (No. %#x) is multiply defined in %S (No. %#x)", dst->name, dst_ref.symbol_idx, src_ref.obj->path, src_ref.symbol_idx);
|
||||
}
|
||||
|
||||
internal B32
|
||||
@@ -128,12 +151,14 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
{
|
||||
B32 can_replace = 0;
|
||||
|
||||
LNK_Obj *dst_obj = dst->ref.obj;
|
||||
LNK_Obj *src_obj = src->ref.obj;
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx);
|
||||
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
|
||||
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src);
|
||||
COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst);
|
||||
COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src);
|
||||
LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst);
|
||||
LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src);
|
||||
LNK_Obj *dst_obj = dst_ref.obj;
|
||||
LNK_Obj *src_obj = src_ref.obj;
|
||||
|
||||
// undefined vs regular
|
||||
if (dst_interp == COFF_SymbolValueInterp_Undefined && src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
@@ -151,7 +176,8 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
weak_parsed = src_parsed;
|
||||
}
|
||||
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->ref.obj->header.is_big_obj);
|
||||
LNK_ObjSymbolRef weak_symbol_ref = lnk_get_obj_symbol_ref(weak);
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak_symbol_ref.obj->header.is_big_obj);
|
||||
if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) {
|
||||
// NOTE: MSVC does not let a weak symbol to replace an undefined one,
|
||||
// but LLD links without errors or warnings, meaning undefined symbols
|
||||
@@ -214,8 +240,8 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
}
|
||||
// weak vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->ref.obj->header.is_big_obj);
|
||||
COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->ref.obj->header.is_big_obj);
|
||||
COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst_ref.obj->header.is_big_obj);
|
||||
COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src_ref.obj->header.is_big_obj);
|
||||
if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) {
|
||||
if (lnk_symbol_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) {
|
||||
can_replace = 0;
|
||||
@@ -250,7 +276,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
U32 dst_section_length;
|
||||
U32 dst_check_sum;
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular) {
|
||||
dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->ref.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum);
|
||||
dst_is_comdat = lnk_try_comdat_props_from_section_number(dst_ref.obj, dst_parsed.section_number, &dst_select, 0, &dst_section_length, &dst_check_sum);
|
||||
} else if (dst_interp == COFF_SymbolValueInterp_Common) {
|
||||
dst_select = COFF_ComdatSelect_Largest;
|
||||
dst_section_length = dst_parsed.value;
|
||||
@@ -264,7 +290,7 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
U32 src_section_length, src_checks;
|
||||
U32 src_check_sum;
|
||||
if (src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
src_is_comdat = lnk_try_comdat_props_from_section_number(src->ref.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum);
|
||||
src_is_comdat = lnk_try_comdat_props_from_section_number(src_ref.obj, src_parsed.section_number, &src_select, 0, &src_section_length, &src_check_sum);
|
||||
} else if (src_interp == COFF_SymbolValueInterp_Common) {
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
src_section_length = src_parsed.value;
|
||||
@@ -356,29 +382,38 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
internal void
|
||||
lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
{
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->ref.obj, dst->ref.symbol_idx);
|
||||
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parse_symbol(dst);
|
||||
COFF_SymbolValueInterpType dst_interp = lnk_interp_symbol(dst);
|
||||
LNK_ObjSymbolRef dst_ref = lnk_get_obj_symbol_ref(dst);
|
||||
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular) {
|
||||
// remove replaced section from the output
|
||||
COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst->ref.obj, dst_parsed.section_number);
|
||||
COFF_SectionHeader *dst_sect = lnk_coff_section_header_from_section_number(dst_ref.obj, dst_parsed.section_number);
|
||||
dst_sect->flags |= COFF_SectionFlag_LnkRemove;
|
||||
|
||||
// remove associated sections from the output
|
||||
for (U32Node *associated_section = dst->ref.obj->associated_sections[dst_parsed.section_number];
|
||||
for (U32Node *associated_section = dst_ref.obj->associated_sections[dst_parsed.section_number];
|
||||
associated_section != 0;
|
||||
associated_section = associated_section->next) {
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst->ref.obj, associated_section->data);
|
||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(dst_ref.obj, associated_section->data);
|
||||
section_header->flags |= COFF_SectionFlag_LnkRemove;
|
||||
}
|
||||
}
|
||||
|
||||
// merge symbol refs
|
||||
LNK_ObjSymbolRefNode *src_last_ref;
|
||||
for (src_last_ref = src->refs; src_last_ref->next != 0; src_last_ref = src_last_ref->next);
|
||||
src_last_ref->next = dst->refs;
|
||||
|
||||
// assert leader section is live
|
||||
#if BUILD_DEBUG
|
||||
{
|
||||
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->ref.obj, src->ref.symbol_idx);
|
||||
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parse_symbol(src);
|
||||
COFF_SymbolValueInterpType src_interp = lnk_interp_symbol(src);
|
||||
LNK_ObjSymbolRef src_ref = lnk_get_obj_symbol_ref(src);
|
||||
|
||||
if (src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src->ref.obj, src_parsed.section_number);
|
||||
COFF_SectionHeader *src_sect = lnk_coff_section_header_from_section_number(src_ref.obj, src_parsed.section_number);
|
||||
AssertAlways(~src_sect->flags & COFF_SectionFlag_LnkRemove);
|
||||
}
|
||||
}
|
||||
@@ -505,10 +540,42 @@ lnk_array_from_symbol_hash_trie_chunk_list(Arena *arena, LNK_SymbolHashTrieChunk
|
||||
return chunks;
|
||||
}
|
||||
|
||||
internal LNK_ObjSymbolRef
|
||||
lnk_get_obj_symbol_ref(LNK_Symbol *symbol)
|
||||
{
|
||||
return symbol->refs->v;
|
||||
}
|
||||
|
||||
internal U64
|
||||
lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol)
|
||||
{
|
||||
U64 count = 0;
|
||||
for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, count += 1);
|
||||
return count;
|
||||
}
|
||||
|
||||
internal LNK_ObjSymbolRef **
|
||||
lnk_get_obj_symbol_ref_many(Arena *arena, LNK_Symbol *symbol, U64 *count_out)
|
||||
{
|
||||
// TODO: would be simpler if we sorted refs on insert/update
|
||||
U64 refs_count = lnk_get_obj_symbol_ref_count(symbol);
|
||||
LNK_ObjSymbolRef **refs = push_array(arena, LNK_ObjSymbolRef *, refs_count);
|
||||
U64 i = 0;
|
||||
for (LNK_ObjSymbolRefNode *node = symbol->refs; node != 0; node = node->next, i += 1) {
|
||||
refs[i] = &node->v;
|
||||
}
|
||||
radsort(refs, refs_count, lnk_obj_symbol_ref_ptr_is_before);
|
||||
if (count_out) {
|
||||
*count_out = refs_count;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
lnk_parse_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
return lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx);
|
||||
LNK_ObjSymbolRef ref = lnk_get_obj_symbol_ref(symbol);
|
||||
return lnk_parsed_symbol_from_coff_symbol_idx(ref.obj, ref.symbol_idx);
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
@@ -559,10 +626,10 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol)
|
||||
|
||||
// does weak symbol have a definition?
|
||||
LNK_Symbol *defn_symbol = lnk_symbol_table_search(symtab, current_parsed.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->ref.obj, defn_symbol->ref.symbol_idx);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parse_symbol(defn_symbol);
|
||||
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->ref;
|
||||
current_symbol = lnk_get_obj_symbol_ref(defn_symbol);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -588,7 +655,7 @@ lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol)
|
||||
if (defn_interp == COFF_SymbolValueInterp_Undefined) { break; }
|
||||
|
||||
// follow symbol definition
|
||||
current_symbol = defn_symbol->ref;
|
||||
current_symbol = lnk_get_obj_symbol_ref(defn_symbol);
|
||||
} else { break; }
|
||||
}
|
||||
|
||||
@@ -666,15 +733,16 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
|
||||
LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id];
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
LNK_ObjSymbolRef symbol_ref = lnk_get_obj_symbol_ref(symbol);
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parse_symbol(symbol);
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_from_parsed_symbol(symbol_parsed);
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
|
||||
LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol->ref);
|
||||
LNK_ObjSymbolRef resolve = lnk_resolve_weak_symbol(symtab, symbol_ref);
|
||||
COFF_ParsedSymbol resolve_parsed = lnk_parsed_symbol_from_coff_symbol_idx(resolve.obj, resolve.symbol_idx);
|
||||
COFF_SymbolValueInterpType resolve_interp = coff_interp_from_parsed_symbol(resolve_parsed);
|
||||
if (resolve_interp == COFF_SymbolValueInterp_Weak) {
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol->ref.obj->header.is_big_obj);
|
||||
if (symbol->ref.obj->header.is_big_obj) {
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(resolve_parsed, symbol_ref.obj->header.is_big_obj);
|
||||
if (symbol_ref.obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol_parsed.raw_symbol;
|
||||
symbol32->section_number = COFF_Symbol_UndefinedSection;
|
||||
symbol32->value = 0;
|
||||
@@ -686,7 +754,7 @@ THREAD_POOL_TASK_FUNC(lnk_replace_weak_with_default_symbol_task)
|
||||
symbol16->storage_class = COFF_SymStorageClass_External;
|
||||
}
|
||||
} else {
|
||||
symbol->ref = resolve;
|
||||
symbol->refs->v = resolve;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,7 +789,7 @@ lnk_replace_weak_with_default_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
|
||||
internal ISectOff
|
||||
lnk_sc_from_symbol(LNK_Symbol *symbol)
|
||||
{
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parsed_symbol_from_coff_symbol_idx(symbol->ref.obj, symbol->ref.symbol_idx);
|
||||
COFF_ParsedSymbol parsed_symbol = lnk_parse_symbol(symbol);
|
||||
|
||||
ISectOff sc = {0};
|
||||
sc.isect = parsed_symbol.section_number;
|
||||
|
||||
@@ -11,11 +11,17 @@ typedef struct LNK_ObjSymbolRef
|
||||
U32 symbol_idx;
|
||||
} LNK_ObjSymbolRef;
|
||||
|
||||
typedef struct LNK_ObjSymbolRefNode
|
||||
{
|
||||
struct LNK_ObjSymbolRefNode *next;
|
||||
LNK_ObjSymbolRef v;
|
||||
} LNK_ObjSymbolRefNode;
|
||||
|
||||
typedef struct LNK_Symbol
|
||||
{
|
||||
String8 name;
|
||||
B8 is_lib_member_linked;
|
||||
LNK_ObjSymbolRef ref;
|
||||
String8 name;
|
||||
B8 is_lib_member_linked;
|
||||
LNK_ObjSymbolRefNode *refs;
|
||||
} LNK_Symbol;
|
||||
|
||||
// --- Symbol Containers -------------------------------------------------------
|
||||
@@ -109,6 +115,8 @@ internal LNK_SymbolHashTrieChunk ** lnk_array_from_symbol_hash_trie_chunk_list(A
|
||||
|
||||
// --- Symbol Helpers ----------------------------------------------------------
|
||||
|
||||
internal LNK_ObjSymbolRef lnk_get_obj_symbol_ref(LNK_Symbol *symbol);
|
||||
internal U64 lnk_get_obj_symbol_ref_count(LNK_Symbol *symbol);
|
||||
internal COFF_ParsedSymbol lnk_parse_symbol(LNK_Symbol *symbol);
|
||||
internal COFF_SymbolValueInterpType lnk_interp_symbol(LNK_Symbol *symbol);
|
||||
internal LNK_ObjSymbolRef lnk_resolve_weak_symbol(LNK_SymbolTable *symtab, LNK_ObjSymbolRef symbol);
|
||||
|
||||
Reference in New Issue
Block a user