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