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); addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4); if(PtrSize == 8) adduintxx(gc, 0, 4); } 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); } } }
vlong adduint64(Sym *s, uint64 v) { return adduintxx(s, v, 8); }
vlong adduint32(Sym *s, uint32 v) { return adduintxx(s, v, 4); }
vlong adduint16(Sym *s, uint16 v) { return adduintxx(s, v, 2); }
vlong adduint8(Sym *s, uint8 v) { return adduintxx(s, v, 1); }
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++; }