summaryrefslogtreecommitdiff
path: root/src/cmd/5l/noop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5l/noop.c')
-rw-r--r--src/cmd/5l/noop.c484
1 files changed, 327 insertions, 157 deletions
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 99a096a31..305ed684e 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -32,18 +32,16 @@
#include "l.h"
#include "../ld/lib.h"
-
-// see ../../runtime/proc.c:/StackGuard
-enum
-{
- StackBig = 4096,
- StackSmall = 128,
-};
+#include "../../pkg/runtime/stack.h"
static Sym* sym_div;
static Sym* sym_divu;
static Sym* sym_mod;
static Sym* sym_modu;
+static Sym* symmorestack;
+static Prog* pmorestack;
+
+static Prog* stacksplit(Prog*, int32);
static void
linkcase(Prog *casep)
@@ -62,16 +60,16 @@ linkcase(Prog *casep)
void
noops(void)
{
- Prog *p, *q, *q1;
+ Prog *p, *q, *q1, *q2;
int o;
- Prog *pmorestack;
- Sym *symmorestack;
+ Sym *tlsfallback, *gmsym;
/*
* find leaf subroutines
* strip NOPs
* expand RET
* expand BECOME pseudo
+ * fixup TLS
*/
if(debug['v'])
@@ -86,6 +84,10 @@ noops(void)
pmorestack = symmorestack->text;
pmorestack->reg |= NOSPLIT;
+ tlsfallback = lookup("runtime.read_tls_fallback", 0);
+ gmsym = S;
+ if(linkmode == LinkExternal)
+ gmsym = lookup("runtime.tlsgm", 0);
q = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
@@ -150,6 +152,82 @@ noops(void)
}
}
break;
+ case AWORD:
+ // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
+ if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
+ if(HEADTYPE == Hopenbsd) {
+ p->as = ARET;
+ } else if(goarm < 7) {
+ if(tlsfallback->type != STEXT) {
+ diag("runtime·read_tls_fallback not defined");
+ errorexit();
+ }
+ // BL runtime.read_tls_fallback(SB)
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = tlsfallback;
+ p->cond = tlsfallback->text;
+ p->to.offset = 0;
+ cursym->text->mark &= ~LEAF;
+ }
+ if(linkmode == LinkExternal) {
+ // runtime.tlsgm is relocated with R_ARM_TLS_LE32
+ // and $runtime.tlsgm will contain the TLS offset.
+ //
+ // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP
+ // ADD REGTMP, <reg>
+ //
+ // In shared mode, runtime.tlsgm is relocated with
+ // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
+ // to the GOT entry containing the TLS offset.
+ //
+ // MOV runtime.tlsgm(SB), REGTMP
+ // ADD REGTMP, <reg>
+ // SUB -tlsoffset, <reg>
+ //
+ // The SUB compensates for tlsoffset
+ // used in runtime.save_gm and runtime.load_gm.
+ q = p;
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = 14;
+ p->reg = NREG;
+ if(flag_shared) {
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ } else {
+ p->from.type = D_CONST;
+ p->from.offset = tlsoffset;
+ }
+ p->from.sym = gmsym;
+ p->from.name = D_EXTERN;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+ p->to.offset = 0;
+
+ p = appendp(p);
+ p->as = AADD;
+ p->scond = 14;
+ p->reg = NREG;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_REG;
+ p->to.reg = (q->to.offset & 0xf000) >> 12;
+ p->to.offset = 0;
+
+ if(flag_shared) {
+ p = appendp(p);
+ p->as = ASUB;
+ p->scond = 14;
+ p->reg = NREG;
+ p->from.type = D_CONST;
+ p->from.offset = -tlsoffset;
+ p->to.type = D_REG;
+ p->to.reg = (q->to.offset & 0xf000) >> 12;
+ p->to.offset = 0;
+ }
+ }
+ }
}
q = p;
}
@@ -180,160 +258,47 @@ noops(void)
break;
}
- if(p->reg & NOSPLIT) {
- q1 = prg();
- q1->as = AMOVW;
- q1->scond |= C_WBIT;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGLINK;
- q1->to.type = D_OREG;
- q1->to.offset = -autosize;
- q1->to.reg = REGSP;
- q1->spadj = autosize;
- q1->link = p->link;
- p->link = q1;
- } else if (autosize < StackBig) {
- // split stack check for small functions
- // MOVW g_stackguard(g), R1
- // CMP R1, $-autosize(SP)
- // MOVW.LO $autosize, R1
- // MOVW.LO $args, R2
- // MOVW.LO R14, R3
- // BL.LO runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // TODO(kaib): add more trampolines
- // TODO(kaib): put stackguard in register
- // TODO(kaib): add support for -K and underflow detection
-
- // MOVW g_stackguard(g), R1
+ if(!(p->reg & NOSPLIT))
+ p = stacksplit(p, autosize); // emit split check
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
+ p->spadj = autosize;
+
+ if(cursym->text->reg & WRAPPER) {
+ // g->panicwrap += autosize;
+ // MOVW panicwrap_offset(g), R3
+ // ADD $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
p = appendp(p);
p->as = AMOVW;
p->from.type = D_OREG;
p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- if(autosize < StackSmall) {
- // CMP R1, SP
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = REGSP;
- } else {
- // MOVW $-autosize(SP), R2
- // CMP R1, R2
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.reg = REGSP;
- p->from.offset = -autosize;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->reg = 2;
- }
-
- // MOVW.LO $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LO $args, R2
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LO R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
+ p->from.offset = 2*PtrSize;
p->to.type = D_REG;
p->to.reg = 3;
-
- // BL.LO runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LO;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
- } else { // > StackBig
- // MOVW $autosize, R1
- // MOVW $args, R2
- // MOVW R14, R3
- // BL runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // MOVW $autosize, R1
+
p = appendp(p);
- p->as = AMOVW;
+ p->as = AADD;
p->from.type = D_CONST;
p->from.offset = autosize;
p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $args, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
p->to.reg = 3;
-
- // BL runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
+
p = appendp(p);
p->as = AMOVW;
- p->scond |= C_WBIT;
p->from.type = D_REG;
- p->from.reg = REGLINK;
+ p->from.reg = 3;
p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- p->spadj = autosize;
+ p->to.reg = REGG;
+ p->to.offset = 2*PtrSize;
}
break;
@@ -343,12 +308,56 @@ noops(void)
if(!autosize) {
p->as = AB;
p->from = zprg.from;
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
+ if(p->to.sym) { // retjmp
+ p->to.type = D_BRANCH;
+ p->cond = p->to.sym->text;
+ } else {
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ }
break;
}
}
+
+ if(cursym->text->reg & WRAPPER) {
+ int cond;
+
+ // Preserve original RET's cond, to allow RET.EQ
+ // in the implementation of reflect.call.
+ cond = p->scond;
+ p->scond = C_SCOND_NONE;
+
+ // g->panicwrap -= autosize;
+ // MOVW panicwrap_offset(g), R3
+ // SUB $autosize, R3
+ // MOVW R3 panicwrap_offset(g)
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->from.offset = 2*PtrSize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(p);
+
+ p->as = ASUB;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p = appendp(p);
+
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->to.type = D_OREG;
+ p->to.reg = REGG;
+ p->to.offset = 2*PtrSize;
+ p = appendp(p);
+
+ p->scond = cond;
+ }
+
p->as = AMOVW;
p->scond |= C_PBIT;
p->from.type = D_OREG;
@@ -359,6 +368,17 @@ noops(void)
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so no spadj.
+
+ if(p->to.sym) { // retjmp
+ p->to.reg = REGLINK;
+ q2 = appendp(p);
+ q2->as = AB;
+ q2->to.type = D_BRANCH;
+ q2->to.sym = p->to.sym;
+ q2->cond = p->to.sym->text;
+ p->to.sym = nil;
+ p = q2;
+ }
break;
case AADD:
@@ -452,14 +472,27 @@ noops(void)
p->to.reg = REGSP;
p->spadj = -8;
- /* SUB $8,SP */
- q1->as = ASUB;
- q1->from.type = D_CONST;
- q1->from.offset = 8;
- q1->from.reg = NREG;
+ /* Keep saved LR at 0(SP) after SP change. */
+ /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
+ /* TODO: Remove SP adjustments; see issue 6699. */
+ q1->as = AMOVW;
+ q1->from.type = D_OREG;
+ q1->from.reg = REGSP;
+ q1->from.offset = 0;
q1->reg = NREG;
q1->to.type = D_REG;
+ q1->to.reg = REGTMP;
+
+ /* SUB $8,SP */
+ q1 = appendp(q1);
+ q1->as = AMOVW;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMP;
+ q1->reg = NREG;
+ q1->to.type = D_OREG;
q1->to.reg = REGSP;
+ q1->to.offset = -8;
+ q1->scond |= C_WBIT;
q1->spadj = 8;
break;
@@ -476,6 +509,143 @@ noops(void)
}
}
+static Prog*
+stacksplit(Prog *p, int32 framesize)
+{
+ int32 arg;
+
+ // MOVW g_stackguard(g), R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ if(framesize <= StackSmall) {
+ // small stack: SP < stackguard
+ // CMP stackguard, SP
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = REGSP;
+ } else if(framesize <= StackBig) {
+ // large stack: SP-framesize < stackguard-StackSmall
+ // MOVW $-framesize(SP), R2
+ // CMP stackguard, R2
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = -framesize;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+ } else {
+ // Such a large stack we need to protect against wraparound
+ // if SP is close to zero.
+ // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
+ // The +StackGuard on both sides is required to keep the left side positive:
+ // SP is allowed to be slightly below stackguard. See stack.h.
+ // CMP $StackPreempt, R1
+ // MOVW.NE $StackGuard(SP), R2
+ // SUB.NE R1, R2
+ // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
+ // CMP.NE R3, R2
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_CONST;
+ p->from.offset = (uint32)StackPreempt;
+ p->reg = 1;
+
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = StackGuard;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(p);
+ p->as = ASUB;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = framesize + (StackGuard - StackSmall);
+ p->to.type = D_REG;
+ p->to.reg = 3;
+ p->scond = C_SCOND_NE;
+
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 3;
+ p->reg = 2;
+ p->scond = C_SCOND_NE;
+ }
+
+ // MOVW.LS $framesize, R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ p->from.offset = framesize;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LS $args, R2
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_CONST;
+ arg = cursym->text->to.offset2;
+ if(arg == 1) // special marker for known 0
+ arg = 0;
+ if(arg&3)
+ diag("misaligned argument size in stack split");
+ p->from.offset = arg;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW.LS R14, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LS;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted
+ p = appendp(p);
+ p->as = ABL;
+ p->scond = C_SCOND_LS;
+ p->to.type = D_BRANCH;
+ p->to.sym = symmorestack;
+ p->cond = pmorestack;
+
+ // BLS start
+ p = appendp(p);
+ p->as = ABLS;
+ p->to.type = D_BRANCH;
+ p->cond = cursym->text->link;
+
+ return p;
+}
+
static void
sigdiv(char *n)
{