summaryrefslogtreecommitdiff
path: root/src/liblink/asm5.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblink/asm5.c')
-rw-r--r--src/liblink/asm5.c618
1 files changed, 428 insertions, 190 deletions
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
index 465b645b2..96df9f791 100644
--- a/src/liblink/asm5.c
+++ b/src/liblink/asm5.c
@@ -35,7 +35,7 @@
#include <bio.h>
#include <link.h>
#include "../cmd/5l/5.out.h"
-#include "../pkg/runtime/stack.h"
+#include "../runtime/stack.h"
typedef struct Optab Optab;
typedef struct Oprang Oprang;
@@ -43,7 +43,7 @@ typedef uchar Opcross[32][2][32];
struct Optab
{
- char as;
+ uchar as;
uchar a1;
char a2;
uchar a3;
@@ -65,52 +65,6 @@ enum
LTO = 1<<1,
LPOOL = 1<<2,
LPCREL = 1<<3,
-
- C_NONE = 0,
- C_REG,
- C_REGREG,
- C_REGREG2,
- C_SHIFT,
- C_FREG,
- C_PSR,
- C_FCR,
-
- C_RCON, /* 0xff rotated */
- C_NCON, /* ~RCON */
- C_SCON, /* 0xffff */
- C_LCON,
- C_LCONADDR,
- C_ZFCON,
- C_SFCON,
- C_LFCON,
-
- C_RACON,
- C_LACON,
-
- C_SBRA,
- C_LBRA,
-
- C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
- C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
- C_HFAUTO, /* both H and F */
- C_SAUTO, /* -0xfff to 0xfff */
- C_LAUTO,
-
- C_HOREG,
- C_FOREG,
- C_HFOREG,
- C_SOREG,
- C_ROREG,
- C_SROREG, /* both nil and R */
- C_LOREG,
-
- C_PC,
- C_SP,
- C_HREG,
-
- C_ADDR, /* reference to relocatable address */
-
- C_GOK,
};
static Optab optab[] =
@@ -355,10 +309,14 @@ static Optab optab[] =
{ AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
{ APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 },
{ AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 },
+ { ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0 },
{ ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
{ ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL
+ { ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0 },
+ { ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0 },
+
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};
@@ -372,6 +330,7 @@ static int checkpool(Link*, Prog*, int);
static int flushpool(Link*, Prog*, int, int);
static void addpool(Link*, Prog*, Addr*);
static void asmout(Link*, Prog*, Optab*, int32*);
+static int asmoutnacl(Link*, int32, Prog*, Optab*, int32 *);
static Optab* oplook(Link*, Prog*);
static int32 oprrr(Link*, int, int);
static int32 olr(Link*, int32, int, int, int);
@@ -390,10 +349,8 @@ static int32 immrot(uint32);
static int32 immaddr(int32);
static int32 opbra(Link*, int, int);
-static Opcross opcross[8];
static Oprang oprange[ALAST];
-static char xcmp[C_GOK+1][C_GOK+1];
-static uchar repop[ALAST];
+static uchar xcmp[C_GOK+1][C_GOK+1];
static Prog zprg = {
.as = AGOK,
@@ -411,6 +368,8 @@ static Prog zprg = {
},
};
+static LSym *deferreturn;
+
static void
nocache(Prog *p)
{
@@ -419,19 +378,6 @@ nocache(Prog *p)
p->to.class = 0;
}
-static int
-scan(Link *ctxt, Prog *op, Prog *p, int c)
-{
- Prog *q;
-
- for(q = op->link; q != p && q != nil; q = q->link){
- q->pc = c;
- c += oplook(ctxt, q)->size;
- nocache(q);
- }
- return c;
-}
-
/* size of a case statement including jump table */
static int32
casesz(Link *ctxt, Prog *p)
@@ -453,13 +399,250 @@ casesz(Link *ctxt, Prog *p)
static void buildop(Link*);
+// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
+// It returns the total number of bytes put in out, and it can change
+// p->pc if extra padding is necessary.
+// In rare cases, asmoutnacl might split p into two instructions.
+// origPC is the PC for this Prog (no padding is taken into account).
+static int
+asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out)
+{
+ int size, reg;
+ Prog *q;
+ Addr *a, *a2;
+
+ size = o->size;
+
+ // instruction specific
+ switch(p->as) {
+ default:
+ if(out != nil)
+ asmout(ctxt, p, o, out);
+ break;
+ case ADATABUNDLE: // align to 16-byte boundary
+ case ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
+ p->pc = (p->pc+15) & ~15;
+ if(out != nil)
+ asmout(ctxt, p, o, out);
+ break;
+ case AUNDEF:
+ case APLD:
+ size = 4;
+ if(out != nil) {
+ switch(p->as) {
+ case AUNDEF:
+ out[0] = 0xe7fedef0; // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
+ break;
+ case APLD:
+ out[0] = 0xe1a01001; // (MOVW R1, R1)
+ break;
+ }
+ }
+ break;
+ case AB:
+ case ABL:
+ if(p->to.type != D_OREG) {
+ if(out != nil)
+ asmout(ctxt, p, o, out);
+ } else {
+ if(p->to.offset != 0 || size != 4 || p->to.reg >= 16 || p->to.reg < 0)
+ ctxt->diag("unsupported instruction: %P", p);
+ if((p->pc&15) == 12)
+ p->pc += 4;
+ if(out != nil) {
+ out[0] = ((p->scond&C_SCOND)<<28) | 0x03c0013f | (p->to.reg << 12) | (p->to.reg << 16); // BIC $0xc000000f, Rx
+ if(p->as == AB)
+ out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff10 | p->to.reg; // BX Rx
+ else // ABL
+ out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff30 | p->to.reg; // BLX Rx
+ }
+ size = 8;
+ }
+ // align the last instruction (the actual BL) to the last instruction in a bundle
+ if(p->as == ABL) {
+ if(deferreturn == nil)
+ deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+ if(p->to.sym == deferreturn)
+ p->pc = ((origPC+15) & ~15) + 16 - size;
+ else
+ p->pc += (16 - ((p->pc+size)&15)) & 15;
+ }
+ break;
+ case ALDREX:
+ case ALDREXD:
+ case AMOVB:
+ case AMOVBS:
+ case AMOVBU:
+ case AMOVD:
+ case AMOVF:
+ case AMOVH:
+ case AMOVHS:
+ case AMOVHU:
+ case AMOVM:
+ case AMOVW:
+ case ASTREX:
+ case ASTREXD:
+ if(p->to.type == D_REG && p->to.reg == 15 && p->from.reg == 13) { // MOVW.W x(R13), PC
+ if(out != nil)
+ asmout(ctxt, p, o, out);
+ if(size == 4) {
+ if(out != nil) {
+ // Note: 5c and 5g reg.c know that DIV/MOD smashes R12
+ // so that this return instruction expansion is valid.
+ out[0] = out[0] & ~0x3000; // change PC to R12
+ out[1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+ out[2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+ }
+ size += 8;
+ if(((p->pc+size) & 15) == 4)
+ p->pc += 4;
+ break;
+ } else {
+ // if the instruction used more than 4 bytes, then it must have used a very large
+ // offset to update R13, so we need to additionally mask R13.
+ if(out != nil) {
+ out[size/4-1] &= ~0x3000; // change PC to R12
+ out[size/4] = ((p->scond&C_SCOND)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
+ out[size/4+1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+ out[size/4+2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+ }
+ // p->pc+size is only ok at 4 or 12 mod 16.
+ if((p->pc+size)%8 == 0)
+ p->pc += 4;
+ size += 12;
+ break;
+ }
+ }
+
+ if(p->to.type == D_REG && p->to.reg == 15)
+ ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p);
+
+ if(p->to.type == D_OREG && p->to.reg == 13 && (p->scond & C_WBIT) && size > 4) {
+ // function prolog with very large frame size: MOVW.W R14,-100004(R13)
+ // split it into two instructions:
+ // ADD $-100004, R13
+ // MOVW R14, 0(R13)
+ q = ctxt->arch->prg();
+ p->scond &= ~C_WBIT;
+ *q = *p;
+ a = &p->to;
+ if(p->to.type == D_OREG)
+ a2 = &q->to;
+ else
+ a2 = &q->from;
+ nocache(q);
+ nocache(p);
+ // insert q after p
+ q->link = p->link;
+ p->link = q;
+ q->pcond = nil;
+ // make p into ADD $X, R13
+ p->as = AADD;
+ p->from = *a;
+ p->from.reg = NREG;
+ p->from.type = D_CONST;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = 13;
+ // make q into p but load/store from 0(R13)
+ q->spadj = 0;
+ *a2 = zprg.from;
+ a2->type = D_OREG;
+ a2->reg = 13;
+ a2->sym = nil;
+ a2->offset = 0;
+ size = oplook(ctxt, p)->size;
+ break;
+ }
+
+ if((p->to.type == D_OREG && p->to.reg != 13 && p->to.reg != 9) || // MOVW Rx, X(Ry), y != 13 && y != 9
+ (p->from.type == D_OREG && p->from.reg != 13 && p->from.reg != 9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
+ if(p->to.type == D_OREG)
+ a = &p->to;
+ else
+ a = &p->from;
+ reg = a->reg;
+ if(size == 4) {
+ // if addr.reg == NREG, then it is probably load from x(FP) with small x, no need to modify.
+ if(reg == NREG) {
+ if(out != nil)
+ asmout(ctxt, p, o, out);
+ } else {
+ if(out != nil)
+ out[0] = ((p->scond&C_SCOND)<<28) | 0x03c00103 | (reg << 16) | (reg << 12); // BIC $0xc0000000, Rx
+ if((p->pc&15) == 12)
+ p->pc += 4;
+ size += 4;
+ if(out != nil)
+ asmout(ctxt, p, o, &out[1]);
+ }
+ break;
+ } else {
+ // if a load/store instruction takes more than 1 word to implement, then
+ // we need to seperate the instruction into two:
+ // 1. explicitly load the address into R11.
+ // 2. load/store from R11.
+ // This won't handle .W/.P, so we should reject such code.
+ if(p->scond & (C_PBIT|C_WBIT))
+ ctxt->diag("unsupported instruction (.P/.W): %P", p);
+ q = ctxt->arch->prg();
+ *q = *p;
+ if(p->to.type == D_OREG)
+ a2 = &q->to;
+ else
+ a2 = &q->from;
+ nocache(q);
+ nocache(p);
+ // insert q after p
+ q->link = p->link;
+ p->link = q;
+ q->pcond = nil;
+ // make p into MOVW $X(R), R11
+ p->as = AMOVW;
+ p->from = *a;
+ p->from.type = D_CONST;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = 11;
+ // make q into p but load/store from 0(R11)
+ *a2 = zprg.from;
+ a2->type = D_OREG;
+ a2->reg = 11;
+ a2->sym = nil;
+ a2->offset = 0;
+ size = oplook(ctxt, p)->size;
+ break;
+ }
+ } else if(out != nil)
+ asmout(ctxt, p, o, out);
+ break;
+ }
+
+ // destination register specific
+ if(p->to.type == D_REG) {
+ switch(p->to.reg) {
+ case 9:
+ ctxt->diag("invalid instruction, cannot write to R9: %P", p);
+ break;
+ case 13:
+ if(out != nil)
+ out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13
+ if(((p->pc+size) & 15) == 0)
+ p->pc += 4;
+ size += 4;
+ break;
+ }
+ }
+ return size;
+}
+
void
span5(Link *ctxt, LSym *cursym)
{
Prog *p, *op;
Optab *o;
- int m, bflag, i, v;
- int32 c, out[6];
+ int m, bflag, i, v, times;
+ int32 c, opc, out[6+3];
uchar *bp;
p = cursym->text;
@@ -472,21 +655,39 @@ span5(Link *ctxt, LSym *cursym)
ctxt->cursym = cursym;
ctxt->autosize = p->to.offset + 4;
- c = 0;
+ c = 0;
- for(op = p, p = p->link; p != nil; op = p, p = p->link) {
+ for(op = p, p = p->link; p != nil || ctxt->blitrl != nil; op = p, p = p->link) {
+ if(p == nil) {
+ if(checkpool(ctxt, op, 0)) {
+ p = op;
+ continue;
+ }
+ // can't happen: blitrl is not nil, but checkpool didn't flushpool
+ ctxt->diag("internal inconsistency");
+ break;
+ }
ctxt->curp = p;
p->pc = c;
o = oplook(ctxt, p);
- m = o->size;
+ if(ctxt->headtype != Hnacl) {
+ m = o->size;
+ } else {
+ m = asmoutnacl(ctxt, c, p, o, nil);
+ c = p->pc; // asmoutnacl might change pc for alignment
+ o = oplook(ctxt, p); // asmoutnacl might change p in rare cases
+ }
+ if(m % 4 != 0 || p->pc % 4 != 0) {
+ ctxt->diag("!pc invalid: %P size=%d", p, m);
+ }
// must check literal pool here in case p generates many instructions
if(ctxt->blitrl){
if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
- p->pc = scan(ctxt, op, p, c);
- c = p->pc;
+ p = op;
+ continue;
}
}
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
ctxt->diag("zero-width instruction\n%P", p);
continue;
}
@@ -506,10 +707,6 @@ span5(Link *ctxt, LSym *cursym)
flushpool(ctxt, p, 0, 0);
c += m;
}
- if(ctxt->blitrl){
- if(checkpool(ctxt, op, 0))
- c = scan(ctxt, op, nil, c);
- }
cursym->size = c;
/*
@@ -518,15 +715,19 @@ span5(Link *ctxt, LSym *cursym)
* generate extra passes putting branches
* around jmps to fix. this is rare.
*/
+ times = 0;
do {
if(ctxt->debugvlog)
Bprint(ctxt->bso, "%5.2f span1\n", cputime());
bflag = 0;
c = 0;
+ times++;
+ cursym->text->pc = 0; // force re-layout the code.
for(p = cursym->text; p != nil; p = p->link) {
ctxt->curp = p;
- p->pc = c;
o = oplook(ctxt,p);
+ if(c > p->pc)
+ p->pc = c;
/* very large branches
if(o->type == 6 && p->pcond) {
otxt = p->pcond->pc - c;
@@ -550,8 +751,22 @@ span5(Link *ctxt, LSym *cursym)
}
}
*/
- m = o->size;
- if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+ opc = p->pc;
+ if(ctxt->headtype != Hnacl)
+ m = o->size;
+ else
+ m = asmoutnacl(ctxt, c, p, o, nil);
+ if(p->pc != opc) {
+ bflag = 1;
+ //print("%P pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
+ }
+ c = p->pc + m;
+ if(m % 4 != 0 || p->pc % 4 != 0) {
+ ctxt->diag("pc invalid: %P size=%d", p, m);
+ }
+ if(m/4 > nelem(out))
+ ctxt->diag("instruction size too large: %d > %d", m/4, nelem(out));
+ if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
if(p->as == ATEXT) {
ctxt->autosize = p->to.offset + 4;
continue;
@@ -559,10 +774,12 @@ span5(Link *ctxt, LSym *cursym)
ctxt->diag("zero-width instruction\n%P", p);
continue;
}
- c += m;
}
cursym->size = c;
} while(bflag);
+ if(c % 4 != 0) {
+ ctxt->diag("sym->size=%d, invalid", c);
+ }
/*
* lay out the code. all the pc-relative code references,
@@ -572,26 +789,49 @@ span5(Link *ctxt, LSym *cursym)
* code references to be relocated too, and then
* perhaps we'd be able to parallelize the span loop above.
*/
- if(ctxt->gmsym == nil)
- ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+ if(ctxt->tlsg == nil)
+ ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
p = cursym->text;
ctxt->autosize = p->to.offset + 4;
symgrow(ctxt, cursym, cursym->size);
bp = cursym->p;
+ c = p->pc; // even p->link might need extra padding
for(p = p->link; p != nil; p = p->link) {
ctxt->pc = p->pc;
ctxt->curp = p;
o = oplook(ctxt, p);
- asmout(ctxt, p, o, out);
- for(i=0; i<o->size/4; i++) {
+ opc = p->pc;
+ if(ctxt->headtype != Hnacl) {
+ asmout(ctxt, p, o, out);
+ m = o->size;
+ } else {
+ m = asmoutnacl(ctxt, c, p, o, out);
+ if(opc != p->pc)
+ ctxt->diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %P", opc, (int32)p->pc, p);
+ }
+ if(m % 4 != 0 || p->pc % 4 != 0) {
+ ctxt->diag("final stage: pc invalid: %P size=%d", p, m);
+ }
+ if(c > p->pc)
+ ctxt->diag("PC padding invalid: want %#lld, has %#d: %P", p->pc, c, p);
+ while(c != p->pc) {
+ // emit 0xe1a00000 (MOVW R0, R0)
+ *bp++ = 0x00;
+ *bp++ = 0x00;
+ *bp++ = 0xa0;
+ *bp++ = 0xe1;
+ c += 4;
+ }
+ for(i=0; i<m/4; i++) {
v = out[i];
*bp++ = v;
*bp++ = v>>8;
*bp++ = v>>16;
*bp++ = v>>24;
}
+ c += m;
}
}
@@ -604,7 +844,7 @@ span5(Link *ctxt, LSym *cursym)
static int
checkpool(Link *ctxt, Prog *p, int sz)
{
- if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+ if(pool.size >= 0xff0 || immaddr((p->pc+sz+4)+4+(12+pool.size) - (pool.start+8)) == 0)
return flushpool(ctxt, p, 1, 0);
else if(p->link == nil)
return flushpool(ctxt, p, 2, 0);
@@ -627,8 +867,15 @@ flushpool(Link *ctxt, Prog *p, int skip, int force)
q->lineno = p->lineno;
ctxt->blitrl = q;
}
- else if(!force && (p->pc+pool.size-pool.start < 2048))
+ else if(!force && (p->pc+(12+pool.size)-pool.start < 2048)) // 12 take into account the maximum nacl literal pool alignment padding size
return 0;
+ if(ctxt->headtype == Hnacl && pool.size % 16 != 0) {
+ // if pool is not multiple of 16 bytes, add an alignment marker
+ q = ctxt->arch->prg();
+ q->as = ADATABUNDLEEND;
+ ctxt->elitrl->link = q;
+ ctxt->elitrl = q;
+ }
ctxt->elitrl->link = p->link;
p->link = ctxt->blitrl;
// BUG(minux): how to correctly handle line number for constant pool entries?
@@ -661,7 +908,11 @@ addpool(Link *ctxt, Prog *p, Addr *a)
switch(c) {
default:
- t.to = *a;
+ t.to.offset = a->offset;
+ t.to.sym = a->sym;
+ t.to.type = a->type;
+ t.to.name = a->name;
+
if(ctxt->flag_shared && t.to.sym != nil)
t.pcrel = p;
break;
@@ -689,6 +940,22 @@ addpool(Link *ctxt, Prog *p, Addr *a)
}
}
+ if(ctxt->headtype == Hnacl && pool.size%16 == 0) {
+ // start a new data bundle
+ q = ctxt->arch->prg();
+ *q = zprg;
+ q->as = ADATABUNDLE;
+ q->pc = pool.size;
+ pool.size += 4;
+ if(ctxt->blitrl == nil) {
+ ctxt->blitrl = q;
+ pool.start = p->pc;
+ } else {
+ ctxt->elitrl->link = q;
+ }
+ ctxt->elitrl = q;
+ }
+
q = ctxt->arch->prg();
*q = t;
q->pc = pool.size;
@@ -758,6 +1025,8 @@ immhalf(int32 v)
return 0;
}
+static int aconsize(Link *ctxt);
+
static int
aclass(Link *ctxt, Addr *a)
{
@@ -792,7 +1061,6 @@ aclass(Link *ctxt, Addr *a)
case D_STATIC:
if(a->sym == 0 || a->sym->name == 0) {
print("null sym external\n");
- print("%D\n", a);
return C_GOK;
}
ctxt->instoffset = 0; // s.b. unused but just in case
@@ -869,7 +1137,7 @@ aclass(Link *ctxt, Addr *a)
case D_NONE:
ctxt->instoffset = a->offset;
if(a->reg != NREG)
- goto aconsize;
+ return aconsize(ctxt);
t = immrot(ctxt->instoffset);
if(t)
@@ -889,15 +1157,11 @@ aclass(Link *ctxt, Addr *a)
case D_AUTO:
ctxt->instoffset = ctxt->autosize + a->offset;
- goto aconsize;
+ return aconsize(ctxt);
case D_PARAM:
ctxt->instoffset = ctxt->autosize + a->offset + 4L;
- aconsize:
- t = immrot(ctxt->instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
+ return aconsize(ctxt);
}
return C_GOK;
@@ -907,6 +1171,17 @@ aclass(Link *ctxt, Addr *a)
return C_GOK;
}
+static int
+aconsize(Link *ctxt)
+{
+ int t;
+
+ t = immrot(ctxt->instoffset);
+ if(t)
+ return C_RACON;
+ return C_LACON;
+}
+
static void
prasm(Prog *p)
{
@@ -917,7 +1192,7 @@ static Optab*
oplook(Link *ctxt, Prog *p)
{
int a1, a2, a3, r;
- char *c1, *c3;
+ uchar *c1, *c3;
Optab *o, *e;
a1 = p->optab;
@@ -941,15 +1216,10 @@ oplook(Link *ctxt, Prog *p)
r = p->as;
o = oprange[r].start;
if(o == 0) {
- a1 = opcross[repop[r]][a1][a2][a3];
- if(a1) {
- p->optab = a1+1;
- return optab+a1;
- }
o = oprange[r].stop; /* just generate an error */
}
if(0 /*debug['O']*/) {
- print("oplook %A %d %d %d\n",
+ print("oplook %A %^ %^ %^\n",
(int)p->as, a1, a2, a3);
print(" %d %d\n", p->from.type, p->to.type);
}
@@ -963,7 +1233,7 @@ oplook(Link *ctxt, Prog *p)
p->optab = (o-optab)+1;
return o;
}
- ctxt->diag("illegal combination %P; %d %d %d, %d %d",
+ ctxt->diag("illegal combination %P; %^ %^ %^, %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);
@@ -1210,11 +1480,16 @@ buildop(Link *ctxt)
case ACLZ:
case AFUNCDATA:
case APCDATA:
+ case ANOP:
+ case ADATABUNDLE:
+ case ADATABUNDLEEND:
break;
}
}
}
+static int32 mov(Link*, Prog*);
+
static void
asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
{
@@ -1272,19 +1547,7 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
break;
case 3: /* add R<<[IR],[R],R */
- mov:
- aclass(ctxt, &p->from);
- o1 = oprrr(ctxt, p->as, p->scond);
- o1 |= p->from.offset;
- rt = p->to.reg;
- r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0;
- if(p->as == AMOVW || p->as == AMVN)
- r = 0;
- else if(r == NREG)
- r = rt;
- o1 |= (r<<16) | (rt<<12);
+ o1 = mov(ctxt, p);
break;
case 4: /* add $I,[R],R */
@@ -1377,11 +1640,11 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
rel->sym = p->to.sym;
rel->add = p->to.offset;
- // runtime.tlsgm (aka gmsym) is special.
+ // runtime.tlsg is special.
// Its "address" is the offset from the TLS thread pointer
// to the thread-local g and m pointers.
// Emit a TLS relocation instead of a standard one.
- if(rel->sym == ctxt->gmsym) {
+ if(rel->sym == ctxt->tlsg) {
rel->type = R_TLS;
if(ctxt->flag_shared)
rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
@@ -1557,19 +1820,23 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= p->from.reg << 0;
break;
- case 38: /* movm $con,oreg -> stm */
- o1 = (0x4 << 25);
- o1 |= p->from.offset & 0xffff;
- o1 |= p->to.reg << 16;
- aclass(ctxt, &p->to);
- goto movm;
-
- case 39: /* movm oreg,$con -> ldm */
- o1 = (0x4 << 25) | (1 << 20);
- o1 |= p->to.offset & 0xffff;
- o1 |= p->from.reg << 16;
- aclass(ctxt, &p->from);
- movm:
+ case 38:
+ case 39:
+ switch(o->type) {
+ case 38: /* movm $con,oreg -> stm */
+ o1 = (0x4 << 25);
+ o1 |= p->from.offset & 0xffff;
+ o1 |= p->to.reg << 16;
+ aclass(ctxt, &p->to);
+ break;
+
+ case 39: /* movm oreg,$con -> ldm */
+ o1 = (0x4 << 25) | (1 << 20);
+ o1 |= p->to.offset & 0xffff;
+ o1 |= p->from.reg << 16;
+ aclass(ctxt, &p->from);
+ break;
+ }
if(ctxt->instoffset != 0)
ctxt->diag("offset must be zero in MOVM; %P", p);
o1 |= (p->scond & C_SCOND) << 28;
@@ -1677,7 +1944,8 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
if(p->from.reg == NREG) {
if(p->as != AMOVW)
ctxt->diag("byte MOV from shifter operand");
- goto mov;
+ o1 = mov(ctxt, p);
+ break;
}
if(p->from.offset&(1<<4))
ctxt->diag("bad shift in LDR");
@@ -1689,7 +1957,8 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
case 60: /* movb R(R),R -> ldrsb indexed */
if(p->from.reg == NREG) {
ctxt->diag("byte MOV from shifter operand");
- goto mov;
+ o1 = mov(ctxt, p);
+ break;
}
if(p->from.offset&(~0xf))
ctxt->diag("bad shift in LDRSB");
@@ -2029,6 +2298,12 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= p->reg;
o1 |= p->to.offset << 16;
break;
+ case 100:
+ // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
+ // DATABUNDLEEND: zero width alignment marker
+ if(p->as == ADATABUNDLE)
+ o1 = 0xe125be70;
+ break;
}
out[0] = o1;
@@ -2038,64 +2313,27 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
out[4] = o5;
out[5] = o6;
return;
+}
-#ifdef NOTDEF
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- lputl(o1);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
- lputl(o1);
- lputl(o2);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- break;
- case 16:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- break;
- case 20:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- break;
- case 24:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
- v, o1, o2, o3, o4, o5, o6, p);
- lputl(o1);
- lputl(o2);
- lputl(o3);
- lputl(o4);
- lputl(o5);
- lputl(o6);
- break;
- }
-#endif
+static int32
+mov(Link *ctxt, Prog *p)
+{
+ int32 o1;
+ int rt, r;
+
+ aclass(ctxt, &p->from);
+ o1 = oprrr(ctxt, p->as, p->scond);
+ o1 |= p->from.offset;
+ rt = p->to.reg;
+ r = p->reg;
+ if(p->to.type == D_NONE)
+ rt = 0;
+ if(p->as == AMOVW || p->as == AMVN)
+ r = 0;
+ else if(r == NREG)
+ r = rt;
+ o1 |= (r<<16) | (rt<<12);
+ return o1;
}
static int32