kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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