mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
factor out weak symbol resolution logic and apply it to the symbol table
when building link context
This commit is contained in:
committed by
Ryan Fleury
parent
7cd5a670e3
commit
d32667546d
@@ -279,6 +279,12 @@ coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_c
|
||||
return COFF_SymbolValueInterp_Regular;
|
||||
}
|
||||
|
||||
internal COFF_SymbolValueInterpType
|
||||
coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol)
|
||||
{
|
||||
return coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class);
|
||||
}
|
||||
|
||||
internal void
|
||||
coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out)
|
||||
{
|
||||
|
||||
@@ -267,6 +267,7 @@ internal COFF_Symbol32Array coff_symbol_array_from_data (Arena *arena, String8
|
||||
internal COFF_Symbol16Node *coff_symbol16_list_push(Arena *arena, COFF_Symbol16List *list, COFF_Symbol16 symbol);
|
||||
|
||||
internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 value, COFF_SymStorageClass storage_class);
|
||||
internal COFF_SymbolValueInterpType coff_interp_from_parsed_symbol(COFF_ParsedSymbol symbol);
|
||||
|
||||
internal void coff_parse_secdef(COFF_ParsedSymbol symbol, B32 is_big_obj, COFF_ComdatSelectType *selection_out, U32 *number_out, U32 *length_out, U32 *check_sum_out);
|
||||
internal COFF_SymbolWeakExt * coff_parse_weak_tag(COFF_ParsedSymbol symbol, B32 is_big_obj);
|
||||
|
||||
+150
-559
@@ -2189,6 +2189,9 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
|
||||
break;
|
||||
}
|
||||
|
||||
// pass over symbol table and replace weak symbols without a strong definition with fallback definitions
|
||||
lnk_finalize_weak_symbols(tp, symtab);
|
||||
|
||||
// log
|
||||
{
|
||||
if (lnk_get_log_status(LNK_Log_InputObj)) {
|
||||
@@ -2207,7 +2210,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
|
||||
}
|
||||
|
||||
exit:;
|
||||
|
||||
LNK_LinkContext link_ctx = {0};
|
||||
link_ctx.symtab = symtab;
|
||||
link_ctx.objs_count = obj_list.count;
|
||||
@@ -2223,13 +2225,6 @@ lnk_build_link_context(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config)
|
||||
#undef state_list_pop
|
||||
}
|
||||
|
||||
internal LNK_SymbolTableFixup *
|
||||
lnk_bsearch_symbol_table_fixup_array(LNK_SymbolTableFixupArray array, U64 symbol_idx)
|
||||
{
|
||||
NotImplemented;
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_remove_associative_sections_task)
|
||||
{
|
||||
@@ -2426,214 +2421,51 @@ THREAD_POOL_TASK_FUNC(lnk_set_comdat_leaders_contribs_task)
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal LNK_SymbolTableFixup *
|
||||
lnk_symbol_table_fixup_list_push(Arena *arena, LNK_SymbolTableFixupList *list)
|
||||
internal B32
|
||||
lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_SymbolDefined symbol, LNK_SymbolDefined *symbol_out)
|
||||
{
|
||||
LNK_SymbolTableFixupNode *node = push_array(arena, LNK_SymbolTableFixupNode, 1);
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
return &node->data;
|
||||
}
|
||||
|
||||
internal LNK_SymbolTableFixupArray
|
||||
lnk_array_from_symbol_table_fixup_list(Arena *arena, LNK_SymbolTableFixupList list)
|
||||
{
|
||||
LNK_SymbolTableFixupArray result = {0};
|
||||
result.v = push_array(arena, LNK_SymbolTableFixup, list.count);
|
||||
for (LNK_SymbolTableFixupNode *n = list.first; n != 0; n = n->next) {
|
||||
result.v[result.count++] = n->data;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_gather_symtab_fixups_task)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[task_id];
|
||||
|
||||
ProfBeginV("%S", obj->path);
|
||||
|
||||
LNK_SymbolTableFixupList fixups = {0};
|
||||
|
||||
HashTable *visited_symbols_ht = hash_table_init(scratch.arena, 32);
|
||||
struct LookupLocation { struct LookupLocation *next; LNK_Obj *obj; U64 symbol_idx; };
|
||||
struct LookupLocation *lookup_first = 0, *lookup_last = 0, *lookup_free_list = 0;
|
||||
|
||||
COFF_ParsedSymbol symbol;
|
||||
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);
|
||||
|
||||
COFF_ParsedSymbol fixup_symbol = symbol;
|
||||
COFF_SymbolValueInterpType fixup_interp = interp;
|
||||
|
||||
for (String8 lookup_name = symbol.name; fixup_interp == COFF_SymbolValueInterp_Weak;) {
|
||||
// search external symbol table for definition
|
||||
LNK_Symbol *defn_symbol = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, lookup_name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_defined(defn_symbol);
|
||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_parsed.section_number, defn_parsed.value, defn_parsed.storage_class);
|
||||
|
||||
// was weak symbol replaced by strong symbol?
|
||||
if (defn_interp != COFF_SymbolValueInterp_Weak) {
|
||||
fixup_interp = defn_interp;
|
||||
fixup_symbol = defn_parsed;
|
||||
break;
|
||||
}
|
||||
|
||||
// strong symbol not found, fallback to tag symbol
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(defn_parsed, defn_symbol->u.defined.obj->header.is_big_obj);
|
||||
COFF_ParsedSymbol tag_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn_symbol->u.defined.obj, weak_ext->tag_index);
|
||||
COFF_SymbolValueInterpType tag_interp = coff_interp_symbol(tag_parsed.section_number, tag_parsed.value, tag_parsed.storage_class);
|
||||
|
||||
// validate tag symbol
|
||||
if (tag_interp == COFF_SymbolValueInterp_Weak) {
|
||||
Assert(!"TODO: report that tag symbol must not be weak");
|
||||
break;
|
||||
}
|
||||
|
||||
// tag is a resolved symbol
|
||||
if (tag_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
fixup_interp = tag_interp;
|
||||
fixup_symbol = tag_parsed;
|
||||
break;
|
||||
}
|
||||
|
||||
// guard against self-referencing weak symbols
|
||||
struct LookupLocation *was_visited = 0;
|
||||
hash_table_search_string_raw(visited_symbols_ht, tag_parsed.name, &was_visited);
|
||||
if (was_visited) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
String8List 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->obj, l->symbol_idx);
|
||||
str8_list_pushf(temp.arena, &list, "\t%S Symbol %S (No.%#llx) =>", l->obj->path, loc_symbol.name, l->symbol_idx);
|
||||
}
|
||||
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(was_visited->obj, was_visited->symbol_idx);
|
||||
str8_list_pushf(temp.arena, &list, "\t%S Symbol %S (No.%#llx)", was_visited->obj->path, loc_symbol.name, was_visited->symbol_idx);
|
||||
|
||||
String8 loc_string = str8_list_join(temp.arena, &list, &(StringJoin){.sep = str8_lit("\n") });
|
||||
lnk_error_obj(LNK_Error_WeakCycle, obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", symbol.name, loc_string);
|
||||
|
||||
temp_end(temp);
|
||||
break;
|
||||
}
|
||||
|
||||
// alloc lookup location
|
||||
struct LookupLocation *loc = lookup_free_list;
|
||||
if (lookup_free_list) { SLLStackPop(lookup_free_list); }
|
||||
else { loc = push_array(scratch.arena, struct LookupLocation, 1); }
|
||||
|
||||
// fill out lookup location
|
||||
loc->obj = defn_symbol->u.defined.obj;
|
||||
loc->symbol_idx = symbol_idx;
|
||||
SLLQueuePush(lookup_first, lookup_last, loc);
|
||||
hash_table_push_string_raw(scratch.arena, visited_symbols_ht, lookup_name, loc);
|
||||
|
||||
// follow undefined tag symbol
|
||||
lookup_name = tag_parsed.name;
|
||||
}
|
||||
|
||||
if (fixup_interp == COFF_SymbolValueInterp_Common) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, fixup_symbol.name);
|
||||
if (defn) {
|
||||
LNK_SymbolTableFixup *fixup = lnk_symbol_table_fixup_list_push(scratch.arena, &fixups);
|
||||
fixup->idx = symbol_idx;
|
||||
fixup->obj_idx = defn->u.defined.obj->input_idx;
|
||||
fixup->obj_symbol_idx = defn->u.defined.symbol_idx;
|
||||
}
|
||||
} else if (fixup_interp == COFF_SymbolValueInterp_Abs) {
|
||||
if (fixup_symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, fixup_symbol.name);
|
||||
|
||||
if (defn == 0) { continue; }
|
||||
if (defn->u.defined.obj == obj && defn->u.defined.symbol_idx == symbol_idx) { continue; }
|
||||
|
||||
LNK_SymbolTableFixup *fixup = lnk_symbol_table_fixup_list_push(scratch.arena, &fixups);
|
||||
fixup->idx = symbol_idx;
|
||||
fixup->obj_idx = defn->u.defined.obj->input_idx;
|
||||
fixup->obj_symbol_idx = defn->u.defined.symbol_idx;
|
||||
}
|
||||
} else if (fixup_interp == COFF_SymbolValueInterp_Undefined) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name);
|
||||
if (defn) {
|
||||
LNK_SymbolTableFixup *fixup = lnk_symbol_table_fixup_list_push(scratch.arena, &fixups);
|
||||
fixup->idx = symbol_idx;
|
||||
fixup->obj_idx = defn->u.defined.obj->input_idx;
|
||||
fixup->obj_symbol_idx = defn->u.defined.symbol_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task->obj_symtab_fixups[obj_idx] = lnk_array_from_symbol_table_fixup_list(arena, fixups);
|
||||
|
||||
ProfEnd();
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_apply_symtab_fixups_task)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
LNK_SymbolTableFixupArray fixups = task->obj_symtab_fixups[obj_idx];
|
||||
|
||||
ProfBeginV("%S\n", obj->path);
|
||||
for EachIndex(fixup_idx, fixups.count) {
|
||||
LNK_SymbolTableFixup *fixup = &fixups.v[fixup_idx];
|
||||
|
||||
COFF_ParsedSymbol fixup_dst = lnk_parsed_symbol_from_coff_symbol_idx(obj, fixup->idx);
|
||||
COFF_SymbolValueInterpType fixup_dst_type = coff_interp_symbol(fixup_dst.section_number, fixup_dst.value, fixup_dst.storage_class);
|
||||
if (task->u.patch_symtabs.fixup_type != fixup_dst_type) { continue; }
|
||||
|
||||
LNK_Obj *fixup_obj_src = task->objs[fixup->obj_idx];
|
||||
COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_obj_src, fixup->obj_symbol_idx);
|
||||
COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class);
|
||||
|
||||
if (fixup_type == COFF_SymbolValueInterp_Regular) {
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = fixup_dst.raw_symbol;
|
||||
symbol32->section_number = fixup_src.section_number;
|
||||
symbol32->value = safe_cast_u32(fixup_src.value);
|
||||
symbol32->type = fixup_src.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = fixup_dst.raw_symbol;
|
||||
symbol16->section_number = safe_cast_u16(fixup_src.section_number);
|
||||
symbol16->value = safe_cast_u32(fixup_src.value);
|
||||
symbol16->type = fixup_src.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
} else if (fixup_type == COFF_SymbolValueInterp_Abs) {
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = fixup_dst.raw_symbol;
|
||||
symbol32->section_number = COFF_Symbol_AbsSection32;
|
||||
symbol32->value = safe_cast_u32(fixup_src.value);
|
||||
symbol32->type = fixup_src.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = fixup_dst.raw_symbol;
|
||||
symbol16->section_number = COFF_Symbol_AbsSection16;
|
||||
symbol16->value = safe_cast_u32(fixup_src.value);
|
||||
symbol16->type = fixup_src.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
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: { *symbol_out = symbol; } break;
|
||||
case COFF_SymbolValueInterp_Weak: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name);
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->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_Undefined) {
|
||||
*symbol_out = defn->u.defined;
|
||||
} else {
|
||||
InvalidPath;
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Undefined: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name);
|
||||
if (defn) {
|
||||
*symbol_out = defn->u.defined;
|
||||
} else {
|
||||
is_resolved = 0;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name);
|
||||
*symbol_out = defn->u.defined;
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Abs: {
|
||||
if (symbol_parsed.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, symbol_parsed.name);
|
||||
*symbol_out = defn->u.defined;
|
||||
} else {
|
||||
*symbol_out = symbol;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Debug: { *symbol_out = symbol; } break;
|
||||
}
|
||||
ProfEnd();
|
||||
return is_resolved;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_gc_sections(U64 objs_count, LNK_Obj **objs, LNK_SectionContrib ***sect_map, LNK_SymbolTableFixupArray *obj_symtab_fixups, U64 roots_count, LNK_Symbol **roots)
|
||||
lnk_gc_sections(LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, LNK_SectionContrib ***sect_map, U64 roots_count, LNK_Symbol **roots)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
@@ -2726,10 +2558,13 @@ lnk_gc_sections(U64 objs_count, LNK_Obj **objs, LNK_SectionContrib ***sect_map,
|
||||
for EachIndex(reloc_idx, t->relocs.count) {
|
||||
COFF_Reloc *reloc = &t->relocs.v[reloc_idx];
|
||||
|
||||
LNK_SymbolTableFixup *fixup = lnk_bsearch_symbol_table_fixup_array(obj_symtab_fixups[t->obj->input_idx], reloc->isymbol);
|
||||
LNK_Obj *reloc_obj; U32 reloc_symbol_idx;
|
||||
if (fixup == 0) { reloc_obj = t->obj, reloc_symbol_idx = reloc->isymbol; }
|
||||
else { reloc_obj = objs[fixup->obj_idx]; reloc_symbol_idx = fixup->obj_symbol_idx; }
|
||||
LNK_SymbolDefined symbol_to_resolve = { .obj = t->obj, .symbol_idx = reloc->isymbol };
|
||||
LNK_SymbolDefined resolved_symbol = {0};
|
||||
B32 is_symbol_resolved = lnk_resolve_symbol(symtab, symbol_to_resolve, &resolved_symbol);
|
||||
if ( ! is_symbol_resolved) { continue; }
|
||||
|
||||
LNK_Obj *reloc_obj = resolved_symbol.obj;
|
||||
U32 reloc_symbol_idx = resolved_symbol.symbol_idx;
|
||||
|
||||
COFF_ParsedSymbol reloc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(reloc_obj, reloc_symbol_idx);
|
||||
COFF_SymbolValueInterpType reloc_symbol_interp = coff_interp_symbol(reloc_symbol.section_number, reloc_symbol.value, reloc_symbol.storage_class);
|
||||
@@ -2905,7 +2740,7 @@ THREAD_POOL_TASK_FUNC(lnk_patch_common_block_leaders_task)
|
||||
ProfBeginFunction();
|
||||
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
Rng1U64 contrib_range = task->u.patch_symtabs.ranges[task_id];
|
||||
Rng1U64 contrib_range = task->u.patch_symtabs.common_block_ranges[task_id];
|
||||
|
||||
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];
|
||||
@@ -3010,275 +2845,76 @@ THREAD_POOL_TASK_FUNC(lnk_patch_regular_symbols_task)
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_abs_symbols_task)
|
||||
internal void
|
||||
lnk_patch_obj_symtab(LNK_SymbolTable *symtab, LNK_Obj *obj, B8 *was_symbol_patched, COFF_SymbolValueInterpType fixup_type)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
ProfBeginV("%S\n", obj->path);
|
||||
|
||||
ProfBeginV("Patch Absolute Symbols [%S]", obj->path);
|
||||
COFF_ParsedSymbol symbol;
|
||||
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);
|
||||
COFF_ParsedSymbol fixup_dst;
|
||||
for (U64 symbol_idx = 0; symbol_idx < obj->header.symbol_count; symbol_idx += (1 + fixup_dst.aux_symbol_count)) {
|
||||
fixup_dst = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx);
|
||||
if (was_symbol_patched[symbol_idx]) { continue; }
|
||||
|
||||
if (interp == COFF_SymbolValueInterp_Abs && symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name);
|
||||
COFF_SymbolValueInterpType fixup_dst_type = coff_interp_symbol(fixup_dst.section_number, fixup_dst.value, fixup_dst.storage_class);
|
||||
if (fixup_type != fixup_dst_type) { continue; }
|
||||
|
||||
if (defn == 0) {
|
||||
continue;
|
||||
}
|
||||
if (defn->u.defined.obj == obj && defn->u.defined.symbol_idx == symbol_idx) {
|
||||
continue;
|
||||
}
|
||||
LNK_SymbolDefined symbol_to_resolve = { .obj = obj, .symbol_idx = symbol_idx };
|
||||
LNK_SymbolDefined fixup_symbol = {0};
|
||||
B32 is_resolved = lnk_resolve_symbol(symtab, symbol_to_resolve, &fixup_symbol);
|
||||
if (is_resolved) {
|
||||
COFF_ParsedSymbol fixup_src = lnk_parsed_symbol_from_coff_symbol_idx(fixup_symbol.obj, fixup_symbol.symbol_idx);
|
||||
COFF_SymbolValueInterpType fixup_type = coff_interp_symbol(fixup_src.section_number, fixup_src.value, fixup_src.storage_class);
|
||||
AssertAlways(fixup_type == COFF_SymbolValueInterp_Regular ||
|
||||
fixup_type == COFF_SymbolValueInterp_Abs ||
|
||||
fixup_type == COFF_SymbolValueInterp_Common);
|
||||
|
||||
COFF_ParsedSymbol defn_symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
|
||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_symbol.section_number, defn_symbol.value, defn_symbol.storage_class);
|
||||
if (defn_interp == COFF_SymbolValueInterp_Regular) {
|
||||
if (defn->u.defined.obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
symbol32->section_number = defn_symbol.section_number;
|
||||
symbol32->value = defn_symbol.value;
|
||||
symbol32->type = defn_symbol.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
|
||||
symbol16->section_number = defn_symbol.section_number;
|
||||
symbol16->value = defn_symbol.value;
|
||||
symbol16->type = defn_symbol.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = fixup_dst.raw_symbol;
|
||||
symbol32->section_number = fixup_src.section_number;
|
||||
symbol32->value = fixup_src.value;
|
||||
symbol32->type = fixup_src.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
InvalidPath;
|
||||
COFF_Symbol16 *symbol16 = fixup_dst.raw_symbol;
|
||||
symbol16->section_number = (U16)fixup_src.section_number;
|
||||
symbol16->value = fixup_src.value;
|
||||
symbol16->type = fixup_src.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
|
||||
was_symbol_patched[symbol_idx] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_patch_weak_external_symbol(B32 is_big_obj, void *symbol, COFF_ParsedSymbol parsed_symbol)
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_common_symbols_task)
|
||||
{
|
||||
COFF_SymbolValueInterpType parsed_symbol_interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class);
|
||||
switch (parsed_symbol_interp) {
|
||||
case COFF_SymbolValueInterp_Regular: {
|
||||
if (is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol;
|
||||
symbol32->section_number = parsed_symbol.section_number;
|
||||
symbol32->value = parsed_symbol.value;
|
||||
symbol32->type = parsed_symbol.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol;
|
||||
symbol16->section_number = safe_cast_u16(parsed_symbol.section_number);
|
||||
symbol16->value = parsed_symbol.value;
|
||||
symbol16->type = parsed_symbol.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
InvalidPath;
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Abs: {
|
||||
if (is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol;
|
||||
symbol32->section_number = COFF_Symbol_AbsSection32;
|
||||
symbol32->value = parsed_symbol.value;
|
||||
symbol32->type = parsed_symbol.type;
|
||||
symbol32->storage_class = COFF_SymStorageClass_Static;
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol;
|
||||
symbol16->section_number = COFF_Symbol_AbsSection16;
|
||||
symbol16->value = parsed_symbol.value;
|
||||
symbol16->type = parsed_symbol.type;
|
||||
symbol16->storage_class = COFF_SymStorageClass_Static;
|
||||
}
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Weak:
|
||||
case COFF_SymbolValueInterp_Debug:
|
||||
case COFF_SymbolValueInterp_Undefined: {
|
||||
InvalidPath;
|
||||
} break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Common);
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_abs_symbols_task)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Abs);
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_undefined_symbols_task)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
|
||||
ProfBeginV("Patch Undefined Symbols [%S]", obj->path);
|
||||
COFF_ParsedSymbol symbol;
|
||||
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_Undefined) {
|
||||
if (symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name);
|
||||
if (defn) {
|
||||
COFF_ParsedSymbol defn_symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
|
||||
|
||||
if (defn_symbol.storage_class == COFF_SymStorageClass_WeakExternal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lnk_patch_weak_external_symbol(obj->header.is_big_obj, symbol.raw_symbol, defn_symbol);
|
||||
} else {
|
||||
// TODO: collect unresolved undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Undefined);
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_with_strong_definition_task)
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_task)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
|
||||
ProfBeginV("Patch Weak Symbols [%S]", obj->path);
|
||||
COFF_ParsedSymbol symbol;
|
||||
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_Weak) {
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name);
|
||||
if (defn) {
|
||||
COFF_ParsedSymbol defn_symbol = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
|
||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_symbol.section_number, defn_symbol.value, defn_symbol.storage_class);
|
||||
if (defn_interp != COFF_SymbolValueInterp_Weak) {
|
||||
lnk_patch_weak_external_symbol(obj->header.is_big_obj, symbol.raw_symbol, defn_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_with_fallback_definition_task)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
|
||||
HashTable *visited_symbols_ht = hash_table_init(scratch.arena, 32);
|
||||
struct LookupLocation {
|
||||
struct LookupLocation *next;
|
||||
LNK_Obj *obj;
|
||||
U64 symbol_idx;
|
||||
};
|
||||
struct LookupLocation *lookup_first = 0;
|
||||
struct LookupLocation *lookup_last = 0;
|
||||
struct LookupLocation *lookup_free_list = 0;
|
||||
|
||||
ProfBegin("Patch Weak Symbols [%S]", obj->path);
|
||||
COFF_ParsedSymbol symbol;
|
||||
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_Undefined && symbol.storage_class == COFF_SymStorageClass_External) {
|
||||
String8 lookup_name = symbol.name;
|
||||
LNK_Obj *lookup_obj = obj;
|
||||
U64 lookup_symbol_idx = symbol_idx;
|
||||
for (;;) {
|
||||
// lookup definition
|
||||
LNK_Symbol *defn = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, lookup_name);
|
||||
if (defn == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// not external symbol? patch and move to next symbol
|
||||
COFF_ParsedSymbol defn_parsed = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, defn->u.defined.symbol_idx);
|
||||
if (defn_parsed.storage_class != COFF_SymStorageClass_WeakExternal) {
|
||||
lnk_patch_weak_external_symbol(obj->header.is_big_obj, symbol.raw_symbol, defn_parsed);
|
||||
break;
|
||||
}
|
||||
|
||||
// check against cyclic refs
|
||||
struct LookupLocation *was_visited = 0;
|
||||
hash_table_search_string_raw(visited_symbols_ht, lookup_name, &was_visited);
|
||||
if (was_visited != 0) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
String8List 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->obj, l->symbol_idx);
|
||||
str8_list_pushf(temp.arena, &list, "\t%S Symbol %S (No.%#llx) =>", l->obj->path, loc_symbol.name, l->symbol_idx);
|
||||
}
|
||||
{
|
||||
COFF_ParsedSymbol loc_symbol = lnk_parsed_symbol_from_coff_symbol_idx(was_visited->obj, was_visited->symbol_idx);
|
||||
str8_list_pushf(temp.arena, &list, "\t%S Symbol %S (No.%#llx)", was_visited->obj->path, loc_symbol.name, was_visited->symbol_idx);
|
||||
}
|
||||
|
||||
String8 loc_string = str8_list_join(temp.arena, &list, &(StringJoin){.sep = str8_lit("\n") });
|
||||
lnk_error_obj(LNK_Error_WeakCycle, obj, "unable to resolve cyclic symbol %S; ref chain:\n%S", symbol.name, loc_string);
|
||||
|
||||
temp_end(temp);
|
||||
break;
|
||||
}
|
||||
struct LookupLocation *loc = lookup_free_list;
|
||||
if (lookup_free_list) {
|
||||
SLLStackPop(lookup_free_list);
|
||||
} else {
|
||||
loc = push_array(scratch.arena, struct LookupLocation, 1);
|
||||
}
|
||||
loc->obj = lookup_obj;
|
||||
loc->symbol_idx = symbol_idx;
|
||||
SLLQueuePush(lookup_first, lookup_last, loc);
|
||||
hash_table_push_string_raw(scratch.arena, visited_symbols_ht, lookup_name, loc);
|
||||
|
||||
// fallback to weak tag for definition
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(defn_parsed, defn->u.defined.obj->header.is_big_obj);
|
||||
COFF_ParsedSymbol parsed_tag = lnk_parsed_symbol_from_coff_symbol_idx(defn->u.defined.obj, weak_ext->tag_index);
|
||||
lookup_name = parsed_tag.name;
|
||||
lookup_obj = defn->u.defined.obj;
|
||||
lookup_symbol_idx = weak_ext->tag_index;
|
||||
}
|
||||
|
||||
hash_table_purge(visited_symbols_ht);
|
||||
lookup_free_list = lookup_first;
|
||||
lookup_first = 0;
|
||||
lookup_last = 0;
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_patch_weak_symbols_with_defined_tags_task)
|
||||
{
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
U64 obj_idx = task_id;
|
||||
LNK_Obj *obj = task->objs[obj_idx];
|
||||
|
||||
ProfBeginV("Patch Weak Symbols [%S]", obj->path);
|
||||
COFF_ParsedSymbol symbol;
|
||||
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_Weak) {
|
||||
COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(symbol, obj->header.is_big_obj);
|
||||
COFF_ParsedSymbol defn_symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, weak_ext->tag_index);
|
||||
COFF_SymbolValueInterpType defn_interp = coff_interp_symbol(defn_symbol.section_number, defn_symbol.value, defn_symbol.storage_class);
|
||||
if (defn_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
lnk_patch_weak_external_symbol(obj->header.is_big_obj, symbol.raw_symbol, defn_symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
LNK_BuildImageTask *task = raw_task;
|
||||
lnk_patch_obj_symtab(task->symtab, task->objs[task_id], task->u.patch_symtabs.was_symbol_patched[task_id], COFF_SymbolValueInterp_Weak);
|
||||
}
|
||||
|
||||
internal U64
|
||||
@@ -4407,14 +4043,15 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
|
||||
LNK_Section *common_block_sect = lnk_section_table_search(sectab, str8_lit(".bss"), PE_BSS_SECTION_FLAGS);
|
||||
|
||||
LNK_BuildImageTask task = {0};
|
||||
task.symtab = symtab;
|
||||
task.sectab = sectab;
|
||||
task.objs_count = objs_count;
|
||||
task.objs = objs;
|
||||
task.function_pad_min = config->function_pad_min;
|
||||
task.default_align = coff_default_align_from_machine(config->machine);
|
||||
task.null_sc = push_array(arena->v[0], LNK_SectionContrib, 1);
|
||||
LNK_BuildImageTask task = {
|
||||
.symtab = symtab,
|
||||
.sectab = sectab,
|
||||
.objs_count = objs_count,
|
||||
.objs = objs,
|
||||
.function_pad_min = config->function_pad_min,
|
||||
.default_align = coff_default_align_from_machine(config->machine),
|
||||
.null_sc = push_array(arena->v[0], LNK_SectionContrib, 1),
|
||||
};
|
||||
|
||||
tp_for_parallel(tp, 0, objs_count, lnk_remove_associative_sections_task, &task);
|
||||
|
||||
@@ -4427,9 +4064,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
for EachIndex(worker_id, tp->worker_count) { task.u.gather_sects.defns[worker_id] = hash_table_init(arena->v[0], 128); }
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Gather Section Definitions");
|
||||
tp_for_parallel(tp, arena, objs_count, lnk_gather_section_definitions_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, arena, objs_count, lnk_gather_section_definitions_task, &task, "Gather Section Definitions");
|
||||
|
||||
ProfBegin("Merge Section Definitions Hash Tables");
|
||||
for (U64 worker_idx = 1; worker_idx < tp->worker_count; worker_idx += 1) {
|
||||
@@ -4519,45 +4154,40 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
for EachIndex(obj_idx, objs_count) { task.sect_map[obj_idx] = push_array(scratch.arena, LNK_SectionContrib *, objs[obj_idx]->header.section_count_no_null); }
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Gather Section Contribs");
|
||||
tp_for_parallel(tp, 0, objs_count, lnk_gather_section_contribs_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_gather_section_contribs_task, &task, "Gather Section Contribs");
|
||||
|
||||
// ensure determinism by sorting section contribs in chunks by input index
|
||||
{
|
||||
ProfBegin("Sort Section Contribs");
|
||||
U64 total_chunk_count = 0;
|
||||
LNK_SectionContribChunk **chunks = 0;
|
||||
|
||||
U64 total_chunk_count = 0;
|
||||
{
|
||||
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
total_chunk_count += sect_n->data.contribs.chunk_count;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
U64 cursor = 0;
|
||||
chunks = push_array(scratch.arena, LNK_SectionContribChunk *, total_chunk_count);
|
||||
task.u.sort_contribs.chunks = push_array(scratch.arena, LNK_SectionContribChunk *, total_chunk_count);
|
||||
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
for (LNK_SectionContribChunk *chunk_n = sect_n->data.contribs.first; chunk_n != 0; chunk_n = chunk_n->next) {
|
||||
chunks[cursor++] = chunk_n;
|
||||
task.u.sort_contribs.chunks[cursor++] = chunk_n;
|
||||
}
|
||||
}
|
||||
Assert(cursor == total_chunk_count);
|
||||
}
|
||||
task.u.sort_contribs.chunks = chunks;
|
||||
|
||||
tp_for_parallel(tp, 0, total_chunk_count, lnk_sort_contribs_task, &task);
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
ProfBegin("Update Section Map With COMDAT Leader Contribs");
|
||||
tp_for_parallel(tp, 0, objs_count, lnk_set_comdat_leaders_contribs_task, &task);
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Gather Obj Symbol Tables Fixups");
|
||||
task.obj_symtab_fixups = push_array(scratch.arena, LNK_SymbolTableFixupArray, objs_count);
|
||||
tp_for_parallel(tp, arena, objs_count, lnk_gather_symtab_fixups_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_set_comdat_leaders_contribs_task, &task, "Update Section Map With COMDAT Leader Contribs");
|
||||
|
||||
if (config->opt_ref == LNK_SwitchState_Yes) {
|
||||
//LNK_Symbol *entry_point_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, config->entry_point_name);
|
||||
//lnk_gc_sections(objs_count, objs, task.sect_map, task.obj_symtab_fixups, 1, &entry_point_symbol);
|
||||
//lnk_gc_sections(symtab, objs_count, objs, task.sect_map, task.obj_symtab_fixups, 1, &entry_point_symbol);
|
||||
}
|
||||
|
||||
// build common block
|
||||
@@ -4568,10 +4198,8 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
{
|
||||
ProfBegin("Build Common Block");
|
||||
|
||||
ProfBegin("Count Contribs");
|
||||
task.u.common_block.counts = push_array(scratch.arena, U64, tp->worker_count);
|
||||
tp_for_parallel(tp, 0, tp->worker_count, lnk_count_common_block_contribs_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_count_common_block_contribs_task, &task, "Count Contribs");
|
||||
|
||||
ProfBegin("Push Contribs");
|
||||
common_block_contribs_count = sum_array_u64(tp->worker_count, task.u.common_block.counts);
|
||||
@@ -4595,7 +4223,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
U64 common_block_cursor = common_block_sect->vsize;
|
||||
|
||||
// compute and assign offsets into the common block
|
||||
for (U64 contrib_idx = 0; contrib_idx < common_block_contribs_count; contrib_idx += 1) {
|
||||
for EachIndex(contrib_idx, common_block_contribs_count) {
|
||||
LNK_CommonBlockContrib *contrib = &common_block_contribs[contrib_idx];
|
||||
U32 size = contrib->u.size;
|
||||
U32 align = Min(32, u64_up_to_pow2(size)); // link.exe caps align at 32 bytes
|
||||
@@ -4620,7 +4248,6 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
// finalize sections layouts
|
||||
{
|
||||
ProfBegin("Finalize Sections Layout");
|
||||
|
||||
@@ -4639,9 +4266,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
}
|
||||
|
||||
if (config->do_function_pad_min == LNK_SwitchState_Yes) {
|
||||
ProfBegin("Flag Hotpatch Section Contribs");
|
||||
tp_for_parallel(tp, arena, objs_count, lnk_flag_hotpatch_contribs_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, arena, objs_count, lnk_flag_hotpatch_contribs_task, &task, "Flag Hotpatch Section Contribs");
|
||||
}
|
||||
|
||||
// assign contribs offsets, sizes, and section indices
|
||||
@@ -4684,39 +4309,29 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
// patch symbol tables
|
||||
{
|
||||
ProfBegin("Patch Symbol Tables");
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
B8 **was_symbol_patched = push_array(temp.arena, B8 *, objs_count);
|
||||
for EachIndex(obj_idx, objs_count) { was_symbol_patched[obj_idx] = push_array(temp.arena, B8, objs[obj_idx]->header.symbol_count); }
|
||||
|
||||
task.u.patch_symtabs.was_symbol_patched = was_symbol_patched;
|
||||
// set up context for patch tasks
|
||||
task.u.patch_symtabs.common_block_sect = common_block_sect;
|
||||
task.u.patch_symtabs.ranges = tp_divide_work(temp.arena, common_block_contribs_count, tp->worker_count);
|
||||
task.u.patch_symtabs.common_block_ranges = tp_divide_work(temp.arena, common_block_contribs_count, tp->worker_count);
|
||||
task.u.patch_symtabs.common_block_contribs = common_block_contribs;
|
||||
task.u.patch_symtabs.was_symbol_patched = push_array(temp.arena, B8 *, objs_count);
|
||||
for EachIndex(obj_idx, objs_count) { task.u.patch_symtabs.was_symbol_patched[obj_idx] = push_array(temp.arena, B8, objs[obj_idx]->header.symbol_count); }
|
||||
|
||||
// flag debug symbols to prevent them from being patched in subsequent passes
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_flag_debug_symbols_task, &task, "Flag Debug Symbols");
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_comdat_leaders_task, &task, "Patch COMDAT Leaders");
|
||||
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_patch_common_block_leaders_task, &task, "Patch Common Block Leaders");
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_regular_symbols_task, &task, "Patch Regular Symbols");
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_flag_debug_symbols_task, &task, "Flag Debug Symbols");
|
||||
|
||||
task.u.patch_symtabs.fixup_type = COFF_SymbolValueInterp_Common;
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_apply_symtab_fixups_task, &task, "Fixup Common Symbols");
|
||||
|
||||
task.u.patch_symtabs.fixup_type = COFF_SymbolValueInterp_Abs;
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_apply_symtab_fixups_task, &task, "Fixup Absolute Symbols");
|
||||
|
||||
task.u.patch_symtabs.fixup_type = COFF_SymbolValueInterp_Undefined;
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_apply_symtab_fixups_task, &task, "Fixup Undefined Symbols");
|
||||
|
||||
task.u.patch_symtabs.fixup_type = COFF_SymbolValueInterp_Weak;
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_apply_symtab_fixups_task, &task, "Fixup Weak Symbols");
|
||||
|
||||
task.u.patch_symtabs.fixup_type = COFF_SymbolValueInterp_Undefined;
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_apply_symtab_fixups_task, &task, "Fixup Undefined Symbols");
|
||||
// patch symbols
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_comdat_leaders_task, &task, "COMDAT Leaders" );
|
||||
tp_for_parallel_prof(tp, 0, tp->worker_count, lnk_patch_common_block_leaders_task, &task, "Common Block Leaders");
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_regular_symbols_task, &task, "Regular Symbols" );
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_common_symbols_task, &task, "Common Symbols" );
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_abs_symbols_task, &task, "Absolute Symbols" );
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_undefined_symbols_task, &task, "Undefined Symbols" );
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_weak_symbols_task, &task, "Weak Symbols" );
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_patch_undefined_symbols_task, &task, "Undefined Symbols" );
|
||||
|
||||
temp_end(temp);
|
||||
ProfEnd();
|
||||
@@ -4725,17 +4340,11 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
// section list -> array
|
||||
task.image_sects = lnk_section_array_from_list(scratch.arena, sectab->list);
|
||||
|
||||
// assign virtual offsets to sections
|
||||
expected_image_header_size = lnk_compute_win32_image_header_size(config, task.image_sects.count);
|
||||
|
||||
// assign virtual space
|
||||
U64 voff_cursor = AlignPow2(expected_image_header_size + sizeof(COFF_SectionHeader), config->sect_align);
|
||||
for (U64 i = 0; i < task.image_sects.count; i += 1) {
|
||||
lnk_assign_section_virtual_space(task.image_sects.v[i], config->sect_align, &voff_cursor);
|
||||
}
|
||||
|
||||
ProfBegin("Patch Virtual Offsets and SIzes in Obj Section Headers");
|
||||
tp_for_parallel(tp, 0, task.objs_count, lnk_patch_virtual_offsets_and_sizes_in_obj_section_headers_task, &task);
|
||||
ProfEnd();
|
||||
for EachIndex(sect_idx, task.image_sects.count) { lnk_assign_section_virtual_space(task.image_sects.v[sect_idx], config->sect_align, &voff_cursor); }
|
||||
tp_for_parallel_prof(tp, 0, task.objs_count, lnk_patch_virtual_offsets_and_sizes_in_obj_section_headers_task, &task, "Patch Virtual Offsets and Sizes in Obj Section Headers");
|
||||
|
||||
// build base relocs
|
||||
if (~config->flags & LNK_ConfigFlag_Fixed) {
|
||||
@@ -4758,35 +4367,25 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
}
|
||||
}
|
||||
|
||||
// assign file space
|
||||
// assign file offsets to sections
|
||||
U64 foff_cursor = AlignPow2(expected_image_header_size, config->file_align);
|
||||
for (U64 i = 0; i < task.image_sects.count; i += 1) {
|
||||
lnk_assign_section_file_space(task.image_sects.v[i], &foff_cursor);
|
||||
}
|
||||
|
||||
ProfBegin("Patch File Offsets And Sizes In Section Headers");
|
||||
tp_for_parallel(tp, 0, task.objs_count, lnk_patch_file_offsets_and_sizes_in_obj_section_headers_task, &task);
|
||||
ProfEnd();
|
||||
for EachIndex(sect_idx, task.image_sects.count) { lnk_assign_section_file_space(task.image_sects.v[sect_idx], &foff_cursor); }
|
||||
tp_for_parallel_prof(tp, 0, task.objs_count, lnk_patch_file_offsets_and_sizes_in_obj_section_headers_task, &task, "Patch File Offsets And Sizes In Section Headers");
|
||||
}
|
||||
|
||||
// build win32 image header
|
||||
{
|
||||
String8List image_header_data = lnk_build_win32_header(sectab->arena, symtab, config, task.image_sects, AlignPow2(expected_image_header_size, config->file_align));
|
||||
|
||||
String8List image_header_data = lnk_build_win32_header(sectab->arena, symtab, config, task.image_sects, AlignPow2(expected_image_header_size, config->file_align));
|
||||
LNK_Section *image_header_sect = lnk_section_table_push(sectab, str8_lit(".rad_linker_image_header_section"), 0);
|
||||
LNK_SectionContribChunk *image_header_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &image_header_sect->contribs, 1, str8_zero());
|
||||
LNK_SectionContrib *image_header_sc = lnk_section_contrib_chunk_push(image_header_sc_chunk, 1);
|
||||
|
||||
image_header_sc->align = config->file_align;
|
||||
image_header_sc->first_data_node = *image_header_data.first;
|
||||
image_header_sc->last_data_node = image_header_data.last;
|
||||
|
||||
lnk_finalize_section_layout(image_header_sect, config->file_align, config->function_pad_min);
|
||||
}
|
||||
|
||||
ProfBegin("Patch Section Symbols");
|
||||
tp_for_parallel(tp, 0, task.objs_count, lnk_patch_section_symbols_task, &task);
|
||||
ProfEnd();
|
||||
tp_for_parallel_prof(tp, 0, task.objs_count, lnk_patch_section_symbols_task, &task, "Patch Section Symbols");
|
||||
|
||||
String8 image_data = {0};
|
||||
{
|
||||
@@ -4795,14 +4394,12 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
LNK_SectionArray sects = lnk_section_array_from_list(scratch.arena, sectab->list);
|
||||
|
||||
U64 image_size = 0;
|
||||
for (U64 sect_idx = 0; sect_idx < sects.count; sect_idx += 1) {
|
||||
image_size += sects.v[sect_idx]->fsize;
|
||||
}
|
||||
for EachIndex(sect_idx, sects.count) { image_size += sects.v[sect_idx]->fsize; }
|
||||
|
||||
image_data.size = image_size;
|
||||
image_data.str = push_array_no_zero(arena->v[0], U8, image_size);
|
||||
|
||||
for (U64 sect_idx = 0; sect_idx < sects.count; sect_idx += 1) {
|
||||
for EachIndex(sect_idx, sects.count) {
|
||||
LNK_Section *sect = sects.v[sect_idx];
|
||||
|
||||
if (~sect->flags & COFF_SectionFlag_CntUninitializedData) {
|
||||
@@ -4815,7 +4412,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
// copy section contribution
|
||||
U64 prev_sc_opl = 0;
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
for EachIndex(sc_idx, sc_chunk->count) {
|
||||
LNK_SectionContrib *sc = sc_chunk->v[sc_idx];
|
||||
|
||||
// fill align bytes
|
||||
@@ -4855,14 +4452,8 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
|
||||
// patch relocs
|
||||
{
|
||||
ProfBegin("Patch Relocs");
|
||||
LNK_ObjRelocPatcher task = {0};
|
||||
task.image_data = image_data;
|
||||
task.objs = objs;
|
||||
task.image_base = pe.image_base;
|
||||
task.image_section_table = image_section_table;
|
||||
tp_for_parallel(tp, 0, objs_count, lnk_obj_reloc_patcher, &task);
|
||||
ProfEnd();
|
||||
LNK_ObjRelocPatcher task = { .image_data = image_data, .objs = objs, .image_base = pe.image_base, .image_section_table = image_section_table };
|
||||
tp_for_parallel_prof(tp, 0, objs_count, lnk_obj_reloc_patcher, &task, "Patch Relocs");
|
||||
}
|
||||
|
||||
// patch load config
|
||||
@@ -4964,7 +4555,7 @@ lnk_build_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolT
|
||||
U64 tls_align = 0;
|
||||
LNK_Section *tls_sect = lnk_section_table_search(sectab, str8_lit(".tls"), PE_TLS_SECTION_FLAGS);
|
||||
for (LNK_SectionContribChunk *sc_chunk = tls_sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
for EachIndex (sc_idx, sc_chunk->count) {
|
||||
Assert(IsPow2(sc_chunk->v[sc_idx]->align));
|
||||
tls_align = Max(tls_align, sc_chunk->v[sc_idx]->align);
|
||||
}
|
||||
|
||||
+1
-28
@@ -25,32 +25,6 @@ typedef struct LNK_ImageContext
|
||||
LNK_SectionTable *sectab;
|
||||
} LNK_ImageContext;
|
||||
|
||||
typedef struct LNK_SymbolTableFixup
|
||||
{
|
||||
U32 idx;
|
||||
U32 obj_idx;
|
||||
U32 obj_symbol_idx;
|
||||
} LNK_SymbolTableFixup;
|
||||
|
||||
typedef struct LNK_SymbolTableFixupNode
|
||||
{
|
||||
LNK_SymbolTableFixup data;
|
||||
struct LNK_SymbolTableFixupNode *next;
|
||||
} LNK_SymbolTableFixupNode;
|
||||
|
||||
typedef struct LNK_SymbolTableFixupList
|
||||
{
|
||||
U64 count;
|
||||
LNK_SymbolTableFixupNode *first;
|
||||
LNK_SymbolTableFixupNode *last;
|
||||
} LNK_SymbolTableFixupList;
|
||||
|
||||
typedef struct LNK_SymbolTableFixupArray
|
||||
{
|
||||
U64 count;
|
||||
LNK_SymbolTableFixup *v;
|
||||
} LNK_SymbolTableFixupArray;
|
||||
|
||||
typedef struct LNK_SectionDefinition
|
||||
{
|
||||
String8 name;
|
||||
@@ -108,7 +82,6 @@ typedef struct
|
||||
U64 function_pad_min;
|
||||
U64 default_align;
|
||||
LNK_SectionContrib *null_sc;
|
||||
LNK_SymbolTableFixupArray *obj_symtab_fixups;
|
||||
LNK_SectionContrib ***sect_map;
|
||||
HashTable *contribs_ht;
|
||||
LNK_SectionArray image_sects;
|
||||
@@ -127,7 +100,7 @@ typedef struct
|
||||
struct {
|
||||
B8 **was_symbol_patched;
|
||||
LNK_Section *common_block_sect;
|
||||
Rng1U64 *ranges;
|
||||
Rng1U64 *common_block_ranges;
|
||||
LNK_CommonBlockContrib *common_block_contribs;
|
||||
COFF_SymbolValueInterpType fixup_type;
|
||||
} patch_symtabs;
|
||||
|
||||
+20
-1
@@ -352,7 +352,6 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table)
|
||||
case COFF_SymbolValueInterp_Weak: {
|
||||
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_list_push(arena, &task->weak_lists[worker_id], defn);
|
||||
} break;
|
||||
case COFF_SymbolValueInterp_Common: {
|
||||
@@ -466,6 +465,19 @@ lnk_coff_section_header_from_section_number(LNK_Obj *obj, U64 section_number)
|
||||
return section_header;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_length_out, U32 *check_sum_out)
|
||||
{
|
||||
Assert(section_number > 0);
|
||||
U32 symbol_idx = obj->comdats[section_number-1];
|
||||
if (symbol_idx != max_U32) {
|
||||
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(obj, symbol_idx);
|
||||
coff_parse_secdef(secdef, obj->header.is_big_obj, select_out, 0, section_length_out, check_sum_out);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx)
|
||||
{
|
||||
@@ -533,6 +545,13 @@ lnk_collect_obj_sections(TP_Context *tp, TP_Arena *arena, U64 objs_count, LNK_Ob
|
||||
return task.out_lists;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_obj_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_Obj *a = raw_a, *b = raw_b;
|
||||
return a->input_idx < b->input_idx;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_parse_msvc_linker_directive(Arena *arena, LNK_Obj *obj, LNK_DirectiveInfo *directive_info, String8 buffer)
|
||||
{
|
||||
|
||||
@@ -109,6 +109,7 @@ internal U32 lnk_obj_get_vol_md(LNK_Obj *obj);
|
||||
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 B32 lnk_try_comdat_props_from_section_number(LNK_Obj *obj, U32 section_number, COFF_ComdatSelectType *select_out, U32 *section_length_out, U32 *check_sum_out);
|
||||
internal B32 lnk_is_coff_section_debug(LNK_Obj *obj, U64 sect_idx);
|
||||
|
||||
// --- Helpers -----------------------------------------------------------------
|
||||
|
||||
+164
-75
@@ -39,6 +39,20 @@ lnk_make_undefined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj)
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_symbol_defined_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_Symbol *a = raw_a, *b = raw_b;
|
||||
return a->u.defined.obj->input_idx < b->u.defined.obj->input_idx;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_symbol_lib_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_Symbol *a = raw_a, *b = raw_b;
|
||||
return a->u.lib.lib->input_idx < b->u.lib.lib->input_idx;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node)
|
||||
{
|
||||
@@ -123,41 +137,27 @@ lnk_error_multiply_defined_symbol(LNK_Symbol *dst, LNK_Symbol *src)
|
||||
internal B32
|
||||
lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
{
|
||||
//Assert(src->type != LNK_Symbol_Undefined);
|
||||
Assert(dst != src);
|
||||
Assert(str8_match(dst->name, src->name, 0));
|
||||
|
||||
B32 can_replace = 0;
|
||||
|
||||
switch (scope) {
|
||||
case LNK_SymbolScope_Lib: {
|
||||
// link.exe picks symbol from lib that is discovered first
|
||||
can_replace = src->u.lib.lib->input_idx < dst->u.lib.lib->input_idx;
|
||||
} break;
|
||||
case LNK_SymbolScope_Import: {
|
||||
can_replace = 1;
|
||||
} break;
|
||||
case LNK_SymbolScope_Defined: {
|
||||
LNK_Obj *dst_obj = dst->u.defined.obj;
|
||||
LNK_Obj *src_obj = src->u.defined.obj;
|
||||
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx);
|
||||
|
||||
COFF_SymbolValueInterpType dst_interp = coff_interp_symbol(dst_parsed.section_number, dst_parsed.value, dst_parsed.storage_class);
|
||||
COFF_SymbolValueInterpType src_interp = coff_interp_symbol(src_parsed.section_number, src_parsed.value, src_parsed.storage_class);
|
||||
LNK_Obj *dst_obj = dst->u.defined.obj;
|
||||
LNK_Obj *src_obj = src->u.defined.obj;
|
||||
COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_coff_symbol_idx(dst->u.defined.obj, dst->u.defined.symbol_idx);
|
||||
COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_coff_symbol_idx(src->u.defined.obj, src->u.defined.symbol_idx);
|
||||
COFF_SymbolValueInterpType dst_interp = coff_interp_from_parsed_symbol(dst_parsed);
|
||||
COFF_SymbolValueInterpType src_interp = coff_interp_from_parsed_symbol(src_parsed);
|
||||
|
||||
// regular vs abs
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
// abs vs regular
|
||||
else if ((dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) ||
|
||||
(dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Abs)) {
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
// abs vs common
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Common) {
|
||||
if (dst->u.defined.obj->input_idx < src->u.defined.obj->input_idx) {
|
||||
if (lnk_symbol_defined_is_before(dst, src)) {
|
||||
can_replace = 1;
|
||||
} else {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
@@ -165,43 +165,35 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
}
|
||||
// common vs abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
if (dst->u.defined.obj->input_idx < src->u.defined.obj->input_idx) {
|
||||
if (lnk_symbol_defined_is_before(dst, src)) {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
}
|
||||
// abs vs abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
// weak vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
can_replace = src->u.defined.obj->input_idx < dst->u.defined.obj->input_idx;
|
||||
can_replace = lnk_symbol_defined_is_before(src, dst);
|
||||
}
|
||||
// weak vs abs
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Abs) {
|
||||
// weak vs regular/abs/common
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Abs || src_interp == COFF_SymbolValueInterp_Common)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// abs vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Abs && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
// regular/abs/common vs weak
|
||||
else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Abs || dst_interp == COFF_SymbolValueInterp_Common) && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
can_replace = 0;
|
||||
}
|
||||
// weak vs (regular, common, abs)
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Weak && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common || src_interp == COFF_SymbolValueInterp_Abs)) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// regular vs weak
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Regular && src_interp == COFF_SymbolValueInterp_Weak) {
|
||||
can_replace = 0;
|
||||
}
|
||||
// (regular, common) vs (regular, common)
|
||||
// regular/common vs regular/common
|
||||
else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) {
|
||||
// parse dst symbol properties
|
||||
B32 dst_is_comdat = 0;
|
||||
COFF_ComdatSelectType dst_select;
|
||||
U32 dst_section_length;
|
||||
U32 dst_check_sum;
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular) {
|
||||
U32 dst_comdat_symbol_idx = dst_obj->comdats[dst_parsed.section_number-1];
|
||||
if (dst_comdat_symbol_idx != max_U32) {
|
||||
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(dst_obj, dst_comdat_symbol_idx);
|
||||
coff_parse_secdef(secdef, dst_obj->header.is_big_obj, &dst_select, 0, &dst_section_length, &dst_check_sum);
|
||||
dst_is_comdat = 1;
|
||||
}
|
||||
dst_is_comdat = lnk_try_comdat_props_from_section_number(dst->u.defined.obj, dst_parsed.section_number, &dst_select, &dst_section_length, &dst_check_sum);
|
||||
} else if (dst_interp == COFF_SymbolValueInterp_Common) {
|
||||
dst_select = COFF_ComdatSelect_Largest;
|
||||
dst_section_length = dst_parsed.value;
|
||||
@@ -209,17 +201,13 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
dst_is_comdat = 1;
|
||||
}
|
||||
|
||||
// parse src symbol properties
|
||||
B32 src_is_comdat = 0;
|
||||
COFF_ComdatSelectType src_select;
|
||||
U32 src_section_length;
|
||||
U32 src_section_length, src_checks;
|
||||
U32 src_check_sum;
|
||||
if (src_interp == COFF_SymbolValueInterp_Regular) {
|
||||
U32 src_comdat_symbol_idx = src_obj->comdats[src_parsed.section_number-1];
|
||||
if (src_comdat_symbol_idx != max_U32) {
|
||||
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(src_obj, src_comdat_symbol_idx);
|
||||
coff_parse_secdef(secdef, src_obj->header.is_big_obj, &src_select, 0, &src_section_length, &src_check_sum);
|
||||
src_is_comdat = 1;
|
||||
}
|
||||
src_is_comdat = lnk_try_comdat_props_from_section_number(src->u.defined.obj, src_parsed.section_number, &src_select, &src_section_length, &src_check_sum);
|
||||
} else if (src_interp == COFF_SymbolValueInterp_Common) {
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
src_section_length = src_parsed.value;
|
||||
@@ -228,18 +216,15 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
}
|
||||
|
||||
// regular non-comdat vs communal
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat &&
|
||||
src_interp == COFF_SymbolValueInterp_Common) {
|
||||
if (dst_interp == COFF_SymbolValueInterp_Regular && !dst_is_comdat && src_interp == COFF_SymbolValueInterp_Common) {
|
||||
can_replace = 0;
|
||||
}
|
||||
// communal vs regular non-comdat
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Common &&
|
||||
src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) {
|
||||
else if (dst_interp == COFF_SymbolValueInterp_Common && src_interp == COFF_SymbolValueInterp_Regular && !src_is_comdat) {
|
||||
can_replace = 1;
|
||||
}
|
||||
// handle COMDATs
|
||||
else if (dst_is_comdat && src_is_comdat) {
|
||||
// handle objs compiled with /GR- and /GR
|
||||
if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest)) {
|
||||
src_select = COFF_ComdatSelect_Largest;
|
||||
}
|
||||
@@ -252,7 +237,7 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
case COFF_ComdatSelect_Null:
|
||||
case COFF_ComdatSelect_Any: {
|
||||
if (src_section_length == dst_section_length) {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
can_replace = lnk_obj_is_before(src_obj, dst_obj);
|
||||
} else {
|
||||
// both COMDATs are valid but to get smaller exe pick smallest
|
||||
can_replace = src_section_length < dst_section_length;
|
||||
@@ -263,19 +248,17 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
} break;
|
||||
case COFF_ComdatSelect_SameSize: {
|
||||
if (dst_section_length == src_section_length) {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
can_replace = lnk_obj_is_before(src_obj, dst_obj);
|
||||
} else {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_ExactMatch: {
|
||||
COFF_SectionHeader *dst_section_table = (COFF_SectionHeader *)str8_substr(dst_obj->data, dst_obj->header.section_table_range).str;
|
||||
COFF_SectionHeader *src_section_table = (COFF_SectionHeader *)str8_substr(src_obj->data, src_obj->header.section_table_range).str;
|
||||
COFF_SectionHeader *dst_sect_header = &dst_section_table[dst_parsed.section_number-1];
|
||||
COFF_SectionHeader *src_sect_header = &src_section_table[src_parsed.section_number-1];
|
||||
String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize));
|
||||
String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize));
|
||||
B32 is_exact_match = 0;
|
||||
COFF_SectionHeader *dst_sect_header = lnk_coff_section_header_from_section_number(dst_obj, dst_parsed.section_number);
|
||||
COFF_SectionHeader *src_sect_header = lnk_coff_section_header_from_section_number(src_obj, src_parsed.section_number);
|
||||
String8 dst_data = str8_substr(dst_obj->data, rng_1u64(dst_sect_header->foff, dst_sect_header->foff + dst_sect_header->fsize));
|
||||
String8 src_data = str8_substr(src_obj->data, rng_1u64(src_sect_header->foff, src_sect_header->foff + src_sect_header->fsize));
|
||||
B32 is_exact_match = 0;
|
||||
if (dst_check_sum != 0 && src_check_sum != 0) {
|
||||
is_exact_match = dst_check_sum == src_check_sum && str8_match(dst_data, src_data, 0);
|
||||
} else {
|
||||
@@ -283,29 +266,25 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
}
|
||||
|
||||
if (is_exact_match) {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
can_replace = lnk_obj_is_before(src_obj, dst_obj);
|
||||
} else {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Largest: {
|
||||
if (dst_section_length == src_section_length) {
|
||||
can_replace = src_obj->input_idx < dst_obj->input_idx;
|
||||
can_replace = lnk_obj_is_before(src_obj, dst_obj);
|
||||
} else {
|
||||
can_replace = dst_section_length < src_section_length;
|
||||
}
|
||||
} break;
|
||||
case COFF_ComdatSelect_Associative: {
|
||||
// ignore
|
||||
} break;
|
||||
default: { InvalidPath; }
|
||||
case COFF_ComdatSelect_Associative: { /* ignore */ } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
} else {
|
||||
String8 src_select_str = coff_string_from_comdat_select_type(src_select);
|
||||
String8 dst_select_str = coff_string_from_comdat_select_type(dst_select);
|
||||
lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj,
|
||||
"%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S",
|
||||
src->name, src_select_str, dst_select_str, dst_obj);
|
||||
src->name, coff_string_from_comdat_select_type(src_select), coff_string_from_comdat_select_type(dst_select), dst_obj);
|
||||
}
|
||||
} else {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
@@ -314,9 +293,15 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src)
|
||||
lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination");
|
||||
}
|
||||
} break;
|
||||
case LNK_SymbolScope_Import: {
|
||||
lnk_error_multiply_defined_symbol(dst, src);
|
||||
} break;
|
||||
case LNK_SymbolScope_Lib: {
|
||||
// link.exe picks symbol from lib that is discovered first
|
||||
can_replace = lnk_symbol_lib_is_before(src, dst);
|
||||
} break;
|
||||
default: { InvalidPath; }
|
||||
}
|
||||
|
||||
return can_replace;
|
||||
}
|
||||
|
||||
@@ -521,6 +506,110 @@ lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, LNK_Obj *obj, String8 fr
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
THREAD_POOL_TASK_FUNC(lnk_finalize_weak_symbols_task)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena,1);
|
||||
|
||||
LNK_FinalizeWeakSymbolsTask *task = raw_task;
|
||||
LNK_SymbolTable *symtab = task->symtab;
|
||||
LNK_SymbolHashTrieChunk *chunk = task->chunks[task_id];
|
||||
|
||||
for EachIndex(i, chunk->count) {
|
||||
LNK_Symbol *symbol = chunk->v[i].symbol;
|
||||
COFF_ParsedSymbol symbol_parsed = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol_parsed.section_number, symbol_parsed.value, symbol_parsed.storage_class);
|
||||
if (symbol_interp == COFF_SymbolValueInterp_Weak) {
|
||||
struct LookupLocation { struct LookupLocation *next; LNK_SymbolDefined symbol; };
|
||||
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;
|
||||
}
|
||||
|
||||
// record visited symbol
|
||||
struct LookupLocation *loc = push_array(scratch.arena, struct LookupLocation, 1);
|
||||
loc->symbol = current_symbol;
|
||||
SLLQueuePush(lookup_first, lookup_last, loc);
|
||||
|
||||
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 && current_interp != COFF_SymbolValueInterp_Undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
// does weak symbol have the strong 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 strong 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 };
|
||||
}
|
||||
|
||||
// replace weak symbol with it's tag
|
||||
symbol->u.defined = current_symbol;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_finalize_weak_symbols(TP_Context *tp, LNK_SymbolTable *symtab)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,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 = 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 };
|
||||
tp_for_parallel(tp, 0, chunks_count, lnk_finalize_weak_symbols_task, &task);
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
lnk_parsed_symbol_from_defined(LNK_Symbol *symbol)
|
||||
{
|
||||
|
||||
@@ -107,6 +107,14 @@ typedef struct LNK_SymbolTable
|
||||
HashTable *alt_names;
|
||||
} LNK_SymbolTable;
|
||||
|
||||
// --- Workers Contensts -------------------------------------------------------
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LNK_SymbolTable *symtab;
|
||||
LNK_SymbolHashTrieChunk **chunks;
|
||||
} LNK_FinalizeWeakSymbolsTask;
|
||||
|
||||
// --- Symbol Make -------------------------------------------------------------
|
||||
|
||||
internal LNK_Symbol * lnk_make_defined_symbol(Arena *arena, String8 name, struct LNK_Obj *obj, U32 symbol_idx);
|
||||
@@ -140,6 +148,8 @@ internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK
|
||||
|
||||
internal void lnk_symbol_table_push_alt_name(LNK_SymbolTable *symtab, struct LNK_Obj *obj, String8 from, String8 to);
|
||||
|
||||
internal void lnk_finalize_weak_symbols(TP_Context *tp, LNK_SymbolTable *symtab);
|
||||
|
||||
// --- Symbol Contrib Helpers --------------------------------------------------
|
||||
|
||||
internal ISectOff lnk_sc_from_symbol(LNK_Symbol *symbol);
|
||||
|
||||
+163
-64
@@ -60,13 +60,13 @@ t_string_from_result(T_Result v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
global String8 g_stdout_file_name = str8_lit_comp("torture");
|
||||
global String8 g_stdout_file_name = str8_lit_comp("torture.out");
|
||||
global U64 g_linker_time_out;
|
||||
global String8 g_linker;
|
||||
global String8 g_wdir;
|
||||
global String8 g_out = str8_lit_comp("torture");
|
||||
global B32 g_verbose;
|
||||
global B32 g_redirect_stdout;
|
||||
global B32 g_redirect_stdout = 1;
|
||||
|
||||
#define T_LINKER_TIME_OUT_EXIT_CODE 999999
|
||||
|
||||
@@ -743,6 +743,128 @@ exit:;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal T_Result
|
||||
t_weak_vs_weak(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
T_Result result = T_Result_Fail;
|
||||
|
||||
String8 a_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".a"), PE_DATA_SECTION_FLAGS, str8_lit("a"));
|
||||
COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_a"), 0, sect);
|
||||
coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol);
|
||||
a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
String8 b_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".b"), PE_DATA_SECTION_FLAGS, str8_lit("b"));
|
||||
COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_b"), 0, sect);
|
||||
coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol);
|
||||
b_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
|
||||
String8 entry_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
U8 text[] = {
|
||||
0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm
|
||||
0xC3 // ret
|
||||
};
|
||||
COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text));
|
||||
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect);
|
||||
COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("w"));
|
||||
coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, symbol);
|
||||
entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; }
|
||||
if (!t_write_file(str8_lit("b.obj"), b_obj)) { goto exit; }
|
||||
if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; }
|
||||
|
||||
int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj b.obj entry.obj");
|
||||
if (linker_exit_code != 0) { goto exit; }
|
||||
|
||||
result = T_Result_Pass;
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal T_Result
|
||||
t_weak_vs_common(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
T_Result result = T_Result_Fail;
|
||||
|
||||
String8 weak_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".a"), PE_DATA_SECTION_FLAGS, str8_lit("a"));
|
||||
COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_a"), 0, sect);
|
||||
coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol);
|
||||
weak_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
String8 common_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
coff_obj_writer_push_symbol_common(obj_writer, str8_lit("w"), 2);
|
||||
common_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
String8 entry_obj;
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
U8 text[] = {
|
||||
0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm
|
||||
0xC3 // ret
|
||||
};
|
||||
COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text));
|
||||
coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect);
|
||||
COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("w"));
|
||||
coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, symbol);
|
||||
entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
if (!t_write_file(str8_lit("weak.obj"), weak_obj)) { goto exit; }
|
||||
if (!t_write_file(str8_lit("common.obj"), common_obj)) { goto exit; }
|
||||
if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; }
|
||||
|
||||
int linker_exit_code;
|
||||
|
||||
linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe common.obj weak.obj entry.obj");
|
||||
if (linker_exit_code != 0) { goto exit; }
|
||||
|
||||
linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe weak.obj common.obj entry.obj");
|
||||
if (linker_exit_code != 0) { goto exit; }
|
||||
|
||||
String8 exe = t_read_file(scratch.arena, str8_lit("a.exe"));
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe);
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
|
||||
String8 string_table = str8_substr(exe, pe.string_table_range);
|
||||
|
||||
COFF_SectionHeader *bss = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".bss"));
|
||||
if (!bss) { goto exit; }
|
||||
if (bss->fsize != 0) { goto exit; }
|
||||
if (bss->vsize != 2) { goto exit; }
|
||||
|
||||
result = T_Result_Pass;
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal T_Result
|
||||
t_abs_vs_weak(void)
|
||||
{
|
||||
@@ -750,8 +872,8 @@ t_abs_vs_weak(void)
|
||||
|
||||
T_Result result = T_Result_Fail;
|
||||
|
||||
U32 abs_value = 0x123;
|
||||
U8 text_code[] = { 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3 };
|
||||
U32 abs_value = 0x123;
|
||||
U8 text_code[] = { 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3 };
|
||||
|
||||
String8 abs_obj;
|
||||
{
|
||||
@@ -777,27 +899,14 @@ t_abs_vs_weak(void)
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
}
|
||||
|
||||
{
|
||||
B32 was_file_written = 0;
|
||||
was_file_written = t_write_file(str8_lit("abs.obj"), abs_obj);
|
||||
if (!was_file_written) {
|
||||
goto exit;
|
||||
}
|
||||
was_file_written = t_write_file(str8_lit("text.obj"), text_obj);
|
||||
if (!was_file_written) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (!t_write_file(str8_lit("abs.obj"), abs_obj)) { goto exit; }
|
||||
if (!t_write_file(str8_lit("text.obj"), text_obj)) { goto exit; }
|
||||
|
||||
int abs_vs_weak_exit_code = t_invoke_linker(str8_lit("/subsystem:console /entry:my_entry /out:a.exe abs.obj text.obj"));
|
||||
if (abs_vs_weak_exit_code != 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (abs_vs_weak_exit_code != 0) { goto exit; }
|
||||
|
||||
int weak_vs_abs_exit_code = t_invoke_linker(str8_lit("/subsystem:console /entry:my_entry /out:a.exe text.obj abs.obj"));
|
||||
if (weak_vs_abs_exit_code != 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (weak_vs_abs_exit_code != 0) { goto exit; }
|
||||
|
||||
String8 exe = t_read_file(scratch.arena, str8_lit("a.exe"));
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe);
|
||||
@@ -805,18 +914,17 @@ t_abs_vs_weak(void)
|
||||
String8 string_table = str8_substr(exe, pe.string_table_range);
|
||||
|
||||
COFF_SectionHeader *text_section = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text"));
|
||||
if (text_section) {
|
||||
String8 text_data = str8_substr(exe, rng_1u64(text_section->foff, text_section->foff + text_section->fsize));
|
||||
String8 inst = str8_prefix(text_data, 2);
|
||||
if (str8_match(inst, str8_array(text_code, 2), 0)) {
|
||||
String8 imm = str8_prefix(str8_skip(text_data, 2), 8);
|
||||
U64 expected_imm = abs_value;
|
||||
if (str8_match(imm, str8_struct(&expected_imm), 0)) {
|
||||
result = T_Result_Pass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (text_section == 0) { goto exit; }
|
||||
|
||||
String8 text_data = str8_substr(exe, rng_1u64(text_section->foff, text_section->foff + text_section->fsize));
|
||||
String8 inst = str8_prefix(text_data, 2);
|
||||
if (!str8_match(inst, str8_array(text_code, 2), 0)) { goto exit; }
|
||||
|
||||
String8 imm = str8_prefix(str8_skip(text_data, 2), 8);
|
||||
U64 expected_imm = abs_value;
|
||||
if (!str8_match(imm, str8_struct(&expected_imm), 0)) { goto exit; }
|
||||
|
||||
result = T_Result_Pass;
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
@@ -1100,30 +1208,27 @@ internal T_Result
|
||||
t_weak_tag(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
T_Result result = T_Result_Fail;
|
||||
|
||||
U32 weak_tag_expected_value = 0x12345678;
|
||||
String8 weak_tag_obj_name = str8_lit("weak_tag.obj");
|
||||
U32 weak_tag_expected_value = 0x12345678;
|
||||
String8 weak_tag_obj_name = str8_lit("weak_tag.obj");
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
COFF_ObjSymbol *tag_symbol = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("abs"), weak_tag_expected_value, COFF_SymStorageClass_Static);
|
||||
COFF_ObjSymbol *weak_first = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("strong_first"), COFF_WeakExt_SearchAlias, tag_symbol);
|
||||
COFF_ObjSymbol *weak_second = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("strong_second"), COFF_WeakExt_SearchAlias, weak_first);
|
||||
|
||||
U8 sect_data[] = { 0, 0, 0, 0 };
|
||||
U8 sect_data[4] = {0};
|
||||
COFF_ObjSection *sect = t_push_data_section(obj_writer, str8_array_fixed(sect_data));
|
||||
coff_obj_writer_section_push_reloc(obj_writer, sect, 0, weak_second, COFF_Reloc_X64_Addr32);
|
||||
|
||||
String8 weak_tag_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
if (!t_write_file(weak_tag_obj_name, weak_tag_obj)) {
|
||||
goto exit;
|
||||
}
|
||||
if (!t_write_file(weak_tag_obj_name, weak_tag_obj)) { goto exit; }
|
||||
}
|
||||
|
||||
String8 entry_name = str8_lit("my_entry");
|
||||
U8 entry_text[] = { 0xC3 };
|
||||
String8 entry_name = str8_lit("my_entry");
|
||||
U8 entry_text[] = { 0xC3 };
|
||||
String8 entry_obj_name = str8_lit("entry.obj");
|
||||
{
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64);
|
||||
@@ -1131,31 +1236,23 @@ t_weak_tag(void)
|
||||
coff_obj_writer_push_symbol_extern(obj_writer, entry_name, 0, text_sect);
|
||||
String8 entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
if (!t_write_file(entry_obj_name, entry_obj)) {
|
||||
goto exit;
|
||||
}
|
||||
if (!t_write_file(entry_obj_name, entry_obj)) { goto exit; }
|
||||
}
|
||||
|
||||
int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:my_entry /out:a.exe %S %S", weak_tag_obj_name, entry_obj_name);
|
||||
if (linker_exit_code == 0) {
|
||||
String8 exe = t_read_file(scratch.arena, str8_lit("a.exe"));
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe);
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
|
||||
String8 string_table = str8_substr(exe, pe.string_table_range);
|
||||
if (linker_exit_code != 0) { goto exit; }
|
||||
|
||||
COFF_SectionHeader *data_section = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".data"));
|
||||
if (!data_section) {
|
||||
goto exit;
|
||||
}
|
||||
if (data_section->vsize != 4) {
|
||||
goto exit;
|
||||
}
|
||||
String8 data = str8_substr(exe, rng_1u64(data_section->foff, data_section->foff + data_section->vsize));
|
||||
if (str8_match(data, str8_struct(&weak_tag_expected_value), 0)) {
|
||||
result = T_Result_Pass;
|
||||
}
|
||||
}
|
||||
String8 exe = t_read_file(scratch.arena, str8_lit("a.exe"));
|
||||
PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe);
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str;
|
||||
String8 string_table = str8_substr(exe, pe.string_table_range);
|
||||
COFF_SectionHeader *data_section = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".data"));
|
||||
String8 data = str8_substr(exe, rng_1u64(data_section->foff, data_section->foff + data_section->vsize));
|
||||
if (!data_section) { goto exit; }
|
||||
if (data_section->vsize != 4) { goto exit; }
|
||||
if (!str8_match(data, str8_struct(&weak_tag_expected_value), 0)) { goto exit; }
|
||||
|
||||
result = T_Result_Pass;
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
@@ -3670,7 +3767,7 @@ entry_point(CmdLine *cmdline)
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
|
||||
//
|
||||
// Targets
|
||||
// Test Targets
|
||||
//
|
||||
static struct {
|
||||
char *label; T_Result (*r)(void);
|
||||
@@ -3681,6 +3778,8 @@ entry_point(CmdLine *cmdline)
|
||||
{ "merge", t_merge },
|
||||
{ "undef_section", t_undef_section },
|
||||
{ "undef_reloc_section", t_undef_reloc_section },
|
||||
{ "weak_vs_weak", t_weak_vs_weak },
|
||||
{ "weak_vs_common", t_weak_vs_common },
|
||||
{ "abs_vs_weak", t_abs_vs_weak },
|
||||
{ "abs_vs_regular", t_abs_vs_regular },
|
||||
{ "abs_vs_common", t_abs_vs_common },
|
||||
|
||||
Reference in New Issue
Block a user