kit

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

commit a7d80ffe34ba3daa813e372cc10b3d8ece9bf97e
parent 7fce439d102fa3b36bdd60442dfb084b28261403
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 29 May 2026 09:10:21 -0700

Fix O1 static data function pointer reachability

Diffstat:
Msrc/opt/opt.c | 117++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 95 insertions(+), 22 deletions(-)

diff --git a/src/opt/opt.c b/src/opt/opt.c @@ -292,43 +292,94 @@ static void opt_mark_symset(OptFuncIndex* index, u8* reachable, u8* queued, } } -static int opt_data_reloc_is_exported_root(OptImpl* o, const Reloc* r) { +static int opt_sym_is_relocatable_data(const ObjSym* s) { + if (!s || s->removed || s->section_id == OBJ_SEC_NONE) return 0; + return s->kind == SK_OBJ || s->kind == SK_TLS || s->kind == SK_COMMON; +} + +static int opt_reloc_inside_sym(const Reloc* r, const ObjSym* s) { + u64 begin, end; + if (!r || r->removed || !opt_sym_is_relocatable_data(s)) return 0; + if (r->section_id != s->section_id) return 0; + begin = s->value; + end = begin + s->size; + if (s->size == 0) end = begin + 1u; + return (u64)r->offset >= begin && (u64)r->offset < end; +} + +static void opt_enqueue_data_sym(OptImpl* o, ObjSymSet* seen, + ObjSymId* queue, u32* qtail, ObjSymId sym) { + const ObjSym* s; + if (sym == OBJ_SYM_NONE || ObjSymSet_get(seen, sym)) return; + s = obj_symbol_get(o->target->obj, sym); + if (!opt_sym_is_relocatable_data(s)) return; + (void)ObjSymSet_set(seen, sym, 1); + queue[(*qtail)++] = sym; +} + +static void opt_enqueue_data_symset(OptImpl* o, ObjSymSet* seen, + ObjSymId* queue, u32* qtail, + const ObjSymSet* refs) { + if (!refs || !refs->cap) return; + for (u32 i = 0; i < refs->cap; ++i) { + ObjSymId sym = refs->slots[i].k; + if (sym != OBJ_SYM_NONE) opt_enqueue_data_sym(o, seen, queue, qtail, sym); + } +} + +static void opt_mark_data_reloc_graph(OptImpl* o, OptFuncIndex* index, + u8* reachable, u8* queued, + u32* func_queue, u32* func_qtail, + ObjSymSet* data_seen, + ObjSymId* data_queue, + u32* data_qhead, u32* data_qtail) { + u32 nrel = obj_reloc_total(o->target->obj); + while (*data_qhead < *data_qtail) { + ObjSymId data_sym = data_queue[(*data_qhead)++]; + const ObjSym* data = obj_symbol_get(o->target->obj, data_sym); + if (!opt_sym_is_relocatable_data(data)) continue; + for (u32 i = 0; i < nrel; ++i) { + const Reloc* r = obj_reloc_at(o->target->obj, i); + if (!opt_reloc_inside_sym(r, data)) continue; + opt_mark_sym(index, reachable, queued, func_queue, func_qtail, r->sym); + opt_enqueue_data_sym(o, data_seen, data_queue, data_qtail, r->sym); + } + } +} + +static ObjSymId opt_data_reloc_exported_root_sym(OptImpl* o, const Reloc* r) { ObjSymIter* it; ObjSymEntry ent; const Section* sec; - if (!r || r->removed || r->section_id == OBJ_SEC_NONE) return 0; + if (!r || r->removed || r->section_id == OBJ_SEC_NONE) return OBJ_SYM_NONE; sec = obj_section_get(o->target->obj, r->section_id); - if (!sec || sec->removed || sec->kind == SEC_TEXT) return 0; - if (sec->flags & SF_RETAIN) return 1; + if (!sec || sec->removed || sec->kind == SEC_TEXT) return OBJ_SYM_NONE; it = obj_symiter_new(o->target->obj); - if (!it) return 0; + if (!it) return OBJ_SYM_NONE; while (obj_symiter_next(it, &ent)) { const ObjSym* s = ent.sym; - u64 begin, end; - if (!s || s->removed || s->section_id != r->section_id) continue; - if (s->kind != SK_OBJ && s->kind != SK_TLS && s->kind != SK_COMMON) - continue; - if (s->bind == SB_LOCAL && !(s->flags & CFREE_CG_SYM_USED)) continue; - begin = s->value; - end = begin + s->size; - if (s->size == 0) end = begin + 1u; - if ((u64)r->offset >= begin && (u64)r->offset < end) { + if (!opt_reloc_inside_sym(r, s)) continue; + if (sec->flags & SF_RETAIN) { obj_symiter_free(it); - return 1; + return ent.id; } + if (s->bind == SB_LOCAL && !(s->flags & CFREE_CG_SYM_USED)) continue; + obj_symiter_free(it); + return ent.id; } obj_symiter_free(it); - return 0; + return OBJ_SYM_NONE; } -static void opt_root_exported_data_relocs(OptImpl* o, OptFuncIndex* index, - u8* reachable, u8* queued, - u32* queue, u32* qtail) { +static void opt_root_exported_data_relocs(OptImpl* o, ObjSymSet* data_seen, + ObjSymId* data_queue, + u32* data_qtail) { u32 nrel = obj_reloc_total(o->target->obj); for (u32 i = 0; i < nrel; ++i) { const Reloc* r = obj_reloc_at(o->target->obj, i); - if (opt_data_reloc_is_exported_root(o, r)) - opt_mark_sym(index, reachable, queued, queue, qtail, r->sym); + ObjSymId sym = opt_data_reloc_exported_root_sym(o, r); + if (sym != OBJ_SYM_NONE) + opt_enqueue_data_sym(o, data_seen, data_queue, data_qtail, sym); } } @@ -372,16 +423,29 @@ static void opt_prune_debug(OptImpl* o) { static void opt_emit_reachable_aarch64(OptImpl* o, const CgIrModule* module) { OptFuncIndex index; + ObjSymSet data_seen; u8* reachable; u8* queued; u32* queue; + ObjSymId* data_queue; u32 qhead = 0; u32 qtail = 0; + u32 data_qhead = 0; + u32 data_qtail = 0; + u32 nsym = 1; if (!module || !module->nfuncs) return; OptFuncIndex_init_cap(&index, o->c->ctx->heap, 0); + ObjSymSet_init_cap(&data_seen, o->c->ctx->heap, 0); reachable = arena_zarray(o->c->tu, u8, module->nfuncs); queued = arena_zarray(o->c->tu, u8, module->nfuncs); queue = arena_array(o->c->tu, u32, module->nfuncs); + { + ObjSymIter* it = obj_symiter_new(o->target->obj); + ObjSymEntry ent; + while (it && obj_symiter_next(it, &ent)) ++nsym; + if (it) obj_symiter_free(it); + } + data_queue = arena_array(o->c->tu, ObjSymId, nsym); for (u32 i = 0; i < module->nfuncs; ++i) { CgIrFunc* f = module->funcs[i]; if (f && f->desc.sym != OBJ_SYM_NONE) @@ -392,11 +456,19 @@ static void opt_emit_reachable_aarch64(OptImpl* o, const CgIrModule* module) { opt_mark_func(reachable, queued, queue, &qtail, i); } opt_root_aliases(o, module, &index, reachable, queued, queue, &qtail); - opt_root_exported_data_relocs(o, &index, reachable, queued, queue, &qtail); + opt_root_exported_data_relocs(o, &data_seen, data_queue, &data_qtail); + opt_mark_data_reloc_graph(o, &index, reachable, queued, queue, &qtail, + &data_seen, data_queue, &data_qhead, + &data_qtail); while (qhead < qtail) { CgIrFunc* f = module->funcs[queue[qhead++]]; opt_mark_symset(&index, reachable, queued, queue, &qtail, &f->call_refs); opt_mark_symset(&index, reachable, queued, queue, &qtail, &f->global_refs); + opt_enqueue_data_symset(o, &data_seen, data_queue, &data_qtail, + &f->global_refs); + opt_mark_data_reloc_graph(o, &index, reachable, queued, queue, &qtail, + &data_seen, data_queue, &data_qhead, + &data_qtail); } for (u32 i = 0; i < module->nfuncs; ++i) { CgIrFunc* cg_func = module->funcs[i]; @@ -417,6 +489,7 @@ static void opt_emit_reachable_aarch64(OptImpl* o, const CgIrModule* module) { opt_run_o1_native(o, f); } opt_refresh_or_prune_aliases(o, module, &index, reachable); + ObjSymSet_fini(&data_seen); OptFuncIndex_fini(&index); }