check COMDAT symlink points to a defined symbol

This commit is contained in:
Nikita Smith
2025-06-25 10:53:23 -07:00
committed by Ryan Fleury
parent 8d324775a2
commit 3eb7debad5
+78 -72
View File
@@ -236,86 +236,92 @@ lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src)
// regular,common vs regular,common // regular,common vs regular,common
else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) && else if ((dst_interp == COFF_SymbolValueInterp_Regular || dst_interp == COFF_SymbolValueInterp_Common) &&
(src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) { (src_interp == COFF_SymbolValueInterp_Regular || src_interp == COFF_SymbolValueInterp_Common)) {
COFF_ComdatSelectType dst_select; U32 dst_comdat_symbol_idx = dst_obj->comdats[dst_parsed.section_number-1];
U32 dst_section_length; U32 src_comdat_symbol_idx = src_obj->comdats[src_parsed.section_number-1];
U32 dst_check_sum; if (dst_comdat_symbol_idx == ~0 || src_comdat_symbol_idx == ~0) {
if (dst_interp == COFF_SymbolValueInterp_Regular) { lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S", dst->name, dst_obj->path);
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(dst_obj, dst_obj->comdats[dst_parsed.section_number-1]);
coff_parse_secdef(secdef, dst_obj->header.is_big_obj, &dst_select, 0, &dst_section_length, &dst_check_sum);
} else { } else {
dst_select = COFF_ComdatSelect_Largest; COFF_ComdatSelectType dst_select;
dst_section_length = dst_parsed.value; U32 dst_section_length;
dst_check_sum = 0; U32 dst_check_sum;
} if (dst_interp == COFF_SymbolValueInterp_Regular) {
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);
} else {
dst_select = COFF_ComdatSelect_Largest;
dst_section_length = dst_parsed.value;
dst_check_sum = 0;
}
COFF_ComdatSelectType src_select; COFF_ComdatSelectType src_select;
U32 src_section_length; U32 src_section_length;
U32 src_check_sum; U32 src_check_sum;
if (src_interp == COFF_SymbolValueInterp_Regular) { if (src_interp == COFF_SymbolValueInterp_Regular) {
COFF_ParsedSymbol secdef = lnk_parsed_symbol_from_coff_symbol_idx(src_obj, src_obj->comdats[src_parsed.section_number-1]); 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); coff_parse_secdef(secdef, src_obj->header.is_big_obj, &src_select, 0, &src_section_length, &src_check_sum);
} else { } else {
src_select = COFF_ComdatSelect_Largest; src_select = COFF_ComdatSelect_Largest;
src_section_length = src_parsed.value; src_section_length = src_parsed.value;
src_check_sum = 0; src_check_sum = 0;
} }
// handle objs compiled with /GR- and /GR // handle objs compiled with /GR- and /GR
if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) || if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) ||
(src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) { (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) {
dst_select = COFF_ComdatSelect_Largest; dst_select = COFF_ComdatSelect_Largest;
src_select = COFF_ComdatSelect_Largest; src_select = COFF_ComdatSelect_Largest;
} }
if (src_select == dst_select) { if (src_select == dst_select) {
switch (src_select) { switch (src_select) {
case COFF_ComdatSelect_Null: case COFF_ComdatSelect_Null:
case COFF_ComdatSelect_Any: { case COFF_ComdatSelect_Any: {
if (src_section_length == dst_section_length) { if (src_section_length == dst_section_length) {
can_replace = src_obj->input_idx < dst_obj->input_idx; can_replace = src_obj->input_idx < dst_obj->input_idx;
} else { } else {
// both COMDATs are valid but to get smaller exe pick smallest // both COMDATs are valid but to get smaller exe pick smallest
can_replace = src_section_length < dst_section_length; can_replace = src_section_length < dst_section_length;
} }
} break; } break;
case COFF_ComdatSelect_NoDuplicates: { case COFF_ComdatSelect_NoDuplicates: {
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path); lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S", dst->name, dst_obj->path);
} break; } break;
case COFF_ComdatSelect_SameSize: { case COFF_ComdatSelect_SameSize: {
if (dst_section_length != src_section_length) { if (dst_section_length != src_section_length) {
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path); lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S", dst->name, dst_obj->path);
} }
} break; } break;
case COFF_ComdatSelect_ExactMatch: { case COFF_ComdatSelect_ExactMatch: {
if (dst_check_sum != src_check_sum) { if (dst_check_sum != src_check_sum) {
lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S.", dst->name, dst_obj->path); lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src_obj, "multiply defined symbol %S in %S", dst->name, dst_obj->path);
} }
} break; } break;
case COFF_ComdatSelect_Largest: { case COFF_ComdatSelect_Largest: {
if (dst_section_length == src_section_length) { if (dst_section_length == src_section_length) {
if (dst_interp == COFF_SymbolValueInterp_Common) { if (dst_interp == COFF_SymbolValueInterp_Common) {
// handle communal variable // handle communal variable
// //
// MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c) // MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c)
can_replace = 1; can_replace = 1;
} else {
can_replace = src_obj->input_idx < dst_obj->input_idx;
}
} else { } else {
can_replace = src_obj->input_idx < dst_obj->input_idx; can_replace = dst_section_length < src_section_length;
} }
} else { } break;
can_replace = dst_section_length < src_section_length; case COFF_ComdatSelect_Associative: {
// ignore
} break;
default: { InvalidPath; }
} }
} break; } else {
case COFF_ComdatSelect_Associative: { String8 src_select_str = coff_string_from_comdat_select_type(src_select);
// ignore String8 dst_select_str = coff_string_from_comdat_select_type(dst_select);
} break; lnk_error_obj(LNK_Warning_UnresolvedComdat, src_obj,
default: { InvalidPath; } "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S",
src->name, src_select_str, dst_select_str, dst_obj);
} }
} 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);
} }
} else { } else {
lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination");