github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/internal/obj/pass.go (about) 1 // Inferno utils/6l/pass.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/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 func brloop(ctxt *Link, p *Prog) *Prog { 36 var q *Prog 37 38 c := 0 39 for q = p; q != nil; q = q.Pcond { 40 if q.As != AJMP || q.Pcond == nil { 41 break 42 } 43 c++ 44 if c >= 5000 { 45 return nil 46 } 47 } 48 49 return q 50 } 51 52 func checkaddr(ctxt *Link, p *Prog, a *Addr) { 53 // Check expected encoding, especially TYPE_CONST vs TYPE_ADDR. 54 switch a.Type { 55 case TYPE_NONE: 56 return 57 58 case TYPE_BRANCH: 59 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 { 60 break 61 } 62 return 63 64 case TYPE_TEXTSIZE: 65 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 { 66 break 67 } 68 return 69 70 //if(a->u.bits != 0) 71 // break; 72 case TYPE_MEM: 73 return 74 75 // TODO(rsc): After fixing SHRQ, check a->index != 0 too. 76 case TYPE_CONST: 77 if a.Name != 0 || a.Sym != nil || a.Reg != 0 { 78 ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p) 79 return 80 } 81 82 if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil { 83 break 84 } 85 return 86 87 case TYPE_FCONST, TYPE_SCONST: 88 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil { 89 break 90 } 91 return 92 93 // TODO(rsc): After fixing PINSRQ, check a->offset != 0 too. 94 // TODO(rsc): After fixing SHRQ, check a->index != 0 too. 95 case TYPE_REG: 96 if a.Scale != 0 || a.Name != 0 || a.Sym != nil { 97 break 98 } 99 return 100 101 case TYPE_ADDR: 102 if a.Val != nil { 103 break 104 } 105 if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil { 106 ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p) 107 } 108 return 109 110 case TYPE_SHIFT: 111 if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil { 112 break 113 } 114 return 115 116 case TYPE_REGREG: 117 if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil { 118 break 119 } 120 return 121 122 case TYPE_REGREG2: 123 return 124 125 case TYPE_REGLIST: 126 return 127 128 // Expect sym and name to be set, nothing else. 129 // Technically more is allowed, but this is only used for *name(SB). 130 case TYPE_INDIR: 131 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil { 132 break 133 } 134 return 135 } 136 137 ctxt.Diag("invalid encoding for argument %v", p) 138 } 139 140 func linkpatch(ctxt *Link, sym *LSym) { 141 var c int32 142 var name string 143 var q *Prog 144 145 ctxt.Cursym = sym 146 147 for p := sym.Text; p != nil; p = p.Link { 148 checkaddr(ctxt, p, &p.From) 149 if p.From3 != nil { 150 checkaddr(ctxt, p, p.From3) 151 } 152 checkaddr(ctxt, p, &p.To) 153 154 if ctxt.Arch.Progedit != nil { 155 ctxt.Arch.Progedit(ctxt, p) 156 } 157 if p.To.Type != TYPE_BRANCH { 158 continue 159 } 160 if p.To.Val != nil { 161 // TODO: Remove To.Val.(*Prog) in favor of p->pcond. 162 p.Pcond = p.To.Val.(*Prog) 163 continue 164 } 165 166 if p.To.Sym != nil { 167 continue 168 } 169 c = int32(p.To.Offset) 170 for q = sym.Text; q != nil; { 171 if int64(c) == q.Pc { 172 break 173 } 174 if q.Forwd != nil && int64(c) >= q.Forwd.Pc { 175 q = q.Forwd 176 } else { 177 q = q.Link 178 } 179 } 180 181 if q == nil { 182 name = "<nil>" 183 if p.To.Sym != nil { 184 name = p.To.Sym.Name 185 } 186 ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(c), p, name) 187 p.To.Type = TYPE_NONE 188 } 189 190 p.To.Val = q 191 p.Pcond = q 192 } 193 194 if ctxt.Flag_optimize { 195 for p := sym.Text; p != nil; p = p.Link { 196 if p.Pcond != nil { 197 p.Pcond = brloop(ctxt, p.Pcond) 198 if p.Pcond != nil { 199 if p.To.Type == TYPE_BRANCH { 200 p.To.Offset = p.Pcond.Pc 201 } 202 } 203 } 204 } 205 } 206 }