diff options
| author | Jan Ziak <0xe2.0x9a.0x9b@gmail.com> | 2012-09-13 15:59:34 -0400 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2012-09-13 15:59:34 -0400 |
| commit | 032e5bfb302714c4f9330540ca3d4087062bdc1a (patch) | |
| tree | fb3855ad7e6a6dafc106a4878c370676ee4aec7a /src/cmd/ld/data.c | |
| parent | 9a82324fb753cfe2e6902ac6835973237829c941 (diff) | |
| download | go-032e5bfb302714c4f9330540ca3d4087062bdc1a.tar.xz | |
ld: add .gcdata and .gcbss sections
R=rsc
CC=golang-dev
https://golang.org/cl/6281048
Diffstat (limited to 'src/cmd/ld/data.c')
| -rw-r--r-- | src/cmd/ld/data.c | 340 |
1 files changed, 235 insertions, 105 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 865f282114..e1d380b317 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -34,6 +34,7 @@ #include "../ld/lib.h" #include "../ld/elf.h" #include "../ld/pe.h" +#include "../../pkg/runtime/mgc0.h" void dynreloc(void); static vlong addaddrplus4(Sym *s, Sym *t, int32 add); @@ -628,41 +629,51 @@ addstring(Sym *s, char *str) } vlong -adduintxx(Sym *s, uint64 v, int wid) +setuintxx(Sym *s, vlong off, uint64 v, int wid) { - int32 i, r, fl; + int32 i, fl; vlong o; uchar *cast; if(s->type == 0) s->type = SDATA; s->reachable = 1; - r = s->size; - s->size += wid; - symgrow(s, s->size); - assert(r+wid <= s->size); + if(s->size < off+wid) { + s->size = off+wid; + symgrow(s, s->size); + } fl = v; cast = (uchar*)&fl; switch(wid) { case 1: - s->p[r] = cast[inuxi1[0]]; + s->p[off] = cast[inuxi1[0]]; break; case 2: for(i=0; i<2; i++) - s->p[r+i] = cast[inuxi2[i]]; + s->p[off+i] = cast[inuxi2[i]]; break; case 4: for(i=0; i<4; i++) - s->p[r+i] = cast[inuxi4[i]]; + s->p[off+i] = cast[inuxi4[i]]; break; case 8: o = v; cast = (uchar*)&o; for(i=0; i<8; i++) - s->p[r+i] = cast[inuxi8[i]]; + s->p[off+i] = cast[inuxi8[i]]; break; } - return r; + return off; +} + +vlong +adduintxx(Sym *s, uint64 v, int wid) +{ + int32 off; + + off = s->size; + setuintxx(s, off, v, wid); + return off; } vlong @@ -689,6 +700,30 @@ adduint64(Sym *s, uint64 v) return adduintxx(s, v, 8); } +void +setuint8(Sym *s, vlong r, uint8 v) +{ + setuintxx(s, r, v, 1); +} + +void +setuint16(Sym *s, vlong r, uint16 v) +{ + setuintxx(s, r, v, 2); +} + +void +setuint32(Sym *s, vlong r, uint32 v) +{ + setuintxx(s, r, v, 4); +} + +void +setuint64(Sym *s, vlong r, uint64 v) +{ + setuintxx(s, r, v, 8); +} + vlong addaddrplus(Sym *s, Sym *t, int32 add) { @@ -793,17 +828,87 @@ dosymtype(void) } } +static int32 +alignsymsize(int32 s) +{ + if(s >= PtrSize) + s = rnd(s, PtrSize); + else if(s > 2) + s = rnd(s, 4); + return s; +} + +static int32 +aligndatsize(int32 datsize, Sym *s) +{ + int32 t; + + if(s->align != 0) { + datsize = rnd(datsize, s->align); + } else { + t = alignsymsize(s->size); + if(t & 1) { + ; + } else if(t & 2) + datsize = rnd(datsize, 2); + else if(t & 4) + datsize = rnd(datsize, 4); + else + datsize = rnd(datsize, 8); + } + return datsize; +} + +static void +gcaddsym(Sym *gc, Sym *s, int32 off) +{ + int32 a; + Sym *gotype; + + if(s->size < PtrSize) + return; + if(strcmp(s->name, ".string") == 0) + return; + + gotype = s->gotype; + if(gotype != nil) { + //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); + adduintxx(gc, GC_CALL, PtrSize); + adduintxx(gc, off, PtrSize); + addaddrplus(gc, decodetype_gc(gotype), 1*PtrSize); + } else { + //print("gcaddsym: %s %d <unknown type>\n", s->name, s->size); + for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { + adduintxx(gc, GC_APTR, PtrSize); + adduintxx(gc, off+a, PtrSize); + } + } +} + void dodata(void) { int32 t, datsize; - Section *sect, *noptr; + Section *sect; Sym *s, *last, **l; + Sym *gcdata1, *gcbss1; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); + // define garbage collection symbols + gcdata1 = lookup("gcdata1", 0); + gcdata1->type = SGCDATA; + gcdata1->reachable = 1; + gcbss1 = lookup("gcbss1", 0); + gcbss1->type = SGCBSS; + gcbss1->reachable = 1; + + // size of .data and .bss section. the zero value is later replaced by the actual size of the section. + adduintxx(gcdata1, 0, PtrSize); + adduintxx(gcbss1, 0, PtrSize); + last = nil; datap = nil; @@ -847,16 +952,102 @@ dodata(void) datap = datsort(datap); /* - * allocate data sections. list is sorted by type, + * allocate sections. list is sorted by type, * so we can just walk it for each piece we want to emit. + * segdata is processed before segtext, because we need + * to see all symbols in the .data and .bss sections in order + * to generate garbage collection information. */ + /* begin segdata */ + + /* skip symbols belonging to segtext */ + s = datap; + for(; s != nil && s->type < SELFSECT; s = s->next); + + /* writable ELF sections */ + datsize = 0; + for(; s != nil && s->type < SNOPTRDATA; s = s->next) { + sect = addsection(&segdata, s->name, 06); + if(s->align != 0) + datsize = rnd(datsize, s->align); + sect->vaddr = datsize; + s->type = SDATA; + s->value = datsize; + datsize += rnd(s->size, PtrSize); + sect->len = datsize - sect->vaddr; + } + + /* pointer-free data */ + sect = addsection(&segdata, ".noptrdata", 06); + sect->vaddr = datsize; + for(; s != nil && s->type < SDATA; s = s->next) { + s->type = SDATA; + t = alignsymsize(s->size); + datsize = aligndatsize(datsize, s); + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + /* data */ + sect = addsection(&segdata, ".data", 06); + sect->vaddr = datsize; + for(; s != nil && s->type < SBSS; s = s->next) { + s->type = SDATA; + t = alignsymsize(s->size); + datsize = aligndatsize(datsize, s); + s->value = datsize; + gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc + datsize += t; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + adduintxx(gcdata1, GC_END, PtrSize); + setuintxx(gcdata1, 0, sect->len, PtrSize); + + /* bss */ + sect = addsection(&segdata, ".bss", 06); + sect->vaddr = datsize; + for(; s != nil && s->type < SNOPTRBSS; s = s->next) { + t = alignsymsize(s->size); + datsize = aligndatsize(datsize, s); + s->value = datsize; + gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc + datsize += t; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + adduintxx(gcbss1, GC_END, PtrSize); + setuintxx(gcbss1, 0, sect->len, PtrSize); + + /* pointer-free bss */ + sect = addsection(&segdata, ".noptrbss", 06); + sect->vaddr = datsize; + for(; s != nil; s = s->next) { + if(s->type > SNOPTRBSS) { + cursym = s; + diag("unexpected symbol type %d", s->type); + } + t = alignsymsize(s->size); + datsize = aligndatsize(datsize, s); + s->value = datsize; + datsize += t; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + /* we finished segdata, begin segtext */ + /* read-only data */ sect = addsection(&segtext, ".rodata", 04); sect->vaddr = 0; datsize = 0; s = datap; - for(; s != nil && s->type < SSYMTAB; s = s->next) { + for(; s != nil && s->type < SGCDATA; s = s->next) { if(s->align != 0) datsize = rnd(datsize, s->align); s->type = SRODATA; @@ -865,6 +1056,28 @@ dodata(void) } sect->len = datsize - sect->vaddr; + /* gcdata */ + sect = addsection(&segtext, ".gcdata", 04); + sect->vaddr = datsize; + for(; s != nil && s->type == SGCDATA; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + + /* gcbss */ + sect = addsection(&segtext, ".gcbss", 04); + sect->vaddr = datsize; + for(; s != nil && s->type == SGCBSS; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + datsize = rnd(datsize, PtrSize); + /* gosymtab */ sect = addsection(&segtext, ".gosymtab", 04); sect->vaddr = datsize; @@ -898,96 +1111,6 @@ dodata(void) datsize += rnd(s->size, PtrSize); sect->len = datsize - sect->vaddr; } - - /* writable ELF sections */ - datsize = 0; - for(; s != nil && s->type < SNOPTRDATA; s = s->next) { - sect = addsection(&segdata, s->name, 06); - if(s->align != 0) - datsize = rnd(datsize, s->align); - sect->vaddr = datsize; - s->type = SDATA; - s->value = datsize; - datsize += rnd(s->size, PtrSize); - sect->len = datsize - sect->vaddr; - } - - /* pointer-free data, then data */ - sect = addsection(&segdata, ".noptrdata", 06); - sect->vaddr = datsize; - noptr = sect; - for(; ; s = s->next) { - if((s == nil || s->type >= SDATA) && sect == noptr) { - // finish noptrdata, start data - datsize = rnd(datsize, 8); - sect->len = datsize - sect->vaddr; - sect = addsection(&segdata, ".data", 06); - sect->vaddr = datsize; - } - if(s == nil || s->type >= SBSS) { - // finish data - sect->len = datsize - sect->vaddr; - break; - } - s->type = SDATA; - t = s->size; - if(t >= PtrSize) - t = rnd(t, PtrSize); - else if(t > 2) - t = rnd(t, 4); - if(s->align != 0) - datsize = rnd(datsize, s->align); - else if(t & 1) { - ; - } else if(t & 2) - datsize = rnd(datsize, 2); - else if(t & 4) - datsize = rnd(datsize, 4); - else - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } - - /* bss, then pointer-free bss */ - noptr = nil; - sect = addsection(&segdata, ".bss", 06); - sect->vaddr = datsize; - for(; ; s = s->next) { - if((s == nil || s->type >= SNOPTRBSS) && noptr == nil) { - // finish bss, start noptrbss - datsize = rnd(datsize, 8); - sect->len = datsize - sect->vaddr; - sect = addsection(&segdata, ".noptrbss", 06); - sect->vaddr = datsize; - noptr = sect; - } - if(s == nil) { - sect->len = datsize - sect->vaddr; - break; - } - if(s->type > SNOPTRBSS) { - cursym = s; - diag("unexpected symbol type %d", s->type); - } - t = s->size; - if(t >= PtrSize) - t = rnd(t, PtrSize); - else if(t > 2) - t = rnd(t, 4); - if(s->align != 0) - datsize = rnd(datsize, s->align); - else if(t & 1) { - ; - } else if(t & 2) - datsize = rnd(datsize, 2); - else if(t & 4) - datsize = rnd(datsize, 4); - else - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } } // assign addresses to text @@ -1038,6 +1161,7 @@ void address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; + Section *gcdata, *gcbss; Sym *sym, *sub; uvlong va; @@ -1084,7 +1208,9 @@ address(void) text = segtext.sect; rodata = text->next; - symtab = rodata->next; + gcdata = rodata->next; + gcbss = gcdata->next; + symtab = gcbss->next; pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { @@ -1101,6 +1227,10 @@ address(void) xdefine("etext", STEXT, text->vaddr + text->len); xdefine("rodata", SRODATA, rodata->vaddr); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); + xdefine("gcdata", SGCDATA, gcdata->vaddr); + xdefine("egcdata", SGCDATA, gcdata->vaddr + gcdata->len); + xdefine("gcbss", SGCBSS, gcbss->vaddr); + xdefine("egcbss", SGCBSS, gcbss->vaddr + gcbss->len); xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); xdefine("pclntab", SRODATA, pclntab->vaddr); |
