polish ICF section color-space picker

This commit is contained in:
Nikita Smith
2026-07-27 14:47:30 -07:00
committed by Ryan Fleury
parent 4235fa85b4
commit cd82268a07
2 changed files with 65 additions and 40 deletions
+62 -39
View File
@@ -2994,16 +2994,13 @@ THREAD_POOL_TASK_FUNC(lnk_opt_ref_task)
internal void internal void
lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj **objs, U64 objs_count) lnk_opt_ref(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Config *config, LNK_Obj **objs, U64 objs_count)
{ {
ProfBegin("/OPT:REF");
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
U32Array *obj_indices = lnk_obj_indices_from_section_counts(scratch.arena, tp->worker_count, objs, objs_count); U32Array *obj_indices = lnk_obj_indices_from_section_counts(scratch.arena, tp->worker_count, objs, objs_count);
LNK_OptTask task = { .symtab = symtab, .config = config, .objs = objs, .objs_count = objs_count, .obj_indices = obj_indices };
ProfScope("/OPT:REF") tp_for_parallel(tp, 0, tp->worker_count, lnk_opt_ref_task, &task);
{
LNK_OptTask task = { .symtab = symtab, .config = config, .objs = objs, .objs_count = objs_count, .obj_indices = obj_indices };
tp_for_parallel(tp, 0, tp->worker_count, lnk_opt_ref_task, &task);
}
scratch_end(scratch); scratch_end(scratch);
ProfEnd();
} }
typedef enum LNK_ICF_ColorSpace typedef enum LNK_ICF_ColorSpace
@@ -3036,46 +3033,73 @@ lnk_icf_color_space_from_section(LNK_Obj *obj, U32 sect_idx)
{ {
LNK_ICF_ColorSpace result = LNK_ICF_ColorSpace_Null; LNK_ICF_ColorSpace result = LNK_ICF_ColorSpace_Null;
// fold read-only COMDAT sections // * section flags filter *
COFF_SectionFlags expected_flags = COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_MemRead; COFF_SectionFlags expected_flags = COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_MemRead;
COFF_SectionFlags exclude_flags = COFF_SectionFlag_LnkRemove | COFF_SectionFlag_MemWrite | LNK_SECTION_FLAG_NOICF; COFF_SectionFlags exclude_flags = COFF_SectionFlag_LnkRemove | COFF_SectionFlag_MemWrite | LNK_SECTION_FLAG_NOICF;
if ((obj->section_flags[sect_idx] & expected_flags) != expected_flags || (obj->section_flags[sect_idx] & exclude_flags) != 0) {
goto exit;
}
if ((obj->section_flags[sect_idx] & expected_flags) == expected_flags && (obj->section_flags[sect_idx] & exclude_flags) == 0) { if (obj->section_flags[sect_idx] & COFF_SectionFlag_CntCode) {
// fold code result = LNK_ICF_ColorSpace_Code;
if (obj->section_flags[sect_idx] & COFF_SectionFlag_CntCode) { goto exit;
result = LNK_ICF_ColorSpace_Code; }
if (obj->section_flags[sect_idx] & COFF_SectionFlag_CntInitializedData) {
U64 section_number = sect_idx + 1;
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, section_number);
String8 section_name = str8_cstring_capped(section_header->name, section_header->name + sizeof(section_header->name));
//
// * include unwind info metadata *
//
if (str8_match(section_name, str8_lit(".xdata"), 0) || str8_match(section_name, str8_lit(".pdata"), 0)) {
result = LNK_ICF_ColorSpace_Unwind;
goto exit;
} }
// fold data
else if (obj->section_flags[sect_idx] & COFF_SectionFlag_CntInitializedData) {
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(obj, sect_idx + 1);
String8 section_name = str8_cstring_capped(section_header->name, section_header->name + sizeof(section_header->name));
// fold unwind info // query COMDAT symlink that is associated with the section number
if (str8_match(section_name, str8_lit(".xdata"), 0) || str8_match(section_name, str8_lit(".pdata"), 0)) { // because the properties are stored in the symbol table
result = LNK_ICF_ColorSpace_Unwind; LNK_ObjSymbolRef comdat_ref = {0};
} else { if (lnk_obj_get_comdat_symlink(obj, section_number, &comdat_ref)) {
LNK_ObjSymbolRef symlink_ref = {0};
if (lnk_obj_get_comdat_symlink(obj, sect_idx + 1, &symlink_ref)) { // load COMDAT symbol name
String8 symlink_name = lnk_symbol_name_from_coff_symbol_idx(symlink_ref.obj, symlink_ref.symbol_idx); String8 comdat_name = lnk_symbol_name_from_coff_symbol_idx(comdat_ref.obj, comdat_ref.symbol_idx);
// fold MSVC vftables separately from other read-only data
if (str8_starts_with(symlink_name, str8_lit(MSCRT_VFTABLE_SYMBOL_PREFIX))) { //
result = LNK_ICF_ColorSpace_VFTable; // * include virtual function tables *
} //
// fold ordinary read-only data COMDATs; do not fold declarations and vtables that require unique addresses if (str8_starts_with(comdat_name, str8_lit(MSCRT_VFTABLE_SYMBOL_PREFIX))) {
else if (!str8_starts_with(symlink_name, str8_lit(MSCRT_VBTABLE_SYMBOL_PREFIX))) { result = LNK_ICF_ColorSpace_VFTable;
COFF_ComdatSelectType select = COFF_ComdatSelect_Null; goto exit;
if (lnk_try_comdat_props_from_section_number(obj, sect_idx + 1, &select, 0, 0, 0)) { }
if (select == COFF_ComdatSelect_Any || select == COFF_ComdatSelect_SameSize ||
select == COFF_ComdatSelect_ExactMatch || select == COFF_ComdatSelect_Largest) { //
result = LNK_ICF_ColorSpace_ConstData; // * include COMDATs *
} //
} COFF_ComdatSelectType select = COFF_ComdatSelect_Null;
} if (lnk_try_comdat_props_from_section_number(obj, section_number, &select, 0, 0, 0)) {
// TODO: ref linkers exclude C++ virtual base tables, not sure why,
// are there tools that assume vbptr is unique for _some_reason_?
if (str8_starts_with(comdat_name, str8_lit(MSCRT_VBTABLE_SYMBOL_PREFIX))) {
goto exit;
}
// following selections are not included in ICF
// 1. NoDuplicate: selection requires a unique address
// 2. Associative: breaks COMDAT ownership model
if (select == COFF_ComdatSelect_Any ||
select == COFF_ComdatSelect_SameSize ||
select == COFF_ComdatSelect_ExactMatch ||
select == COFF_ComdatSelect_Largest) {
result = LNK_ICF_ColorSpace_ConstData;
goto exit;
} }
} }
} }
} }
exit:;
return result; return result;
} }
@@ -3095,8 +3119,7 @@ lnk_icf_atomic_min_u64(U64 *dst, U64 value)
// and a new refinement round is run. By default, the algorithm loops until // and a new refinement round is run. By default, the algorithm loops until
// partitions stabilize. Equivalence is established by comparing cryptographic // partitions stabilize. Equivalence is established by comparing cryptographic
// 128-bit hashes; in theory, the chance of collisions are near the birthday // 128-bit hashes; in theory, the chance of collisions are near the birthday
// paradox with BLAKE3 and the other downside it is susceptible to adversarial // paradox with BLAKE3
// inputs.
THREAD_POOL_TASK_FUNC(lnk_opt_icf_task) THREAD_POOL_TASK_FUNC(lnk_opt_icf_task)
{ {
ProfBeginFunction(); ProfBeginFunction();
+3 -1
View File
@@ -33,8 +33,10 @@
// PE_TLSHeader32 or PE_TLSHeader64, according to machine type. // PE_TLSHeader32 or PE_TLSHeader64, according to machine type.
#define MSCRT_TLS_SYMBOL_NAME "_tls_used" #define MSCRT_TLS_SYMBOL_NAME "_tls_used"
// MSVC C++ vftable symbols start with this decorated-name prefix. // vftable symbols
#define MSCRT_VFTABLE_SYMBOL_PREFIX "??_7" #define MSCRT_VFTABLE_SYMBOL_PREFIX "??_7"
// vbptr symbols
#define MSCRT_VBTABLE_SYMBOL_PREFIX "??_8" #define MSCRT_VBTABLE_SYMBOL_PREFIX "??_8"
//////////////////////////////// ////////////////////////////////