// maxalign returns the maximum required alignment for // the list of symbols s; the list stops when s->type exceeds type. static int32 maxalign(Sym *s, int type) { int32 align, max; max = 0; for(; s != S && s->type <= type; s = s->next) { align = symalign(s); if(max < align) max = align; } return max; }
static int32 aligndatsize(int32 datsize, Sym *s) { return rnd(datsize, symalign(s)); }
void dodata(void) { int32 n; vlong datsize; Section *sect; Segment *segro; LSym *s, *last, **l; LSym *gcdata, *gcbss; ProgGen gen; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); last = nil; datap = nil; for(s=ctxt->allsym; s!=S; s=s->allsym) { if(!s->reachable || s->special) continue; if(STEXT < s->type && s->type < SXREF) { if(s->onlist) sysfatal("symbol %s listed multiple times", s->name); s->onlist = 1; if(last == nil) datap = s; else last->next = s; s->next = nil; last = s; } } for(s = datap; s != nil; s = s->next) { if(s->np > s->size) diag("%s: initialize bounds (%lld < %d)", s->name, (vlong)s->size, s->np); } /* * now that we have the datap list, but before we start * to assign addresses, record all the necessary * dynamic relocations. these will grow the relocation * symbol, which is itself data. * * on darwin, we need the symbol table numbers for dynreloc. */ if(HEADTYPE == Hdarwin) machosymorder(); dynreloc(); /* some symbols may no longer belong in datap (Mach-O) */ for(l=&datap; (s=*l) != nil; ) { if(s->type <= STEXT || SXREF <= s->type) *l = s->next; else l = &s->next; } *l = nil; datap = listsort(datap, datcmp, offsetof(LSym, next)); /* * 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); sect->align = symalign(s); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SDATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); sect->len = datsize - sect->vaddr; } /* pointer-free data */ sect = addsection(&segdata, ".noptrdata", 06); sect->align = maxalign(s, SINITARR-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect; linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SDATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; /* shared library initializer */ if(flag_shared) { sect = addsection(&segdata, ".init_array", 06); sect->align = maxalign(s, SINITARR); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; for(; s != nil && s->type == SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; } /* data */ sect = addsection(&segdata, ".data", 06); sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.data", 0)->sect = sect; linklookup(ctxt, "runtime.edata", 0)->sect = sect; gcdata = linklookup(ctxt, "runtime.gcdata", 0); proggeninit(&gen, gcdata); for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SINITARR) { ctxt->cursym = s; diag("unexpected symbol type %d", s->type); } s->sect = sect; s->type = SDATA; datsize = aligndatsize(datsize, s); s->value = datsize - sect->vaddr; proggenaddsym(&gen, s); // gc growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; proggenfini(&gen, sect->len); // gc /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.bss", 0)->sect = sect; linklookup(ctxt, "runtime.ebss", 0)->sect = sect; gcbss = linklookup(ctxt, "runtime.gcbss", 0); proggeninit(&gen, gcbss); for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); s->value = datsize - sect->vaddr; proggenaddsym(&gen, s); // gc growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; proggenfini(&gen, sect->len); // gc /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect; linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect; for(; s != nil && s->type == SNOPTRBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; linklookup(ctxt, "runtime.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); sect->align = PtrSize; sect->vaddr = 0; datsize = 0; for(; s != nil && s->type == STLSBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize; } else { // Might be internal linking but still using cgo. // In that case, the only possible STLSBSS symbol is runtime.tlsg. // Give it offset 0, because it's the only thing here. if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) { s->value = 0; s = s->next; } } if(s != nil) { ctxt->cursym = nil; diag("unexpected symbol type %d for %s", s->type, s->name); } /* * We finished data, begin read-only data. * Not all systems support a separate read-only non-executable data section. * ELF systems do. * OS X and Plan 9 do not. * Windows PE may, but if so we have not implemented it. * And if we're using external linking mode, the point is moot, * since it's not our decision; that code expects the sections in * segtext. */ if(iself && linkmode == LinkInternal) segro = &segrodata; else segro = &segtext; s = datap; datsize = 0; /* read-only executable ELF, Mach-O sections */ for(; s != nil && s->type < STYPE; s = s->next) { sect = addsection(&segtext, s->name, 04); sect->align = symalign(s); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); sect->len = datsize - sect->vaddr; } /* read-only data */ sect = addsection(segro, ".rodata", 04); sect->align = maxalign(s, STYPELINK-1); datsize = rnd(datsize, sect->align); sect->vaddr = 0; linklookup(ctxt, "runtime.rodata", 0)->sect = sect; linklookup(ctxt, "runtime.erodata", 0)->sect = sect; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; /* typelink */ sect = addsection(segro, ".typelink", 04); sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.typelink", 0)->sect = sect; linklookup(ctxt, "runtime.etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; /* gosymtab */ sect = addsection(segro, ".gosymtab", 04); sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.symtab", 0)->sect = sect; linklookup(ctxt, "runtime.esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; /* gopclntab */ sect = addsection(segro, ".gopclntab", 04); sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; linklookup(ctxt, "runtime.pclntab", 0)->sect = sect; linklookup(ctxt, "runtime.epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; /* read-only ELF, Mach-O sections */ for(; s != nil && s->type < SELFSECT; s = s->next) { sect = addsection(segro, s->name, 04); sect->align = symalign(s); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SRODATA; s->value = datsize - sect->vaddr; 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("read-only data segment too large"); } /* number the sections */ n = 1; for(sect = segtext.sect; sect != nil; sect = sect->next) sect->extnum = n++; for(sect = segrodata.sect; sect != nil; sect = sect->next) sect->extnum = n++; for(sect = segdata.sect; sect != nil; sect = sect->next) sect->extnum = n++; }
void dodata(void) { int32 n, datsize; 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("gcdata", 0); gcdata1->type = STYPE; gcdata1->reachable = 1; gcbss1 = lookup("gcbss", 0); gcbss1->type = STYPE; 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; for(s=allsym; s!=S; s=s->allsym) { if(!s->reachable || s->special) continue; if(STEXT < s->type && s->type < SXREF) { if(last == nil) datap = s; else last->next = s; s->next = nil; last = s; } } for(s = datap; s != nil; s = s->next) { if(s->np > s->size) diag("%s: initialize bounds (%lld < %d)", s->name, (vlong)s->size, s->np); } /* * now that we have the datap list, but before we start * to assign addresses, record all the necessary * dynamic relocations. these will grow the relocation * symbol, which is itself data. * * on darwin, we need the symbol table numbers for dynreloc. */ if(HEADTYPE == Hdarwin) machosymorder(); dynreloc(); /* some symbols may no longer belong in datap (Mach-O) */ for(l=&datap; (s=*l) != nil; ) { if(s->type <= STEXT || SXREF <= s->type) *l = s->next; else l = &s->next; } *l = nil; if(flag_shared) { for(s=datap; s != nil; s = s->next) { if(s->rel_ro) s->type = SDATARELRO; } } datap = listsort(datap, datcmp, offsetof(Sym, next)); /* * 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); sect->align = symalign(s); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SDATA; s->value = datsize; datsize += s->size; sect->len = datsize - sect->vaddr; } /* pointer-free data */ sect = addsection(&segdata, ".noptrdata", 06); sect->align = maxalign(s, SDATARELRO-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("noptrdata", 0)->sect = sect; lookup("enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SDATARELRO; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SDATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; /* dynamic relocated rodata */ if(flag_shared) { sect = addsection(&segdata, ".data.rel.ro", 06); sect->align = maxalign(s, SDATARELRO); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("datarelro", 0)->sect = sect; lookup("edatarelro", 0)->sect = sect; for(; s != nil && s->type == SDATARELRO; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SDATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; } /* data */ sect = addsection(&segdata, ".data", 06); sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("data", 0)->sect = sect; lookup("edata", 0)->sect = sect; for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SDATARELRO) { cursym = s; diag("unexpected symbol type %d", s->type); } s->sect = sect; s->type = SDATA; datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc datsize += s->size; } sect->len = datsize - sect->vaddr; adduintxx(gcdata1, GC_END, PtrSize); setuintxx(gcdata1, 0, sect->len, PtrSize); /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("bss", 0)->sect = sect; lookup("ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc datsize += s->size; } sect->len = datsize - sect->vaddr; adduintxx(gcbss1, GC_END, PtrSize); setuintxx(gcbss1, 0, sect->len, PtrSize); /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("noptrbss", 0)->sect = sect; lookup("enoptrbss", 0)->sect = sect; for(; s != nil; s = s->next) { if(s->type > SNOPTRBSS) { cursym = s; diag("unexpected symbol type %d", s->type); } datsize = aligndatsize(datsize, s); s->sect = sect; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; lookup("end", 0)->sect = sect; /* we finished segdata, begin segtext */ s = datap; datsize = 0; /* read-only data */ sect = addsection(&segtext, ".rodata", 04); sect->align = maxalign(s, STYPELINK-1); sect->vaddr = 0; lookup("rodata", 0)->sect = sect; lookup("erodata", 0)->sect = sect; datsize = 0; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; /* typelink */ sect = addsection(&segtext, ".typelink", 04); sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("typelink", 0)->sect = sect; lookup("etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; /* gosymtab */ sect = addsection(&segtext, ".gosymtab", 04); sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("symtab", 0)->sect = sect; lookup("esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; /* gopclntab */ sect = addsection(&segtext, ".gopclntab", 04); sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("pclntab", 0)->sect = sect; lookup("epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; /* read-only ELF, Mach-O sections */ for(; s != nil && s->type < SELFSECT; s = s->next) { sect = addsection(&segtext, s->name, 04); sect->align = symalign(s); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; sect->len = datsize - sect->vaddr; } /* number the sections */ n = 1; for(sect = segtext.sect; sect != nil; sect = sect->next) sect->extnum = n++; for(sect = segdata.sect; sect != nil; sect = sect->next) sect->extnum = n++; }
static vlong aligndatsize(vlong datsize, LSym *s) { return rnd(datsize, symalign(s)); }