This source file includes following definitions.
- writeobj
- writesym
- wrint
- wrstring
- wrpath
- wrdata
- wrpathsym
- wrsym
- ldobjfile
- readsym
- rdint
- rdstring
- rddata
- rdsym
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/ld/textflag.h"
static void writesym(Link*, Biobuf*, LSym*);
static void wrint(Biobuf*, int64);
static void wrstring(Biobuf*, char*);
static void wrpath(Link *, Biobuf*, char*);
static void wrdata(Biobuf*, void*, int);
static void wrsym(Biobuf*, LSym*);
static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
static void readsym(Link*, Biobuf*, char*, char*);
static int64 rdint(Biobuf*);
static char *rdstring(Biobuf*);
static void rddata(Biobuf*, uchar**, int*);
static LSym *rdsym(Link*, Biobuf*, char*);
void
writeobj(Link *ctxt, Biobuf *b)
{
int flag;
Hist *h;
LSym *s, *text, *etext, *curtext, *data, *edata;
Plist *pl;
Prog *p, *plink;
Auto *a;
text = nil;
curtext = nil;
data = nil;
etext = nil;
edata = nil;
for(pl = ctxt->plist; pl != nil; pl = pl->link) {
for(p = pl->firstpc; p != nil; p = plink) {
plink = p->link;
p->link = nil;
if(p->as == ctxt->arch->AEND)
continue;
if(p->as == ctxt->arch->ATYPE) {
if(curtext == nil)
continue;
a = emallocz(sizeof *a);
a->asym = p->from.sym;
a->aoffset = p->from.offset;
a->type = ctxt->arch->symtype(&p->from);
a->gotype = p->from.gotype;
a->link = curtext->autom;
curtext->autom = a;
continue;
}
if(p->as == ctxt->arch->AGLOBL) {
s = p->from.sym;
if(s->seenglobl++)
print("duplicate %P\n", p);
if(s->onlist)
sysfatal("symbol %s listed multiple times", s->name);
s->onlist = 1;
if(data == nil)
data = s;
else
edata->next = s;
s->next = nil;
s->size = p->to.offset;
if(s->type == 0 || s->type == SXREF)
s->type = SBSS;
if(ctxt->arch->thechar == '5')
flag = p->reg;
else
flag = p->from.scale;
if(flag & DUPOK)
s->dupok = 1;
if(flag & RODATA)
s->type = SRODATA;
else if(flag & NOPTR)
s->type = SNOPTRBSS;
edata = s;
continue;
}
if(p->as == ctxt->arch->ADATA) {
savedata(ctxt, p->from.sym, p, "<input>");
continue;
}
if(p->as == ctxt->arch->ATEXT) {
s = p->from.sym;
if(s == nil) {
curtext = nil;
continue;
}
if(s->text != nil)
sysfatal("duplicate TEXT for %s", s->name);
if(s->onlist)
sysfatal("symbol %s listed multiple times", s->name);
s->onlist = 1;
if(text == nil)
text = s;
else
etext->next = s;
etext = s;
if(ctxt->arch->thechar == '5')
flag = p->reg;
else
flag = p->from.scale;
if(flag & DUPOK)
s->dupok = 1;
if(flag & NOSPLIT)
s->nosplit = 1;
s->next = nil;
s->type = STEXT;
s->text = p;
s->etext = p;
curtext = s;
continue;
}
if(curtext == nil)
continue;
s = curtext;
s->etext->link = p;
s->etext = p;
}
}
for(s = text; s != nil; s = s->next) {
mkfwd(s);
linkpatch(ctxt, s);
ctxt->arch->follow(ctxt, s);
ctxt->arch->addstacksplit(ctxt, s);
ctxt->arch->assemble(ctxt, s);
linkpcln(ctxt, s);
}
Bputc(b, 0);
Bputc(b, 0);
Bprint(b, "go13ld");
Bputc(b, 1);
for(h = ctxt->hist; h != nil; h = h->link)
if(h->offset < 0)
wrstring(b, h->name);
wrstring(b, "");
for(s = text; s != nil; s = s->next)
writesym(ctxt, b, s);
for(s = data; s != nil; s = s->next)
writesym(ctxt, b, s);
Bputc(b, 0xff);
Bputc(b, 0xff);
Bprint(b, "go13ld");
}
static void
writesym(Link *ctxt, Biobuf *b, LSym *s)
{
Reloc *r;
int i, j, c, n;
Pcln *pc;
Prog *p;
Auto *a;
char *name;
if(ctxt->debugasm) {
Bprint(ctxt->bso, "%s ", s->name);
if(s->version)
Bprint(ctxt->bso, "v=%d ", s->version);
if(s->type)
Bprint(ctxt->bso, "t=%d ", s->type);
if(s->dupok)
Bprint(ctxt->bso, "dupok ");
if(s->nosplit)
Bprint(ctxt->bso, "nosplit ");
Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
if(s->type == STEXT) {
Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
if(s->leaf)
Bprint(ctxt->bso, " leaf");
}
Bprint(ctxt->bso, "\n");
for(p=s->text; p != nil; p = p->link)
Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
for(i=0; i<s->np; ) {
Bprint(ctxt->bso, "\t%#06ux", i);
for(j=i; j<i+16 && j<s->np; j++)
Bprint(ctxt->bso, " %02ux", s->p[j]);
for(; j<i+16; j++)
Bprint(ctxt->bso, " ");
Bprint(ctxt->bso, " ");
for(j=i; j<i+16 && j<s->np; j++) {
c = s->p[j];
if(' ' <= c && c <= 0x7e)
Bprint(ctxt->bso, "%c", c);
else
Bprint(ctxt->bso, ".");
}
Bprint(ctxt->bso, "\n");
i += 16;
}
for(i=0; i<s->nr; i++) {
r = &s->r[i];
name = "";
if(r->sym != nil)
name = r->sym->name;
Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
}
}
Bputc(b, 0xfe);
wrint(b, s->type);
wrstring(b, s->name);
wrint(b, s->version);
wrint(b, s->dupok);
wrint(b, s->size);
wrsym(b, s->gotype);
wrdata(b, s->p, s->np);
wrint(b, s->nr);
for(i=0; i<s->nr; i++) {
r = &s->r[i];
wrint(b, r->off);
wrint(b, r->siz);
wrint(b, r->type);
wrint(b, r->add);
wrint(b, r->xadd);
wrsym(b, r->sym);
wrsym(b, r->xsym);
}
if(s->type == STEXT) {
wrint(b, s->args);
wrint(b, s->locals);
wrint(b, s->nosplit);
wrint(b, s->leaf);
n = 0;
for(a = s->autom; a != nil; a = a->link)
n++;
wrint(b, n);
for(a = s->autom; a != nil; a = a->link) {
wrsym(b, a->asym);
wrint(b, a->aoffset);
if(a->type == ctxt->arch->D_AUTO)
wrint(b, A_AUTO);
else if(a->type == ctxt->arch->D_PARAM)
wrint(b, A_PARAM);
else
sysfatal("%s: invalid local variable type %d", s->name, a->type);
wrsym(b, a->gotype);
}
pc = s->pcln;
wrdata(b, pc->pcsp.p, pc->pcsp.n);
wrdata(b, pc->pcfile.p, pc->pcfile.n);
wrdata(b, pc->pcline.p, pc->pcline.n);
wrint(b, pc->npcdata);
for(i=0; i<pc->npcdata; i++)
wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
wrint(b, pc->nfuncdata);
for(i=0; i<pc->nfuncdata; i++)
wrsym(b, pc->funcdata[i]);
for(i=0; i<pc->nfuncdata; i++)
wrint(b, pc->funcdataoff[i]);
wrint(b, pc->nfile);
for(i=0; i<pc->nfile; i++)
wrpathsym(ctxt, b, pc->file[i]);
}
}
static void
wrint(Biobuf *b, int64 sval)
{
uint64 uv, v;
uchar buf[10], *p;
uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
p = buf;
for(v = uv; v >= 0x80; v >>= 7)
*p++ = v | 0x80;
*p++ = v;
Bwrite(b, buf, p - buf);
}
static void
wrstring(Biobuf *b, char *s)
{
wrdata(b, s, strlen(s));
}
static void
wrpath(Link *ctxt, Biobuf *b, char *p)
{
int i, n;
if (!ctxt->windows || strchr(p, '\\') == nil) {
wrstring(b, p);
return;
} else {
n = strlen(p);
wrint(b, n);
for (i = 0; i < n; i++)
Bputc(b, p[i] == '\\' ? '/' : p[i]);
}
}
static void
wrdata(Biobuf *b, void *v, int n)
{
wrint(b, n);
Bwrite(b, v, n);
}
static void
wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
{
if(s == nil) {
wrint(b, 0);
wrint(b, 0);
return;
}
wrpath(ctxt, b, s->name);
wrint(b, s->version);
}
static void
wrsym(Biobuf *b, LSym *s)
{
if(s == nil) {
wrint(b, 0);
wrint(b, 0);
return;
}
wrstring(b, s->name);
wrint(b, s->version);
}
static char startmagic[] = "\x00\x00go13ld";
static char endmagic[] = "\xff\xffgo13ld";
void
ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
int c;
uchar buf[8];
int64 start;
char *lib;
start = Boffset(f);
ctxt->version++;
memset(buf, 0, sizeof buf);
Bread(f, buf, sizeof buf);
if(memcmp(buf, startmagic, sizeof buf) != 0)
sysfatal("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
if((c = Bgetc(f)) != 1)
sysfatal("%s: invalid file version number %d", pn, c);
for(;;) {
lib = rdstring(f);
if(lib[0] == 0)
break;
addlib(ctxt, pkg, pn, lib);
}
for(;;) {
c = Bgetc(f);
Bungetc(f);
if(c == 0xff)
break;
readsym(ctxt, f, pkg, pn);
}
memset(buf, 0, sizeof buf);
Bread(f, buf, sizeof buf);
if(memcmp(buf, endmagic, sizeof buf) != 0)
sysfatal("%s: invalid file end", pn);
if(Boffset(f) != start+len)
sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
}
static void
readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
{
int i, j, c, t, v, n, size, dupok;
static int ndup;
char *name;
Reloc *r;
LSym *s, *dup;
Pcln *pc;
Auto *a;
if(Bgetc(f) != 0xfe)
sysfatal("readsym out of sync");
t = rdint(f);
name = expandpkg(rdstring(f), pkg);
v = rdint(f);
if(v != 0 && v != 1)
sysfatal("invalid symbol version %d", v);
dupok = rdint(f);
size = rdint(f);
if(v != 0)
v = ctxt->version;
s = linklookup(ctxt, name, v);
dup = nil;
if(s->type != 0 && s->type != SXREF) {
if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
if(s->np > 0) {
dup = s;
s = linknewsym(ctxt, ".dup", ndup++);
}
}
s->file = pkg;
s->dupok = dupok;
if(t == SXREF)
sysfatal("bad sxref");
if(t == 0)
sysfatal("missing type for %s in %s", name, pn);
s->type = t;
if(s->size < size)
s->size = size;
s->gotype = rdsym(ctxt, f, pkg);
rddata(f, &s->p, &s->np);
s->maxp = s->np;
n = rdint(f);
if(n > 0) {
s->r = emallocz(n * sizeof s->r[0]);
s->nr = n;
s->maxr = n;
for(i=0; i<n; i++) {
r = &s->r[i];
r->off = rdint(f);
r->siz = rdint(f);
r->type = rdint(f);
r->add = rdint(f);
r->xadd = rdint(f);
r->sym = rdsym(ctxt, f, pkg);
r->xsym = rdsym(ctxt, f, pkg);
}
}
if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
}
if(s->type == STEXT) {
s->args = rdint(f);
s->locals = rdint(f);
s->nosplit = rdint(f);
s->leaf = rdint(f);
n = rdint(f);
for(i=0; i<n; i++) {
a = emallocz(sizeof *a);
a->asym = rdsym(ctxt, f, pkg);
a->aoffset = rdint(f);
a->type = rdint(f);
a->gotype = rdsym(ctxt, f, pkg);
a->link = s->autom;
s->autom = a;
}
s->pcln = emallocz(sizeof *s->pcln);
pc = s->pcln;
rddata(f, &pc->pcsp.p, &pc->pcsp.n);
rddata(f, &pc->pcfile.p, &pc->pcfile.n);
rddata(f, &pc->pcline.p, &pc->pcline.n);
n = rdint(f);
pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
pc->npcdata = n;
for(i=0; i<n; i++)
rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
n = rdint(f);
pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
pc->nfuncdata = n;
for(i=0; i<n; i++)
pc->funcdata[i] = rdsym(ctxt, f, pkg);
for(i=0; i<n; i++)
pc->funcdataoff[i] = rdint(f);
n = rdint(f);
pc->file = emallocz(n * sizeof pc->file[0]);
pc->nfile = n;
for(i=0; i<n; i++)
pc->file[i] = rdsym(ctxt, f, pkg);
if(dup == nil) {
if(s->onlist)
sysfatal("symbol %s listed multiple times", s->name);
s->onlist = 1;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
ctxt->etextp = s;
}
}
if(ctxt->debugasm) {
Bprint(ctxt->bso, "%s ", s->name);
if(s->version)
Bprint(ctxt->bso, "v=%d ", s->version);
if(s->type)
Bprint(ctxt->bso, "t=%d ", s->type);
if(s->dupok)
Bprint(ctxt->bso, "dupok ");
if(s->nosplit)
Bprint(ctxt->bso, "nosplit ");
Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
if(s->type == STEXT)
Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
Bprint(ctxt->bso, "\n");
for(i=0; i<s->np; ) {
Bprint(ctxt->bso, "\t%#06ux", i);
for(j=i; j<i+16 && j<s->np; j++)
Bprint(ctxt->bso, " %02ux", s->p[j]);
for(; j<i+16; j++)
Bprint(ctxt->bso, " ");
Bprint(ctxt->bso, " ");
for(j=i; j<i+16 && j<s->np; j++) {
c = s->p[j];
if(' ' <= c && c <= 0x7e)
Bprint(ctxt->bso, "%c", c);
else
Bprint(ctxt->bso, ".");
}
Bprint(ctxt->bso, "\n");
i += 16;
}
for(i=0; i<s->nr; i++) {
r = &s->r[i];
Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
}
}
}
static int64
rdint(Biobuf *f)
{
int c;
uint64 uv;
int shift;
uv = 0;
for(shift = 0;; shift += 7) {
if(shift >= 64)
sysfatal("corrupt input");
c = Bgetc(f);
uv |= (uint64)(c & 0x7F) << shift;
if(!(c & 0x80))
break;
}
return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
}
static char*
rdstring(Biobuf *f)
{
int n;
char *p;
n = rdint(f);
p = emallocz(n+1);
Bread(f, p, n);
return p;
}
static void
rddata(Biobuf *f, uchar **pp, int *np)
{
*np = rdint(f);
*pp = emallocz(*np);
Bread(f, *pp, *np);
}
static LSym*
rdsym(Link *ctxt, Biobuf *f, char *pkg)
{
int n, v;
char *p;
LSym *s;
n = rdint(f);
if(n == 0) {
rdint(f);
return nil;
}
p = emallocz(n+1);
Bread(f, p, n);
v = rdint(f);
if(v != 0)
v = ctxt->version;
s = linklookup(ctxt, expandpkg(p, pkg), v);
if(v == 0 && s->name[0] == '$' && s->type == 0) {
if(strncmp(s->name, "$f32.", 5) == 0) {
int32 i32;
i32 = strtoul(s->name+5, nil, 16);
s->type = SRODATA;
adduint32(ctxt, s, i32);
s->reachable = 0;
} else if(strncmp(s->name, "$f64.", 5) == 0) {
int64 i64;
i64 = strtoull(s->name+5, nil, 16);
s->type = SRODATA;
adduint64(ctxt, s, i64);
s->reachable = 0;
}
}
return s;
}