diff --git a/CHANGELOG.md b/CHANGELOG.md index 242ba133..809c77b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v0.9.26-alpha + +## Linker Changes + +- Implemented /DEBUG:GHASH + # v0.9.25-alpha ## Debugger Changes diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 78eee9f2..81fe3b13 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1237,7 +1237,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List LNK_DebugMode debug_mode = lnk_debug_mode_from_string(value_strings.first->string); if (debug_mode == LNK_DebugMode_GHash) { config->debug_mode = LNK_DebugMode_Full; - lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, cmd_switch, "GHASH is not supported, switching to FULL"); + config->ghash = 1; } else if (debug_mode == LNK_DebugMode_FastLink) { config->debug_mode = LNK_DebugMode_Full; lnk_error_cmd_switch(LNK_Warning_Cmdl, obj, cmd_switch, "FASTLINK is not supported, switching to FULL"); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 513a3f9d..45817553 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -266,6 +266,7 @@ typedef struct LNK_Config Arena *arena; LNK_ConfigFlags flags; LNK_DebugMode debug_mode; + B32 ghash; LNK_SwitchState opt_ref; LNK_SwitchState opt_icf; LNK_SwitchState opt_lbr; diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index 6466705f..51e30c05 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -279,7 +279,9 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, input.debug_s_list_arr = lnk_collect_obj_sections(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug$S"), 0); input.debug_p_list_arr = lnk_collect_obj_sections(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug$P"), 0); input.debug_t_list_arr = lnk_collect_obj_sections(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug$T"), 0); - input.debug_h_list_arr = lnk_collect_obj_sections(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug$H"), 0); + if (config->ghash) { + input.debug_h_list_arr = lnk_collect_obj_sections(tp, tp_arena, obj_count, obj_arr, str8_lit(".debug$H"), 0); + } ProfEnd(); if (lnk_get_log_status(LNK_Log_Debug) || PROFILE_TELEMETRY) { @@ -288,7 +290,9 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, for EachNode(n, String8Node, input.debug_s_list_arr[obj_idx].first) { total_debug_s_size += n->string.size; } for EachNode(n, String8Node, input.debug_t_list_arr[obj_idx].first) { total_debug_t_size += n->string.size; } for EachNode(n, String8Node, input.debug_p_list_arr[obj_idx].first) { total_debug_p_size += n->string.size; } - for EachNode(n, String8Node, input.debug_h_list_arr[obj_idx].first) { total_debug_h_size += n->string.size; } + if (config->ghash) { + for EachNode(n, String8Node, input.debug_h_list_arr[obj_idx].first) { total_debug_h_size += n->string.size; } + } } ProfNoteV("Total .debug$S Input Size: %M", total_debug_s_size); @@ -324,7 +328,9 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, tp_for_parallel_prof(tp, tp_arena, obj_count, lnk_parse_debug_t_task, &parse_types, "Parse .debug$T"); input.debug_h_arr = push_array(tp_arena->v[0], CV_DebugH, input.obj_count); - tp_for_parallel_prof(tp, tp_arena, obj_count, lnk_parse_debug_h_task, &input, "Parse .debug$H"); + if (config->ghash) { + tp_for_parallel_prof(tp, tp_arena, obj_count, lnk_parse_debug_h_task, &input, "Parse .debug$H"); + } } ProfEnd(); @@ -426,6 +432,7 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_Config *config, MemoryCopyTyped(input.obj_arr, prev.obj_arr, prev.count); MemoryCopyTyped(input.debug_s_arr, prev.debug_s_arr, prev.count); MemoryCopyTyped(input.debug_t_arr, prev.debug_t_arr, prev.count); + MemoryCopyTyped(input.debug_h_arr, prev.debug_h_arr, prev.count); MemoryCopyTyped(input.obj_to_ts, prev.obj_to_ts, prev.count); MemorySet(input.obj_to_ts + input.obj_count, 0xff, ts_arr.count * sizeof(input.obj_to_ts[0])); @@ -1437,15 +1444,14 @@ lnk_merge_types(TP_Context *tp, TP_Arena *tp_temp, LNK_CodeViewInput *input) for EachElement(i, hash_targets) { task.indices = hash_targets[i].hash_indices; ProfBegin("Hash [Count: %.*s]", str8_varg(str8_from_count(scratch.arena, task.indices.count))); - tp_for_parallel(tp, 0, hash_targets[i].indices.count, hash_targets[i].hasher_task, &task); + tp_for_parallel(tp, 0, task.indices.count, hash_targets[i].hasher_task, &task); ProfEnd(); } #if BUILD_DEBUG for EachIndex(i, input->count) { for EachIndex(k, input->debug_h_arr[i].count) { - Assert(input->debug_h_arr[i].v[k] != 0 && - input->debug_h_arr[i].v[k] != 1); + Assert(input->debug_h_arr[i].v[k] != 0); } } #endif diff --git a/src/llvm/llvm.h b/src/llvm/llvm.h index e0b61cc7..0ddc399f 100644 --- a/src/llvm/llvm.h +++ b/src/llvm/llvm.h @@ -18,12 +18,13 @@ typedef enum LLVM_GHashAlgEnum typedef struct LLVM_GHash { U32 magic; - LLVM_GHashAlg hash_alg; U16 version; + LLVM_GHashAlg hash_alg; // * hashes[] } LLVM_GHash; internal String8 llvm_string_from_ghash_alg(LLVM_GHashAlg v); +internal U64 llvm_hash_size_from_alg(LLVM_GHashAlg v); #endif // LLVM_H diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index 3cb0c418..cd9557a7 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -5028,7 +5028,7 @@ TEST(ghash_check_corrupt) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; @@ -5075,7 +5075,7 @@ TEST(ghash_check_magic) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; @@ -5122,7 +5122,7 @@ TEST(ghash_check_version) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; @@ -5161,7 +5161,7 @@ TEST(ghash_check_hash_alg) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; @@ -5200,7 +5200,7 @@ TEST(ghash_match_debug_t) T_Ok(t_write_entry_obj()); String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj debug.obj"), max_U64, arena, &output); + t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj debug.obj"), max_U64, arena, &output); T_Ok(g_last_exit_code == 0); B32 is_warning_found = 0; @@ -5213,7 +5213,6 @@ TEST(ghash_match_debug_t) T_Ok(is_warning_found); } -#if 0 TEST(ghash_basic) { String8 a_obj; @@ -5239,23 +5238,57 @@ TEST(ghash_basic) coff_obj_writer_release(&cow); } + String8 b_obj; + { + String8List t = {0}; str8_serial_begin(arena, &t); + str8_serial_push_u32(arena, &t, CV_Signature_C13); + str8_serial_push_string(arena, &t, cv_make_leaf(arena, CV_LeafKind_STRUCTURE, str8_struct(&(CV_LeafStruct){ .props = CV_TypeProp_FwdRef }), CV_LeafAlign)); + str8_serial_push_string(arena, &t, cv_make_leaf(arena, CV_LeafKind_UNION, str8_struct(&(CV_LeafUnion){ .props = CV_TypeProp_FwdRef }), CV_LeafAlign)); + str8_serial_push_string(arena, &t, cv_make_leaf(arena, CV_LeafKind_ENUM, str8_struct(&(CV_LeafEnum){ .props = CV_TypeProp_FwdRef }), CV_LeafAlign)); + String8 debug_t = str8_serial_end(arena, &t); + + String8List h = {0}; str8_serial_begin(arena, &h); + str8_serial_push_struct(arena, &h, (&(LLVM_GHash){ .magic = LLVM_GHash_Magic, .hash_alg = LLVM_GHashAlg_BLAKE3, .version = LLVM_GHash_CurrentVersion })); + str8_serial_push_u64(arena, &h, 4); + str8_serial_push_u64(arena, &h, 5); + str8_serial_push_u64(arena, &h, 6); + String8 debug_h = str8_serial_end(arena, &h); + + COFF_ObjWriter *cow = coff_obj_writer_alloc(0, COFF_MachineType_X64); + coff_obj_writer_push_section(cow, str8_lit(".debug$T"), PE_DEBUG_SECTION_FLAGS, debug_t); + coff_obj_writer_push_section(cow, str8_lit(".debug$H"), PE_DEBUG_SECTION_FLAGS, debug_h); + b_obj = coff_obj_writer_serialize(arena, cow); + coff_obj_writer_release(&cow); + } + T_Ok(t_write_file(str8_lit("a.obj"), a_obj)); + T_Ok(t_write_file(str8_lit("b.obj"), b_obj)); T_Ok(t_write_entry_obj()); - String8 output = {0}; - t_invoke_(t_radlink_path(), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj a.obj"), max_U64, arena, &output); + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:ghash entry.obj a.obj b.obj"); T_Ok(g_last_exit_code == 0); - B32 is_warning_found = 0; - String8 a_obj_path = t_make_file_path(arena, str8_lit("a.obj")); - String8 expected_line = str8f(arena, "Warning(%03u): %S: mismatched .debug$H hash count and type count: got 3 hashes for 2 types", LNK_Warning_GHash, a_obj_path); - for (String8 i = output; i.size > 0 && !is_warning_found; ) { - String8 line = t_chop_line(&i); - is_warning_found = str8_match(expected_line, line, StringMatchFlag_CaseInsensitive); + { + String8 raw_pdb = t_read_file(arena, str8_lit("a.pdb")); + MSF_Parsed *msf_parsed = msf_parsed_from_data(arena, raw_pdb); + String8 raw_tpi = msf_data_from_stream(msf_parsed, PDB_FixedStream_Tpi); + PDB_TpiParsed *tpi = pdb_tpi_from_data(arena, raw_tpi); + U64 leaf_count = tpi->itype_opl - tpi->itype_first; + T_Ok(leaf_count == 6); + } + + t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe /debug:full entry.obj a.obj b.obj"); + T_Ok(g_last_exit_code == 0); + + { + String8 raw_pdb = t_read_file(arena, str8_lit("a.pdb")); + MSF_Parsed *msf_parsed = msf_parsed_from_data(arena, raw_pdb); + String8 raw_tpi = msf_data_from_stream(msf_parsed, PDB_FixedStream_Tpi); + PDB_TpiParsed *tpi = pdb_tpi_from_data(arena, raw_tpi); + U64 leaf_count = tpi->itype_opl - tpi->itype_first; + T_Ok(leaf_count == 3); } - T_Ok(is_warning_found); } -#endif TEST(patch_cv_symbol_tree) {