]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/ld: fix some 64-bit issues
authorRob Pike <r@golang.org>
Tue, 30 Apr 2013 05:44:20 +0000 (22:44 -0700)
committerRob Pike <r@golang.org>
Tue, 30 Apr 2013 05:44:20 +0000 (22:44 -0700)
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

src/cmd/ld/data.c
src/cmd/ld/elf.c
src/cmd/ld/ldmacho.c
src/cmd/ld/lib.h

index fa34aa3a12651d1898e3cf327c005e8e609b604f..f7e585b917d31464aa6f6e7fb3ab5ac72cad5b15 100644 (file)
@@ -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;
index 22bc64f8f025dc6dc76e7555773d60c5ebc99acd..056f95b9cc87465f949289d6116121809d12c1f1 100644 (file)
@@ -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;
index 098cb7beffc45753120aaedb68b3bd90015526d9..d384a5094b1351a286915f5244ca4c86d1561c18 100644 (file)
@@ -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
index 9bdfe95c411884f6254d3a5e8982e025d77aea41..5b077e381fb34daf80ed81e4ad30bfd35750ad2f 100644 (file)
@@ -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);