123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- // Based on cmd/internal/obj/ppc64/obj9.go.
- //
- // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
- // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
- // Portions Copyright © 1997-1999 Vita Nuova Limited
- // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
- // Portions Copyright © 2004,2006 Bruce Ellis
- // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
- // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
- // Portions Copyright © 2009 The Go Authors. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- package s390x
- import (
- "github.com/twitchyliquid64/golang-asm/obj"
- "github.com/twitchyliquid64/golang-asm/objabi"
- "github.com/twitchyliquid64/golang-asm/sys"
- "math"
- )
- func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
- p.From.Class = 0
- p.To.Class = 0
- c := ctxtz{ctxt: ctxt, newprog: newprog}
- // Rewrite BR/BL to symbol as TYPE_BRANCH.
- switch p.As {
- case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
- if p.To.Sym != nil {
- p.To.Type = obj.TYPE_BRANCH
- }
- }
- // Rewrite float constants to values stored in memory unless they are +0.
- switch p.As {
- case AFMOVS:
- if p.From.Type == obj.TYPE_FCONST {
- f32 := float32(p.From.Val.(float64))
- if math.Float32bits(f32) == 0 { // +0
- break
- }
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = ctxt.Float32Sym(f32)
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
- }
- case AFMOVD:
- if p.From.Type == obj.TYPE_FCONST {
- f64 := p.From.Val.(float64)
- if math.Float64bits(f64) == 0 { // +0
- break
- }
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = ctxt.Float64Sym(f64)
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
- }
- // put constants not loadable by LOAD IMMEDIATE into memory
- case AMOVD:
- if p.From.Type == obj.TYPE_CONST {
- val := p.From.Offset
- if int64(int32(val)) != val &&
- int64(uint32(val)) != val &&
- int64(uint64(val)&(0xffffffff<<32)) != val {
- p.From.Type = obj.TYPE_MEM
- p.From.Sym = ctxt.Int64Sym(p.From.Offset)
- p.From.Name = obj.NAME_EXTERN
- p.From.Offset = 0
- }
- }
- }
- // Rewrite SUB constants into ADD.
- switch p.As {
- case ASUBC:
- if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
- p.From.Offset = -p.From.Offset
- p.As = AADDC
- }
- case ASUB:
- if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
- p.From.Offset = -p.From.Offset
- p.As = AADD
- }
- }
- if c.ctxt.Flag_dynlink {
- c.rewriteToUseGot(p)
- }
- }
- // Rewrite p, if necessary, to access global data via the global offset table.
- func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
- // At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in
- // assembly code.
- if p.As == AEXRL {
- return
- }
- // We only care about global data: NAME_EXTERN means a global
- // symbol in the Go sense, and p.Sym.Local is true for a few
- // internally defined symbols.
- // Rewrites must not clobber flags and therefore cannot use the
- // ADD instruction.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
- // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
- // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx or REGTMP2; MOVD $<off>(Rx or REGTMP2), Rx
- if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
- c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
- }
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_GOTREF
- q := p
- if p.From.Offset != 0 {
- target := p.To.Reg
- if target == REG_R0 {
- // Cannot use R0 as input to address calculation.
- // REGTMP might be used by the assembler.
- p.To.Reg = REGTMP2
- }
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_ADDR
- q.From.Offset = p.From.Offset
- q.From.Reg = p.To.Reg
- q.To.Type = obj.TYPE_REG
- q.To.Reg = target
- p.From.Offset = 0
- }
- }
- if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
- c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
- }
- var source *obj.Addr
- // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP2; MOVD (REGTMP2), Ry
- // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP2; MOVD Ry, (REGTMP2)
- // An addition may be inserted between the two MOVs if there is an offset.
- if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
- if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
- c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
- }
- source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
- source = &p.To
- } else {
- return
- }
- if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
- return
- }
- if source.Sym.Type == objabi.STLSBSS {
- return
- }
- if source.Type != obj.TYPE_MEM {
- c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
- }
- p1 := obj.Appendp(p, c.newprog)
- p2 := obj.Appendp(p1, c.newprog)
- p1.As = AMOVD
- p1.From.Type = obj.TYPE_MEM
- p1.From.Sym = source.Sym
- p1.From.Name = obj.NAME_GOTREF
- p1.To.Type = obj.TYPE_REG
- p1.To.Reg = REGTMP2
- p2.As = p.As
- p2.From = p.From
- p2.To = p.To
- if p.From.Name == obj.NAME_EXTERN {
- p2.From.Reg = REGTMP2
- p2.From.Name = obj.NAME_NONE
- p2.From.Sym = nil
- } else if p.To.Name == obj.NAME_EXTERN {
- p2.To.Reg = REGTMP2
- p2.To.Name = obj.NAME_NONE
- p2.To.Sym = nil
- } else {
- return
- }
- obj.Nopout(p)
- }
- func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- // TODO(minux): add morestack short-cuts with small fixed frame-size.
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
- return
- }
- c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
- textstksiz := p.To.Offset
- if textstksiz == -8 {
- // Compatibility hack.
- p.From.Sym.Set(obj.AttrNoFrame, true)
- textstksiz = 0
- }
- if textstksiz%8 != 0 {
- c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
- }
- if p.From.Sym.NoFrame() {
- if textstksiz != 0 {
- c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
- }
- }
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
- /*
- * find leaf subroutines
- * strip NOPs
- * expand RET
- */
- var q *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
- switch p.As {
- case obj.ATEXT:
- q = p
- p.Mark |= LEAF
- case ABL, ABCL:
- q = p
- c.cursym.Func.Text.Mark &^= LEAF
- fallthrough
- case ABC,
- ABRC,
- ABEQ,
- ABGE,
- ABGT,
- ABLE,
- ABLT,
- ABLEU,
- ABLTU,
- ABNE,
- ABR,
- ABVC,
- ABVS,
- ACRJ,
- ACGRJ,
- ACLRJ,
- ACLGRJ,
- ACIJ,
- ACGIJ,
- ACLIJ,
- ACLGIJ,
- ACMPBEQ,
- ACMPBGE,
- ACMPBGT,
- ACMPBLE,
- ACMPBLT,
- ACMPBNE,
- ACMPUBEQ,
- ACMPUBGE,
- ACMPUBGT,
- ACMPUBLE,
- ACMPUBLT,
- ACMPUBNE:
- q = p
- p.Mark |= BRANCH
- default:
- q = p
- }
- }
- autosize := int32(0)
- var pLast *obj.Prog
- var pPre *obj.Prog
- var pPreempt *obj.Prog
- wasSplit := false
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
- pLast = p
- switch p.As {
- case obj.ATEXT:
- autosize = int32(textstksiz)
- if p.Mark&LEAF != 0 && autosize == 0 {
- // A leaf function with no locals has no frame.
- p.From.Sym.Set(obj.AttrNoFrame, true)
- }
- if !p.From.Sym.NoFrame() {
- // If there is a stack frame at all, it includes
- // space to save the LR.
- autosize += int32(c.ctxt.FixedFrameSize())
- }
- if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
- // A leaf function with a small stack can be marked
- // NOSPLIT, avoiding a stack check.
- p.From.Sym.Set(obj.AttrNoSplit, true)
- }
- p.To.Offset = int64(autosize)
- q := p
- if !p.From.Sym.NoSplit() {
- p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
- pPre = p
- p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
- wasSplit = true //need post part of split
- }
- if autosize != 0 {
- // Make sure to save link register for non-empty frame, even if
- // it is a leaf function, so that traceback works.
- // Store link register before decrementing SP, so if a signal comes
- // during the execution of the function prologue, the traceback
- // code will not see a half-updated stack frame.
- // This sequence is not async preemptible, as if we open a frame
- // at the current SP, it will clobber the saved LR.
- q = c.ctxt.StartUnsafePoint(p, c.newprog)
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_LR
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REGSP
- q.To.Offset = int64(-autosize)
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_ADDR
- q.From.Offset = int64(-autosize)
- q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REGSP
- q.Spadj = autosize
- q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
- } else if c.cursym.Func.Text.Mark&LEAF == 0 {
- // A very few functions that do not return to their caller
- // (e.g. gogo) are not identified as leaves but still have
- // no frame.
- c.cursym.Func.Text.Mark |= LEAF
- }
- if c.cursym.Func.Text.Mark&LEAF != 0 {
- c.cursym.Set(obj.AttrLeaf, true)
- break
- }
- if c.cursym.Func.Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVD g_panic(g), R3
- // CMP R3, $0
- // BEQ end
- // MOVD panic_argp(R3), R4
- // ADD $(autosize+8), R1, R5
- // CMP R4, R5
- // BNE end
- // ADD $8, R1, R6
- // MOVD R6, panic_argp(R3)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes.
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R3
- q = obj.Appendp(q, c.newprog)
- q.As = ACMP
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R3
- q.To.Type = obj.TYPE_CONST
- q.To.Offset = 0
- q = obj.Appendp(q, c.newprog)
- q.As = ABEQ
- q.To.Type = obj.TYPE_BRANCH
- p1 := q
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REG_R3
- q.From.Offset = 0 // Panic.argp
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R4
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R5
- q = obj.Appendp(q, c.newprog)
- q.As = ACMP
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R4
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R5
- q = obj.Appendp(q, c.newprog)
- q.As = ABNE
- q.To.Type = obj.TYPE_BRANCH
- p2 := q
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = c.ctxt.FixedFrameSize()
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R6
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R6
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REG_R3
- q.To.Offset = 0 // Panic.argp
- q = obj.Appendp(q, c.newprog)
- q.As = obj.ANOP
- p1.To.SetTarget(q)
- p2.To.SetTarget(q)
- }
- case obj.ARET:
- retTarget := p.To.Sym
- if c.cursym.Func.Text.Mark&LEAF != 0 {
- if autosize == 0 {
- p.As = ABR
- p.From = obj.Addr{}
- if retTarget == nil {
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
- } else {
- p.To.Type = obj.TYPE_BRANCH
- p.To.Sym = retTarget
- }
- p.Mark |= BRANCH
- break
- }
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(autosize)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGSP
- p.Spadj = -autosize
- q = obj.Appendp(p, c.newprog)
- q.As = ABR
- q.From = obj.Addr{}
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_LR
- q.Mark |= BRANCH
- q.Spadj = autosize
- break
- }
- p.As = AMOVD
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGSP
- p.From.Offset = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
- q = p
- if autosize != 0 {
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize)
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REGSP
- q.Spadj = -autosize
- }
- q = obj.Appendp(q, c.newprog)
- q.As = ABR
- q.From = obj.Addr{}
- if retTarget == nil {
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_LR
- } else {
- q.To.Type = obj.TYPE_BRANCH
- q.To.Sym = retTarget
- }
- q.Mark |= BRANCH
- q.Spadj = autosize
- case AADD:
- if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
- p.Spadj = int32(-p.From.Offset)
- }
- case obj.AGETCALLERPC:
- if cursym.Leaf() {
- /* MOVD LR, Rd */
- p.As = AMOVD
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_LR
- } else {
- /* MOVD (RSP), Rd */
- p.As = AMOVD
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGSP
- }
- }
- }
- if wasSplit {
- c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
- }
- }
- func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
- var q *obj.Prog
- // MOVD g_stackguard(g), R3
- p = obj.Appendp(p, c.newprog)
- p.As = AMOVD
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGG
- p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
- if c.cursym.CFunc() {
- p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
- }
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R3
- // Mark the stack bound check and morestack call async nonpreemptible.
- // If we get preempted here, when resumed the preemption request is
- // cleared, but we'll still call morestack, which will double the stack
- // unnecessarily. See issue #35470.
- p = c.ctxt.StartUnsafePoint(p, c.newprog)
- q = nil
- if framesize <= objabi.StackSmall {
- // small stack: SP < stackguard
- // CMPUBGE stackguard, SP, label-of-call-to-morestack
- p = obj.Appendp(p, c.newprog)
- //q1 = p
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R3
- p.Reg = REGSP
- p.As = ACMPUBGE
- p.To.Type = obj.TYPE_BRANCH
- } else if framesize <= objabi.StackBig {
- // large stack: SP-framesize < stackguard-StackSmall
- // ADD $-(framesize-StackSmall), SP, R4
- // CMPUBGE stackguard, R4, label-of-call-to-morestack
- p = obj.Appendp(p, c.newprog)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = -(int64(framesize) - objabi.StackSmall)
- p.Reg = REGSP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R4
- p = obj.Appendp(p, c.newprog)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R3
- p.Reg = REG_R4
- p.As = ACMPUBGE
- p.To.Type = obj.TYPE_BRANCH
- } 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.
- //
- // Preemption sets stackguard to StackPreempt, a very large value.
- // That breaks the math above, so we have to check for that explicitly.
- // // stackguard is R3
- // CMP R3, $StackPreempt
- // BEQ label-of-call-to-morestack
- // ADD $StackGuard, SP, R4
- // SUB R3, R4
- // MOVD $(framesize+(StackGuard-StackSmall)), TEMP
- // CMPUBGE TEMP, R4, label-of-call-to-morestack
- p = obj.Appendp(p, c.newprog)
- p.As = ACMP
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R3
- p.To.Type = obj.TYPE_CONST
- p.To.Offset = objabi.StackPreempt
- p = obj.Appendp(p, c.newprog)
- q = p
- p.As = ABEQ
- p.To.Type = obj.TYPE_BRANCH
- p = obj.Appendp(p, c.newprog)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(objabi.StackGuard)
- p.Reg = REGSP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R4
- p = obj.Appendp(p, c.newprog)
- p.As = ASUB
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R3
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R4
- p = obj.Appendp(p, c.newprog)
- p.As = AMOVD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REGTMP
- p = obj.Appendp(p, c.newprog)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REGTMP
- p.Reg = REG_R4
- p.As = ACMPUBGE
- p.To.Type = obj.TYPE_BRANCH
- }
- return p, q
- }
- func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
- // Now we are at the end of the function, but logically
- // we are still in function prologue. We need to fix the
- // SP data and PCDATA.
- spfix := obj.Appendp(p, c.newprog)
- spfix.As = obj.ANOP
- spfix.Spadj = -framesize
- pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
- pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
- // MOVD LR, R5
- p = obj.Appendp(pcdata, c.newprog)
- pPre.To.SetTarget(p)
- p.As = AMOVD
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_LR
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R5
- if pPreempt != nil {
- pPreempt.To.SetTarget(p)
- }
- // BL runtime.morestack(SB)
- p = obj.Appendp(p, c.newprog)
- p.As = ABL
- p.To.Type = obj.TYPE_BRANCH
- if c.cursym.CFunc() {
- p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
- p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
- } else {
- p.To.Sym = c.ctxt.Lookup("runtime.morestack")
- }
- p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
- // BR start
- p = obj.Appendp(p, c.newprog)
- p.As = ABR
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(c.cursym.Func.Text.Link)
- return p
- }
- var unaryDst = map[obj.As]bool{
- ASTCK: true,
- ASTCKC: true,
- ASTCKE: true,
- ASTCKF: true,
- ANEG: true,
- ANEGW: true,
- AVONE: true,
- AVZERO: true,
- }
- var Links390x = obj.LinkArch{
- Arch: sys.ArchS390X,
- Init: buildop,
- Preprocess: preprocess,
- Assemble: spanz,
- Progedit: progedit,
- UnaryDst: unaryDst,
- DWARFRegisters: S390XDWARFRegisters,
- }
|