diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index fa34aa3a126..f7e585b917d 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -38,7 +38,7 @@ #include "../../pkg/runtime/mgc0.h" void dynreloc(void); -static vlong addaddrplus4(Sym *s, Sym *t, int32 add); +static vlong addaddrplus4(Sym *s, Sym *t, vlong add); /* * divide-and-conquer list-link @@ -259,6 +259,10 @@ relocsym(Sym *s) cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); case 4: + if(o != (int32)o) { + cursym = S; + diag("relocation address is too big: %#llx", o); + } fl = o; cast = (uchar*)&fl; for(i=0; i<4; i++) @@ -716,7 +720,7 @@ addstring(Sym *s, char *str) } vlong -setuintxx(Sym *s, vlong off, uint64 v, int wid) +setuintxx(Sym *s, vlong off, uint64 v, vlong wid) { int32 i, fl; vlong o; @@ -756,7 +760,7 @@ setuintxx(Sym *s, vlong off, uint64 v, int wid) vlong adduintxx(Sym *s, uint64 v, int wid) { - int32 off; + vlong off; off = s->size; setuintxx(s, off, v, wid); @@ -812,7 +816,7 @@ setuint64(Sym *s, vlong r, uint64 v) } vlong -addaddrplus(Sym *s, Sym *t, int32 add) +addaddrplus(Sym *s, Sym *t, vlong add) { vlong i; Reloc *r; @@ -833,7 +837,7 @@ addaddrplus(Sym *s, Sym *t, int32 add) } static vlong -addaddrplus4(Sym *s, Sym *t, int32 add) +addaddrplus4(Sym *s, Sym *t, vlong add) { vlong i; Reloc *r; @@ -854,7 +858,7 @@ addaddrplus4(Sym *s, Sym *t, int32 add) } vlong -addpcrelplus(Sym *s, Sym *t, int32 add) +addpcrelplus(Sym *s, Sym *t, vlong add) { vlong i; Reloc *r; @@ -881,7 +885,7 @@ addaddr(Sym *s, Sym *t) } vlong -setaddrplus(Sym *s, vlong off, Sym *t, int32 add) +setaddrplus(Sym *s, vlong off, Sym *t, vlong add) { Reloc *r; @@ -958,8 +962,8 @@ symalign(Sym *s) return align; } -static int32 -aligndatsize(int32 datsize, Sym *s) +static vlong +aligndatsize(vlong datsize, Sym *s) { return rnd(datsize, symalign(s)); } @@ -981,9 +985,9 @@ maxalign(Sym *s, int type) } static void -gcaddsym(Sym *gc, Sym *s, int32 off) +gcaddsym(Sym *gc, Sym *s, vlong off) { - int32 a; + vlong a; Sym *gotype; if(s->size < PtrSize) @@ -1008,10 +1012,24 @@ gcaddsym(Sym *gc, Sym *s, int32 off) } } +void +growdatsize(vlong *datsizep, Sym *s) +{ + vlong datsize; + + datsize = *datsizep; + if(s->size < 0) + diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size); + if(datsize + s->size < datsize) + diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size); + *datsizep = datsize + s->size; +} + void dodata(void) { - int32 n, datsize; + int32 n; + vlong datsize; Section *sect; Sym *s, *last, **l; Sym *gcdata1, *gcbss1; @@ -1109,7 +1127,7 @@ dodata(void) s->sect = sect; s->type = SDATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); sect->len = datsize - sect->vaddr; } @@ -1125,7 +1143,7 @@ dodata(void) s->sect = sect; s->type = SDATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1142,7 +1160,7 @@ dodata(void) s->sect = sect; s->type = SDATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; } @@ -1164,7 +1182,7 @@ dodata(void) datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1183,7 +1201,7 @@ dodata(void) datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1201,10 +1219,15 @@ dodata(void) datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; lookup("end", 0)->sect = sect; + + // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. + if(datsize != (uint32)datsize) { + diag("data or bss segment too large"); + } if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) { sect = addsection(&segdata, ".tbss", 06); @@ -1215,7 +1238,7 @@ dodata(void) datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize; } @@ -1240,7 +1263,7 @@ dodata(void) s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1256,7 +1279,7 @@ dodata(void) s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1272,7 +1295,7 @@ dodata(void) s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1288,7 +1311,7 @@ dodata(void) s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; @@ -1301,9 +1324,14 @@ dodata(void) s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += s->size; + growdatsize(&datsize, s); sect->len = datsize - sect->vaddr; } + + // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. + if(datsize != (uint32)datsize) { + diag("text segment too large"); + } /* number the sections */ n = 1; diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 22bc64f8f02..056f95b9cc8 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -1110,7 +1110,7 @@ asmbelfsetup(void) void asmbelf(vlong symo) { - int a, o; + vlong a, o; vlong startva, resoff; ElfEhdr *eh; ElfPhdr *ph, *pph, *pnote; diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index 098cb7beffc..d384a5094b1 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -804,9 +804,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) // // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] secaddr = c->seg.sect[rel->symnum-1].addr; - rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr; + rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr; } else - rp->add = e->e32(s->p+rp->off); + rp->add = (int32)e->e32(s->p+rp->off); // For i386 Mach-O PC-relative, the addend is written such that // it *is* the PC being subtracted. Use that to make diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 9bdfe95c411..5b077e381fb 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -237,10 +237,10 @@ vlong adduint32(Sym*, uint32); vlong adduint64(Sym*, uint64); vlong adduintxx(Sym*, uint64, int); vlong addaddr(Sym*, Sym*); -vlong addaddrplus(Sym*, Sym*, int32); -vlong addpcrelplus(Sym*, Sym*, int32); +vlong addaddrplus(Sym*, Sym*, vlong); +vlong addpcrelplus(Sym*, Sym*, vlong); vlong addsize(Sym*, Sym*); -vlong setaddrplus(Sym*, vlong, Sym*, int32); +vlong setaddrplus(Sym*, vlong, Sym*, vlong); vlong setaddr(Sym*, vlong, Sym*); void setuint8(Sym*, vlong, uint8); void setuint16(Sym*, vlong, uint16);