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,36 +433,20 @@ 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);
n = sym->size;
q = sym->p;
while(n >= 16) {
Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
addr += 16;
q += 16;
n -= 16;
}
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;
Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name);
n = sym->size;
q = sym->p;
while(n >= 16) {
Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
addr += 16;
q += 16;
n -= 16;
}
if(n > 0)
Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
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;
......
This diff is collapsed.
......@@ -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,34 +75,29 @@ 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 {
else {
if(oldval < 0 || oldval >= nfiles)
sysfatal("bad pcdata %d", oldval);
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,10 +163,7 @@ 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);
off = setuint32(ctxt, ftab, off, ctxt->cursym->args);
// frame int32
// TODO: Remove entirely. The pcsp table is more precise.
......@@ -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)
debug['F'] = 1;
ctxt->goarm = goarm;
}
if(thechar == '5' && ctxt->goarm == 5)
debug['F'] = 1;
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);
// 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;
}
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)
{
char *q, *q2;
while(p) {
q = utfrune(p, '/');
if(ctxt->windows) {
q2 = utfrune(p, '\\');
if(q2 && (!q || q2 < q))
q = q2;
}
if(!q) {
ctxt->arch->zfile(b, p, strlen(p));
return;
}
if(q > p)
ctxt->arch->zfile(b, p, q-p);
p = q + 1;
}
}
#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:"
}
}
outzfile(ctxt, b, 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
linkouthist(Link *ctxt, Biobuf *b)
linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
{
Hist *h;
char *p, ds[] = {'c', ':', '/', 0};
char *tofree;
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;
static int first = 1;
static char *goroot, *goroot_final;
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;
}
}
Hist *h;
char buf[1024], *file;
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);
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;
}
} else {
if(p[0] == '/') {
// full rooted name, like /home/rsc/dir/file.go
ctxt->arch->zfile(b, "/", 1); // leading "/"
outzfile(ctxt, b, p+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);
// beginning of file
if(n < HISTSZ) {
a[n].incl = h;
a[n].idel = h->line;
a[n].line = 0;
}
n++;
}
continue;
}
ctxt->arch->zhist(b, h->line, h->offset);
if(tofree) {
free(tofree);
tofree = nil;
n--;
if(n > 0 && n < HISTSZ) {
d = h->line - a[n].incl->line;
a[n-1].ldel += d;
a[n-1].idel += d;
}
}
if(n > HISTSZ)
n = HISTSZ;
if(n <= 0) {
*f = linklookup(ctxt, "??", HistVersion);
*l = 0;
return;
}
n--;
if(a[n].line) {
file = a[n].line->name;
dlno = a[n].ldel-1;
} else {
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);
p = cursym->text;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
cursym->locals = autoffset;
cursym->args = p->to.offset2;
if(ctxt->debugzerostack) {
p = cursym->text;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
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)
{
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)
nopout(Prog *p)
{
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*
......@@ -374,6 +356,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
autoffset = textstksiz;
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)
......@@ -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*
......@@ -324,6 +280,9 @@ addstacksplit(Link *ctxt, LSym *cursym)
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
cursym->locals = autoffset;
cursym->args = p->to.offset2;
q = nil;
......@@ -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,
};
This diff is collapsed.
......@@ -70,23 +70,21 @@ 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;
continue;
}
}
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.sym != nil)
continue;
c = p->to.offset;
for(q = sym->text; q != nil;) {
if(c == q->pc)
......@@ -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);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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