Commit a9f6db58 authored by Russ Cox's avatar Russ Cox

cmd/ld: move instruction selection + layout into compilers, assemblers

- new object file reader/writer (liblink/objfile.c)
- remove old object file writing routines
- add pcdata iterator
- remove all trace of "line number stack" and "path fragments" from
  object files, linker (!!!)
- dwarf now writes a single "compilation unit" instead of one per package

This CL disables the check for chains of no-split functions that
could overflow the stack red zone. A future CL will attack the problem
of reenabling that check (issue 6931).

This CL is just the liblink and cmd/ld changes.
There are minor associated adjustments in CL 37030045.
Each depends on the other.

R=golang-dev, dave, iant
CC=golang-dev
https://golang.org/cl/39680043
parent 870e821d
......@@ -34,7 +34,6 @@ typedef struct LSym LSym;
typedef struct Reloc Reloc;
typedef struct Auto Auto;
typedef struct Hist Hist;
typedef struct Hist2 Hist2;
typedef struct Link Link;
typedef struct Plist Plist;
typedef struct LinkArch LinkArch;
......@@ -42,6 +41,7 @@ typedef struct Library Library;
typedef struct Pcln Pcln;
typedef struct Pcdata Pcdata;
typedef struct Pciter Pciter;
// prevent incompatible type signatures between liblink and 8l on Plan 9
#pragma incomplete struct Node
......@@ -154,11 +154,11 @@ struct LSym
char* dynimplib;
char* dynimpvers;
struct Section* sect;
Hist2* hist; // for ATEXT
// STEXT
Auto* autom;
Prog* text;
Prog* etext;
Pcln* pcln;
// SDATA, SBSS
......@@ -286,18 +286,21 @@ struct Pcln
int lastindex;
};
enum
// Pcdata iterator.
// for(pciterinit(&it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
struct Pciter
{
LinkMaxHist = 40,
Pcdata d;
uchar *p;
uint32 pc;
uint32 nextpc;
int32 value;
int start;
int done;
};
// TODO: Replace uses of Hist2 with Hist and delete this.
struct Hist2
{
int32 line;
int32 off;
LSym *file;
};
void pciterinit(Pciter*, Pcdata*);
void pciternext(Pciter*);
// symbol version, incremented each time a file is loaded.
// version==1 is reserved for savehist.
......@@ -377,20 +380,13 @@ struct Link
int nlibrary;
int tlsoffset;
void (*diag)(char*, ...);
void (*dwarfaddfrag)(int, char*);
LSym* histfrog[LinkMaxHist];
int histfrogp;
int histgen;
int mode;
Auto* curauto;
Auto* curhist;
LSym* cursym;
int version;
LSym* textp;
LSym* etextp;
Hist2* histcopy;
Hist2* hist2;
int32 nhist2;
int32 maxhist2;
int32 histdepth;
int32 nhistfile;
LSym* filesyms;
......@@ -400,6 +396,7 @@ struct Link
struct LinkArch
{
char* name; // "arm", "amd64", and so on
int thechar; // '5', '6', and so on
void (*addstacksplit)(Link*, LSym*);
void (*assemble)(Link*, LSym*);
......@@ -407,17 +404,11 @@ struct LinkArch
void (*follow)(Link*, LSym*);
int (*iscall)(Prog*);
int (*isdata)(Prog*);
void (*ldobj)(Link*, Biobuf*, char*, int64, char*);
void (*nopout)(Prog*);
Prog* (*prg)(void);
void (*progedit)(Link*, Prog*);
void (*settextflag)(Prog*, int);
int (*symtype)(Addr*);
int (*textflag)(Prog*);
void (*zfile)(Biobuf*, char*, int);
void (*zhist)(Biobuf*, int, vlong);
void (*zprog)(Link*, Biobuf*, Prog*, int, int, int, int);
void (*zname)(Biobuf*, LSym*, int);
int minlc;
int ptrsize;
......@@ -432,14 +423,19 @@ struct LinkArch
int D_PCREL;
int D_SCONST;
int D_SIZE;
int D_STATIC;
int ACALL;
int ADATA;
int AEND;
int AFUNCDATA;
int AGLOBL;
int AJMP;
int ANOP;
int APCDATA;
int ARET;
int ATEXT;
int ATYPE;
int AUSEFIELD;
};
......@@ -473,6 +469,8 @@ extern uchar inuxi8[8];
// asm5.c
void span5(Link *ctxt, LSym *s);
int chipfloat5(Link *ctxt, float64 e);
int chipzero5(Link *ctxt, float64 e);
// asm6.c
void span6(Link *ctxt, LSym *s);
......@@ -504,23 +502,20 @@ vlong setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid);
void symgrow(Link *ctxt, LSym *s, int32 siz);
// go.c
void double2ieee(uint64 *ieee, double native);
void* emallocz(long n);
void* erealloc(void *p, long n);
char* estrdup(char *p);
char* expandpkg(char *t0, char *pkg);
// ieee.c
void double2ieee(uint64 *ieee, double native);
// ld.c
void addhist(Link *ctxt, int32 line, int type);
void addlib(Link *ctxt, char *src, char *obj);
void addlib(Link *ctxt, char *src, char *obj, char *path);
void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg);
void collapsefrog(Link *ctxt, LSym *s);
void copyhistfrog(Link *ctxt, char *buf, int nbuf);
int find1(int32 l, int c);
Hist2* gethist(Link *ctxt);
void linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l);
void linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l);
void histtoauto(Link *ctxt);
void mkfwd(LSym*);
void nuxiinit(void);
......@@ -529,13 +524,20 @@ Prog* copyp(Link*, Prog*);
Prog* appendp(Link*, Prog*);
vlong atolwhex(char*);
// list[568].c
void listinit5(void);
void listinit6(void);
void listinit8(void);
// obj.c
int linklinefmt(Link *ctxt, Fmt *fp);
void linklinehist(Link *ctxt, int lineno, char *f, int offset);
Plist* linknewplist(Link *ctxt);
void linkouthist(Link *ctxt, Biobuf *b);
void linkprfile(Link *ctxt, int32 l);
void linkwritefuncs(Link *ctxt, Biobuf *b);
// objfile.c
void ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path);
void linkwriteobj(Link *ctxt, Biobuf *b);
// pass.c
Prog* brchain(Link *ctxt, Prog *p);
......@@ -545,24 +547,14 @@ void linkpatch(Link *ctxt, LSym *sym);
// pcln.c
void linkpcln(Link*, LSym*);
// rdobj5.c
void ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout5(Prog *p);
// rdobj6.c
void ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout6(Prog *p);
// rdobj8.c
void ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout8(Prog *p);
// sym.c
LSym* linklookup(Link *ctxt, char *name, int v);
Link* linknew(LinkArch*);
LSym* linknewsym(Link *ctxt, char *symb, int v);
LSym* linkrlookup(Link *ctxt, char *name, int v);
int linksymfmt(Fmt *f);
int headtype(char*);
char* headstr(int);
extern char* anames5[];
extern char* anames6[];
......
......@@ -77,8 +77,6 @@ archinit(void)
case Hfreebsd:
case Hnetbsd:
debug['d'] = 0; // with dynamic linking
ctxt->tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
// this number is known to ../../pkg/runtime/rt0_*_arm.s
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
......@@ -96,5 +94,5 @@ archinit(void)
// embed goarm to runtime.goarm
s = linklookup(ctxt, "runtime.goarm", 0);
s->type = SRODATA;
adduint8(ctxt, s, goarm);
adduint8(ctxt, s, ctxt->goarm);
}
......@@ -92,11 +92,6 @@ archinit(void)
INITRND = 4096;
break;
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from 0(GS) to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c.
*/
ctxt->tlsoffset = 0x8a0;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITRND == -1)
......@@ -111,13 +106,6 @@ archinit(void)
case Hnetbsd: /* netbsd */
case Hopenbsd: /* openbsd */
case Hdragonfly: /* dragonfly */
/*
* ELF uses TLS offset negative from FS.
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
* Also known to ../../pkg/runtime/sys_linux_amd64.s
* and ../../pkg/runtime/cgo/gcc_linux_amd64.c.
*/
ctxt->tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
......
......@@ -72,7 +72,6 @@ archinit(void)
errorexit();
case Hplan9: /* plan 9 */
ctxt->tlsoffset = -8;
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+32;
......@@ -82,11 +81,6 @@ archinit(void)
INITRND = 4096;
break;
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from %gs to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c.
*/
ctxt->tlsoffset = 0x468;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITTEXT == -1)
......@@ -101,13 +95,6 @@ archinit(void)
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
/*
* ELF uses TLS offsets negative from %gs.
* Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
* Also known to ../../pkg/runtime/sys_linux_386.s
* and ../../pkg/runtime/cgo/gcc_linux_386.c.
*/
ctxt->tlsoffset = -8;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
......
......@@ -401,8 +401,7 @@ void
codeblk(int32 addr, int32 size)
{
LSym *sym;
int32 eaddr, n, epc;
Prog *p;
int32 eaddr, n;
uchar *q;
if(debug['a'])
......@@ -434,9 +433,8 @@ codeblk(int32 addr, int32 size)
Bprint(&bso, " %.2ux", 0);
Bprint(&bso, "\n");
}
p = sym->text;
if(p == nil) {
Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name);
n = sym->size;
q = sym->p;
......@@ -449,21 +447,6 @@ codeblk(int32 addr, int32 size)
if(n > 0)
Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
addr += n;
continue;
}
Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
for(p = p->link; p != P; p = p->link) {
if(p->link != P)
epc = p->link->pc;
else
epc = sym->value + sym->size;
Bprint(&bso, "%.6llux\t", (uvlong)p->pc);
q = sym->p + p->pc - sym->value;
n = epc - p->pc;
Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
addr += n;
}
}
if(addr < eaddr) {
......@@ -1031,7 +1014,6 @@ void
textaddress(void)
{
uvlong va;
Prog *p;
Section *sect;
LSym *sym, *sub;
......@@ -1052,17 +1034,11 @@ textaddress(void)
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) {
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) {
if(sym->size == 0 && sym->sub != S)
ctxt->cursym = sym;
}
va += sym->size;
}
sect->len = va - sect->vaddr;
......
......@@ -1371,140 +1371,25 @@ defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
newrefattr(dv, DW_AT_type, dt);
}
// TODO(lvd) For now, just append them all to the first compilation
// unit (that should be main), in the future distribute them to the
// appropriate compilation units.
static void
movetomodule(DWDie *parent)
{
DWDie *die;
for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
die = dwroot.child->child;
while(die->link != nil)
die = die->link;
die->link = parent->child;
}
/*
* Filename fragments for the line history stack.
*/
static char **ftab;
static int ftabsize;
void
dwarfaddfrag(int n, char *frag)
{
int s;
if (n >= ftabsize) {
s = ftabsize;
ftabsize = 1 + n + (n >> 2);
ftab = erealloc(ftab, ftabsize * sizeof(ftab[0]));
memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
}
if (*frag == '<')
frag++;
ftab[n] = frag;
}
// Returns a malloc'ed string, piecewise copied from the ftab.
static char *
decodez(char *s)
{
int len, o;
char *ss, *f;
char *r, *rb, *re;
len = 0;
ss = s + 1; // first is 0
while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
if (o < 0 || o >= ftabsize) {
diag("dwarf: corrupt z entry");
return 0;
}
f = ftab[o];
if (f == nil) {
diag("dwarf: corrupt z entry");
return 0;
}
len += strlen(f) + 1; // for the '/'
ss += 2;
}
if (len == 0)
return 0;
r = malloc(len + 1);
if(r == nil) {
diag("out of memory");
errorexit();
}
rb = r;
re = rb + len + 1;
s++;
while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
f = ftab[o];
if (rb == r || rb[-1] == '/')
rb = seprint(rb, re, "%s", f);
else
rb = seprint(rb, re, "/%s", f);
s += 2;
}
return r;
}
/*
* The line history itself
*/
static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
static int histfilesize;
static int histfilecap;
static void
clearhistfile(void)
{
int i;
// [0] holds "<eof>"
for (i = 1; i < histfilesize; i++)
free(histfile[i]);
histfilesize = 0;
}
static int
addhistfile(char *zentry)
{
char *fname;
if (histfilesize == histfilecap) {
histfilecap = 2 * histfilecap + 2;
histfile = erealloc(histfile, histfilecap * sizeof(char*));
}
if (histfilesize == 0)
histfile[histfilesize++] = "<eof>";
fname = decodez(zentry);
// print("addhistfile %d: %s\n", histfilesize, fname);
if (fname == 0)
return -1;
// Don't fill with duplicates (check only top one).
if (strcmp(fname, histfile[histfilesize-1]) == 0) {
free(fname);
return histfilesize - 1;
}
histfile[histfilesize++] = fname;
return histfilesize - 1;
}
// if the histfile stack contains ..../runtime/runtime_defs.go
// use that to set gdbscript
static void
finddebugruntimepath(void)
finddebugruntimepath(LSym *s)
{
USED(s);
/* TODO
int i, l;
char *c;
......@@ -1516,139 +1401,7 @@ finddebugruntimepath(void)
break;
}
}
}
// Go's runtime C sources are sane, and Go sources nest only 1 level,
// so a handful would be plenty, if it weren't for the fact that line
// directives can push an unlimited number of them.
static struct {
int file;
vlong line;
} *includestack;
static int includestacksize;
static int includetop;
static vlong absline;
typedef struct Linehist Linehist;
struct Linehist {
Linehist *link;
vlong absline;
vlong line;
int file;
};
static Linehist *linehist;
static void
checknesting(void)
{
if (includetop < 0) {
diag("dwarf: corrupt z stack");
errorexit();
}
if (includetop >= includestacksize) {
includestacksize += 1;
includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize);
includestack = erealloc(includestack, includestacksize * sizeof *includestack);
}
}
/*
* Return false if the a->link chain contains no history, otherwise
* returns true and finds z and Z entries in the Auto list (of a
* Prog), and resets the history stack
*/
static int
inithist(Auto *a)
{
Linehist *lh;
for (; a; a = a->link)
if (a->type == D_FILE)
break;
if (a==nil)
return 0;
// We have a new history. They are guaranteed to come completely
// at the beginning of the compilation unit.
if (a->aoffset != 1) {
diag("dwarf: stray 'z' with offset %d", a->aoffset);
return 0;
}
// Clear the history.
clearhistfile();
includetop = 0;
checknesting();
includestack[includetop].file = 0;
includestack[includetop].line = -1;
absline = 0;
while (linehist != nil) {
lh = linehist->link;
free(linehist);
linehist = lh;
}
// Construct the new one.
for (; a; a = a->link) {
if (a->type == D_FILE) { // 'z'
int f = addhistfile(a->asym->name);
if (f < 0) { // pop file
includetop--;
checknesting();
} else { // pushed a file (potentially same)
includestack[includetop].line += a->aoffset - absline;
includetop++;
checknesting();
includestack[includetop].file = f;
includestack[includetop].line = 1;
}
absline = a->aoffset;
} else if (a->type == D_FILE1) { // 'Z'
// We could just fixup the current
// linehist->lineno, but there doesn't appear to
// be a guarantee that every 'Z' is preceded
// by its own 'z', so do the safe thing and
// update the stack and push a new Linehist
// entry
includestack[includetop].line = a->aoffset;
} else
continue;
if (linehist == 0 || linehist->absline != absline) {
Linehist* lh = malloc(sizeof *lh);
if(lh == nil) {
diag("out of memory");
errorexit();
}
lh->link = linehist;
lh->absline = absline;
linehist = lh;
}
linehist->file = includestack[includetop].file;
linehist->line = includestack[includetop].line;
}
return 1;
}
static Linehist *
searchhist(vlong absline)
{
Linehist *lh;
for (lh = linehist; lh; lh = lh->link)
if (lh->absline <= absline)
break;
return lh;
}
static int
guesslang(char *s)
{
if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
return DW_LANG_Go;
return DW_LANG_C;
*/
}
/*
......@@ -1744,17 +1497,16 @@ flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_le
static void
writelines(void)
{
Prog *q;
LSym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
int currfile;
int i, lang, da, dt;
Linehist *lh;
vlong pc, epc;
int i, lang, da, dt, line, file;
DWDie *dwinfo, *dwfunc, *dwvar, **dws;
DWDie *varhash[HASHSIZE];
char *n, *nn;
Pciter pcfile, pcline;
LSym **files, *f;
if(linesec == S)
linesec = linklookup(ctxt, ".dwarfline", 0);
......@@ -1765,39 +1517,20 @@ writelines(void)
pc = 0;
epc = 0;
epcs = S;
lc = 1;
llc = 1;
currfile = -1;
lineo = cpos();
dwinfo = nil;
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
if(s->text == P)
continue;
// Look for history stack. If we find one,
// we're entering a new compilation unit
if (inithist(s->autom)) {
flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
print("dwarf writelines found %s\n", histfile[1]);
Linehist* lh;
for (lh = linehist; lh; lh = lh->link)
print("\t%8lld: [%4lld]%s\n",
lh->absline, lh->line, histfile[lh->file]);
}
lang = DW_LANG_Go;
lang = guesslang(histfile[1]);
finddebugruntimepath();
s = ctxt->textp;
dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup(histfile[1]));
dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go"));
newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, (char*)s);
newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
......@@ -1816,75 +1549,72 @@ writelines(void)
cput(1); // standard_opcode_lengths[4]
cput(0); // include_directories (empty)
for (i=1; i < histfilesize; i++) {
strnput(histfile[i], strlen(histfile[i]) + 4);
files = emallocz(ctxt->nhistfile*sizeof files[0]);
for(f = ctxt->filesyms; f != nil; f = f->next)
files[f->value-1] = f;
for(i=0; i<ctxt->nhistfile; i++) {
strnput(files[i]->name, strlen(files[i]->name) + 4);
// 4 zeros: the string termination + 3 fields.
}
cput(0); // terminate file_names.
headerend = cpos();
pc = s->text->pc;
epc = pc;
epcs = s;
currfile = 1;
lc = 1;
llc = 1;
cput(0); // start extended opcode
uleb128put(1 + PtrSize);
cput(DW_LNE_set_address);
pc = s->value;
line = 1;
file = 1;
if(linkmode == LinkExternal)
adddwarfrel(linesec, s, lineo, PtrSize, 0);
else
addrput(pc);
}
if(s->text == nil)
continue;
if (unitstart < 0) {
diag("dwarf: reachable code before seeing any history: %P", s->text);
continue;
}
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
epc = s->value + s->size;
epcs = s;
newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s);
if (s->version == 0)
newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
if(s->text->link == nil)
if(s->pcln == nil)
continue;
for(q = s->text; q != P; q = q->link) {
lh = searchhist(q->lineno);
if (lh == nil) {
diag("dwarf: corrupt history or bad absolute line: %P", q);
finddebugruntimepath(s);
pciterinit(&pcfile, &s->pcln->pcfile);
pciterinit(&pcline, &s->pcln->pcline);
while(!pcfile.done && !pcline.done) {
if(pc - s->value >= pcfile.nextpc) {
pciternext(&pcfile);
continue;
}
if (lh->file < 1) { // 0 is the past-EOF entry.
// diag("instruction with line number past EOF in %s: %P", histfile[1], q);
if(pc - s->value >= pcline.nextpc) {
pciternext(&pcline);
continue;
}
lline = lh->line + q->lineno - lh->absline;
if (debug['v'] > 1)
print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
if(pcfile.nextpc < pcline.nextpc)
epc = pcfile.nextpc;
else
epc = pcline.nextpc;
epc += s->value;
if (q->lineno == lc)
continue;
if (currfile != lh->file) {
currfile = lh->file;
if(file != pcfile.value) {
cput(DW_LNS_set_file);
uleb128put(currfile);
uleb128put(pcfile.value);
file = pcfile.value;
}
putpclcdelta(q->pc - pc, lline - llc);
pc = q->pc;
lc = q->lineno;
llc = lline;
putpclcdelta(epc - pc, pcline.value - line);
pc = epc;
line = pcline.value;
}
da = 0;
......@@ -1970,9 +1700,9 @@ putpccfadelta(vlong deltapc, vlong cfa)
static void
writeframes(void)
{
Prog *p, *q;
LSym *s;
vlong fdeo, fdesize, pad, cfa, pc;
vlong fdeo, fdesize, pad;
Pciter pcsp;
if(framesec == S)
framesec = linklookup(ctxt, ".dwarfframe", 0);
......@@ -2005,7 +1735,7 @@ writeframes(void)
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
if(s->text == nil)
if(s->pcln == nil)
continue;
fdeo = cpos();
......@@ -2015,17 +1745,8 @@ writeframes(void)
addrput(0); // initial location
addrput(0); // address range
cfa = PtrSize; // CFA starts at sp+PtrSize
p = s->text;
pc = p->pc;
for(q = p; q->link != P; q = q->link) {
if (q->spadj == 0)
continue;
cfa += q->spadj;
putpccfadelta(q->link->pc - pc, cfa);
pc = q->link->pc;
}
for(pciterinit(&pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp))
putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value);
fdesize = cpos() - fdeo - 4; // exclude the length field.
pad = rnd(fdesize, PtrSize) - fdesize;
......@@ -2041,7 +1762,7 @@ writeframes(void)
}
else {
LPUT(0);
addrput(p->pc);
addrput(s->value);
}
addrput(s->size);
cseek(fdeo + 4 + fdesize);
......
......@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Register 'f' symbol file fragments. Doing this while parsing the
* .6 input saves a pass over the symbol table later.
*/
void dwarfaddfrag(int n, char* frag);
/*
* Emit debug_abbrevs, debug_info and debug_line sections to current
* offset in cout.
......
......@@ -558,23 +558,22 @@ static void
markflood(void)
{
Auto *a;
Prog *p;
LSym *s;
int i;
for(s=markq; s!=S; s=s->queue) {
if(s->text) {
if(s->type == STEXT) {
if(debug['v'] > 1)
Bprint(&bso, "marktext %s\n", s->name);
for(a=s->autom; a; a=a->link)
mark1(a->gotype, s);
for(p=s->text; p != P; p=p->link) {
mark1(p->from.sym, s);
mark1(p->to.sym, s);
}
}
for(i=0; i<s->nr; i++)
mark1(s->r[i].sym, s);
if(s->pcln) {
for(i=0; i<s->pcln->nfuncdata; i++)
mark1(s->pcln->funcdata[i], s);
}
mark1(s->gotype, s);
mark1(s->sub, s);
mark1(s->outer, s);
......@@ -606,43 +605,11 @@ markextra[] =
"_modu",
};
static int
isz(Auto *a)
{
for(; a; a=a->link)
if(a->type == D_FILE || a->type == D_FILE1)
return 1;
return 0;
}
static void
addz(LSym *s, Auto *z)
{
Auto *a, *last;
// strip out non-z
last = nil;
for(a = z; a != nil; a = a->link) {
if(a->type == D_FILE || a->type == D_FILE1) {
if(last == nil)
z = a;
else
last->link = a;
last = a;
}
}
if(last) {
last->link = s->autom;
s->autom = z;
}
}
void
deadcode(void)
{
int i;
LSym *s, *last, *p;
Auto *z;
Fmt fmt;
if(debug['v'])
......@@ -665,23 +632,14 @@ deadcode(void)
// remove dead text but keep file information (z symbols).
last = nil;
z = nil;
for(s = ctxt->textp; s != nil; s = s->next) {
if(!s->reachable) {
if(isz(s->autom))
z = s->autom;
if(!s->reachable)
continue;
}
if(last == nil)
ctxt->textp = s;
else
last->next = s;
last = s;
if(z != nil) {
if(!isz(s->autom))
addz(s, z);
z = nil;
}
}
if(last == nil)
ctxt->textp = nil;
......
......@@ -182,12 +182,17 @@ loadlib(void)
// whether to initialize the TLS. So give it one. This could
// be handled differently but it's an unusual case.
loadinternal("runtime/cgo");
// Pretend that we really imported the package.
// This will do no harm if we did in fact import it.
s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0);
s->type = SDATA;
s->dupok = 1;
s->reachable = 1;
// Provided by the code that imports the package.
// Since we are simulating the import, we have to provide this string.
addstrdata("go.string.\"runtime/cgo\"", "runtime/cgo");
}
for(i=0; i<ctxt->libraryp; i++) {
......@@ -765,7 +770,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n
Bseek(f, import1, 0);
ctxt->arch->ldobj(ctxt, f, pkg, eof - Boffset(f), pn);
ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn);
free(pn);
return;
......@@ -979,6 +984,9 @@ enum
CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call
};
// TODO: Record enough information in new object files to
// allow stack checks here.
void
dostkcheck(void)
{
......@@ -988,6 +996,7 @@ dostkcheck(void)
morestack = linklookup(ctxt, "runtime.morestack", 0);
newstack = linklookup(ctxt, "runtime.newstack", 0);
// TODO
// First the nosplits on their own.
for(s = ctxt->textp; s != nil; s = s->next) {
if(s->text == nil || s->text->link == nil || (ctxt->arch->textflag(s->text) & NOSPLIT) == 0)
......@@ -1137,34 +1146,6 @@ stkprint(Chain *ch, int limit)
print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
}
int
headtype(char *name)
{
int i;
for(i=0; headers[i].name; i++)
if(strcmp(name, headers[i].name) == 0) {
headstring = headers[i].name;
return headers[i].val;
}
fprint(2, "unknown header type -H %s\n", name);
errorexit();
return -1; // not reached
}
char*
headstr(int v)
{
static char buf[20];
int i;
for(i=0; headers[i].name; i++)
if(v == headers[i].val)
return headers[i].name;
snprint(buf, sizeof buf, "%d", v);
return buf;
}
int
Yconv(Fmt *fp)
{
......@@ -1267,6 +1248,13 @@ usage(void)
void
setheadtype(char *s)
{
int h;
h = headtype(s);
if(h < 0) {
fprint(2, "unknown header type -H %s\n", s);
errorexit();
}
HEADTYPE = headtype(s);
}
......@@ -1337,9 +1325,6 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
}
for(s = ctxt->textp; s != nil; s = s->next) {
if(s->text == nil)
continue;
put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
for(a=s->autom; a; a=a->link) {
......@@ -1434,10 +1419,8 @@ undefsym(LSym *s)
r = &s->r[i];
if(r->sym == nil) // happens for some external ARM relocs
continue;
if(r->sym->type == Sxxx || r->sym->type == SXREF) {
if(r->sym->type == Sxxx || r->sym->type == SXREF)
diag("undefined: %s", r->sym->name);
continue;
}
if(!r->sym->reachable)
diag("use of unreachable symbol: %s", r->sym->name);
}
......
......@@ -162,8 +162,6 @@ EXTERN char* cbpmax;
if(--cbc <= 0)\
cflush(); }
EXTERN int goarm;
void Lflag(char *arg);
int Yconv(Fmt *fp);
int Zconv(Fmt *fp);
......
......@@ -54,33 +54,15 @@ ftabaddstring(LSym *ftab, char *s)
return start;
}
static uint32
getvarint(uchar **pp)
{
uchar *p;
int shift;
uint32 v;
v = 0;
p = *pp;
for(shift = 0;; shift += 7) {
v |= (*p & 0x7F) << shift;
if(!(*p++ & 0x80))
break;
}
*pp = p;
return v;
}
static void
renumberfiles(LSym **files, int nfiles, Pcdata *d)
{
int i;
LSym *f;
Pcdata out;
Pciter it;
uint32 v;
int32 oldval, newval, val, dv;
uchar *p;
// Give files numbers.
for(i=0; i<nfiles; i++) {
......@@ -93,19 +75,12 @@ renumberfiles(LSym **files, int nfiles, Pcdata *d)
}
}
oldval = -1;
newval = -1;
memset(&out, 0, sizeof out);
p = d->p;
while(p < d->p + d->n) {
for(pciterinit(&it, d); !it.done; pciternext(&it)) {
// value delta
v = getvarint(&p);
if(v == 0 && p != d->p) {
addvarint(&out, 0);
break;
}
dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
oldval += dv;
oldval = it.value;
if(oldval == -1)
val = -1;
else {
......@@ -114,14 +89,16 @@ renumberfiles(LSym **files, int nfiles, Pcdata *d)
val = files[oldval]->value;
}
dv = val - newval;
v = (uint32)(dv<<1) ^ (uint32)(dv>>31);
v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31);
addvarint(&out, v);
// pc delta
v = getvarint(&p);
addvarint(&out, v);
addvarint(&out, it.nextpc - it.pc);
}
// terminating value delta
addvarint(&out, 0);
free(d->p);
*d = out;
}
......@@ -186,9 +163,6 @@ pclntab(void)
// args int32
// TODO: Move into funcinfo.
if(ctxt->cursym->text == nil)
off = setuint32(ctxt, ftab, off, ArgsSizeUnknown);
else
off = setuint32(ctxt, ftab, off, ctxt->cursym->args);
// frame int32
......@@ -197,10 +171,7 @@ pclntab(void)
// when a called function doesn't have argument information.
// We need to make sure everything has argument information
// and then remove this.
if(ctxt->cursym->text == nil)
off = setuint32(ctxt, ftab, off, 0);
else
off = setuint32(ctxt, ftab, off, (uint32)ctxt->cursym->text->to.offset+PtrSize);
off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + PtrSize);
if(pcln != &zpcln)
renumberfiles(pcln->file, pcln->nfile, &pcln->pcfile);
......
......@@ -42,30 +42,13 @@
char *noname = "<none>";
char* paramspace = "FP";
Header headers[] = {
"darwin", Hdarwin,
"dragonfly", Hdragonfly,
"elf", Helf,
"freebsd", Hfreebsd,
"linux", Hlinux,
"netbsd", Hnetbsd,
"openbsd", Hopenbsd,
"plan9", Hplan9,
"windows", Hwindows,
"windowsgui", Hwindows,
0, 0
};
void
main(int argc, char *argv[])
{
char *p;
ctxt = linknew(thelinkarch);
ctxt->thechar = thechar;
ctxt->thestring = thestring;
ctxt->diag = diag;
ctxt->dwarfaddfrag = dwarfaddfrag;
ctxt->bso = &bso;
Binit(&bso, 1, OWRITE);
......@@ -81,16 +64,8 @@ main(int argc, char *argv[])
linkmode = LinkAuto;
nuxiinit();
if(thechar == '5') {
p = getgoarm();
if(p != nil)
goarm = atoi(p);
else
goarm = 6;
if(goarm == 5)
if(thechar == '5' && ctxt->goarm == 5)
debug['F'] = 1;
ctxt->goarm = goarm;
}
flagcount("1", "use alternate profiling code", &debug['1']);
if(thechar == '6')
......@@ -186,13 +161,8 @@ main(int argc, char *argv[])
mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
}
patch();
deadcode();
follow();
dostkoff();
paramspace = "SP"; /* (FP) now (SP) on output */
span();
pcln();
doelf();
if(HEADTYPE == Hdarwin)
......
......@@ -383,8 +383,6 @@ static int32 oshrr(Link*, int, int, int, int);
static int32 omvl(Link*, Prog*, Addr*, int);
static int32 immaddr(int32);
static int aclass(Link*, Addr*);
static int chipzero(Link*, float64);
static int chipfloat(Link*, float64);
static int32 immrot(uint32);
static int32 immaddr(int32);
static int32 opbra(Link*, int, int);
......@@ -857,9 +855,9 @@ aclass(Link *ctxt, Addr *a)
return C_GOK;
case D_FCONST:
if(chipzero(ctxt, a->u.dval) >= 0)
if(chipzero5(ctxt, a->u.dval) >= 0)
return C_ZFCON;
if(chipfloat(ctxt, a->u.dval) >= 0)
if(chipfloat5(ctxt, a->u.dval) >= 0)
return C_SFCON;
return C_LFCON;
......@@ -950,7 +948,7 @@ oplook(Link *ctxt, Prog *p)
o = oprange[r].stop; /* just generate an error */
}
if(0 /*debug['O']*/) {
print("oplook %A %O %O %O\n",
print("oplook %A %d %d %d\n",
(int)p->as, a1, a2, a3);
print(" %d %d\n", p->from.type, p->to.type);
}
......@@ -964,8 +962,9 @@ oplook(Link *ctxt, Prog *p)
p->optab = (o-optab)+1;
return o;
}
ctxt->diag("illegal combination %A %O %O %O, %d %d",
p->as, a1, a2, a3, p->from.type, p->to.type);
ctxt->diag("illegal combination %P; %d %d %d, %d %d",
p, a1, a2, a3, p->from.type, p->to.type);
ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name);
prasm(p);
if(o == 0)
o = optab;
......@@ -1557,7 +1556,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
aclass(ctxt, &p->from);
movm:
if(ctxt->instoffset != 0)
ctxt->diag("offset must be zero in MOVM");
ctxt->diag("offset must be zero in MOVM; %P", p);
o1 |= (p->scond & C_SCOND) << 28;
if(p->scond & C_PBIT)
o1 |= 1 << 24;
......@@ -1878,7 +1877,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
o1 = 0xeeb00b00; // VMOV imm 64
o1 |= (p->scond & C_SCOND) << 28;
o1 |= p->to.reg << 12;
v = chipfloat(ctxt, p->from.u.dval);
v = chipfloat5(ctxt, p->from.u.dval);
o1 |= (v&0xf) << 0;
o1 |= (v&0xf0) << 12;
break;
......@@ -2392,8 +2391,8 @@ omvl(Link *ctxt, Prog *p, Addr *a, int dr)
return o1;
}
static int
chipzero(Link *ctxt, float64 e)
int
chipzero5(Link *ctxt, float64 e)
{
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
if(ctxt->goarm < 7 || e != 0)
......@@ -2401,8 +2400,8 @@ chipzero(Link *ctxt, float64 e)
return 0;
}
static int
chipfloat(Link *ctxt, float64 e)
int
chipfloat5(Link *ctxt, float64 e)
{
int n;
ulong h1;
......
......@@ -1677,6 +1677,7 @@ span6(Link *ctxt, LSym *s)
sysfatal("loop");
}
} while(loop);
c += -c&(FuncAlign-1);
s->size = c;
if(0 /* debug['a'] > 1 */) {
......
......@@ -155,11 +155,15 @@ static uchar ytext[] =
};
static uchar ynop[] =
{
Ynone, Ynone, Zpseudo,1,
Ynone, Yml, Zpseudo,1,
Ynone, Yrf, Zpseudo,1,
Yml, Ynone, Zpseudo,1,
Yrf, Ynone, Zpseudo,1,
Ynone, Ynone, Zpseudo,0,
Ynone, Yiauto, Zpseudo,0,
Ynone, Yml, Zpseudo,0,
Ynone, Yrf, Zpseudo,0,
Yiauto, Ynone, Zpseudo,0,
Ynone, Yxr, Zpseudo,0,
Yml, Ynone, Zpseudo,0,
Yrf, Ynone, Zpseudo,0,
Yxr, Ynone, Zpseudo,1,
0
};
static uchar yfuncdata[] =
......@@ -1255,6 +1259,7 @@ span8(Link *ctxt, LSym *s)
sysfatal("bad code");
}
} while(loop);
c += -c&(FuncAlign-1);
s->size = c;
if(0 /* debug['a'] > 1 */) {
......
......@@ -35,329 +35,14 @@
#include <link.h>
void
copyhistfrog(Link *ctxt, char *buf, int nbuf)
addlib(Link *ctxt, char *src, char *obj, char *pathname)
{
char *p, *ep;
char name[1024], pname[1024], *p;
int i;
p = buf;
ep = buf + nbuf;
for(i=0; i<ctxt->histfrogp; i++) {
p = seprint(p, ep, "%s", ctxt->histfrog[i]->name+1);
if(i+1<ctxt->histfrogp && (p == buf || p[-1] != '/'))
p = seprint(p, ep, "/");
}
}
void
addhist(Link *ctxt, int32 line, int type)
{
Auto *u;
LSym *s;
int i, j, k;
u = emallocz(sizeof(Auto));
s = emallocz(sizeof(LSym));
s->name = emallocz(2*(ctxt->histfrogp+1) + 1);
u->asym = s;
u->type = type;
u->aoffset = line;
u->link = ctxt->curhist;
ctxt->curhist = u;
s->name[0] = 0;
j = 1;
for(i=0; i<ctxt->histfrogp; i++) {
k = ctxt->histfrog[i]->value;
s->name[j+0] = k>>8;
s->name[j+1] = k;
j += 2;
}
s->name[j] = 0;
s->name[j+1] = 0;
}
void
histtoauto(Link *ctxt)
{
Auto *l;
while(l = ctxt->curhist) {
ctxt->curhist = l->link;
l->link = ctxt->curauto;
ctxt->curauto = l;
}
}
void
collapsefrog(Link *ctxt, LSym *s)
{
int i;
/*
* bad encoding of path components only allows
* MAXHIST components. if there is an overflow,
* first try to collapse xxx/..
*/
for(i=1; i<ctxt->histfrogp; i++)
if(strcmp(ctxt->histfrog[i]->name+1, "..") == 0) {
memmove(ctxt->histfrog+i-1, ctxt->histfrog+i+1,
(ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
ctxt->histfrogp--;
goto out;
}
/*
* next try to collapse .
*/
for(i=0; i<ctxt->histfrogp; i++)
if(strcmp(ctxt->histfrog[i]->name+1, ".") == 0) {
memmove(ctxt->histfrog+i, ctxt->histfrog+i+1,
(ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
goto out;
}
/*
* last chance, just truncate from front
*/
memmove(ctxt->histfrog+0, ctxt->histfrog+1,
(ctxt->histfrogp-1)*sizeof(ctxt->histfrog[0]));
out:
ctxt->histfrog[ctxt->histfrogp-1] = s;
}
// Saved history stacks encountered while reading archives.
// Keeping them allows us to answer virtual lineno -> file:line
// queries.
//
// The history stack is a complex data structure, described best at the
// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
// One of the key benefits of interpreting it here is that the runtime
// does not have to. Perhaps some day the compilers could generate
// a simpler linker input too.
// savehist processes a single line, off history directive
// found in the input object file.
void
savehist(Link *ctxt, int32 line, int32 off)
{
char tmp[1024];
LSym *file;
Hist2 *h;
// NOTE(rsc): We used to do the copyctxt->histfrog first and this
// condition was if(tmp[0] != '\0') to check for an empty string,
// implying that ctxt->histfrogp == 0, implying that this is a history pop.
// However, on Windows in the misc/cgo test, the linker is
// presented with an ANAME corresponding to an empty string,
// that ANAME ends up being the only ctxt->histfrog, and thus we have
// a situation where ctxt->histfrogp > 0 (not a pop) but the path we find
// is the empty string. Really that shouldn't happen, but it doesn't
// seem to be bothering anyone yet, and it's easier to fix the condition
// to test ctxt->histfrogp than to track down where that empty string is
// coming from. Probably it is coming from go tool pack's P command.
if(ctxt->histfrogp > 0) {
tmp[0] = '\0';
copyhistfrog(ctxt, tmp, sizeof tmp);
file = linklookup(ctxt, tmp, HistVersion);
} else
file = nil;
if(file != nil && line == 1 && off == 0) {
// start of new stack
if(ctxt->histdepth != 0)
sysfatal("history stack phase error: unexpected start of new stack depth=%d file=%s", ctxt->histdepth, tmp);
ctxt->nhist2 = 0;
ctxt->histcopy = nil;
}
if(ctxt->nhist2 >= ctxt->maxhist2) {
if(ctxt->maxhist2 == 0)
ctxt->maxhist2 = 1;
ctxt->maxhist2 *= 2;
ctxt->hist2 = erealloc(ctxt->hist2, ctxt->maxhist2*sizeof ctxt->hist2[0]);
}
h = &ctxt->hist2[ctxt->nhist2++];
h->line = line;
h->off = off;
h->file = file;
if(file != nil) {
if(off == 0)
ctxt->histdepth++;
} else {
if(off != 0)
sysfatal("history stack phase error: bad offset in pop");
ctxt->histdepth--;
}
}
// gethist returns the history stack currently in effect.
// The result is valid indefinitely.
Hist2*
gethist(Link *ctxt)
{
if(ctxt->histcopy == nil) {
if(ctxt->nhist2 == 0)
return nil;
ctxt->histcopy = emallocz((ctxt->nhist2+1)*sizeof ctxt->hist2[0]);
memmove(ctxt->histcopy, ctxt->hist2, ctxt->nhist2*sizeof ctxt->hist2[0]);
ctxt->histcopy[ctxt->nhist2].line = -1;
}
return ctxt->histcopy;
}
typedef struct Hstack Hstack;
struct Hstack
{
Hist2 *h;
int delta;
};
// getline sets *f to the file number and *l to the line number
// of the virtual line number line according to the history stack h.
void
linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l)
{
Hstack stk[100];
int nstk, start;
Hist2 *top, *h0;
static Hist2 *lasth;
static int32 laststart, lastend, lastdelta;
static LSym *lastfile;
h0 = h;
*f = 0;
*l = 0;
start = 0;
if(h == nil || line == 0) {
print("%s: getline: h=%p line=%d\n", ctxt->cursym->name, h, line);
return;
}
// Cache span used during last lookup, so that sequential
// translation of line numbers in compiled code is efficient.
if(!ctxt->debughist && lasth == h && laststart <= line && line < lastend) {
*f = lastfile;
*l = line - lastdelta;
return;
}
if(ctxt->debughist)
print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
nstk = 0;
for(; h->line != -1; h++) {
if(ctxt->debughist)
print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
if(h->line > line) {
if(nstk == 0)
sysfatal("history stack phase error: empty stack at line %d", (int)line);
top = stk[nstk-1].h;
lasth = h;
lastfile = top->file;
laststart = start;
lastend = h->line;
lastdelta = stk[nstk-1].delta;
*f = lastfile;
*l = line - lastdelta;
if(ctxt->debughist)
print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
return;
}
if(h->file == nil) {
// pop included file
if(nstk == 0)
sysfatal("history stack phase error: stack underflow");
nstk--;
if(nstk > 0)
stk[nstk-1].delta += h->line - stk[nstk].h->line;
start = h->line;
} else if(h->off == 0) {
// push included file
if(nstk >= nelem(stk))
sysfatal("history stack phase error: stack overflow");
start = h->line;
stk[nstk].h = h;
stk[nstk].delta = h->line - 1;
nstk++;
} else {
// #line directive
if(nstk == 0)
sysfatal("history stack phase error: stack underflow");
stk[nstk-1].h = h;
stk[nstk-1].delta = h->line - h->off;
start = h->line;
}
if(ctxt->debughist)
print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
}
sysfatal("history stack phase error: cannot find line for %d", line);
nstk = 0;
for(h = h0; h->line != -1; h++) {
print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
if(h->file == nil)
nstk--;
else if(h->off == 0)
nstk++;
}
}
void
addlib(Link *ctxt, char *src, char *obj)
{
char name[1024], pname[1024], comp[256], *p;
int i, search;
if(ctxt->histfrogp <= 0)
return;
search = 0;
if(ctxt->histfrog[0]->name[1] == '/') {
sprint(name, "");
i = 1;
} else
if(isalpha((uchar)ctxt->histfrog[0]->name[1]) && ctxt->histfrog[0]->name[2] == ':') {
strcpy(name, ctxt->histfrog[0]->name+1);
i = 1;
} else
if(ctxt->histfrog[0]->name[1] == '.') {
sprint(name, ".");
i = 0;
} else {
sprint(name, "");
i = 0;
search = 1;
}
for(; i<ctxt->histfrogp; i++) {
snprint(comp, sizeof comp, "%s", ctxt->histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
break;
memmove(p+1, p+2, strlen(p+2)+1);
p[0] = ctxt->thechar;
}
for(;;) {
p = strstr(comp, "$M");
if(p == 0)
break;
if(strlen(comp)+strlen(ctxt->thestring)-2+1 >= sizeof comp)
sysfatal("library component too long");
memmove(p+strlen(ctxt->thestring), p+2, strlen(p+2)+1);
memmove(p, ctxt->thestring, strlen(ctxt->thestring));
}
if(strlen(name) + strlen(comp) + 3 >= sizeof(name))
sysfatal("library component too long");
if(i > 0 || !search)
strcat(name, "/");
strcat(name, comp);
}
if(strlen(pathname) >= sizeof name)
sysfatal("addlib pathname too long");
strcpy(name, pathname);
cleanname(name);
// runtime.a -> runtime
......@@ -376,15 +61,12 @@ addlib(Link *ctxt, char *src, char *obj)
if(p != nil)
*p = '.';
if(search) {
// try dot, -L "libdir", and then goroot.
for(i=0; i<ctxt->nlibdir; i++) {
snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
if(access(pname, AEXIST) >= 0)
break;
}
}else
strcpy(pname, name);
cleanname(pname);
/* runtime.a -> runtime */
......
......@@ -87,130 +87,81 @@ linklinefmt(Link *ctxt, Fmt *fp)
return 0;
}
static void
outzfile(Link *ctxt, Biobuf *b, char *p)
// This is a simplified copy of linklinefmt above.
// It doesn't allow printing the full stack, and it returns the file name and line number separately.
// TODO: Unify with linklinefmt somehow.
void
linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
{
char *q, *q2;
struct
{
Hist* incl; /* start of this include file */
int32 idel; /* delta line number to apply to include */
Hist* line; /* start of this #line directive */
int32 ldel; /* delta line number to apply to #line */
} a[HISTSZ];
int32 lno, d, dlno;
int n;
Hist *h;
char buf[1024], *file;
while(p) {
q = utfrune(p, '/');
if(ctxt->windows) {
q2 = utfrune(p, '\\');
if(q2 && (!q || q2 < q))
q = q2;
lno = line;
n = 0;
for(h=ctxt->hist; h!=nil; h=h->link) {
if(h->offset < 0)
continue;
if(lno < h->line)
break;
if(h->name) {
if(h->offset > 0) {
// #line directive
if(n > 0 && n < HISTSZ) {
a[n-1].line = h;
a[n-1].ldel = h->line - h->offset + 1;
}
if(!q) {
ctxt->arch->zfile(b, p, strlen(p));
return;
} else {
// beginning of file
if(n < HISTSZ) {
a[n].incl = h;
a[n].idel = h->line;
a[n].line = 0;
}
if(q > p)
ctxt->arch->zfile(b, p, q-p);
p = q + 1;
n++;
}
}
#define isdelim(c) (c == '/' || c == '\\')
static void
outwinname(Link *ctxt, Biobuf *b, Hist *h, char *ds, char *p)
{
if(isdelim(p[0])) {
// full rooted name
ctxt->arch->zfile(b, ds, 3); // leading "c:/"
outzfile(ctxt, b, p+1);
} else {
// relative name
if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[1] == ':') {
if(tolowerrune(ds[0]) == tolowerrune(ctxt->pathname[0])) {
// using current drive
ctxt->arch->zfile(b, ctxt->pathname, 3); // leading "c:/"
outzfile(ctxt, b, ctxt->pathname+3);
} else {
// using drive other then current,
// we don't have any simple way to
// determine current working directory
// there, therefore will output name as is
ctxt->arch->zfile(b, ds, 2); // leading "c:"
continue;
}
n--;
if(n > 0 && n < HISTSZ) {
d = h->line - a[n].incl->line;
a[n-1].ldel += d;
a[n-1].idel += d;
}
outzfile(ctxt, b, p);
}
}
void
linkouthist(Link *ctxt, Biobuf *b)
{
Hist *h;
char *p, ds[] = {'c', ':', '/', 0};
char *tofree;
int n;
static int first = 1;
static char *goroot, *goroot_final;
if(n > HISTSZ)
n = HISTSZ;
if(first) {
// Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
first = 0;
goroot = getenv("GOROOT");
goroot_final = getenv("GOROOT_FINAL");
if(goroot == nil)
goroot = "";
if(goroot_final == nil)
goroot_final = goroot;
if(strcmp(goroot, goroot_final) == 0) {
goroot = nil;
goroot_final = nil;
}
if(n <= 0) {
*f = linklookup(ctxt, "??", HistVersion);
*l = 0;
return;
}
tofree = nil;
for(h = ctxt->hist; h != nil; h = h->link) {
p = h->name;
if(p) {
if(goroot != nil) {
n = strlen(goroot);
if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
tofree = smprint("%s%s", goroot_final, p+n);
p = tofree;
}
}
if(ctxt->windows) {
// if windows variable is set, then, we know already,
// pathname is started with windows drive specifier
// and all '\' were replaced with '/' (see lex.c)
if(isdelim(p[0]) && isdelim(p[1])) {
// file name has network name in it,
// like \\server\share\dir\file.go
ctxt->arch->zfile(b, "//", 2); // leading "//"
outzfile(ctxt, b, p+2);
} else if(p[1] == ':') {
// file name has drive letter in it
ds[0] = p[0];
outwinname(ctxt, b, h, ds, p+2);
} else {
// no drive letter in file name
outwinname(ctxt, b, h, ctxt->pathname, p);
}
} else {
if(p[0] == '/') {
// full rooted name, like /home/rsc/dir/file.go
ctxt->arch->zfile(b, "/", 1); // leading "/"
outzfile(ctxt, b, p+1);
n--;
if(a[n].line) {
file = a[n].line->name;
dlno = a[n].ldel-1;
} else {
// relative name, like dir/file.go
if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[0] == '/') {
ctxt->arch->zfile(b, "/", 1); // leading "/"
outzfile(ctxt, b, ctxt->pathname+1);
}
outzfile(ctxt, b, p);
}
}
}
ctxt->arch->zhist(b, h->line, h->offset);
if(tofree) {
free(tofree);
tofree = nil;
}
file = a[n].incl->name;
dlno = a[n].idel-1;
}
if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':'))
snprint(buf, sizeof buf, "%s", file);
else
snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
lno -= dlno;
*f = linklookup(ctxt, buf, HistVersion);
*l = lno;
}
void
......@@ -299,105 +250,3 @@ linknewplist(Link *ctxt)
return pl;
}
static struct {
struct { LSym *sym; short type; } h[NSYM];
int sym;
} z;
static void
zsymreset(void)
{
for(z.sym=0; z.sym<NSYM; z.sym++) {
z.h[z.sym].sym = nil;
z.h[z.sym].type = 0;
}
z.sym = 1;
}
static int
zsym(Link *ctxt, Biobuf *b, LSym *s, int t, int *new)
{
int i;
*new = 0;
if(s == nil)
return 0;
i = s->symid;
if(i < 0 || i >= NSYM)
i = 0;
if(z.h[i].type == t && z.h[i].sym == s)
return i;
i = z.sym;
s->symid = i;
ctxt->arch->zname(b, s, t);
z.h[i].sym = s;
z.h[i].type = t;
if(++z.sym >= NSYM)
z.sym = 1;
*new = 1;
return i;
}
static int
zsymaddr(Link *ctxt, Biobuf *b, Addr *a, int *new)
{
return zsym(ctxt, b, a->sym, ctxt->arch->symtype(a), new);
}
void
linkwritefuncs(Link *ctxt, Biobuf *b)
{
int32 pcloc;
Plist *pl;
LSym *s;
Prog *p;
int sf, st, gf, gt, new;
zsymreset();
// fix up pc
pcloc = 0;
for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
continue;
for(p=pl->firstpc; p!=nil; p=p->link) {
p->loc = pcloc;
if(!ctxt->arch->isdata(p))
pcloc++;
}
}
// put out functions
for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
continue;
// -S prints code; -S -S prints code and data
if(ctxt->debugasm && (pl->name || ctxt->debugasm>1)) {
s = pl->name;
print("\n--- prog list \"%lS\" ---\n", s);
for(p=pl->firstpc; p!=nil; p=p->link)
print("%P\n", p);
}
for(p=pl->firstpc; p!=nil; p=p->link) {
for(;;) {
sf = zsymaddr(ctxt, b, &p->from, &new);
gf = zsym(ctxt, b, p->from.gotype, ctxt->arch->D_EXTERN, &new);
if(new && sf == gf)
continue;
st = zsymaddr(ctxt, b, &p->to, &new);
if(new && (st == sf || st == gf))
continue;
gt = zsym(ctxt, b, p->to.gotype, ctxt->arch->D_EXTERN, &new);
if(new && (gt == sf || gt == gf || gt == st))
continue;
break;
}
ctxt->arch->zprog(ctxt, b, p, sf, gf, st, gt);
}
}
}
......@@ -35,12 +35,6 @@
#include "../cmd/5l/5.out.h"
#include "../pkg/runtime/stack.h"
static Addr noaddr = {
.type = D_NONE,
.name = D_NONE,
.reg = NREG,
};
static Prog zprg = {
.as = AGOK,
.scond = 14,
......@@ -57,142 +51,12 @@ static Prog zprg = {
},
};
static void
zname(Biobuf *b, LSym *s, int t)
{
BPUTC(b, ANAME); /* as */
BPUTC(b, t); /* type */
BPUTC(b, s->symid); /* sym */
Bwrite(b, s->name, strlen(s->name)+1);
}
static void
zfile(Biobuf *b, char *p, int n)
{
BPUTC(b, ANAME);
BPUTC(b, D_FILE);
BPUTC(b, 1);
BPUTC(b, '<');
Bwrite(b, p, n);
BPUTC(b, 0);
}
static void
zaddr(Biobuf *b, Addr *a, int s, int gotype)
{
int32 l;
uint64 e;
int i;
char *n;
switch(a->type) {
case D_STATIC:
case D_AUTO:
case D_EXTERN:
case D_PARAM:
// TODO(kaib): remove once everything seems to work
sysfatal("We should no longer generate these as types");
default:
BPUTC(b, a->type);
BPUTC(b, a->reg);
BPUTC(b, s);
BPUTC(b, a->name);
BPUTC(b, gotype);
}
switch(a->type) {
default:
print("unknown type %d in zaddr\n", a->type);
case D_NONE:
case D_REG:
case D_FREG:
case D_PSR:
break;
case D_CONST2:
l = a->offset2;
BPUTLE4(b, l); // fall through
case D_OREG:
case D_CONST:
case D_SHIFT:
case D_STATIC:
case D_AUTO:
case D_EXTERN:
case D_PARAM:
l = a->offset;
BPUTLE4(b, l);
break;
case D_BRANCH:
if(a->offset == 0 || a->u.branch != nil) {
if(a->u.branch == nil)
sysfatal("unpatched branch %D", a);
a->offset = a->u.branch->loc;
}
l = a->offset;
BPUTLE4(b, l);
break;
case D_SCONST:
n = a->u.sval;
for(i=0; i<NSNAME; i++) {
BPUTC(b, *n);
n++;
}
break;
case D_REGREG:
case D_REGREG2:
BPUTC(b, a->offset);
break;
case D_FCONST:
double2ieee(&e, a->u.dval);
BPUTLE4(b, e);
BPUTLE4(b, e >> 32);
break;
}
}
static void
zhist(Biobuf *b, int line, vlong offset)
{
Addr a;
BPUTC(b, AHISTORY);
BPUTC(b, C_SCOND_NONE);
BPUTC(b, NREG);
BPUTLE4(b, line);
zaddr(b, &noaddr, 0, 0);
a = noaddr;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
zaddr(b, &a, 0, 0);
}
static int
symtype(Addr *a)
{
return a->name;
}
static void
zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
{
USED(ctxt);
BPUTC(b, p->as);
BPUTC(b, p->scond);
BPUTC(b, p->reg);
BPUTLE4(b, p->lineno);
zaddr(b, &p->from, sf, gf);
zaddr(b, &p->to, st, gt);
}
static int
isdata(Prog *p)
{
......@@ -223,6 +87,68 @@ settextflag(Prog *p, int f)
p->reg = f;
}
static void
progedit(Link *ctxt, Prog *p)
{
char literal[64];
LSym *s;
p->from.class = 0;
p->to.class = 0;
// Rewrite B/BL to symbol as D_BRANCH.
switch(p->as) {
case AB:
case ABL:
if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
p->to.type = D_BRANCH;
break;
}
// Rewrite float constants to values stored in memory.
switch(p->as) {
case AMOVF:
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
int32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
p->from.name = D_EXTERN;
p->from.offset = 0;
}
break;
case AMOVD:
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
int64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
p->from.name = D_EXTERN;
p->from.offset = 0;
}
break;
}
}
static Prog*
prg(void)
{
......@@ -293,11 +219,14 @@ addstacksplit(Link *ctxt, LSym *cursym)
softfloat(ctxt, cursym);
if(ctxt->debugzerostack) {
p = cursym->text;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
cursym->locals = autoffset;
cursym->args = p->to.offset2;
if(ctxt->debugzerostack) {
if(autoffset && !(p->reg&NOSPLIT)) {
// MOVW $4(R13), R1
p = appendp(ctxt, p);
......@@ -427,15 +356,10 @@ addstacksplit(Link *ctxt, LSym *cursym)
if(ctxt->headtype == Hopenbsd) {
p->as = ARET;
} else if(ctxt->goarm < 7) {
if(tlsfallback->type != STEXT) {
ctxt->diag("runtime·read_tls_fallback not defined");
sysfatal("tlsfallback");
}
// BL runtime.read_tls_fallback(SB)
p->as = ABL;
p->to.type = D_BRANCH;
p->to.sym = tlsfallback;
p->pcond = tlsfallback->text;
p->to.offset = 0;
cursym->text->mark &= ~LEAF;
}
......@@ -578,7 +502,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
p->from = zprg.from;
if(p->to.sym) { // retjmp
p->to.type = D_BRANCH;
p->pcond = p->to.sym->text;
} else {
p->to.type = D_OREG;
p->to.offset = 0;
......@@ -643,7 +566,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
q2->as = AB;
q2->to.type = D_BRANCH;
q2->to.sym = p->to.sym;
q2->pcond = p->to.sym->text;
p->to.sym = nil;
p = q2;
}
......@@ -698,7 +620,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
p->as = ABL;
p->lineno = q1->lineno;
p->to.type = D_BRANCH;
p->pcond = p;
switch(o) {
case ADIV:
p->to.sym = ctxt->sym_div;
......@@ -775,17 +696,14 @@ addstacksplit(Link *ctxt, LSym *cursym)
static void
softfloat(Link *ctxt, LSym *cursym)
{
Prog *p, *next, *psfloat;
Prog *p, *next;
LSym *symsfloat;
int wasfloat;
if(!ctxt->debugfloat)
if(ctxt->goarm > 5)
return;
symsfloat = linklookup(ctxt, "_sfloat", 0);
psfloat = nil;
if(symsfloat->type == STEXT)
psfloat = symsfloat->text;
wasfloat = 0;
for(p = cursym->text; p != nil; p = p->link)
......@@ -827,8 +745,6 @@ softfloat(Link *ctxt, LSym *cursym)
goto notsoft;
soft:
if (psfloat == nil)
ctxt->diag("floats used with _sfloat not defined");
if (!wasfloat || (p->mark&LABEL)) {
next = ctxt->arch->prg();
*next = *p;
......@@ -839,7 +755,6 @@ softfloat(Link *ctxt, LSym *cursym)
p->as = ABL;
p->to.type = D_BRANCH;
p->to.sym = symsfloat;
p->pcond = psfloat;
p->lineno = next->lineno;
p = next;
......@@ -1145,6 +1060,7 @@ loop:
LinkArch linkarm = {
.name = "arm",
.thechar = '5',
.addstacksplit = addstacksplit,
.assemble = span5,
......@@ -1152,16 +1068,11 @@ LinkArch linkarm = {
.follow = follow,
.iscall = iscall,
.isdata = isdata,
.ldobj = ldobj5,
.nopout = nopout5,
.prg = prg,
.progedit = progedit,
.settextflag = settextflag,
.symtype = symtype,
.textflag = textflag,
.zfile = zfile,
.zhist = zhist,
.zname = zname,
.zprog = zprog,
.minlc = 4,
.ptrsize = 4,
......@@ -1175,13 +1086,18 @@ LinkArch linkarm = {
.D_PCREL = D_PCREL,
.D_SCONST = D_SCONST,
.D_SIZE = D_SIZE,
.D_STATIC = D_STATIC,
.ACALL = ABL,
.ADATA = ADATA,
.AEND = AEND,
.AFUNCDATA = AFUNCDATA,
.AGLOBL = AGLOBL,
.AJMP = AB,
.ANOP = ANOP,
.APCDATA = APCDATA,
.ARET = ARET,
.ATEXT = ATEXT,
.ATYPE = ATYPE,
.AUSEFIELD = AUSEFIELD,
};
......@@ -35,12 +35,6 @@
#include "../cmd/6l/6.out.h"
#include "../pkg/runtime/stack.h"
static Addr noaddr = {
.type = D_NONE,
.index = D_NONE,
.scale = 0,
};
static Prog zprg = {
.back = 2,
.as = AGOK,
......@@ -55,118 +49,11 @@ static Prog zprg = {
};
static void
zname(Biobuf *b, LSym *s, int t)
{
BPUTLE2(b, ANAME); /* as */
BPUTC(b, t); /* type */
BPUTC(b, s->symid); /* sym */
Bwrite(b, s->name, strlen(s->name)+1);
}
static void
zfile(Biobuf *b, char *p, int n)
{
BPUTLE2(b, ANAME);
BPUTC(b, D_FILE);
BPUTC(b, 1);
BPUTC(b, '<');
Bwrite(b, p, n);
BPUTC(b, 0);
}
static void
zaddr(Biobuf *b, Addr *a, int s, int gotype)
nopout(Prog *p)
{
int32 l;
uint64 e;
int i, t;
char *n;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
if(gotype != 0)
t |= T_GOTYPE;
switch(a->type) {
case D_BRANCH:
if(a->offset == 0 || a->u.branch != nil) {
if(a->u.branch == nil)
sysfatal("unpatched branch %D", a);
a->offset = a->u.branch->loc;
}
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0) {
t |= T_OFFSET;
l = a->offset;
if((vlong)l != a->offset)
t |= T_64;
}
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
BPUTC(b, t);
if(t & T_INDEX) { /* implies index, scale */
BPUTC(b, a->index);
BPUTC(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
BPUTLE4(b, l);
if(t & T_64) {
l = a->offset>>32;
BPUTLE4(b, l);
}
}
if(t & T_SYM) /* implies sym */
BPUTC(b, s);
if(t & T_FCONST) {
double2ieee(&e, a->u.dval);
BPUTLE4(b, e);
BPUTLE4(b, e >> 32);
return;
}
if(t & T_SCONST) {
n = a->u.sval;
for(i=0; i<NSNAME; i++) {
BPUTC(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
BPUTC(b, a->type);
if(t & T_GOTYPE)
BPUTC(b, gotype);
}
static void
zhist(Biobuf *b, int line, vlong offset)
{
Addr a;
BPUTLE2(b, AHISTORY);
BPUTLE4(b, line);
zaddr(b, &noaddr, 0, 0);
a = noaddr;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
zaddr(b, &a, 0, 0);
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
static int
......@@ -180,17 +67,6 @@ symtype(Addr *a)
return t;
}
static void
zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
{
USED(ctxt);
BPUTLE2(b, p->as);
BPUTLE4(b, p->lineno);
zaddr(b, &p->from, sf, gf);
zaddr(b, &p->to, st, gt);
}
static int
isdata(Prog *p)
{
......@@ -224,8 +100,15 @@ settextflag(Prog *p, int f)
static void
progedit(Link *ctxt, Prog *p)
{
char literal[64];
LSym *s;
Prog *q;
if(p->from.type == D_INDIR+D_GS || p->from.index == D_GS)
p->from.offset += ctxt->tlsoffset;
if(p->to.type == D_INDIR+D_GS || p->to.index == D_GS)
p->to.offset += ctxt->tlsoffset;
if(ctxt->gmsym == nil)
ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
......@@ -313,6 +196,105 @@ progedit(Link *ctxt, Prog *p)
p->from.offset = 0;
}
}
// Maintain information about code generation mode.
if(ctxt->mode == 0)
ctxt->mode = 64;
p->mode = ctxt->mode;
switch(p->as) {
case AMODE:
if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE) {
switch((int)p->from.offset) {
case 16:
case 32:
case 64:
ctxt->mode = p->from.offset;
break;
}
}
nopout(p);
break;
}
// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
switch(p->as) {
case ACALL:
case AJMP:
case ARET:
if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
p->to.type = D_BRANCH;
break;
}
// Rewrite float constants to values stored in memory.
switch(p->as) {
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(p->from.type == D_FCONST) {
int32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
break;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(p->from.type == D_FCONST) {
int64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
break;
}
}
static char*
......@@ -375,6 +357,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
if(autoffset < 0)
autoffset = 0;
cursym->args = p->to.offset>>32;
cursym->locals = textstksiz;
if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
for(q = p; q != nil; q = q->link)
if(q->as == ACALL)
......@@ -1033,24 +1018,19 @@ prg(void)
LinkArch linkamd64 = {
.name = "amd64",
.thechar = '6',
.zprog = zprog,
.zhist = zhist,
.zfile = zfile,
.zname = zname,
.isdata = isdata,
.ldobj = ldobj6,
.nopout = nopout6,
.symtype = symtype,
.iscall = iscall,
.datasize = datasize,
.textflag = textflag,
.settextflag = settextflag,
.progedit = progedit,
.prg = prg,
.addstacksplit = addstacksplit,
.assemble = span6,
.datasize = datasize,
.follow = follow,
.iscall = iscall,
.isdata = isdata,
.prg = prg,
.progedit = progedit,
.settextflag = settextflag,
.symtype = symtype,
.textflag = textflag,
.minlc = 1,
.ptrsize = 8,
......@@ -1064,13 +1044,18 @@ LinkArch linkamd64 = {
.D_PCREL = D_PCREL,
.D_SCONST = D_SCONST,
.D_SIZE = D_SIZE,
.D_STATIC = D_STATIC,
.ACALL = ACALL,
.ADATA = ADATA,
.AEND = AEND,
.AFUNCDATA = AFUNCDATA,
.AGLOBL = AGLOBL,
.AJMP = AJMP,
.ANOP = ANOP,
.APCDATA = APCDATA,
.ARET = ARET,
.ATEXT = ATEXT,
.ATYPE = ATYPE,
.AUSEFIELD = AUSEFIELD,
};
......@@ -35,12 +35,6 @@
#include "../cmd/8l/8.out.h"
#include "../pkg/runtime/stack.h"
static Addr noaddr = {
.type = D_NONE,
.index = D_NONE,
.scale = 1,
};
static Prog zprg = {
.back = 2,
.as = AGOK,
......@@ -56,119 +50,6 @@ static Prog zprg = {
},
};
static void
zname(Biobuf *b, LSym *s, int t)
{
BPUTLE2(b, ANAME); /* as */
BPUTC(b, t); /* type */
BPUTC(b, s->symid); /* sym */
Bwrite(b, s->name, strlen(s->name)+1);
}
static void
zfile(Biobuf *b, char *p, int n)
{
BPUTLE2(b, ANAME);
BPUTC(b, D_FILE);
BPUTC(b, 1);
BPUTC(b, '<');
Bwrite(b, p, n);
BPUTC(b, 0);
}
static void
zaddr(Biobuf *b, Addr *a, int s, int gotype)
{
int32 l;
uint64 e;
int i, t;
char *n;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
if(gotype != 0)
t |= T_GOTYPE;
switch(a->type) {
case D_BRANCH:
if(a->offset == 0 || a->u.branch != nil) {
if(a->u.branch == nil)
sysfatal("unpatched branch %D", a);
a->offset = a->u.branch->loc;
}
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0)
t |= T_OFFSET;
if(a->offset2 != 0)
t |= T_OFFSET2;
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
BPUTC(b, t);
if(t & T_INDEX) { /* implies index, scale */
BPUTC(b, a->index);
BPUTC(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
BPUTLE4(b, l);
}
if(t & T_OFFSET2) { /* implies offset */
l = a->offset2;
BPUTLE4(b, l);
}
if(t & T_SYM) /* implies sym */
BPUTC(b, s);
if(t & T_FCONST) {
double2ieee(&e, a->u.dval);
BPUTLE4(b, e);
BPUTLE4(b, e >> 32);
return;
}
if(t & T_SCONST) {
n = a->u.sval;
for(i=0; i<NSNAME; i++) {
BPUTC(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
BPUTC(b, a->type);
if(t & T_GOTYPE)
BPUTC(b, gotype);
}
static void
zhist(Biobuf *b, int line, vlong offset)
{
Addr a;
BPUTLE2(b, AHISTORY);
BPUTLE4(b, line);
zaddr(b, &noaddr, 0, 0);
a = noaddr;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
zaddr(b, &a, 0, 0);
}
static int
symtype(Addr *a)
{
......@@ -180,17 +61,6 @@ symtype(Addr *a)
return t;
}
static void
zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
{
USED(ctxt);
BPUTLE2(b, p->as);
BPUTLE4(b, p->lineno);
zaddr(b, &p->from, sf, gf);
zaddr(b, &p->to, st, gt);
}
static int
isdata(Prog *p)
{
......@@ -225,6 +95,13 @@ static void
progedit(Link *ctxt, Prog *p)
{
Prog *q;
char literal[64];
LSym *s;
if(p->from.type == D_INDIR+D_GS)
p->from.offset += ctxt->tlsoffset;
if(p->to.type == D_INDIR+D_GS)
p->to.offset += ctxt->tlsoffset;
if(ctxt->headtype == Hwindows) {
// Convert
......@@ -287,6 +164,85 @@ progedit(Link *ctxt, Prog *p)
p->from.offset = 0;
}
}
// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
switch(p->as) {
case ACALL:
case AJMP:
case ARET:
if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
p->to.type = D_BRANCH;
break;
}
// Rewrite float constants to values stored in memory.
switch(p->as) {
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(p->from.type == D_FCONST) {
int32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
break;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(p->from.type == D_FCONST) {
int64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
break;
}
}
static Prog*
......@@ -325,6 +281,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
if(autoffset < 0)
autoffset = 0;
cursym->locals = autoffset;
cursym->args = p->to.offset2;
q = nil;
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
......@@ -894,6 +853,7 @@ loop:
LinkArch link386 = {
.name = "386",
.thechar = '8',
.addstacksplit = addstacksplit,
.assemble = span8,
......@@ -901,17 +861,11 @@ LinkArch link386 = {
.follow = follow,
.iscall = iscall,
.isdata = isdata,
.ldobj = ldobj8,
.nopout = nopout8,
.prg = prg,
.progedit = progedit,
.settextflag = settextflag,
.symtype = symtype,
.textflag = textflag,
.zfile = zfile,
.zhist = zhist,
.zname = zname,
.zprog = zprog,
.minlc = 1,
.ptrsize = 4,
......@@ -925,13 +879,18 @@ LinkArch link386 = {
.D_PCREL = D_PCREL,
.D_SCONST = D_SCONST,
.D_SIZE = D_SIZE,
.D_STATIC = D_STATIC,
.ACALL = ACALL,
.ADATA = ADATA,
.AEND = AEND,
.AFUNCDATA = AFUNCDATA,
.AGLOBL = AGLOBL,
.AJMP = AJMP,
.ANOP = ANOP,
.APCDATA = APCDATA,
.ARET = ARET,
.ATEXT = ATEXT,
.ATYPE = ATYPE,
.AUSEFIELD = AUSEFIELD,
};
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Writing and reading of Go object files.
//
// Originally, Go object files were Plan 9 object files, but no longer.
// Now they are more like standard object files, in that each symbol is defined
// by an associated memory image (bytes) and a list of relocations to apply
// during linking. We do not (yet?) use a standard file format, however.
// For now, the format is chosen to be as simple as possible to read and write.
// It may change for reasons of efficiency, or we may even switch to a
// standard file format if there are compelling benefits to doing so.
// See golang.org/s/go13linker for more background.
//
// The file format is:
//
// - magic header: "\x00\x00go13ld"
// - sequence of strings giving dependencies (imported packages)
// - empty string (marks end of sequence)
// - sequence of defined symbols
// - byte 0xff (marks end of sequence)
// - magic footer: "\xff\xffgo13ld"
//
// All integers are stored in a zigzag varint format.
// See golang.org/s/go12symtab for a definition.
//
// Data blocks and strings are both stored as an integer
// followed by that many bytes.
//
// A symbol reference is a string name followed by a version.
// An empty name corresponds to a nil LSym* pointer.
//
// Each symbol is laid out as the following fields (taken from LSym*):
//
// - byte 0xfe (sanity check for synchronization)
// - type [int]
// - name [string]
// - version [int]
// - dupok [int]
// - size [int]
// - gotype [symbol reference]
// - p [data block]
// - nr [int]
// - r [nr relocations]
//
// If type == STEXT, there are a few more fields:
//
// - args [int]
// - locals [int]
// - nlocal [int]
// - local [nlocal automatics]
// - pcln [pcln table]
//
// Each relocation has the encoding:
//
// - off [int]
// - siz [int]
// - type [int]
// - add [int]
// - xadd [int]
// - sym [symbol reference]
// - xsym [symbol reference]
//
// Each local has the encoding:
//
// - asym [symbol reference]
// - offset [int]
// - type [int]
// - gotype [symbol reference]
//
// The pcln table has the encoding:
//
// - pcsp [data block]
// - pcfile [data block]
// - pcline [data block]
// - npcdata [int]
// - pcdata [npcdata data blocks]
// - nfuncdata [int]
// - funcdata [nfuncdata symbol references]
// - funcdatasym [nfuncdata ints]
// - nfile [int]
// - file [nfile symbol references]
//
// The file layout is architecture-independent.
// The meaning is almost architecture-independent:
// the only field with architecture-dependent meaning is the
// relocation's type field.
//
// TODO(rsc): The file format is good for a first pass but needs work.
// - There are SymID in the object file that should really just be strings.
// - The actual symbol memory images are interlaced with the symbol
// metadata. They should be separated, to reduce the I/O required to
// load just the metadata.
// - The symbol references should be shortened, either with a symbol
// table or by using a simple backward index to an earlier mentioned symbol.
#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 wrdata(Biobuf*, void*, int);
static void wrsym(Biobuf*, LSym*);
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
linkwriteobj(Link *ctxt, Biobuf *b)
{
int flag;
Hist *h;
LSym *s, *text, *etext, *curtext, *data, *edata;
Plist *pl;
Prog *p, *plink;
Auto *a;
// Build list of symbols, and assign instructions to lists.
// Ignore ctxt->plist boundaries. There are no guarantees there,
// and the C compilers and assemblers just use one big list.
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) {
// Assume each TYPE instruction describes
// a different local variable or parameter,
// so no dedup.
// Using only the TYPE instructions means
// that we discard location information about local variables
// in C and assembly functions; that information is inferred
// from ordinary references, because there are no TYPE
// instructions there. Without the type information, gdb can't
// use the locations, so we don't bother to save them.
// If something else could use them, we could arrange to
// preserve them.
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->size) print("duplicate %P\n", p);
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) {
// func _() { }
curtext = nil;
continue;
}
if(s->text != nil)
sysfatal("duplicate TEXT for %s", s->name);
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;
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;
}
}
// Turn functions into machine code images.
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);
}
// Emit header.
Bputc(b, 0);
Bputc(b, 0);
Bprint(b, "go13ld");
// Emit autolib.
for(h = ctxt->hist; h != nil; h = h->link)
if(h->offset < 0)
wrstring(b, h->name);
wrstring(b, "");
// Emit symbols.
for(s = text; s != nil; s = s->next)
writesym(ctxt, b, s);
for(s = data; s != nil; s = s->next)
writesym(ctxt, b, s);
// Emit footer.
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;
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 ");
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(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];
Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->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);
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);
wrint(b, 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++)
wrsym(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
wrdata(Biobuf *b, void *v, int n)
{
wrint(b, n);
Bwrite(b, v, n);
}
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]);
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;
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);
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)
s = linklookup(ctxt, ".dup", ndup++); // scratch
}
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->type == STEXT) {
s->args = rdint(f);
s->locals = 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(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 ");
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)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;
}
......@@ -70,22 +70,20 @@ linkpatch(Link *ctxt, LSym *sym)
{
int32 c;
Prog *p, *q;
LSym *s;
ctxt->cursym = sym;
for(p = sym->text; p != nil; p = p->link) {
if(ctxt->arch->progedit)
ctxt->arch->progedit(ctxt, p);
if(p->as == ctxt->arch->ACALL || (p->as == ctxt->arch->AJMP && p->to.type != ctxt->arch->D_BRANCH) || (p->as == ctxt->arch->ARET && p->to.sym != nil)) {
s = p->to.sym;
// The STEXT check avoids rewriting indirect call to addr in memory on x86.
if(s && s->type == STEXT) {
p->to.type = ctxt->arch->D_BRANCH;
if(p->to.type != ctxt->arch->D_BRANCH)
continue;
if(p->to.u.branch != nil) {
// TODO: Remove to.u.branch in favor of p->pcond.
p->pcond = p->to.u.branch;
continue;
}
}
if(p->to.type != ctxt->arch->D_BRANCH)
if(p->to.sym != nil)
continue;
c = p->to.offset;
for(q = sym->text; q != nil;) {
......@@ -101,6 +99,7 @@ linkpatch(Link *ctxt, LSym *sym)
c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = ctxt->arch->D_NONE;
}
p->to.u.branch = q;
p->pcond = q;
}
......
......@@ -66,8 +66,10 @@ funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link
val = -1;
oldval = val;
if(func->text == nil)
if(func->text == nil) {
ctxt->debugpcln -= dbg;
return;
}
pc = func->text->pc;
......@@ -156,9 +158,11 @@ pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *ar
LSym *f;
Pcln *pcln;
USED(sym);
if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
return oldval;
linkgetline(ctxt, sym->hist, p->lineno, &f, &l);
linkgetline(ctxt, p->lineno, &f, &l);
if(f == nil) {
// print("getline failed for %s %P\n", ctxt->cursym->name, p);
return oldval;
......@@ -296,3 +300,65 @@ linkpcln(Link *ctxt, LSym *cursym)
}
}
}
// iteration over encoded pcdata tables.
static uint32
getvarint(uchar **pp)
{
uchar *p;
int shift;
uint32 v;
v = 0;
p = *pp;
for(shift = 0;; shift += 7) {
v |= (*p & 0x7F) << shift;
if(!(*p++ & 0x80))
break;
}
*pp = p;
return v;
}
void
pciternext(Pciter *it)
{
uint32 v;
int32 dv;
it->pc = it->nextpc;
if(it->done)
return;
if(it->p >= it->d.p + it->d.n) {
it->done = 1;
return;
}
// value delta
v = getvarint(&it->p);
if(v == 0 && !it->start) {
it->done = 1;
return;
}
it->start = 0;
dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
it->value += dv;
// pc delta
v = getvarint(&it->p);
it->nextpc = it->pc + v;
}
void
pciterinit(Pciter *it, Pcdata *d)
{
it->d = *d;
it->p = it->d.p;
it->pc = 0;
it->nextpc = 0;
it->value = -1;
it->start = 1;
it->done = 0;
pciternext(it);
}
// Inferno utils/5l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/5l/5.out.h"
// TODO: remove duplicate chipzero, chipfloat
static void finish(Link*);
static int
chipzero(Link *ctxt, float64 e)
{
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
if(ctxt->goarm < 7 || e != 0)
return -1;
return 0;
}
static int
chipfloat(Link *ctxt, float64 e)
{
int n;
ulong h1;
int32 l, h;
uint64 ei;
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
if(ctxt->goarm < 7)
goto no;
memmove(&ei, &e, 8);
l = (int32)ei;
h = (int32)(ei>>32);
if(l != 0 || (h&0xffff) != 0)
goto no;
h1 = h & 0x7fc00000;
if(h1 != 0x40000000 && h1 != 0x3fc00000)
goto no;
n = 0;
// sign bit (a)
if(h & 0x80000000)
n |= 1<<7;
// exp sign bit (b)
if(h1 == 0x3fc00000)
n |= 1<<6;
// rest of exp and mantissa (cd-efgh)
n |= (h >> 16) & 0x3f;
//print("match %.8lux %.8lux %d\n", l, h, n);
return n;
no:
return -1;
}
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o == 0)
return nil;
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int i, c;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
a->type = BGETC(f);
a->reg = BGETC(f);
c = BGETC(f);
if(c < 0 || c > NSYM){
print("sym out of range: %d\n", c);
BPUTC(f, ALAST+1);
return;
}
a->sym = h[c];
a->name = BGETC(f);
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
if((schar)a->reg < 0 || a->reg > NREG) {
print("register out of range %d\n", a->reg);
BPUTC(f, ALAST+1);
return; /* force real diagnostic */
}
if(a->type == D_CONST || a->type == D_OCONST) {
if(a->name == D_EXTERN || a->name == D_STATIC) {
s = a->sym;
if(s != nil && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
if(0 && !s->fnptr && s->name[0] != '.')
print("%s used as function pointer\n", s->name);
s->fnptr = 1; // over the top cos of SXREF
}
}
}
switch(a->type) {
default:
print("unknown type %d\n", a->type);
BPUTC(f, ALAST+1);
return; /* force real diagnostic */
case D_NONE:
case D_REG:
case D_FREG:
case D_PSR:
case D_FPCR:
break;
case D_REGREG:
case D_REGREG2:
a->offset = BGETC(f);
break;
case D_CONST2:
a->offset2 = BGETLE4(f); // fall through
case D_BRANCH:
case D_OREG:
case D_CONST:
case D_OCONST:
case D_SHIFT:
a->offset = BGETLE4(f);
break;
case D_SCONST:
Bread(f, a->u.sval, NSNAME);
break;
case D_FCONST:
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
break;
}
s = a->sym;
if(s == nil)
return;
i = a->name;
if(i != D_AUTO && i != D_PARAM) {
if(s && gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link)
if(u->asym == s)
if(u->type == i) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
u = emallocz(sizeof(Auto));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = i;
u->gotype = gotype;
}
void
nopout5(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
Prog *p;
LSym *h[NSYM], *s;
int v, o, r, skip;
uint32 sig;
char *name;
int ntext;
int32 eof, autosize;
char src[1024], *x, literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->pc;
skip = 0;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
if(o <= AXXX || o >= ALAST) {
ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
sysfatal("probably not a .5 file");
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME)
sig = BGETLE4(f);
v = BGETC(f); /* type */
o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0) {
fprint(2, "%s: name too long\n", pn);
sysfatal("invalid object file");
}
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
ctxt->diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
}
if(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h)) {
fprint(2, "%s: mangled input file\n", pn);
sysfatal("invalid object");
}
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(Prog));
p->as = o;
p->scond = BGETC(f);
p->reg = BGETC(f);
p->lineno = BGETLE4(f);
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
ctxt->diag("register out of range %A %d", p->as, p->reg);
p->link = nil;
p->pcond = nil;
if(ctxt->debugread)
print("%P\n", p);
switch(o) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s == nil) {
ctxt->diag("GLOBL must have a name\n%P", p);
sysfatal("mangled input");
}
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->value = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->diag("redefinition: %s\n%P", s->name, p);
s->type = SBSS;
s->value = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->reg & DUPOK)
s->dupok = 1;
if(p->reg & RODATA)
s->type = SRODATA;
else if(p->reg & NOPTR)
s->type = SNOPTRBSS;
break;
case ADATA:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s->file == nil)
s->file = pn;
else if(s->file != pn) {
ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
sysfatal("mangled input");
}
savedata(ctxt, s, p, pn);
free(p);
break;
case AGOK:
ctxt->diag("unknown opcode\n%P", p);
p->pc = ctxt->pc;
ctxt->pc++;
break;
case ATYPE:
if(skip)
goto casedef;
ctxt->pc++;
goto loop;
case ATEXT:
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
s = p->from.sym;
if(s == nil) {
ctxt->diag("TEXT must have a name\n%P", p);
sysfatal("mangled input");
}
ctxt->cursym = s;
if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
skip = 1;
goto casedef;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(ctxt->debugvlog)
Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
skip = 0;
if(s->type != 0 && s->type != SXREF)
ctxt->diag("redefinition: %s\n%P", s->name, p);
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
if(fromgotype) {
if(s->gotype && s->gotype != fromgotype)
ctxt->diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
ctxt->etextp = s;
autosize = (p->to.offset+3L) & ~3L;
p->to.offset = autosize;
autosize += 4;
s->type = STEXT;
s->hist = gethist(ctxt);
s->text = p;
s->value = ctxt->pc;
s->args = p->to.offset2;
lastp = p;
p->pc = ctxt->pc;
ctxt->pc++;
break;
case ASUB:
if(p->from.type == D_CONST)
if(p->from.name == D_NONE)
if(p->from.offset < 0) {
p->from.offset = -p->from.offset;
p->as = AADD;
}
goto casedef;
case AADD:
if(p->from.type == D_CONST)
if(p->from.name == D_NONE)
if(p->from.offset < 0) {
p->from.offset = -p->from.offset;
p->as = ASUB;
}
goto casedef;
case AMOVWD:
case AMOVWF:
case AMOVDW:
case AMOVFW:
case AMOVFD:
case AMOVDF:
// case AMOVF:
// case AMOVD:
case ACMPF:
case ACMPD:
case AADDF:
case AADDD:
case ASUBF:
case ASUBD:
case AMULF:
case AMULD:
case ADIVF:
case ADIVD:
goto casedef;
case AMOVF:
if(skip)
goto casedef;
if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 &&
(chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 9 max */
sprint(literal, "$%.17gf", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
float32 f32;
int32 i32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
p->from.name = D_EXTERN;
p->from.offset = 0;
}
goto casedef;
case AMOVD:
if(skip)
goto casedef;
if(p->from.type == D_FCONST && chipfloat(ctxt, p->from.u.dval) < 0 &&
(chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 18 max */
sprint(literal, "$%.17g", p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
p->from.name = D_EXTERN;
p->from.offset = 0;
}
goto casedef;
default:
casedef:
if(skip)
nopout5(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
break;
}
lastp->link = p;
lastp = p;
break;
}
goto loop;
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}
// Inferno utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/6l/6.out.h"
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void finish(Link*);
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int t;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->offset = 0;
if(t & T_OFFSET) {
a->offset = BGETLE4(f);
if(t & T_64) {
a->offset &= 0xFFFFFFFFULL;
a->offset |= (uvlong)BGETLE4(f) << 32;
}
}
a->sym = nil;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
a->type = D_NONE;
if(t & T_FCONST) {
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->u.sval, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
if(a->type < 0 || a->type >= D_SIZE)
mangle(pn);
gotype = nil;
if(t & T_GOTYPE)
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
s = a->sym;
t = a->type;
if(t == D_INDIR+D_GS || a->index == D_GS)
a->offset += ctxt->tlsoffset;
if(t != D_AUTO && t != D_PARAM) {
if(s && gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
}
switch(t) {
case D_FILE:
case D_FILE1:
case D_AUTO:
case D_PARAM:
if(s == nil)
mangle(pn);
}
u = emallocz(sizeof(*u));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
u->gotype = gotype;
}
void
nopout6(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
vlong ipc;
Prog *p;
int v, o, r, skip, mode;
LSym *h[NSYM], *s;
uint32 sig;
char *name, *x;
int ntext;
vlong eof;
char src[1024], literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->pc;
skip = 0;
mode = 64;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
sysfatal("%s:#%lld: opcode out of range: %#ux\n\tprobably not a .6 file", pn, Boffset(f), o);
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME)
sig = BGETLE4(f);
USED(sig);
v = BGETC(f); /* type */
o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0)
sysfatal("%s: name too long", pn);
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h))
mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
if(ctxt->dwarfaddfrag)
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(*p));
p->as = o;
p->lineno = BGETLE4(f);
p->back = 2;
p->mode = mode;
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
switch(p->as) {
case ATEXT:
case ADATA:
case AGLOBL:
if(p->from.sym == nil)
mangle(pn);
break;
}
if(ctxt->debugread)
print("%P\n", p);
switch(p->as) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->diag("%s: redefinition: %s in %s",
pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
case ADATA:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
if(s->dupok) {
// if(ctxt->debugvlog)
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s->file == nil)
s->file = pn;
else if(s->file != pn)
sysfatal("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
savedata(ctxt, s, p, pn);
free(p);
goto loop;
case AGOK:
ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
ctxt->pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
ctxt->pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: %s: redefinition", pn, s->name);
return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(ctxt->debugvlog && ctxt->bso)
Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
skip = 0;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
ctxt->etextp = s;
s->text = p;
ctxt->cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
if(fromgotype) {
if(s->gotype && s->gotype != fromgotype)
ctxt->diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
s->type = STEXT;
s->hist = gethist(ctxt);
s->value = ctxt->pc;
s->args = p->to.offset >> 32;
lastp = p;
p->pc = ctxt->pc++;
goto loop;
case AMODE:
if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
switch((int)p->from.offset){
case 16: case 32: case 64:
mode = p->from.offset;
break;
}
}
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
sprint(literal, "$%.17gf", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int32 i32;
float32 f32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
sprint(literal, "$%.17g", p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
if(skip)
nopout6(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}
// Inferno utils/8l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/8l/8.out.h"
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void finish(Link*);
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int t;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->type = D_NONE;
a->offset = 0;
if(t & T_OFFSET)
a->offset = BGETLE4(f);
a->offset2 = 0;
if(t & T_OFFSET2) {
a->offset2 = BGETLE4(f);
a->type = D_CONST2;
}
a->sym = nil;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->u.sval, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
gotype = nil;
if(t & T_GOTYPE)
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
t = a->type;
if(t == D_INDIR+D_GS)
a->offset += ctxt->tlsoffset;
s = a->sym;
if(s == nil)
return;
if(t != D_AUTO && t != D_PARAM) {
if(gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
}
u = emallocz(sizeof(*u));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
u->gotype = gotype;
}
void
nopout8(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
Prog *p;
int v, o, r, skip;
LSym *h[NSYM], *s;
uint32 sig;
int ntext;
int32 eof;
char *name, *x;
char src[1024], literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->pc;
skip = 0;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
print(" probably not a .%c file\n", ctxt->thechar);
sysfatal("invalid file");
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME)
sig = BGETLE4(f);
USED(sig);
v = BGETC(f); /* type */
o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0)
sysfatal("%s: name too long", pn);
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h))
mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(*p));
p->as = o;
p->lineno = BGETLE4(f);
p->back = 2;
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
if(ctxt->debugread)
print("%P\n", p);
switch(p->as) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->diag("%s: redefinition: %s in %s",
pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
case ADATA:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
if(s->dupok) {
// if(ctxt->debugvlog)
// Bprint(ctxt->bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s->file == nil)
s->file = pn;
else if(s->file != pn) {
ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
sysfatal("multiple init");
}
savedata(ctxt, s, p, pn);
free(p);
goto loop;
case AGOK:
ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
ctxt->pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
ctxt->pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: %s: redefinition", pn, s->name);
return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(ctxt->debugvlog)
ctxt->diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
skip = 0;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
ctxt->etextp = s;
s->text = p;
ctxt->cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
s->type = STEXT;
s->hist = gethist(ctxt);
s->value = ctxt->pc;
s->args = p->to.offset2;
lastp = p;
p->pc = ctxt->pc++;
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
sprint(literal, "$(%.17gf)", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
float32 f32;
int32 i32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
sprint(literal, "$%.17g",
p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
if(skip)
nopout8(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}
......@@ -40,6 +40,47 @@ yy_isalpha(int c)
return c >= 0 && c <= 0xFF && isalpha(c);
}
static struct {
char *name;
int val;
} headers[] = {
"darwin", Hdarwin,
"dragonfly", Hdragonfly,
"elf", Helf,
"freebsd", Hfreebsd,
"linux", Hlinux,
"netbsd", Hnetbsd,
"openbsd", Hopenbsd,
"plan9", Hplan9,
"windows", Hwindows,
"windowsgui", Hwindows,
0, 0
};
int
headtype(char *name)
{
int i;
for(i=0; headers[i].name; i++)
if(strcmp(name, headers[i].name) == 0)
return headers[i].val;
return -1;
}
char*
headstr(int v)
{
static char buf[20];
int i;
for(i=0; headers[i].name; i++)
if(v == headers[i].val)
return headers[i].name;
snprint(buf, sizeof buf, "%d", v);
return buf;
}
Link*
linknew(LinkArch *arch)
{
......@@ -53,8 +94,6 @@ linknew(LinkArch *arch)
ctxt->arch = arch;
ctxt->version = HistVersion;
// TODO: Make caller pass in ctxt->arch,
// so that for example 6g only has the linkamd64 code.
p = getgoarch();
if(strncmp(p, arch->name, strlen(arch->name)) != 0)
sysfatal("invalid goarch %s (want %s or derivative)", p, arch->name);
......@@ -72,6 +111,59 @@ linknew(LinkArch *arch)
}
ctxt->pathname = strdup(buf);
ctxt->headtype = headtype(getgoos());
if(ctxt->headtype < 0)
sysfatal("unknown goos %s", getgoos());
// Record thread-local storage offset.
switch(ctxt->headtype) {
default:
sysfatal("unknown thread-local storage offset for %s", headstr(ctxt->headtype));
case Hplan9:
ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
break;
case Hwindows:
break;
case Hlinux:
case Hfreebsd:
case Hnetbsd:
case Hopenbsd:
case Hdragonfly:
/*
* ELF uses TLS offset negative from FS.
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
* Known to low-level assembly in package runtime and runtime/cgo.
*/
ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
break;
case Hdarwin:
/*
* OS X system constants - offset from 0(GS) to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_*.c.
*/
switch(ctxt->arch->thechar) {
default:
sysfatal("unknown thread-local storage offset for darwin/%s", ctxt->arch->name);
case '6':
ctxt->tlsoffset = 0x8a0;
break;
case '8':
ctxt->tlsoffset = 0x468;
break;
}
break;
}
// On arm, record goarm.
if(ctxt->arch->thechar == '5') {
p = getgoarm();
if(p != nil)
ctxt->goarm = atoi(p);
else
ctxt->goarm = 6;
}
return ctxt;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment