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:
| M | src/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);
}