func readprog(b *bufio.Reader, p *liblink.Prog) { if !undef[p] { panic("double-def") } delete(undef, p) p.Pc = rdint(b) p.Lineno = int(rdint(b)) p.Link = rdprog(b) p.As = int(rdint(b)) p.Reg = int(rdint(b)) p.Scond = int(rdint(b)) p.Width = int8(rdint(b)) readaddr(b, &p.From) readaddr(b, &p.To) }
func stacksplit(ctxt *liblink.Link, p *liblink.Prog, framesize int64, noctxt int) *liblink.Prog { var arg int // MOVW g_stackguard(g), R1 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_OREG p.From.Reg = REGG p.To.Typ = D_REG p.To.Reg = 1 if framesize <= liblink.StackSmall { // small stack: SP < stackguard // CMP stackguard, SP p = liblink.Appendp(ctxt, p) p.As = ACMP p.From.Typ = D_REG p.From.Reg = 1 p.Reg = REGSP } else if framesize <= liblink.StackBig { // large stack: SP-framesize < stackguard-StackSmall // MOVW $-framesize(SP), R2 // CMP stackguard, R2 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Reg = REGSP p.From.Offset = -framesize p.To.Typ = D_REG p.To.Reg = 2 p = liblink.Appendp(ctxt, p) p.As = ACMP p.From.Typ = 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 = liblink.Appendp(ctxt, p) p.As = ACMP p.From.Typ = D_CONST p.From.Offset = int64(uint32(liblink.StackPreempt & 0xFFFFFFFF)) p.Reg = 1 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Reg = REGSP p.From.Offset = liblink.StackGuard p.To.Typ = D_REG p.To.Reg = 2 p.Scond = C_SCOND_NE p = liblink.Appendp(ctxt, p) p.As = ASUB p.From.Typ = D_REG p.From.Reg = 1 p.To.Typ = D_REG p.To.Reg = 2 p.Scond = C_SCOND_NE p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Offset = framesize + (liblink.StackGuard - liblink.StackSmall) p.To.Typ = D_REG p.To.Reg = 3 p.Scond = C_SCOND_NE p = liblink.Appendp(ctxt, p) p.As = ACMP p.From.Typ = D_REG p.From.Reg = 3 p.Reg = 2 p.Scond = C_SCOND_NE } // MOVW.LS $framesize, R1 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Scond = C_SCOND_LS p.From.Typ = D_CONST p.From.Offset = framesize p.To.Typ = D_REG p.To.Reg = 1 // MOVW.LS $args, R2 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Scond = C_SCOND_LS p.From.Typ = D_CONST arg = ctxt.Cursym.Text.To.Offset2 if arg == 1 { // special marker for known 0 arg = 0 } if arg&3 != 0 { ctxt.Diag("misaligned argument size in stack split") } p.From.Offset = int64(arg) p.To.Typ = D_REG p.To.Reg = 2 // MOVW.LS R14, R3 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Scond = C_SCOND_LS p.From.Typ = D_REG p.From.Reg = REGLINK p.To.Typ = D_REG p.To.Reg = 3 // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted p = liblink.Appendp(ctxt, p) p.As = ABL p.Scond = C_SCOND_LS p.To.Typ = D_BRANCH p.To.Sym = ctxt.Symmorestack[noctxt] // BLS start p = liblink.Appendp(ctxt, p) p.As = ABLS p.To.Typ = D_BRANCH p.Pcond = ctxt.Cursym.Text.Link return p }
func addstacksplit(ctxt *liblink.Link, cursym *liblink.LSym) { var p *liblink.Prog var pl *liblink.Prog var q *liblink.Prog var q1 *liblink.Prog var q2 *liblink.Prog var o int var autosize int64 var autoffset int64 autosize = 0 if ctxt.Symmorestack[0] == nil { ctxt.Symmorestack[0] = liblink.Linklookup(ctxt, "runtime.morestack", 0) ctxt.Symmorestack[1] = liblink.Linklookup(ctxt, "runtime.morestack_noctxt", 0) } q = nil ctxt.Cursym = cursym if cursym.Text == nil || cursym.Text.Link == nil { return } 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 != 0 { if autoffset != 0 && p.Reg&liblink.NOSPLIT == 0 { // MOVW $4(R13), R1 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Reg = 13 p.From.Offset = 4 p.To.Typ = D_REG p.To.Reg = 1 // MOVW $n(R13), R2 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Reg = 13 p.From.Offset = 4 + autoffset p.To.Typ = D_REG p.To.Reg = 2 // MOVW $0, R3 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_CONST p.From.Offset = 0 p.To.Typ = D_REG p.To.Reg = 3 // L: // MOVW.nil R3, 0(R1) +4 // CMP R1, R2 // BNE L pl = liblink.Appendp(ctxt, p) p = pl p.As = AMOVW p.From.Typ = D_REG p.From.Reg = 3 p.To.Typ = D_OREG p.To.Reg = 1 p.To.Offset = 4 p.Scond |= C_PBIT p = liblink.Appendp(ctxt, p) p.As = ACMP p.From.Typ = D_REG p.From.Reg = 1 p.Reg = 2 p = liblink.Appendp(ctxt, p) p.As = ABNE p.To.Typ = D_BRANCH p.Pcond = pl } } /* * find leaf subroutines * strip NOPs * expand RET * expand BECOME pseudo */ for p = cursym.Text; p != nil; p = p.Link { switch p.As { case ACASE: if ctxt.Flag_shared != 0 { linkcase(p) } case ATEXT: p.Mark |= LEAF case ARET: break case ADIV, ADIVU, AMOD, AMODU: q = p if ctxt.Sym_div == nil { initdiv(ctxt) } cursym.Text.Mark &^= LEAF continue case ANOP: q1 = p.Link q.Link = q1 /* q is non-nop */ if q1 != nil { q1.Mark |= p.Mark } continue case ABL, ABX, ADUFFZERO, ADUFFCOPY: cursym.Text.Mark &^= LEAF fallthrough case ABCASE, AB, ABEQ, ABNE, ABCS, ABHS, ABCC, ABLO, ABMI, ABPL, ABVS, ABVC, ABHI, ABLS, ABGE, ABLT, ABGT, ABLE: q1 = p.Pcond if q1 != nil { for q1.As == ANOP { q1 = q1.Link p.Pcond = q1 } } break } q = p } for p = cursym.Text; p != nil; p = p.Link { o = p.As switch o { case ATEXT: autosize = p.To.Offset + 4 if autosize <= 4 { if cursym.Text.Mark&LEAF != 0 { p.To.Offset = -4 autosize = 0 } } if autosize == 0 && cursym.Text.Mark&LEAF == 0 { if ctxt.Debugvlog != 0 { fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name) liblink.Bflush(ctxt.Bso) } cursym.Text.Mark |= LEAF } if cursym.Text.Mark&LEAF != 0 { cursym.Leaf = 1 if autosize == 0 { break } } if p.Reg&liblink.NOSPLIT == 0 { p = stacksplit(ctxt, p, autosize, bool2int(cursym.Text.Reg&liblink.NEEDCTXT == 0)) // emit split check } // MOVW.W R14,$-autosize(SP) p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Scond |= C_WBIT p.From.Typ = D_REG p.From.Reg = REGLINK p.To.Typ = D_OREG p.To.Offset = -autosize p.To.Reg = REGSP p.Spadj = autosize if cursym.Text.Reg&liblink.WRAPPER != 0 { // g->panicwrap += autosize; // MOVW panicwrap_offset(g), R3 // ADD $autosize, R3 // MOVW R3 panicwrap_offset(g) p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_OREG p.From.Reg = REGG p.From.Offset = 2 * ctxt.Arch.Ptrsize p.To.Typ = D_REG p.To.Reg = 3 p = liblink.Appendp(ctxt, p) p.As = AADD p.From.Typ = D_CONST p.From.Offset = autosize p.To.Typ = D_REG p.To.Reg = 3 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_REG p.From.Reg = 3 p.To.Typ = D_OREG p.To.Reg = REGG p.To.Offset = 2 * ctxt.Arch.Ptrsize } case ARET: nocache_obj5(p) if cursym.Text.Mark&LEAF != 0 { if autosize == 0 { p.As = AB p.From = zprg_obj5.From if p.To.Sym != nil { // retjmp p.To.Typ = D_BRANCH } else { p.To.Typ = D_OREG p.To.Offset = 0 p.To.Reg = REGLINK } break } } if cursym.Text.Reg&liblink.WRAPPER != 0 { var scond int // Preserve original RET's cond, to allow RET.EQ // in the implementation of reflect.call. scond = 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.Typ = D_OREG p.From.Reg = REGG p.From.Offset = 2 * ctxt.Arch.Ptrsize p.To.Typ = D_REG p.To.Reg = 3 p = liblink.Appendp(ctxt, p) p.As = ASUB p.From.Typ = D_CONST p.From.Offset = autosize p.To.Typ = D_REG p.To.Reg = 3 p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Typ = D_REG p.From.Reg = 3 p.To.Typ = D_OREG p.To.Reg = REGG p.To.Offset = 2 * ctxt.Arch.Ptrsize p = liblink.Appendp(ctxt, p) p.Scond = scond } p.As = AMOVW p.Scond |= C_PBIT p.From.Typ = D_OREG p.From.Offset = autosize p.From.Reg = REGSP p.To.Typ = D_REG p.To.Reg = REGPC // If there are instructions following // this ARET, they come from a branch // with the same stackframe, so no spadj. if p.To.Sym != nil { // retjmp p.To.Reg = REGLINK q2 = liblink.Appendp(ctxt, p) q2.As = AB q2.To.Typ = D_BRANCH q2.To.Sym = p.To.Sym p.To.Sym = nil p = q2 } case AADD: if p.From.Typ == D_CONST && p.From.Reg == NREG && p.To.Typ == D_REG && p.To.Reg == REGSP { p.Spadj = -p.From.Offset } case ASUB: if p.From.Typ == D_CONST && p.From.Reg == NREG && p.To.Typ == D_REG && p.To.Reg == REGSP { p.Spadj = p.From.Offset } case ADIV, ADIVU, AMOD, AMODU: if ctxt.Debugdivmod != 0 { break } if p.From.Typ != D_REG { break } if p.To.Typ != D_REG { break } q1 = p /* MOV a,4(SP) */ p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Lineno = q1.Lineno p.From.Typ = D_REG p.From.Reg = q1.From.Reg p.To.Typ = D_OREG p.To.Reg = REGSP p.To.Offset = 4 /* MOV b,REGTMP */ p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Lineno = q1.Lineno p.From.Typ = D_REG p.From.Reg = q1.Reg if q1.Reg == NREG { p.From.Reg = q1.To.Reg } p.To.Typ = D_REG p.To.Reg = REGTMP p.To.Offset = 0 /* CALL appropriate */ p = liblink.Appendp(ctxt, p) p.As = ABL p.Lineno = q1.Lineno p.To.Typ = D_BRANCH switch o { case ADIV: p.To.Sym = ctxt.Sym_div case ADIVU: p.To.Sym = ctxt.Sym_divu case AMOD: p.To.Sym = ctxt.Sym_mod case AMODU: p.To.Sym = ctxt.Sym_modu break } /* MOV REGTMP, b */ p = liblink.Appendp(ctxt, p) p.As = AMOVW p.Lineno = q1.Lineno p.From.Typ = D_REG p.From.Reg = REGTMP p.From.Offset = 0 p.To.Typ = D_REG p.To.Reg = q1.To.Reg /* ADD $8,SP */ p = liblink.Appendp(ctxt, p) p.As = AADD p.Lineno = q1.Lineno p.From.Typ = D_CONST p.From.Reg = NREG p.From.Offset = 8 p.Reg = NREG p.To.Typ = D_REG p.To.Reg = REGSP p.Spadj = -8 /* 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.Typ = D_OREG q1.From.Reg = REGSP q1.From.Offset = 0 q1.Reg = NREG q1.To.Typ = D_REG q1.To.Reg = REGTMP /* SUB $8,SP */ q1 = liblink.Appendp(ctxt, q1) q1.As = AMOVW q1.From.Typ = D_REG q1.From.Reg = REGTMP q1.Reg = NREG q1.To.Typ = D_OREG q1.To.Reg = REGSP q1.To.Offset = -8 q1.Scond |= C_WBIT q1.Spadj = 8 case AMOVW: if (p.Scond&C_WBIT != 0) && p.To.Typ == D_OREG && p.To.Reg == REGSP { p.Spadj = -p.To.Offset } if (p.Scond&C_PBIT != 0) && p.From.Typ == D_OREG && p.From.Reg == REGSP && p.To.Reg != REGPC { p.Spadj = -p.From.Offset } if p.From.Typ == D_CONST && p.From.Reg == REGSP && p.To.Typ == D_REG && p.To.Reg == REGSP { p.Spadj = -p.From.Offset } break } } }