From 8da56025b3fdbe4112734b9bb529b42504bc98b2 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 8 May 2025 15:55:12 -0700 Subject: [PATCH] patch section symbol and test for relocations to discarded memory --- src/linker/lnk.c | 73 +++++++++++++++++++++++++------- src/linker/lnk_error.h | 1 + src/linker/lnk_obj.c | 10 ++++- src/linker/lnk_section_table.c | 76 +++++++++++++++++++--------------- src/linker/lnk_section_table.h | 2 +- src/torture/torture.c | 23 +++++----- 6 files changed, 122 insertions(+), 63 deletions(-) diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 518cc8b9..133d9eec 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1592,7 +1592,7 @@ THREAD_POOL_TASK_FUNC(lnk_emit_base_relocs_from_objs_task) COFF_ParsedSymbol symbol = lnk_parsed_symbol_from_coff_symbol_idx(obj, r->isymbol); COFF_SymbolValueInterpType symbol_interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - B32 is_symbol_address = symbol_interp == COFF_SymbolValueInterp_Regular; + B32 is_symbol_address = symbol_interp != COFF_SymbolValueInterp_Abs; if (is_symbol_address) { B32 is_addr32 = 0, is_addr64 = 0; @@ -2155,6 +2155,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S for (U64 defn_idx = 0; defn_idx < sect_defns_count; defn_idx += 1) { LNK_SectionDefinition *sect_defn = sect_defns[defn_idx]; + // warn about conflicting section flags for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { LNK_Section *sect = §_n->data; if (str8_match(sect->name, sect_defn->name, 0)) { @@ -2172,6 +2173,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S } } + // reserve chunk for contribs LNK_Section *sect = lnk_section_table_search(sectab, sect_defn->name, sect_defn->flags); if (sect == 0) { sect = lnk_section_table_push(sectab, sect_defn->name, sect_defn->flags); @@ -2185,7 +2187,6 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S ProfEnd(); } - U64 expected_image_header_size; { // gather section contribs @@ -2228,8 +2229,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S data_n->string = sect_data; // fill out contrib - LNK_SectionContribChunk *sc_chunk = sect->contribs.first; - LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(sc_chunk, 1); + LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(sect->contribs.first, 1); sc->align = sc_align; sc->data_list = data_n; sc->u.obj_idx = obj_idx; @@ -2552,17 +2552,19 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S 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) { - LNK_Symbol *defn = lnk_symbol_table_search(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 (symbol.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *defn = lnk_symbol_table_search(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; + 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 } - - lnk_patch_weak_external_symbol(obj->header.is_big_obj, symbol.raw_symbol, defn_symbol); - } else { - // TODO: collect unresolved undefined } } } @@ -2731,9 +2733,9 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S if (~config->flags & LNK_ConfigFlag_Fixed) { String8List base_relocs_data = lnk_build_base_relocs(tp, arena, config, objs_count, objs); if (base_relocs_data.total_size) { - LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); - LNK_SectionContribChunk *sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1); - LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(sc_chunk, 1); + LNK_Section *reloc = lnk_section_table_push(sectab, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); + LNK_SectionContribChunk *first_sc_chunk = lnk_section_contrib_chunk_list_push_chunk(sectab->arena, &reloc->contribs, 1); + LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(first_sc_chunk, 1); sc->data_list = base_relocs_data.first; sc->align = 1; sc->u.sort_idx_size = 0; @@ -2790,6 +2792,45 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S sects = lnk_section_array_from_list(scratch.arena, sectab->list); } + // patch section symbols + { + for (U64 obj_idx = 0; obj_idx < objs_count; obj_idx += 1) { + LNK_Obj *obj = objs[obj_idx]; + + 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_Section) { + LNK_Section *sect = lnk_section_table_search(sectab, symbol.name, symbol.value); + if (sect) { + if (~sect->flags & COFF_SectionFlag_MemDiscardable) { + LNK_SectionContrib *first_sc = lnk_get_first_section_contrib(sect); + if (obj->header.is_big_obj) { + COFF_Symbol32 *symbol32 = symbol.raw_symbol; + symbol32->section_number = safe_cast_u32(first_sc->u.sect_idx + 1); + symbol32->value = first_sc->u.off; + symbol32->storage_class = COFF_SymStorageClass_Static; + } else { + COFF_Symbol16 *symbol16 = symbol.raw_symbol; + symbol16->section_number = safe_cast_u16(first_sc->u.sect_idx + 1); + symbol16->value = first_sc->u.off; + symbol16->storage_class = COFF_SymStorageClass_Static; + } + } else { + lnk_error_obj(LNK_Error_SectRefsDiscardedMemory, obj, "symbol %S (No. 0x%llx) references section with discard flag", symbol.name, symbol_idx); + } + } else { + lnk_error_obj(LNK_Error_UndefinedSymbol, obj, "undefined section symbol %S (No 0x%llx) refers to section that does not exist", symbol.name, symbol_idx); + } + } + } + } + } + } + String8 image_data = {0}; { ProfBegin("Image Fill"); diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index b528a8ef..b00f8491 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -33,6 +33,7 @@ typedef enum LNK_Error_LargeAddrAwareRequired, LNK_Error_InvalidPath, LNK_Error_MultiplyDefinedSymbol, + LNK_Error_SectRefsDiscardedMemory, LNK_Error_StopLast, LNK_Error_First, diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index 370ab8b7..6a1f12da 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -347,8 +347,14 @@ THREAD_POOL_TASK_FUNC(lnk_input_coff_symbol_table) case COFF_SymbolValueInterp_Undefined: { LNK_Symbol *s = lnk_symbol_table_search(task->symtab, LNK_SymbolScope_Defined, symbol.name); if (s == 0) { - LNK_Symbol *undef = lnk_make_undefined_symbol(arena, symbol.name, obj); - lnk_symbol_list_push(arena, &task->undef_lists[worker_id], undef); + if (symbol.storage_class == COFF_SymStorageClass_External) { + LNK_Symbol *undef = lnk_make_undefined_symbol(arena, symbol.name, obj); + lnk_symbol_list_push(arena, &task->undef_lists[worker_id], undef); + } else if (symbol.storage_class == COFF_SymStorageClass_Section) { + // lookup is performed during image patching step + } else { + Assert(!"unexpected storage class on undefined symbol"); + } } } break; case COFF_SymbolValueInterp_Debug: { diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index e1f855c6..ac36ca88 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -67,34 +67,6 @@ lnk_section_contrib_chunk_list_concat_in_place(LNK_SectionContribChunkList *list } } -internal void -lnk_section_list_remove(LNK_SectionList *list, LNK_SectionNode *node) -{ - if (list->count > 0) { - if (list->first == node) { - list->first = list->first->next; - list->count -= 1; - - if (list->last == node) { - list->last = 0; - } - } else { - for (LNK_SectionNode *curr = list->first, *prev = 0; curr != 0; prev = curr, curr = curr->next) { - if (curr == node) { - prev->next = curr->next; - list->count -= 1; - - if (list->last == curr) { - list->last = prev; - } - - break; - } - } - } - } -} - internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionList list) { @@ -108,6 +80,17 @@ lnk_section_array_from_list(Arena *arena, LNK_SectionList list) return result; } +internal LNK_SectionContrib * +lnk_get_first_section_contrib(LNK_Section *sect) +{ + if (sect->contribs.chunk_count > 0) { + if (sect->contribs.first->count > 0) { + return §->contribs.first->v[0]; + } + } + return 0; +} + internal LNK_SectionTable * lnk_section_table_alloc(void) { @@ -154,7 +137,7 @@ lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags sect->name = push_str8_copy(sect->arena, name); sect->flags = flags; sect->has_layout = 1; - + LNK_SectionList *sect_list = §ab->list; SLLQueuePush(sect_list->first, sect_list->last, sect_node); sect_list->count += 1; @@ -172,18 +155,43 @@ lnk_section_table_remove(LNK_SectionTable *sectab, String8 name) ProfBeginFunction(); // find node - LNK_SectionNode *sect_n; - for (sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { - if (str8_match(sect_n->data.name, name, 0)) { + LNK_SectionNode *node; + for (node = sectab->list.first; node != 0; node = node->next) { + if (str8_match(node->data.name, name, 0)) { break; } } // remove node - lnk_section_list_remove(§ab->list, sect_n); + { + LNK_SectionList *list = §ab->list; + if (list->count > 0) { + if (list->first == node) { + list->first = list->first->next; + list->count -= 1; + + if (list->last == node) { + list->last = 0; + } + } else { + for (LNK_SectionNode *curr = list->first, *prev = 0; curr != 0; prev = curr, curr = curr->next) { + if (curr == node) { + prev->next = curr->next; + list->count -= 1; + + if (list->last == curr) { + list->last = prev; + } + + break; + } + } + } + } + } // push to free list - SLLQueuePush(sectab->free_list.first, sectab->free_list.last, sect_n); + SLLQueuePush(sectab->free_list.first, sectab->free_list.last, node); sectab->free_list.count += 1; ProfEnd(); diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index d468728d..38e80288 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -68,6 +68,7 @@ typedef struct LNK_Section B32 is_merged; LNK_SectionContribChunkList contribs; + LNK_SectionContrib *first_contrib_chunk; U64 voff; U64 vsize; @@ -113,7 +114,6 @@ internal U16 lnk_default_align_from_machine(COFF_MachineType machine); //////////////////////////////// -internal void lnk_section_list_remove(LNK_SectionList *list, LNK_SectionNode *node); internal LNK_SectionArray lnk_section_array_from_list(Arena *arena, LNK_SectionList list); //////////////////////////////// diff --git a/src/torture/torture.c b/src/torture/torture.c index 9978a78f..4663d81d 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -891,14 +891,14 @@ t_undef_reloc_section(void) { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - U8 data[] = { 0, 0, 0, 0 }; - COFF_ObjSection *data_section = t_push_data_section(obj_writer, str8_array_fixed(data)); - COFF_ObjSymbol *foo = coff_obj_writer_push_symbol_undef_section(obj_writer, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); - coff_obj_writer_section_push_reloc(obj_writer, data_section, 0, foo, COFF_Reloc_X64_Addr32Nb); - U8 text[] = { 0xC3 }; COFF_ObjSection *text_section = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), LNK_TEXT_SECTION_FLAGS, str8_array_fixed(text)); - coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("my_entry"), 0, text_section); + COFF_ObjSymbol *my_entry_symbol = coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("my_entry"), 0, text_section); + + U8 data[8] = { 0 }; + COFF_ObjSection *data_section = t_push_data_section(obj_writer, str8_array_fixed(data)); + COFF_ObjSymbol *foo = coff_obj_writer_push_symbol_undef_section(obj_writer, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); + coff_obj_writer_section_push_reloc(obj_writer, data_section, 0, foo, COFF_Reloc_X64_Addr64); main_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); @@ -912,7 +912,11 @@ t_undef_reloc_section(void) t_write_file(str8_lit("sec_defn.obj"), sec_defn_obj); int linker_exit_code = t_invoke_linker(str8_lit("/subsystem:console /entry:my_entry /out:a.exe main.obj sec_defn.obj")); - if (linker_exit_code == 0) { + if (t_ident_linker() == T_Linker_RAD) { + if (linker_exit_code != LNK_Error_SectRefsDiscardedMemory) { + goto exit; + } + } else if (linker_exit_code == 0) { goto exit; } @@ -1428,7 +1432,6 @@ t_import_export(void) T_Result result = T_Result_Fail; - String8 export_obj_name = str8_lit("export.obj"); String8 export_obj_payload = str8_lit("test"); U8 export_text[] = { 0xC3 }; @@ -1600,8 +1603,8 @@ entry_point(CmdLine *cmdline) { "invalid_bss", t_invalid_bss }, { "common_block", t_common_block }, //{ "base_relocs", t_base_relocs }, - { "simple_lib_test", t_simple_lib_test }, - { "import_export", t_import_export }, + { "simple_lib_test", t_simple_lib_test }, + { "import_export", t_import_export }, }; //