vlong addstring(Sym *s, char *str) { int n; int32 r; if(s->type == 0) s->type = SNOPTRDATA; s->reachable = 1; r = s->size; n = strlen(str)+1; if(strcmp(s->name, ".shstrtab") == 0) elfsetstring(str, r); symgrow(s, r+n); memmove(s->p+r, str, n); s->size += n; return r; }
vlong addsize(Sym *s, Sym *t) { vlong i; Reloc *r; if(s->type == 0) s->type = SDATA; s->reachable = 1; i = s->size; s->size += PtrSize; symgrow(s, s->size); r = addrel(s); r->sym = t; r->off = i; r->siz = PtrSize; r->type = D_SIZE; return i; }
vlong addpcrelplus(Sym *s, Sym *t, int32 add) { vlong i; Reloc *r; if(s->type == 0) s->type = SDATA; s->reachable = 1; i = s->size; s->size += 4; symgrow(s, s->size); r = addrel(s); r->sym = t; r->off = i; r->add = add; r->type = D_PCREL; r->siz = 4; return i; }
vlong addaddrplus(Sym *s, Sym *t, int32 add) { vlong i; Reloc *r; if(s->type == 0) s->type = SDATA; s->reachable = 1; i = s->size; s->size += PtrSize; symgrow(s, s->size); r = addrel(s); r->sym = t; r->off = i; r->siz = PtrSize; r->type = D_ADDR; r->add = add; return i; }
vlong setaddrplus(Sym *s, vlong off, Sym *t, int32 add) { Reloc *r; if(s->type == 0) s->type = SDATA; s->reachable = 1; if(off+PtrSize > s->size) { s->size = off + PtrSize; symgrow(s, s->size); } r = addrel(s); r->sym = t; r->off = off; r->siz = PtrSize; r->type = D_ADDR; r->add = add; return off; }
vlong adduintxx(Sym *s, uint64 v, int wid) { int32 i, r, 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); fl = v; cast = (uchar*)&fl; switch(wid) { case 1: s->p[r] = cast[inuxi1[0]]; break; case 2: for(i=0; i<2; i++) s->p[r+i] = cast[inuxi2[i]]; break; case 4: for(i=0; i<4; i++) s->p[r+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]]; break; } return r; }
vlong setuintxx(Sym *s, vlong off, uint64 v, int wid) { int32 i, fl; vlong o; uchar *cast; if(s->type == 0) s->type = SDATA; s->reachable = 1; if(s->size < off+wid) { s->size = off+wid; symgrow(s, s->size); } fl = v; cast = (uchar*)&fl; switch(wid) { case 1: s->p[off] = cast[inuxi1[0]]; break; case 2: for(i=0; i<2; i++) s->p[off+i] = cast[inuxi2[i]]; break; case 4: for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: o = v; cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } return off; }
void savedata(Sym *s, Prog *p, char *pn) { int32 off, siz, i, fl; uchar *cast; vlong o; Reloc *r; off = p->from.offset; siz = p->datasize; if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) mangle(pn); symgrow(s, off+siz); switch(p->to.type) { default: diag("bad data: %P", p); break; case D_FCONST: switch(siz) { default: case 4: fl = ieeedtof(&p->to.ieee); cast = (uchar*)&fl; for(i=0; i<4; i++) s->p[off+i] = cast[fnuxi4[i]]; break; case 8: cast = (uchar*)&p->to.ieee; for(i=0; i<8; i++) s->p[off+i] = cast[fnuxi8[i]]; break; } break; case D_SCONST: for(i=0; i<siz; i++) s->p[off+i] = p->to.scon[i]; break; case D_CONST: if(p->to.sym) goto Addr; o = p->to.offset; fl = o; cast = (uchar*)&fl; switch(siz) { default: diag("bad nuxi %d\n%P", siz, p); break; case 1: s->p[off] = cast[inuxi1[0]]; break; case 2: for(i=0; i<2; i++) s->p[off+i] = cast[inuxi2[i]]; break; case 4: for(i=0; i<4; i++) s->p[off+i] = cast[inuxi4[i]]; break; case 8: cast = (uchar*)&o; for(i=0; i<8; i++) s->p[off+i] = cast[inuxi8[i]]; break; } break; case D_ADDR: case D_SIZE: Addr: r = addrel(s); r->off = off; r->siz = siz; r->sym = p->to.sym; r->type = p->to.type; if(r->type != D_SIZE) r->type = D_ADDR; r->add = p->to.offset; break; } }
void adddynsym(Sym *s) { Sym *d, *str; int t; char *name; vlong off; if(s->dynid >= 0) return; if(s->dynimpname == nil) diag("adddynsym: no dynamic name for %s", s->name); if(iself) { s->dynid = nelfsym++; d = lookup(".dynsym", 0); /* name */ name = s->dynimpname; if(name == nil) name = s->name; adduint32(d, addstring(lookup(".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) adduint32(d, 0); else addaddr(d, s); /* size */ adduint32(d, 0); /* type */ t = STB_GLOBAL << 4; if(s->dynexport && (s->type&SMASK) == STEXT) t |= STT_FUNC; else t |= STT_OBJECT; adduint8(d, t); adduint8(d, 0); /* shndx */ if(!s->dynexport && s->dynimpname != nil) adduint16(d, SHN_UNDEF); else { switch(s->type) { default: case STEXT: t = 11; break; case SRODATA: t = 12; break; case SDATA: t = 13; break; case SBSS: t = 14; break; } adduint16(d, t); } } else if(HEADTYPE == Hdarwin) { // Mach-O symbol nlist32 d = lookup(".dynsym", 0); name = s->dynimpname; if(name == nil) name = s->name; if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps symgrow(d, ndynexp*12); } if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp() s->dynid = -s->dynid-100; off = s->dynid*12; } else { off = d->size; s->dynid = off/12; } // darwin still puts _ prefixes on all C symbols str = lookup(".dynstr", 0); setuint32(d, off, str->size); off += 4; adduint8(str, '_'); addstring(str, name); if(s->type == SDYNIMPORT) { setuint8(d, off, 0x01); // type - N_EXT - external symbol off++; setuint8(d, off, 0); // section off++; } else { setuint8(d, off, 0x0f); off++; switch(s->type) { default: case STEXT: setuint8(d, off, 1); break; case SDATA: setuint8(d, off, 2); break; case SBSS: setuint8(d, off, 4); break; } off++; } setuint16(d, off, 0); // desc off += 2; if(s->type == SDYNIMPORT) setuint32(d, off, 0); // value else setaddr(d, off, s); off += 4; } else if(HEADTYPE != Hwindows) { diag("adddynsym: unsupported binary format"); } }
void span1(Sym *s) { Prog *p, *q; int32 c, v, loop; uchar *bp; int n, m, i; cursym = s; if(s->p != nil) return; for(p = s->text; p != P; p = p->link) { p->back = 2; // use short branches first time through if((q = p->pcond) != P && (q->back & 2)) p->back |= 1; // backward jump if(p->as == AADJSP) { p->to.type = D_SP; v = -p->from.offset; p->from.offset = v; p->as = p->mode != 64? AADDL: AADDQ; if(v < 0) { p->as = p->mode != 64? ASUBL: ASUBQ; v = -v; p->from.offset = v; } if(v == 0) p->as = ANOP; } } n = 0; do { loop = 0; memset(s->r, 0, s->nr*sizeof s->r[0]); s->nr = 0; s->np = 0; c = 0; for(p = s->text; p != P; p = p->link) { p->pc = c; // process forward jumps to p for(q = p->comefrom; q != P; q = q->forwd) { v = p->pc - (q->pc + q->mark); if(q->back & 2) { // short if(v > 127) { loop++; q->back ^= 2; } if(q->as == AJCXZL) s->p[q->pc+2] = v; else s->p[q->pc+1] = v; } else { bp = s->p + q->pc + q->mark - 4; *bp++ = v; *bp++ = v>>8; *bp++ = v>>16; *bp = v>>24; } } p->comefrom = P; asmins(p); p->pc = c; m = andptr-and; symgrow(s, p->pc+m); memmove(s->p+p->pc, and, m); p->mark = m; c += m; } if(++n > 20) { diag("span must be looping"); errorexit(); } } while(loop); s->size = c; if(debug['a'] > 1) { print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0); for(i=0; i<s->np; i++) { print(" %.2ux", s->p[i]); if(i%16 == 15) print("\n %.6ux", i+1); } if(i%16) print("\n"); for(i=0; i<s->nr; i++) { Reloc *r; r = &s->r[i]; print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add); } } }