Commit e4c4edf6 authored by Rob Pike's avatar Rob Pike

cmd/ld: fix some 64-bit issues

A few places in the linker pushed 64-bit values through 32-bit holes,
including in relocation.
Clean them up, and check for a few other overflows as well.
Tests to follow.

R=dsymonds
CC=gobot, golang-dev
https://golang.org/cl/9032043
parent 5c20a4f2
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "../../pkg/runtime/mgc0.h" #include "../../pkg/runtime/mgc0.h"
void dynreloc(void); 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 * divide-and-conquer list-link
...@@ -259,6 +259,10 @@ relocsym(Sym *s) ...@@ -259,6 +259,10 @@ relocsym(Sym *s)
cursym = s; cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name); diag("bad reloc size %#ux for %s", siz, r->sym->name);
case 4: case 4:
if(o != (int32)o) {
cursym = S;
diag("relocation address is too big: %#llx", o);
}
fl = o; fl = o;
cast = (uchar*)&fl; cast = (uchar*)&fl;
for(i=0; i<4; i++) for(i=0; i<4; i++)
...@@ -716,7 +720,7 @@ addstring(Sym *s, char *str) ...@@ -716,7 +720,7 @@ addstring(Sym *s, char *str)
} }
vlong vlong
setuintxx(Sym *s, vlong off, uint64 v, int wid) setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
{ {
int32 i, fl; int32 i, fl;
vlong o; vlong o;
...@@ -756,7 +760,7 @@ setuintxx(Sym *s, vlong off, uint64 v, int wid) ...@@ -756,7 +760,7 @@ setuintxx(Sym *s, vlong off, uint64 v, int wid)
vlong vlong
adduintxx(Sym *s, uint64 v, int wid) adduintxx(Sym *s, uint64 v, int wid)
{ {
int32 off; vlong off;
off = s->size; off = s->size;
setuintxx(s, off, v, wid); setuintxx(s, off, v, wid);
...@@ -812,7 +816,7 @@ setuint64(Sym *s, vlong r, uint64 v) ...@@ -812,7 +816,7 @@ setuint64(Sym *s, vlong r, uint64 v)
} }
vlong vlong
addaddrplus(Sym *s, Sym *t, int32 add) addaddrplus(Sym *s, Sym *t, vlong add)
{ {
vlong i; vlong i;
Reloc *r; Reloc *r;
...@@ -833,7 +837,7 @@ addaddrplus(Sym *s, Sym *t, int32 add) ...@@ -833,7 +837,7 @@ addaddrplus(Sym *s, Sym *t, int32 add)
} }
static vlong static vlong
addaddrplus4(Sym *s, Sym *t, int32 add) addaddrplus4(Sym *s, Sym *t, vlong add)
{ {
vlong i; vlong i;
Reloc *r; Reloc *r;
...@@ -854,7 +858,7 @@ addaddrplus4(Sym *s, Sym *t, int32 add) ...@@ -854,7 +858,7 @@ addaddrplus4(Sym *s, Sym *t, int32 add)
} }
vlong vlong
addpcrelplus(Sym *s, Sym *t, int32 add) addpcrelplus(Sym *s, Sym *t, vlong add)
{ {
vlong i; vlong i;
Reloc *r; Reloc *r;
...@@ -881,7 +885,7 @@ addaddr(Sym *s, Sym *t) ...@@ -881,7 +885,7 @@ addaddr(Sym *s, Sym *t)
} }
vlong vlong
setaddrplus(Sym *s, vlong off, Sym *t, int32 add) setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
{ {
Reloc *r; Reloc *r;
...@@ -958,8 +962,8 @@ symalign(Sym *s) ...@@ -958,8 +962,8 @@ symalign(Sym *s)
return align; return align;
} }
static int32 static vlong
aligndatsize(int32 datsize, Sym *s) aligndatsize(vlong datsize, Sym *s)
{ {
return rnd(datsize, symalign(s)); return rnd(datsize, symalign(s));
} }
...@@ -981,9 +985,9 @@ maxalign(Sym *s, int type) ...@@ -981,9 +985,9 @@ maxalign(Sym *s, int type)
} }
static void static void
gcaddsym(Sym *gc, Sym *s, int32 off) gcaddsym(Sym *gc, Sym *s, vlong off)
{ {
int32 a; vlong a;
Sym *gotype; Sym *gotype;
if(s->size < PtrSize) if(s->size < PtrSize)
...@@ -1008,10 +1012,24 @@ gcaddsym(Sym *gc, Sym *s, int32 off) ...@@ -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 void
dodata(void) dodata(void)
{ {
int32 n, datsize; int32 n;
vlong datsize;
Section *sect; Section *sect;
Sym *s, *last, **l; Sym *s, *last, **l;
Sym *gcdata1, *gcbss1; Sym *gcdata1, *gcbss1;
...@@ -1109,7 +1127,7 @@ dodata(void) ...@@ -1109,7 +1127,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SDATA; s->type = SDATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
} }
...@@ -1125,7 +1143,7 @@ dodata(void) ...@@ -1125,7 +1143,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SDATA; s->type = SDATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1142,7 +1160,7 @@ dodata(void) ...@@ -1142,7 +1160,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SDATA; s->type = SDATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
} }
...@@ -1164,7 +1182,7 @@ dodata(void) ...@@ -1164,7 +1182,7 @@ dodata(void)
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->value = datsize; s->value = datsize;
gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1183,7 +1201,7 @@ dodata(void) ...@@ -1183,7 +1201,7 @@ dodata(void)
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->value = datsize; s->value = datsize;
gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1201,10 +1219,15 @@ dodata(void) ...@@ -1201,10 +1219,15 @@ dodata(void)
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->sect = sect; s->sect = sect;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
lookup("end", 0)->sect = sect; 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) { if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
sect = addsection(&segdata, ".tbss", 06); sect = addsection(&segdata, ".tbss", 06);
...@@ -1215,7 +1238,7 @@ dodata(void) ...@@ -1215,7 +1238,7 @@ dodata(void)
datsize = aligndatsize(datsize, s); datsize = aligndatsize(datsize, s);
s->sect = sect; s->sect = sect;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize; sect->len = datsize;
} }
...@@ -1240,7 +1263,7 @@ dodata(void) ...@@ -1240,7 +1263,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SRODATA; s->type = SRODATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1256,7 +1279,7 @@ dodata(void) ...@@ -1256,7 +1279,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SRODATA; s->type = SRODATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1272,7 +1295,7 @@ dodata(void) ...@@ -1272,7 +1295,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SRODATA; s->type = SRODATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1288,7 +1311,7 @@ dodata(void) ...@@ -1288,7 +1311,7 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SRODATA; s->type = SRODATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
} }
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
...@@ -1301,9 +1324,14 @@ dodata(void) ...@@ -1301,9 +1324,14 @@ dodata(void)
s->sect = sect; s->sect = sect;
s->type = SRODATA; s->type = SRODATA;
s->value = datsize; s->value = datsize;
datsize += s->size; growdatsize(&datsize, s);
sect->len = datsize - sect->vaddr; 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 */ /* number the sections */
n = 1; n = 1;
......
...@@ -1110,7 +1110,7 @@ asmbelfsetup(void) ...@@ -1110,7 +1110,7 @@ asmbelfsetup(void)
void void
asmbelf(vlong symo) asmbelf(vlong symo)
{ {
int a, o; vlong a, o;
vlong startva, resoff; vlong startva, resoff;
ElfEhdr *eh; ElfEhdr *eh;
ElfPhdr *ph, *pph, *pnote; ElfPhdr *ph, *pph, *pnote;
......
...@@ -804,9 +804,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) ...@@ -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] // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
secaddr = c->seg.sect[rel->symnum-1].addr; 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 } 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 // For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make // it *is* the PC being subtracted. Use that to make
......
...@@ -237,10 +237,10 @@ vlong adduint32(Sym*, uint32); ...@@ -237,10 +237,10 @@ vlong adduint32(Sym*, uint32);
vlong adduint64(Sym*, uint64); vlong adduint64(Sym*, uint64);
vlong adduintxx(Sym*, uint64, int); vlong adduintxx(Sym*, uint64, int);
vlong addaddr(Sym*, Sym*); vlong addaddr(Sym*, Sym*);
vlong addaddrplus(Sym*, Sym*, int32); vlong addaddrplus(Sym*, Sym*, vlong);
vlong addpcrelplus(Sym*, Sym*, int32); vlong addpcrelplus(Sym*, Sym*, vlong);
vlong addsize(Sym*, Sym*); vlong addsize(Sym*, Sym*);
vlong setaddrplus(Sym*, vlong, Sym*, int32); vlong setaddrplus(Sym*, vlong, Sym*, vlong);
vlong setaddr(Sym*, vlong, Sym*); vlong setaddr(Sym*, vlong, Sym*);
void setuint8(Sym*, vlong, uint8); void setuint8(Sym*, vlong, uint8);
void setuint16(Sym*, vlong, uint16); void setuint16(Sym*, vlong, uint16);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment