// assign addresses to text void textaddress(void) { uvlong va; Section *sect; LSym *sym, *sub; addsection(&segtext, ".text", 05); // Assign PCs in text segment. // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; sect->align = funcalign; linklookup(ctxt, "runtime.text", 0)->sect = sect; linklookup(ctxt, "runtime.etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; for(sym = ctxt->textp; sym != nil; sym = sym->next) { sym->sect = sect; if(sym->type & SSUB) continue; if(sym->align != 0) va = rnd(va, sym->align); else va = rnd(va, funcalign); sym->value = 0; for(sub = sym; sub != S; sub = sub->sub) sub->value += va; if(sym->size == 0 && sym->sub != S) ctxt->cursym = sym; va += sym->size; } sect->len = va - sect->vaddr; }
// assign addresses to text void textaddress(void) { uvlong va; Prog *p; Section *sect; Sym *sym, *sub; addsection(&segtext, ".text", 05); // Assign PCs in text segment. // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; lookup("text", 0)->sect = sect; lookup("etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; for(sym = textp; sym != nil; sym = sym->next) { sym->sect = sect; if(sym->type & SSUB) continue; if(sym->align != 0) va = rnd(va, sym->align); else if(sym->text != P) va = rnd(va, FuncAlign); sym->value = 0; for(sub = sym; sub != S; sub = sub->sub) { sub->value += va; for(p = sub->text; p != P; p = p->link) p->pc += sub->value; } if(sym->size == 0 && sym->sub != S) { cursym = sym; } va += sym->size; } // Align end of code so that rodata starts aligned. // 128 bytes is likely overkill but definitely cheap. va = rnd(va, 128); sect->len = va - sect->vaddr; }
void dodata(void) { int32 t, datsize; Section *sect, *noptr; Sym *s, *last, **l; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); 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. */ 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 = datsort(datap); /* * allocate data sections. list is sorted by type, * so we can just walk it for each piece we want to emit. */ /* read-only data */ sect = addsection(&segtext, ".rodata", 04); sect->vaddr = 0; datsize = 0; s = datap; for(; s != nil && s->type < SSYMTAB; s = s->next) { if(s->align != 0) datsize = rnd(datsize, s->align); s->type = SRODATA; s->value = datsize; datsize += rnd(s->size, PtrSize); } sect->len = datsize - sect->vaddr; /* gosymtab */ sect = addsection(&segtext, ".gosymtab", 04); sect->vaddr = datsize; for(; s != nil && s->type < SPCLNTAB; s = s->next) { s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; datsize = rnd(datsize, PtrSize); /* gopclntab */ sect = addsection(&segtext, ".gopclntab", 04); sect->vaddr = datsize; for(; s != nil && s->type < SELFROSECT; s = s->next) { s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; datsize = rnd(datsize, PtrSize); /* read-only ELF sections */ for(; s != nil && s->type < SELFSECT; s = s->next) { sect = addsection(&segtext, s->name, 04); if(s->align != 0) datsize = rnd(datsize, s->align); sect->vaddr = datsize; s->type = SRODATA; s->value = datsize; 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; } }
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++; }
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++; }