symresolve.h (3257B)
1 #ifndef KIT_OBJ_SYMRESOLVE_H 2 #define KIT_OBJ_SYMRESOLVE_H 3 4 #include "obj/obj.h" 5 6 /* Symbol-resolution policy, factored out of the linker so it has one source of 7 * truth and a second caller can reuse it: link_resolve_symbols runs it at link 8 * time, and the LTO staging coordinator runs it at the per-TU merge boundary 9 * (doc/plan/LTO.md §3). It is a pure decision over symbol attributes — no 10 * linker state, no allocation. The entangled bookkeeping (the globals hash, the 11 * per-input map, COMDAT section discard, DSO iteration) stays in the caller. */ 12 13 /* Defined-symbol binding precedence: strong (global) beats weak beats local. */ 14 static inline int symresolve_bind_strength(u16 bind) { 15 switch (bind) { 16 case SB_GLOBAL: 17 return 3; 18 case SB_WEAK: 19 return 2; 20 case SB_LOCAL: 21 return 1; 22 default: 23 return 0; 24 } 25 } 26 27 /* A symbol that contributes a definition: not SK_UNDEF, and either an 28 * absolute/common/file pseudo-def or anchored to a real section. */ 29 static inline int symresolve_sym_is_def(const ObjSym* s) { 30 return s && s->kind != SK_UNDEF && 31 (s->kind == SK_ABS || s->kind == SK_COMMON || s->kind == SK_FILE || 32 s->section_id != OBJ_SEC_NONE); 33 } 34 35 /* An unreferenced global/weak extern declaration: a header artifact, not a real 36 * demand. The frontend synthesizes one per visible prototype, so pruning these 37 * keeps unused archive members from being pulled in. */ 38 static inline int symresolve_sym_is_spurious_undef(const ObjSym* s) { 39 return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && 40 s->kind != SK_COMMON && !s->referenced && 41 (s->bind == SB_GLOBAL || s->bind == SB_WEAK); 42 } 43 44 /* The decision-relevant attributes of a defining symbol. `in_comdat` is true 45 * when the definition lives in an SF_GROUP (COMDAT/SELECTANY) section — the 46 * caller computes it, since it requires the section table. */ 47 typedef struct SymAttrs { 48 u16 bind; /* SymBind */ 49 u16 kind; /* SymKind */ 50 u64 size; 51 u32 common_align; /* SK_COMMON only; 0 otherwise */ 52 u8 in_comdat; 53 } SymAttrs; 54 55 typedef enum SymMergeKind { 56 SYM_MERGE_KEEP_EXISTING, /* existing definition wins; drop incoming */ 57 SYM_MERGE_REPLACE, /* incoming definition wins; overwrite existing */ 58 SYM_MERGE_COMMON, /* common+common, incoming larger: take it with 59 * merged_align = max(both) */ 60 SYM_MERGE_COMDAT_DISCARD, /* COFF SELECTANY: keep existing, discard the 61 * incoming COMDAT section */ 62 SYM_MERGE_ODR_ERROR, /* duplicate strong definition */ 63 } SymMergeKind; 64 65 typedef struct SymMergeResult { 66 SymMergeKind kind; 67 u32 merged_align; /* valid only for SYM_MERGE_COMMON */ 68 } SymMergeResult; 69 70 /* Resolve two definitions of the same name. Both `existing` and `incoming` are 71 * definitions (the caller filters undefs and spurious externs first). Mirrors 72 * the linker's historical precedence exactly: common merging takes the larger 73 * (max align), a real definition beats a common, a stronger binding wins, 74 * strong-vs-strong is an ODR error unless both are COMDAT, and weak-vs-weak / 75 * weaker-incoming keeps the first. */ 76 SymMergeResult symresolve_merge(SymAttrs existing, SymAttrs incoming); 77 78 #endif