作者:duhaibo040
项目:go-
func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
// RegTo2 is set on the instructions we insert here so they don't get
// processed twice.
if p.RegTo2 != 0 {
return
}
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return
}
// Any Prog (aside from the above special cases) with an Addr with Name ==
// NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.cx
// inserted before it.
isName := func(a *obj.Addr) bool {
if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
return false
}
if a.Sym.Type == obj.STLSBSS {
return false
}
return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
}
if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
// Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
// to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
// respectively.
if p.To.Type != obj.TYPE_REG {
q := obj.Appendp(ctxt, p)
q.As = p.As
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_CX
q.To = p.To
p.As = AMOVL
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_CX
p.To.Sym = nil
p.To.Name = obj.NAME_NONE
}
}
if !isName(&p.From) && !isName(&p.To) && (p.From3 == nil || !isName(p.From3)) {
return
}
q := obj.Appendp(ctxt, p)
q.RegTo2 = 1
r := obj.Appendp(ctxt, q)
r.RegTo2 = 1
q.As = obj.ACALL
q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
q.To.Type = obj.TYPE_MEM
q.To.Name = obj.NAME_EXTERN
q.To.Sym.Local = true
r.As = p.As
r.Scond = p.Scond
r.From = p.From
r.From3 = p.From3
r.Reg = p.Reg
r.To = p.To
obj.Nopout(p)
}
作者:hurkg
项目:g
func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog) *obj.Prog {
// MOVD LR, R5
p = obj.Appendp(ctxt, p)
pPre.Pcond = 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.Pcond = p
}
// BL runtime.morestack(SB)
p = obj.Appendp(ctxt, p)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
if ctxt.Cursym.Cfunc {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
} else {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
}
// BR start
p = obj.Appendp(ctxt, p)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
p.Pcond = ctxt.Cursym.Text.Link
return p
}
作者:kuangchanglan
项目:g
func stacksplitPost(ctxt *obj.Link, 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(ctxt, p)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := obj.Appendp(ctxt, spfix)
pcdata.Lineno = ctxt.Cursym.Text.Lineno
pcdata.Mode = ctxt.Cursym.Text.Mode
pcdata.As = obj.APCDATA
pcdata.From.Type = obj.TYPE_CONST
pcdata.From.Offset = obj.PCDATA_StackMapIndex
pcdata.To.Type = obj.TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
// MOVD LR, R5
p = obj.Appendp(ctxt, pcdata)
pPre.Pcond = 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.Pcond = p
}
// BL runtime.morestack(SB)
p = obj.Appendp(ctxt, p)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
if ctxt.Cursym.Cfunc {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
} else {
p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
}
// BR start
p = obj.Appendp(ctxt, p)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
p.Pcond = ctxt.Cursym.Text.Link
return p
}
作者:Harvey-O
项目:g
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
// Leaf function with no frame is effectively NOSPLIT.
if framesize == 0 {
return p
}
var mov, add, sub obj.As
if ctxt.Mode&Mips64 != 0 {
add = AADDV
mov = AMOVV
sub = ASUBVU
} else {
add = AADDU
mov = AMOVW
sub = ASUBU
}
// MOV g_stackguard(g), R1
p = obj.Appendp(ctxt, p)
p.As = mov
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
var q *obj.Prog
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// AGTU SP, stackguard, R1
p = obj.Appendp(ctxt, p)
p.As = ASGTU
p.From.Type = obj.TYPE_REG
p.From.Reg = REGSP
p.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-framesize, SP, R2
// SGTU R2, stackguard, R1
p = obj.Appendp(ctxt, p)
p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(-framesize)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ASGTU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
p.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
} 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 R1
// MOV $StackPreempt, R2
// BEQ R1, R2, label-of-call-to-morestack
// ADD $StackGuard, SP, R2
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R1
// SGTU R2, R1, R1
p = obj.Appendp(ctxt, p)
p.As = mov
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackPreempt
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
q = p
p.As = ABEQ
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
p.To.Type = obj.TYPE_BRANCH
p.Mark |= BRANCH
p = obj.Appendp(ctxt, p)
p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
//.........这里部分代码省略.........
作者:Harvey-O
项目:g
//.........这里部分代码省略.........
} else {
add = AADDU
mov = AMOVW
}
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
for p := cursym.Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
autosize = int32(textstksiz + ctxt.FixedFrameSize())
if (p.Mark&LEAF != 0) && autosize <= int32(ctxt.FixedFrameSize()) {
autosize = 0
} else if autosize&4 != 0 && ctxt.Mode&Mips64 != 0 {
autosize += 4
}
p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
if p.From3.Offset&obj.NOSPLIT == 0 {
p = stacksplit(ctxt, p, autosize) // emit split check
}
q = p
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 decrement SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
q = obj.Appendp(ctxt, q)
q.As = mov
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_REG
q.From.Reg = REGLINK
q.To.Type = obj.TYPE_MEM
q.To.Offset = int64(-autosize)
q.To.Reg = REGSP
q = obj.Appendp(ctxt, q)
q.As = add
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(-autosize)
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Spadj = +autosize
} else if cursym.Text.Mark&LEAF == 0 {
if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
if ctxt.Debugvlog != 0 {
ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
cursym.Text.Mark |= LEAF
}
}
if cursym.Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
break
}
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
作者:kluesk
项目:go-akaro
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt int) *obj.Prog {
// MOV g_stackguard(g), R1
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
if ctxt.Cursym.Cfunc != 0 {
p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
q := (*obj.Prog)(nil)
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// MOV SP, R2
// CMP stackguard, R2
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// SUB $framesize, SP, R2
// CMP stackguard, R2
p = obj.Appendp(ctxt, p)
p.As = ASUB
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} 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
// BEQ label_of_call_to_morestack
// ADD $StackGuard, SP, R2
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R3
// CMP R3, R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackPreempt
p.Reg = REG_R1
p = obj.Appendp(ctxt, p)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
p = obj.Appendp(ctxt, p)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
//.........这里部分代码省略.........
作者:duhaibo040
项目:go-
// Rewrite p, if necessary, to access global data via the global offset table.
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
var add, lea, mov obj.As
var reg int16
if p.Mode == 64 {
add = AADDQ
lea = ALEAQ
mov = AMOVQ
reg = REG_R15
} else {
add = AADDL
lea = ALEAL
mov = AMOVL
reg = REG_CX
}
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
// $MOV [email protected], $reg
// $ADD $offset, $reg
// CALL $reg
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
} else {
sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
}
offset := p.To.Offset
p.As = mov
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
p.From.Sym = sym
p.To.Type = obj.TYPE_REG
p.To.Reg = reg
p.To.Offset = 0
p.To.Sym = nil
p1 := obj.Appendp(ctxt, p)
p1.As = add
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = reg
p2 := obj.Appendp(ctxt, p1)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_REG
p2.To.Reg = reg
}
// 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.
if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
// $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
p.As = mov
p.From.Type = obj.TYPE_ADDR
}
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
// $MOV $sym, Rx becomes $MOV [email protected], Rx
// $MOV $sym+<off>, Rx becomes $MOV [email protected], Rx; $LEA <off>(Rx), Rx
// On 386 only, more complicated things like PUSHL $sym become $MOV [email protected], CX; PUSHL CX
cmplxdest := false
pAs := p.As
var dest obj.Addr
if p.To.Type != obj.TYPE_REG || pAs != mov {
if p.Mode == 64 {
ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
}
cmplxdest = true
dest = p.To
p.As = mov
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_CX
p.To.Sym = nil
p.To.Name = obj.NAME_NONE
}
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
q := p
if p.From.Offset != 0 {
q = obj.Appendp(ctxt, p)
q.As = lea
q.From.Type = obj.TYPE_MEM
q.From.Reg = p.To.Reg
q.From.Offset = p.From.Offset
q.To = p.To
p.From.Offset = 0
}
if cmplxdest {
q = obj.Appendp(ctxt, q)
q.As = pAs
q.To = dest
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_CX
}
}
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
//.........这里部分代码省略.........
作者:arnold
项目:g
func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Class = 0
p.To.Class = 0
// Rewrite B/BL to symbol as TYPE_BRANCH.
switch p.As {
case AB,
ABL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
p.To.Type = obj.TYPE_BRANCH
}
}
// Replace TLS register fetches on older ARM procesors.
switch p.As {
// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
case AMRC:
if p.To.Offset&0xffff0fff == 0xee1d0f70 {
// Because the instruction might be rewriten to a BL which returns in R0
// the register must be zero.
if p.To.Offset&0xf000 != 0 {
ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
}
if ctxt.Goarm < 7 {
// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
if progedit_tlsfallback == nil {
progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0)
}
// MOVW LR, R11
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
// BL runtime.read_tls_fallback(SB)
p = obj.Appendp(ctxt, p)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = progedit_tlsfallback
p.To.Offset = 0
// MOVW R11, LR
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGLINK
break
}
}
// Otherwise, MRC/MCR instructions need no further treatment.
p.As = AWORD
}
// Rewrite float constants to values stored in memory.
switch p.As {
case AMOVF:
if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
f32 := float32(p.From.Val.(float64))
i32 := math.Float32bits(f32)
literal := fmt.Sprintf("$f32.%08x", i32)
s := obj.Linklookup(ctxt, literal, 0)
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
case AMOVD:
if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
i64 := math.Float64bits(p.From.Val.(float64))
literal := fmt.Sprintf("$f64.%016x", i64)
s := obj.Linklookup(ctxt, literal, 0)
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
}
}
作者:gmw
项目:g
/*
// instruction scheduling
if(debug['Q'] == 0)
return;
curtext = nil;
q = nil; // p - 1
q1 = firstp; // top of block
o = 0; // count of instructions
for(p = firstp; p != nil; p = p1) {
p1 = p->link;
o++;
if(p->mark & NOSCHED){
if(q1 != p){
sched(q1, q);
}
for(; p != nil; p = p->link){
if(!(p->mark & NOSCHED))
break;
q = p;
}
p1 = p;
q1 = p;
o = 0;
continue;
}
if(p->mark & (LABEL|SYNC)) {
if(q1 != p)
sched(q1, q);
q1 = p;
o = 1;
}
if(p->mark & (BRANCH|SYNC)) {
sched(q1, p);
q1 = p1;
o = 0;
}
if(o >= NSCHED) {
sched(q1, p);
q1 = p1;
o = 0;
}
q = p;
}
*/
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
// MOVD g_stackguard(g), R3
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
if ctxt.Cursym.Cfunc != 0 {
p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
var q *obj.Prog
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
p = obj.Appendp(ctxt, p)
p.As = ACMPU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_REG
p.To.Reg = REGSP
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-framesize, SP, R4
// CMP stackguard, R4
p = obj.Appendp(ctxt, p)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(-framesize)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p = obj.Appendp(ctxt, p)
p.As = ACMPU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
} 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
//.........这里部分代码省略.........
作者:gmw
项目:g
// Rewrite p, if necessary, to access global data via the global offset table.
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
// MOVD [email protected], R12
// ADD $offset, R12
// MOVD R12, CTR
// BL (CTR)
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
} else {
sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
}
offset := p.To.Offset
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
p.From.Sym = sym
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R12
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
p1 := obj.Appendp(ctxt, p)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REG_R12
p2 := obj.Appendp(ctxt, p1)
p2.As = AMOVD
p2.From.Type = obj.TYPE_REG
p2.From.Reg = REG_R12
p2.To.Type = obj.TYPE_REG
p2.To.Reg = REG_CTR
p3 := obj.Appendp(ctxt, p2)
p3.As = obj.ACALL
p3.From.Type = obj.TYPE_REG
p3.From.Reg = REG_R12
p3.To.Type = obj.TYPE_REG
p3.To.Reg = REG_CTR
}
// 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.
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
// MOVD $sym, Rx becomes MOVD [email protected], Rx
// MOVD $sym+<off>, Rx becomes MOVD [email protected], Rx; ADD <off>, Rx
if p.As != AMOVD {
ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
}
if p.To.Type != obj.TYPE_REG {
ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
}
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
q := obj.Appendp(ctxt, p)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
q.To = p.To
p.From.Offset = 0
}
}
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
// MOVx sym, Ry becomes MOVD [email protected], REGTMP; MOVx (REGTMP), Ry
// MOVx Ry, sym becomes MOVD [email protected], REGTMP; MOVx Ry, (REGTMP)
// 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 {
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 == obj.STLSBSS {
return
}
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
p1 := obj.Appendp(ctxt, p)
p2 := obj.Appendp(ctxt, p1)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
p1.From.Sym = source.Sym
//.........这里部分代码省略.........
作者:kluesk
项目:go-akaro
func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
autosize := int32(0)
if ctxt.Symmorestack[0] == nil {
ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
}
ctxt.Cursym = cursym
if cursym.Text == nil || cursym.Text.Link == nil {
return
}
softfloat(ctxt, cursym)
p := cursym.Text
autoffset := int32(p.To.Offset)
if autoffset < 0 {
autoffset = 0
}
cursym.Locals = autoffset
cursym.Args = p.To.U.Argsize
if ctxt.Debugzerostack != 0 {
if autoffset != 0 && p.From3.Offset&obj.NOSPLIT == 0 {
// MOVW $4(R13), R1
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REG_R13
p.From.Offset = 4
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// MOVW $n(R13), R2
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REG_R13
p.From.Offset = 4 + int64(autoffset)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
// MOVW $0, R3
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_CONST
p.From.Offset = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
// L:
// MOVW.nil R3, 0(R1) +4
// CMP R1, R2
// BNE L
pl := obj.Appendp(ctxt, p)
p := pl
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_MEM
p.To.Reg = REG_R1
p.To.Offset = 4
p.Scond |= C_PBIT
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ABNE
p.To.Type = obj.TYPE_BRANCH
p.Pcond = pl
}
}
/*
* find leaf subroutines
* strip NOPs
* expand RET
* expand BECOME pseudo
*/
var q1 *obj.Prog
var q *obj.Prog
for p := cursym.Text; p != nil; p = p.Link {
switch p.As {
case ACASE:
if ctxt.Flag_shared != 0 {
linkcase(p)
}
case obj.ATEXT:
p.Mark |= LEAF
//.........这里部分代码省略.........
作者:kuangchanglan
项目:g
//.........这里部分代码省略.........
var p2 *obj.Prog
var pLast *obj.Prog
var pPre *obj.Prog
var pPreempt *obj.Prog
wasSplit := false
for p := cursym.Text; p != nil; p = p.Link {
pLast = p
switch p.As {
case obj.ATEXT:
autosize = int32(textstksiz)
if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 {
// A leaf function with no locals has no frame.
p.From3.Offset |= obj.NOFRAME
}
if p.From3.Offset&obj.NOFRAME == 0 {
// If there is a stack frame at all, it includes
// space to save the LR.
autosize += int32(ctxt.FixedFrameSize())
}
p.To.Offset = int64(autosize)
q = p
if p.From3.Offset&obj.NOSPLIT == 0 && p.From3.Offset&obj.NOFRAME == 0 {
p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check
pPre = p
wasSplit = true //need post part of split
}
if autosize != 0 {
q = obj.Appendp(ctxt, p)
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
} else if cursym.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.
cursym.Text.Mark |= LEAF
}
if cursym.Text.Mark&LEAF != 0 {
cursym.Leaf = true
break
}
q = obj.Appendp(ctxt, q)
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 = 0
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
// CMP R3, $0
作者:kuangchanglan
项目:g
/*
// instruction scheduling
if(debug['Q'] == 0)
return;
curtext = nil;
q = nil; // p - 1
q1 = firstp; // top of block
o = 0; // count of instructions
for(p = firstp; p != nil; p = p1) {
p1 = p->link;
o++;
if(p->mark & NOSCHED){
if(q1 != p){
sched(q1, q);
}
for(; p != nil; p = p->link){
if(!(p->mark & NOSCHED))
break;
q = p;
}
p1 = p;
q1 = p;
o = 0;
continue;
}
if(p->mark & (LABEL|SYNC)) {
if(q1 != p)
sched(q1, q);
q1 = p;
o = 1;
}
if(p->mark & (BRANCH|SYNC)) {
sched(q1, p);
q1 = p1;
o = 0;
}
if(o >= NSCHED) {
sched(q1, p);
q1 = p1;
o = 0;
}
q = p;
}
*/
func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
var q *obj.Prog
// MOVD g_stackguard(g), R3
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
q = nil
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
//p.To.Type = obj.TYPE_REG
//p.To.Reg = REGSP
// q1: BLT done
p = obj.Appendp(ctxt, p)
//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
//p = obj.Appendp(ctxt, p)
//p.As = ACMPU
//p.From.Type = obj.TYPE_REG
//p.From.Reg = REG_R3
//p.To.Type = obj.TYPE_REG
//p.To.Reg = REGSP
//p = obj.Appendp(ctxt, p)
//p.As = ABGE
//p.To.Type = obj.TYPE_BRANCH
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-framesize, SP, R4
// CMP stackguard, R4
p = obj.Appendp(ctxt, p)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(-framesize)
p.Reg = REGSP
//.........这里部分代码省略.........
作者:kuangchanglan
项目:g
// Rewrite p, if necessary, to access global data via the global offset table.
func rewriteToUseGot(ctxt *obj.Link, 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.
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
// MOVD $sym, Rx becomes MOVD [email protected], Rx
// MOVD $sym+<off>, Rx becomes MOVD [email protected], Rx; ADD <off>, Rx
if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
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 {
q = obj.Appendp(ctxt, p)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
q.To = p.To
p.From.Offset = 0
}
}
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
// MOVD sym, Ry becomes MOVD [email protected], REGTMP; MOVD (REGTMP), Ry
// MOVD Ry, sym becomes MOVD [email protected], REGTMP; MOVD Ry, (REGTMP)
// 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 {
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 == obj.STLSBSS {
return
}
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
p1 := obj.Appendp(ctxt, p)
p2 := obj.Appendp(ctxt, p1)
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 = REGTMP
p2.As = p.As
p2.From = p.From
p2.To = p.To
if p.From.Name == obj.NAME_EXTERN {
p2.From.Reg = REGTMP
p2.From.Name = obj.NAME_NONE
p2.From.Sym = nil
} else if p.To.Name == obj.NAME_EXTERN {
p2.To.Reg = REGTMP
p2.To.Name = obj.NAME_NONE
p2.To.Sym = nil
} else {
return
}
obj.Nopout(p)
}
作者:srei
项目:g
//.........这里部分代码省略.........
q.Link = q1 /* q is non-nop */
q1.Mark |= p.Mark
continue
default:
q = p
continue
}
}
autosize := int32(0)
var o int
var p1 *obj.Prog
var p2 *obj.Prog
for p := cursym.Text; p != nil; p = p.Link {
o = int(p.As)
switch o {
case obj.ATEXT:
autosize = int32(textstksiz + 8)
if (p.Mark&LEAF != 0) && autosize <= 8 {
autosize = 0
} else if autosize&4 != 0 {
autosize += 4
}
p.To.Offset = int64(autosize) - 8
if p.From3.Offset&obj.NOSPLIT == 0 {
p = stacksplit(ctxt, p, autosize) // emit split check
}
q = p
if autosize != 0 {
q = obj.Appendp(ctxt, p)
q.As = AADDV
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(-autosize)
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Spadj = +autosize
} else if cursym.Text.Mark&LEAF == 0 {
if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
if ctxt.Debugvlog != 0 {
fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
ctxt.Bso.Flush()
}
cursym.Text.Mark |= LEAF
}
}
if cursym.Text.Mark&LEAF != 0 {
cursym.Leaf = 1
break
}
q = obj.Appendp(ctxt, q)
q.As = AMOVV
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_REG
q.From.Reg = REGLINK
q.To.Type = obj.TYPE_MEM
q.To.Offset = int64(0)
q.To.Reg = REGSP
作者:kluesk
项目:go-akaro
func progedit(ctxt *obj.Link, p *obj.Prog) {
// Maintain information about code generation mode.
if ctxt.Mode == 0 {
ctxt.Mode = ctxt.Arch.Regsize * 8
}
p.Mode = int8(ctxt.Mode)
switch p.As {
case AMODE:
if p.From.Type == obj.TYPE_CONST || (p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_NONE) {
switch int(p.From.Offset) {
case 16, 32, 64:
ctxt.Mode = int(p.From.Offset)
}
}
obj.Nopout(p)
}
// Thread-local storage references use the TLS pseudo-register.
// As a register, TLS refers to the thread-local storage base, and it
// can only be loaded into another register:
//
// MOVQ TLS, AX
//
// An offset from the thread-local storage base is written off(reg)(TLS*1).
// Semantically it is off(reg), but the (TLS*1) annotation marks this as
// indexing from the loaded TLS base. This emits a relocation so that
// if the linker needs to adjust the offset, it can. For example:
//
// MOVQ TLS, AX
// MOVQ 8(AX)(TLS*1), CX // load m into CX
//
// On systems that support direct access to the TLS memory, this
// pair of instructions can be reduced to a direct TLS memory reference:
//
// MOVQ 8(TLS), CX // load m into CX
//
// The 2-instruction and 1-instruction forms correspond roughly to
// ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
//
// We applies this rewrite on systems that support the 1-instruction form.
// The decision is made using only the operating system (and probably
// the -shared flag, eventually), not the link mode. If some link modes
// on a particular operating system require the 2-instruction form,
// then all builds for that operating system will use the 2-instruction
// form, so that the link mode decision can be delayed to link time.
//
// In this way, all supported systems use identical instructions to
// access TLS, and they are rewritten appropriately first here in
// liblink and then finally using relocations in the linker.
if canuselocaltls(ctxt) {
// Reduce TLS initial exec model to TLS local exec model.
// Sequences like
// MOVQ TLS, BX
// ... off(BX)(TLS*1) ...
// become
// NOP
// ... off(TLS) ...
//
// TODO(rsc): Remove the Hsolaris special case. It exists only to
// guarantee we are producing byte-identical binaries as before this code.
// But it should be unnecessary.
if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != obj.Hsolaris {
obj.Nopout(p)
}
if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
p.From.Reg = REG_TLS
p.From.Scale = 0
p.From.Index = REG_NONE
}
if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
p.To.Reg = REG_TLS
p.To.Scale = 0
p.To.Index = REG_NONE
}
} else {
// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
// The instruction
// MOVQ off(TLS), BX
// becomes the sequence
// MOVQ TLS, BX
// MOVQ off(BX)(TLS*1), BX
// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
q := obj.Appendp(ctxt, p)
q.As = p.As
q.From = p.From
q.From.Type = obj.TYPE_MEM
q.From.Reg = p.To.Reg
q.From.Index = REG_TLS
q.From.Scale = 2 // TODO: use 1
q.To = p.To
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_TLS
p.From.Index = REG_NONE
p.From.Offset = 0
}
}
//.........这里部分代码省略.........
作者:hurkg
项目:g
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
// MOV g_stackguard(g), R1
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
if ctxt.Cursym.Cfunc {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
q := (*obj.Prog)(nil)
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// MOV SP, R2
// CMP stackguard, R2
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// SUB $framesize, SP, R2
// CMP stackguard, R2
p = obj.Appendp(ctxt, p)
p.As = ASUB
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} 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
// BEQ label_of_call_to_morestack
// ADD $StackGuard, SP, R2
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R3
// CMP R3, R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackPreempt
p.Reg = REG_R1
p = obj.Appendp(ctxt, p)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
p = obj.Appendp(ctxt, p)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
//.........这里部分代码省略.........
作者:kluesk
项目:go-akaro
func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Class = 0
p.To.Class = 0
// Rewrite B/BL to symbol as TYPE_BRANCH.
switch p.As {
case AB,
ABL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
p.To.Type = obj.TYPE_BRANCH
}
}
// Replace TLS register fetches on older ARM procesors.
switch p.As {
// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
case AMRC:
if p.To.Offset&0xffff0fff == 0xee1d0f70 {
// Because the instruction might be rewriten to a BL which returns in R0
// the register must be zero.
if p.To.Offset&0xf000 != 0 {
ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
}
if ctxt.Goarm < 7 {
// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
if progedit_tlsfallback == nil {
progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0)
}
// MOVW LR, R11
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
// BL runtime.read_tls_fallback(SB)
p = obj.Appendp(ctxt, p)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = progedit_tlsfallback
p.To.Offset = 0
// MOVW R11, LR
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGLINK
break
}
}
// Otherwise, MRC/MCR instructions need no further treatment.
p.As = AWORD
}
// Rewrite float constants to values stored in memory.
switch p.As {
case AMOVF:
if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
f32 := float32(p.From.U.Dval)
i32 := math.Float32bits(f32)
literal := fmt.Sprintf("$f32.%08x", i32)
s := obj.Linklookup(ctxt, literal, 0)
if s.Type == 0 {
s.Type = obj.SRODATA
obj.Adduint32(ctxt, s, i32)
s.Reachable = 0
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
case AMOVD:
if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
i64 := math.Float64bits(p.From.U.Dval)
literal := fmt.Sprintf("$f64.%016x", i64)
s := obj.Linklookup(ctxt, literal, 0)
if s.Type == 0 {
s.Type = obj.SRODATA
obj.Adduint64(ctxt, s, i64)
s.Reachable = 0
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
//.........这里部分代码省略.........
作者:hurkg
项目:g
//.........这里部分代码省略.........
q1 = ctxt.NewProg()
q1.As = AMOVD
q1.Lineno = p.Lineno
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGLINK
q1.To.Type = obj.TYPE_MEM
q1.Scond = C_XPRE
q1.To.Offset = int64(-aoffset)
q1.To.Reg = REGSP
q1.Link = q.Link
q1.Spadj = aoffset
q.Link = q1
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
// CMP ZR, R1
// BEQ end
// MOV panic_argp(R1), R2
// ADD $(autosize+8), RSP, R3
// CMP R2, R3
// BNE end
// ADD $8, RSP, R4
// MOVD R4, panic_argp(R1)
// end:
// NOP
//
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes.
q = q1
q = obj.Appendp(ctxt, q)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
q = obj.Appendp(ctxt, q)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REGZERO
q.Reg = REG_R1
q = obj.Appendp(ctxt, q)
q.As = ABEQ
q.To.Type = obj.TYPE_BRANCH
q1 = q
q = obj.Appendp(ctxt, q)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R1
q.From.Offset = 0 // Panic.argp
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R2
q = obj.Appendp(ctxt, q)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(ctxt.Autosize) + 8
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
作者:kluesk
项目:go-akaro
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt bool) *obj.Prog {
// MOVW g_stackguard(g), R1
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
if ctxt.Cursym.Cfunc != 0 {
p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REGSP
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// MOVW $-framesize(SP), R2
// CMP stackguard, R2
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REGSP
p.From.Offset = int64(-framesize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} 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 = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
p.Reg = REG_R1
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REGSP
p.From.Offset = obj.StackGuard
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
p = obj.Appendp(ctxt, p)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p.Scond = C_SCOND_NE
p = obj.Appendp(ctxt, p)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R2
p.Scond = C_SCOND_NE
}
// MOVW.LS R14, R3
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.Scond = C_SCOND_LS
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_REG
//.........这里部分代码省略.........