summaryrefslogtreecommitdiff
path: root/src/cmd/6l/span.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6l/span.c')
-rw-r--r--src/cmd/6l/span.c1282
1 files changed, 556 insertions, 726 deletions
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 15f931bcb..5251f19bb 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -28,34 +28,33 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
-#include "../ld/elf.h"
static int rexflag;
static int asmode;
+static vlong vaddr(Adr*, Reloc*);
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v;
- vlong c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ if(s->p != nil)
+ return;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -70,378 +69,253 @@ span(void)
p->as = ANOP;
}
}
+
n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
-start:
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- asmins(p);
- p->pc = c;
- m = andptr-and;
- p->mark = m;
- c += m;
- }
-
-loop:
- n++;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping\n");
- errorexit();
- }
- again = 0;
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH || p->back & 0100) {
- if(p->back)
- p->pc = c;
asmins(p);
+ p->pc = c;
m = andptr-and;
- if(m != p->mark) {
- p->mark = m;
- again++;
- }
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
}
- p->pc = c;
- c += p->mark;
- }
- if(again) {
- textsize = c;
- goto loop;
- }
- if(INITRND) {
- INITDAT = rnd(c, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(++n > 20) {
+ diag("span must be looping");
+ errorexit();
+ }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %llux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, vlong v)
+span(void)
{
- Sym *s;
+ Prog *p, *q;
+ int32 v;
+ int n;
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
-void
-putsymb(char *s, int t, vlong v, vlong size, int ver, Sym *go)
-{
- int i, f, l;
- vlong gv;
-
- if(t == 'f')
- s++;
- l = 4;
- if(!debug['8']){
- lputb(v>>32);
- l = 8;
- }
- lputb(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- diag("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- if(l == 8)
- lputb(gv>>32);
- lputb(gv);
- symsize += l + 1 + i+1 + l;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->p != nil)
+ continue;
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8llux %s %s (%.8llux)\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-genasmsym(void (*put)(char*, int, vlong, vlong, int, Sym*))
+xdefine(char *p, int t, vlong v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s->name, 'B', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SFIXED:
- put(s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(p = textp; p != P; p = p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- put(a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- if(!s->reachable)
- continue;
- put(s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(".frame", 'm', p->to.offset+8, 0, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmsym(void)
+instinit(void)
{
- genasmsym(putsymb);
-}
+ int c, i;
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-
-int
-putelfstr(char *s)
-{
- int off, n;
-
- if(elfstrsize == 0 && s[0] != 0) {
- // first entry must be empty string
- putelfstr("");
- }
-
- n = strlen(s)+1;
- if(elfstrsize+n > maxelfstr) {
- maxelfstr = 2*(elfstrsize+n+(1<<20));
- elfstrdat = realloc(elfstrdat, maxelfstr);
- }
- off = elfstrsize;
- elfstrsize += n;
- memmove(elfstrdat+off, s, n);
- return off;
-}
-
-void
-putelfsymb(char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
- break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
- break;
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil) {
+ diag("phase error in optab: %d (%A)", i, c);
+ errorexit();
+ }
+ opindex[c] = &optab[i];
}
-
- stroff = putelfstr(s);
- lputl(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- wputl(shndx);
- vputl(addr);
- vputl(size);
-}
-void
-asmelfsym(void)
-{
- genasmsym(putelfsymb);
-}
-
-void
-asmlc(void)
-{
- vlong oldpc;
- Prog *p;
- int32 oldlc, v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['O'])
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- continue;
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Yax*Ymax + Yxm] = 1;
+ ycover[Ycx*Ymax + Yxm] = 1;
+ ycover[Yrx*Ymax + Yxm] = 1;
+ ycover[Yrl*Ymax + Yxm] = 1;
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(debug['O'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['O'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['O']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['O']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['O']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
}
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+}
+
+int
+prefixof(Adr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
}
- if(debug['v'] || debug['O'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
+ return 0;
}
int
@@ -641,11 +515,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -670,10 +544,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[(int)a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -719,7 +593,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d/%d/%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -727,10 +601,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -739,12 +609,25 @@ put4(int32 v)
}
static void
-put8(vlong v)
+relput4(Prog *p, Adr *a)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */
- reloca = nil;
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
}
+ put4(v);
+}
+
+static void
+put8(vlong v)
+{
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -756,24 +639,41 @@ put8(vlong v)
andptr += 8;
}
+/*
+static void
+relput8(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + andptr - and;
+ }
+ put8(v);
+}
+*/
+
vlong
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-vlong
-vaddr(Adr *a)
+static vlong
+vaddr(Adr *a, Reloc *r)
{
int t;
vlong v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -783,34 +683,18 @@ vaddr(Adr *a)
case D_STATIC:
case D_EXTERN:
s = a->sym;
- if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if((uvlong)s->value < (uvlong)INITTEXT)
- v += INITTEXT; /* TO DO */
- v += s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- default:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
- }
+ if(!s->reachable)
+ diag("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
return v;
}
@@ -819,55 +703,51 @@ static void
asmandsz(Adr *a, int r, int rex, int m64)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
rex &= (0x40 | Rxr);
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR) {
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+ rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
return;
}
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmandsz(&aa, r, rex, m64);
- return;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
}
if(t >= D_AL && t <= D_X0+15) {
if(v)
@@ -876,72 +756,84 @@ asmandsz(Adr *a, int r, int rex, int m64)
rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
return;
}
- if(t >= D_INDIR) {
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
t -= D_INDIR;
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- if(asmode != 64){
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
- return;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- put4(v);
+
+ rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ if(asmode != 64){
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmandsz(&aa, r, rex, m64);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -1173,14 +1065,25 @@ doasm(Prog *p)
Prog *q, pp;
uchar *t;
Movtab *mo;
- int z, op, ft, tt, xo, l;
+ int z, op, ft, tt, xo, l, pre;
vlong v;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
o = opindex[p->as];
if(o == nil) {
diag("asmins: missing op %P", p);
return;
}
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *andptr++ = pre;
if(p->ft == 0)
p->ft = oclass(&p->from);
@@ -1244,7 +1147,7 @@ found:
diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
if(op == 0x0f) {
*andptr++ = op;
@@ -1350,64 +1253,74 @@ found:
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmando(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zibo_m_xm:
z = mediaop(o, op, t[3], z);
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
*andptr++ = op;
- *andptr++ = v;
+ *andptr++ = vaddr(a, nil);
break;
case Zib_rp:
rexflag |= regrex[p->to.type] & (Rxb|0x40);
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zo_iw:
*andptr++ = op;
if(p->from.type != D_NONE){
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
break;
case Ziq_rp:
+ v = vaddr(&p->from, &rel);
l = v>>32;
- if(l == 0){
+ if(l == 0 && rel.siz != 8){
//p->mark |= 0100;
//print("zero: %llux %P\n", v, p);
rexflag &= ~(0x40|Rxw);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put4(v);
}else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
//p->mark |= 0100;
@@ -1419,6 +1332,11 @@ found:
//print("all: %llux %P\n", v, p);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put8(v);
}
break;
@@ -1426,53 +1344,54 @@ found:
case Zib_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmando(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmando(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1490,74 +1409,132 @@ found:
asmand(&p->to, &p->to);
break;
- case Zbr:
+ case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
+ *andptr++ = op;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
break;
- case Zcall:
+ case Zbr:
+ case Zjmp:
+ // TODO: jump across functions needs reloc
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
}
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
}
- break;
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
- case Zjmp:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+*/
+ break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ if(q == nil) {
+ diag("loop without target");
+ errorexit();
}
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
break;
case Zbyte:
+ v = vaddr(&p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1730,6 +1707,7 @@ void
asmins(Prog *p)
{
int n, np, c;
+ Reloc *r;
rexflag = 0;
andptr = and;
@@ -1739,7 +1717,7 @@ asmins(Prog *p)
/*
* as befits the whole approach of the architecture,
* the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3 prefix bytes, but
+ * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
* before the 0f opcode escape!), or it might be ignored.
* note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
*/
@@ -1748,164 +1726,16 @@ asmins(Prog *p)
n = andptr - and;
for(np = 0; np < n; np++) {
c = and[np];
- if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
break;
}
+ for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ r->off++;
+ }
memmove(and+np+1, and+np, n-np);
and[np] = 0x40 | rexflag;
andptr++;
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lputb(0);
- t = 0;
- lputb(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lputb(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lputb(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wputb(ra);
- t += 2;
- }
- else{
- lputb(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lputb(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}