diff options
Diffstat (limited to 'src/liblink/asm5.c')
-rw-r--r-- | src/liblink/asm5.c | 618 |
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 |