github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/obj/pass.go (about) 1 // Inferno utils/6l/pass.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package obj 32 33 // Code and data passes. 34 35 // brloop returns the ultimate destination of the series of unconditional jumps beginning at p. 36 // In the case of an infinite loop, brloop returns nil. 37 func brloop(p *Prog) *Prog { 38 c := 0 39 for q := p; q != nil; q = q.To.Target() { 40 if q.As != AJMP || q.To.Target() == nil { 41 return q 42 } 43 c++ 44 if c >= 5000 { 45 // infinite loop 46 return nil 47 } 48 } 49 panic("unreachable") 50 } 51 52 // checkaddr checks that a has an expected encoding, especially TYPE_CONST vs TYPE_ADDR. 53 func checkaddr(ctxt *Link, p *Prog, a *Addr) { 54 switch a.Type { 55 case TYPE_NONE, TYPE_REGREG2, TYPE_REGLIST: 56 return 57 58 case TYPE_BRANCH, TYPE_TEXTSIZE: 59 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 { 60 break 61 } 62 return 63 64 case TYPE_MEM: 65 return 66 67 case TYPE_CONST: 68 // TODO(rsc): After fixing SHRQ, check a.Index != 0 too. 69 if a.Name != 0 || a.Sym != nil || a.Reg != 0 { 70 ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p) 71 return 72 } 73 74 if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil { 75 break 76 } 77 return 78 79 case TYPE_FCONST, TYPE_SCONST: 80 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil { 81 break 82 } 83 return 84 85 case TYPE_REG: 86 // TODO(rsc): After fixing PINSRQ, check a.Offset != 0 too. 87 // TODO(rsc): After fixing SHRQ, check a.Index != 0 too. 88 if a.Scale != 0 || a.Name != 0 || a.Sym != nil { 89 break 90 } 91 return 92 93 case TYPE_ADDR: 94 if a.Val != nil { 95 break 96 } 97 if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil { 98 ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p) 99 } 100 return 101 102 case TYPE_SHIFT, TYPE_REGREG: 103 if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil { 104 break 105 } 106 return 107 108 case TYPE_INDIR: 109 // Expect sym and name to be set, nothing else. 110 // Technically more is allowed, but this is only used for *name(SB). 111 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil { 112 break 113 } 114 return 115 case TYPE_SPECIAL: 116 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Class != 0 || a.Sym != nil { 117 break 118 } 119 return 120 } 121 122 ctxt.Diag("invalid encoding for argument %v", p) 123 } 124 125 func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) { 126 for p := sym.Func().Text; p != nil; p = p.Link { 127 checkaddr(ctxt, p, &p.From) 128 for _, v := range p.RestArgs { 129 checkaddr(ctxt, p, &v.Addr) 130 } 131 checkaddr(ctxt, p, &p.To) 132 133 if ctxt.Arch.Progedit != nil { 134 ctxt.Arch.Progedit(ctxt, p, newprog) 135 } 136 if p.To.Type != TYPE_BRANCH { 137 continue 138 } 139 if p.To.Val != nil { 140 continue 141 } 142 143 if p.To.Sym != nil { 144 continue 145 } 146 q := sym.Func().Text 147 for q != nil && p.To.Offset != q.Pc { 148 if q.Forwd != nil && p.To.Offset >= q.Forwd.Pc { 149 q = q.Forwd 150 } else { 151 q = q.Link 152 } 153 } 154 155 if q == nil { 156 name := "<nil>" 157 if p.To.Sym != nil { 158 name = p.To.Sym.Name 159 } 160 ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(p.To.Offset), p, name) 161 p.To.Type = TYPE_NONE 162 } 163 164 p.To.SetTarget(q) 165 } 166 167 if !ctxt.Flag_optimize { 168 return 169 } 170 171 // Collapse series of jumps to jumps. 172 for p := sym.Func().Text; p != nil; p = p.Link { 173 if p.To.Target() == nil { 174 continue 175 } 176 p.To.SetTarget(brloop(p.To.Target())) 177 if p.To.Target() != nil && p.To.Type == TYPE_BRANCH { 178 p.To.Offset = p.To.Target().Pc 179 } 180 } 181 }