From a6c2f8a9177eeae64b83e4aeafe46dbe310b3861 Mon Sep 17 00:00:00 2001 From: lemon Date: Thu, 25 Dec 2025 13:28:56 +0100 Subject: avoid GOT relocations in unnecessary instances Also change xcon to have a flagset for symbols (whether it's a function, locally defined; later: thread local, etc). --- c/c.c | 2 +- ir/intrin.c | 2 +- ir/ir.c | 8 ++++---- ir/ir.h | 9 +++++++-- x86_64/emit.c | 12 +++++------- x86_64/isel.c | 2 +- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/c/c.c b/c/c.c index e070924..8a06272 100644 --- a/c/c.c +++ b/c/c.c @@ -2867,7 +2867,7 @@ expraddr(struct function *fn, const struct expr *ex) uchar *p = objout.code ? objout.textbegin + off : objout.rodata.p + off; memcpy(p, fn->name, typearrlen(decl->ty)-1); } - return mksymref(decl->sym, decl->ty.t == TYFUNC); + return mksymref(decl->sym, (SFUNC & -(decl->ty.t == TYFUNC)) | (SLOCAL & -(decl->scls == SCSTATIC || decl->isdef))); default: assert(0); } diff --git a/ir/intrin.c b/ir/intrin.c index d31f9bb..dcd05a5 100644 --- a/ir/intrin.c +++ b/ir/intrin.c @@ -24,7 +24,7 @@ intrin(struct block *blk, int *curi, enum intrin in, struct arg *args, int narg, /* memcpy */ *args[1].ty = *args[0].ty = mktyperef(cls2type(KPTR)); insertinstr(blk, (*curi)++, mkarginstr(cls2type(cls), mkintcon(cls, td->siz))); - *this = mkinstr(Ocall, 0, mksymref(intern("memcpy"), 1), this->r); + *this = mkinstr(Ocall, 0, mksymref(intern("memcpy"), SFUNC), this->r); calltab.p[this->r.i].narg = 3; calltab.p[this->r.i].ret = cls2type(0); return 0; diff --git a/ir/ir.c b/ir/ir.c index 1f1c9bc..29d52d4 100644 --- a/ir/ir.c +++ b/ir/ir.c @@ -101,7 +101,7 @@ newcon(const struct xcon *con) { uint h = hashb(0, con, sizeof *con); uint i = h, n = countof(conht); - assert((con->issym ^ con->isdat && !(con->isdat && con->isfunc)) || con->cls); + assert((con->issym ^ con->isdat) || con->cls); for (;; ++i) { i &= countof(conht) - 1; if (!conht[i].issym && !conht[i].isdat && !conht[i].cls) { @@ -145,9 +145,9 @@ mkfltcon(enum irclass k, double f) } union ref -mksymref(internstr s, bool isfunc) +mksymref(internstr s, enum symflags symflags) { - struct xcon con = { .issym = 1, .sym = s, .isfunc = isfunc }; + struct xcon con = { .issym = 1, .sym = s, .flag = symflags }; return mkref(RXCON, newcon(&con)); } @@ -172,7 +172,7 @@ mkdatref(internstr name, union type ctype, uint siz, uint align, const void *byt if (n) memcpy(p, bytes, n); if (dat.section != Stext) memset(p+n, 0, siz - n); vpush(&dattab, dat); - return mkref(RXCON, newcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1})); + return mkref(RXCON, newcon(&(struct xcon){.isdat = 1, .deref = deref, .dat = dattab.n - 1, .flag = SLOCAL})); } internstr diff --git a/ir/ir.h b/ir/ir.h index 8e18e1f..8402864 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -25,9 +25,14 @@ struct irdat { internstr name; }; +enum symflags { + SLOCAL = 1, + SFUNC = 2, +}; struct xcon { - bool issym, isdat, isfunc, deref; + bool issym, isdat, deref; uchar cls; + uchar flag; union { internstr sym; int dat; @@ -255,7 +260,7 @@ union ref mkfltcon(enum irclass, double); #define isaddrcon(r,derefok) ((r).t == RXCON && !conht[(r).i].cls && (derefok || !conht[(r).i].deref)) #define intconval(r) ((r).t == RICON ? (r).i : conht[(r).i].i) #define fltconval(r) ((r).t == RICON ? (r).i : conht[(r).i].f) -union ref mksymref(internstr, bool isfunc); +union ref mksymref(internstr, enum symflags); union ref mkdatref(internstr name, union type ctype, uint siz, uint align, const void *, uint n, bool deref); internstr xcon2sym(int ref); struct instr mkalloca(uint siz, uint align); diff --git a/x86_64/emit.c b/x86_64/emit.c index 6f989f6..6e48965 100644 --- a/x86_64/emit.c +++ b/x86_64/emit.c @@ -336,12 +336,11 @@ encode(uchar **pcode, const struct desc *tab, int ntab, enum irclass k, struct o int disp = mem.disp - 4 - offs[en->operenc]; internstr sym = xcon2sym(mem.con); B(/*mod 0*/ (reg & 7) << 3 | RBP); - if (objhassym(sym, &addr) == Stext) { + if (objhassym(sym, &addr) == Stext && mem.t != OSYMGOT) { I32(addr - (*pcode - objout.textbegin) + disp); } else { enum relockind r = REL_PCREL32; - if (mem.t == OSYMGOT) - r = (rex ? REL_GOTPCRELX_REX : REL_GOTPCRELX); + if (mem.t == OSYMGOT) r = rex ? REL_GOTPCRELX_REX : REL_GOTPCRELX; objreloc(xcon2sym(mem.con), r, Stext, *pcode - objout.textbegin, disp); I32(0); } @@ -870,8 +869,8 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope } /* normal (not 2-address) case */ Lea: - if (isaddrcon(addr->base,0) && (ccopt.pic || conht[addr->base.i].isfunc) - && !objhassym(xcon2sym(addr->base.i), NULL)) { + if (isaddrcon(addr->base,0) && (ccopt.pic || (conht[addr->base.i].flag & SFUNC)) + && !(conht[addr->base.i].flag & SLOCAL)) { assert(!addr->disp && !addr->index.bits); val = addr->base; goto GOTLoad; @@ -881,8 +880,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope /* dst = 0 -> xor dst, dst; but only if it is ok to clobber flags */ Xxor(pcode, kisint(cls) ? KI32 : cls, dst, dst); } else if (isaddrcon(val,0)) { - if ((ccopt.pic || conht[val.i].isfunc) - && !objhassym(xcon2sym(val.i), NULL)) { + if ((ccopt.pic || (conht[val.i].flag & SFUNC)) && !(conht[val.i].flag & SLOCAL)) { GOTLoad: /* for mov reg, [rip(sym@GOTPCREL)] */ Xmov(pcode, cls, dst, mkoper(OSYMGOT, .con = val.i, .cindex = NOINDEX)); diff --git a/x86_64/isel.c b/x86_64/isel.c index 9c99608..40d8db4 100644 --- a/x86_64/isel.c +++ b/x86_64/isel.c @@ -305,7 +305,7 @@ fuseaddr(union ref *r, struct block *blk, int *curi) if (r->t != RSTACK && r->t != RTMP) return 0; if (!aadd(&addr, blk, curi, *r)) return 0; - if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || conht[addr.base.i].isfunc)) { + if (isaddrcon(addr.base,0) && (ccopt.pic || (ccopt.pie && addr.index.bits) || (conht[addr.base.i].flag & SFUNC))) { /* pic needs to load from GOT */ /* pie cannot encode RIP-relative address with index register */ /* first load symbol address into a temp register */ -- cgit v1.2.3