From d8b4e87af669c2b260686a5db67f7f02b4c164d9 Mon Sep 17 00:00:00 2001 From: lemon Date: Sun, 14 Dec 2025 12:15:59 +0100 Subject: various relocation related optimization With 59ca5a8db, querying if a symbol is defined is cheap. If we're compiling code that calls foo() and we defined foo() in this compilation unit, we already know its offset within the .text section, so use it instead of emitting a relocation for the linker to handle. Also, put small literal data in the .text section instead of .rodata. This seems to improve performance (cache locality?), and as a bonus, it will be good for aarch64's instr encoding with smallish PC-relative offsets. --- obj/elf.c | 29 +++++++++++++++-------------- obj/obj.c | 42 ++++++++++++++++++++++++------------------ obj/obj.h | 2 +- 3 files changed, 40 insertions(+), 33 deletions(-) (limited to 'obj') diff --git a/obj/elf.c b/obj/elf.c index e20da99..521a159 100644 --- a/obj/elf.c +++ b/obj/elf.c @@ -91,16 +91,23 @@ enum { BSS_SHNDX = 4, }; +static const char sect2ndx[] = { + [Snone] = SHN_UND, + [Stext] = TEXT_SHNDX, [Srodata] = RODATA_SHNDX, + [Sdata] = DATA_SHNDX, [Sbss] = BSS_SHNDX, +}, shndx2sect[] = { + [SHN_UND] = Snone, + [TEXT_SHNDX] = Stext, [RODATA_SHNDX] = Srodata, + [DATA_SHNDX] = Sdata, [BSS_SHNDX] = Sbss, +}; + enum section -elfhassym(const char *nam) +elfhassym(const char *nam, uint *value) { struct sym *sym = findsym(nam); - if (sym) switch (sym->shndx) { - case SHN_UND: return Snone; - case TEXT_SHNDX: return Stext; - case RODATA_SHNDX: return Srodata; - case DATA_SHNDX: return Sdata; - case BSS_SHNDX: return Sbss; + if (sym) { + if (value) *value = sym->value; + return shndx2sect[sym->shndx]; } return Snone; } @@ -115,13 +122,7 @@ elfaddsym(const char *nam, int info, enum section sect, uvlong value, uvlong siz } sym->bind = info >> 4; sym->type = info & 0xF; - switch (sect) { - case Snone: sym->shndx = SHN_UND; break; - case Stext: sym->shndx = TEXT_SHNDX; break; - case Srodata: sym->shndx = RODATA_SHNDX; break; - case Sdata: sym->shndx = DATA_SHNDX; break; - case Sbss: sym->shndx = BSS_SHNDX; break; - } + sym->shndx = sect2ndx[sect]; sym->value = value; sym->size = size; if (sym == &sym0) { diff --git a/obj/obj.c b/obj/obj.c index fa62e9e..2d8b497 100644 --- a/obj/obj.c +++ b/obj/obj.c @@ -6,7 +6,7 @@ void elfinit(void); -enum section elfhassym(const char *); +enum section elfhassym(const char *, uint *value); void elfaddsym(const char *, int info, enum section, uvlong value, uvlong size); void elfreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); void elffini(struct wbuf *); @@ -40,38 +40,44 @@ objdeffunc(const char *nam, bool globl, uint off, uint siz) } enum section -objhassym(const char *name) +objhassym(const char *name, uint *off) { - return elfhassym(name); + return elfhassym(name, off); } uint objnewdat(const char *name, enum section sec, bool globl, uint siz, uint align) { + struct objfile *o = &objout; uint off; - assert(siz && align && ispo2(align)); - switch (sec) { default: assert(0); + case Stext: + assert(align <= targ_primsizes[TYPTR]); + assert(o->textend - siz > o->code); + while ((o->code - o->textbegin) & (align - 1)) ++o->code; + off = o->code - o->textbegin; + o->code += siz; + break; case Srodata: - if (align > objout.rodataalign) objout.rodataalign = align; - while (objout.rodata.n & (align - 1)) vpush(&objout.rodata, 0); - off = objout.rodata.n; - vresize(&objout.rodata, objout.rodata.n + siz); - memset(objout.rodata.p+off, 0, siz); + if (align > o->rodataalign) o->rodataalign = align; + while (o->rodata.n & (align - 1)) vpush(&o->rodata, 0); + off = o->rodata.n; + vresize(&o->rodata, o->rodata.n + siz); + memset(o->rodata.p+off, 0, siz); break; case Sdata: - if (align > objout.dataalign) objout.dataalign = align; - while (objout.data.n & (align - 1)) vpush(&objout.data, 0); - off = objout.data.n; - vresize(&objout.data, objout.data.n + siz); - memset(objout.data.p+off, 0, siz); + if (align > o->dataalign) o->dataalign = align; + while (o->data.n & (align - 1)) vpush(&o->data, 0); + off = o->data.n; + vresize(&o->data, o->data.n + siz); + memset(o->data.p+off, 0, siz); break; case Sbss: - if (align > objout.bssalign) objout.bssalign = align; - off = alignup(objout.nbss, align); - objout.nbss = off + siz; + if (align > o->bssalign) o->bssalign = align; + off = alignup(o->nbss, align); + o->nbss = off + siz; break; } diff --git a/obj/obj.h b/obj/obj.h index 8e9dea8..59769ff 100644 --- a/obj/obj.h +++ b/obj/obj.h @@ -23,7 +23,7 @@ enum section { Snone, Stext, Srodata, Sdata, Sbss }; void objini(const char *infile, const char *outfile); void objdeffunc(const char *nam, bool globl, uint off, uint siz); -enum section objhassym(const char *name); +enum section objhassym(const char *name, uint *off); uint objnewdat(const char *name, enum section, bool globl, uint siz, uint align); void objreloc(const char *sym, enum relockind, enum section, uint off, vlong addend); void objfini(void); -- cgit v1.2.3