From 2c5fb7e7ef4ba7d915bef269bd3d3d67ea48bda5 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Thu, 8 May 2025 16:30:54 -0700 Subject: [PATCH] guard against merges with resource and base reloc sections --- src/linker/lnk_config.c | 14 ++++++++++++++ src/linker/lnk_error.h | 2 ++ src/linker/lnk_section_table.c | 17 +++++++++++++++++ src/torture/torture.c | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 756b3b01..e6a1f1ce 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1306,6 +1306,20 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } break; + case LNK_CmdSwitch_Merge: { + if (value_strings.node_count == 1) { + LNK_MergeDirective merge = {0};; + if (lnk_parse_merge_directive(push_str8_copy(arena, value_strings.first->string), &merge)) { + lnk_merge_directive_list_push(arena, &config->merge_list, merge); + } else { + lnk_error_cmd_switch(LNK_Warning_InvalidMergeDirectiveFormat, obj_path, lib_path, cmd_switch, "invalid merge directive format expected \"/MERGE:FROM=TO\" but got \"%S\"", + value_strings.first->string); + } + } else { + lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "invalid number of parameters %d", value_strings.node_count); + } + } break; + case LNK_CmdSwitch_Natvis: { // warn about invalid natvis extension for (String8Node *node = value_strings.first; node != 0; node = node->next) { diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index b00f8491..d1fa096c 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -34,6 +34,7 @@ typedef enum LNK_Error_InvalidPath, LNK_Error_MultiplyDefinedSymbol, LNK_Error_SectRefsDiscardedMemory, + LNK_Error_IllegalSectionMerge, LNK_Error_StopLast, LNK_Error_First, @@ -54,6 +55,7 @@ typedef enum LNK_Error_Last, LNK_Warning_First, + LNK_Warning_InvalidMergeDirectiveFormat, LNK_Warning_AmbiguousMerge, LNK_Warning_AtypicalStartIndex, LNK_Warning_Cmdl, diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index ccc48343..e5726782 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -240,9 +240,26 @@ lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_l { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); + LNK_Section **src_dst = push_array(scratch.arena, LNK_Section *, sectab->id_max); for (LNK_MergeDirectiveNode *merge_node = merge_list.first; merge_node != 0; merge_node = merge_node->next) { LNK_MergeDirective *merge = &merge_node->data; + + // guard against illegal merges + { + local_persist String8 illegal_merge_sections[] = { + str8_lit_comp(".rsrc"), + str8_lit_comp(".reloc"), + }; + for (U64 i = 0; i < ArrayCount(illegal_merge_sections); i += 1) { + if (str8_match(merge->src, illegal_merge_sections[i], 0)) { + lnk_error(LNK_Error_IllegalSectionMerge, "illegal to merge %S with %S", illegal_merge_sections[i], merge->dst); + } + if (str8_match(merge->dst, illegal_merge_sections[i], 0)) { + lnk_error(LNK_Error_IllegalSectionMerge, "illegal to merge %S with %S", merge->src, illegal_merge_sections[i]); + } + } + } // are we trying to merge section that was already merged? LNK_Section *merge_sect = 0; diff --git a/src/torture/torture.c b/src/torture/torture.c index 4663d81d..64127fec 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -1333,7 +1333,36 @@ t_base_relocs(void) } String8 out_name = str8_lit("a.exe"); - int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:%S /dynamicbase /largeaddressaware:no /out:%S %S %S", entry_name, out_name, main_obj_name, func_obj_name); + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:my_entry /dynamicbase /largeaddressaware:no /out:a.exe main.obj func.obj"); + if (linker_exit_code != 0) { + goto exit; + } + + // it is illegal to merge .reloc with other sections + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:my_entry /dynamicbase /largeaddressaware:no /out:a.exe /merge:.reloc=.rdata main.obj func.obj"); + if (t_ident_linker() == T_Linker_RAD) { + if (linker_exit_code != LNK_Error_IllegalSectionMerge) { + goto exit; + } + } else { + if (linker_exit_code == 0) { + goto exit; + } + } + + // the other way around is illegal too + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:my_entry /dynamicbase /largeaddressaware:no /out:a.exe /merge:.rdata=.reloc main.obj func.obj"); + if (t_ident_linker() == T_Linker_RAD) { + if (linker_exit_code != LNK_Error_IllegalSectionMerge) { + goto exit; + } + } else { + if (linker_exit_code == 0) { + goto exit; + } + } + + result = T_Result_Pass; exit:; scratch_end(scratch); @@ -1602,7 +1631,7 @@ entry_point(CmdLine *cmdline) { "flag_conf", t_flag_conf }, { "invalid_bss", t_invalid_bss }, { "common_block", t_common_block }, - //{ "base_relocs", t_base_relocs }, + { "base_relocs", t_base_relocs }, { "simple_lib_test", t_simple_lib_test }, { "import_export", t_import_export }, };