...

Source file src/cmd/internal/obj/pass.go

     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	// 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.Pcond {
    40			if q.As != AJMP || q.Pcond == 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		}
   116	
   117		ctxt.Diag("invalid encoding for argument %v", p)
   118	}
   119	
   120	func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
   121		for p := sym.Func.Text; p != nil; p = p.Link {
   122			checkaddr(ctxt, p, &p.From)
   123			if p.GetFrom3() != nil {
   124				checkaddr(ctxt, p, p.GetFrom3())
   125			}
   126			checkaddr(ctxt, p, &p.To)
   127	
   128			if ctxt.Arch.Progedit != nil {
   129				ctxt.Arch.Progedit(ctxt, p, newprog)
   130			}
   131			if p.To.Type != TYPE_BRANCH {
   132				continue
   133			}
   134			if p.To.Val != nil {
   135				// TODO: Remove To.Val.(*Prog) in favor of p->pcond.
   136				p.Pcond = p.To.Val.(*Prog)
   137				continue
   138			}
   139	
   140			if p.To.Sym != nil {
   141				continue
   142			}
   143			q := sym.Func.Text
   144			for q != nil && p.To.Offset != q.Pc {
   145				if q.Forwd != nil && p.To.Offset >= q.Forwd.Pc {
   146					q = q.Forwd
   147				} else {
   148					q = q.Link
   149				}
   150			}
   151	
   152			if q == nil {
   153				name := "<nil>"
   154				if p.To.Sym != nil {
   155					name = p.To.Sym.Name
   156				}
   157				ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(p.To.Offset), p, name)
   158				p.To.Type = TYPE_NONE
   159			}
   160	
   161			p.To.Val = q
   162			p.Pcond = q
   163		}
   164	
   165		if !ctxt.Flag_optimize {
   166			return
   167		}
   168	
   169		// Collapse series of jumps to jumps.
   170		for p := sym.Func.Text; p != nil; p = p.Link {
   171			if p.Pcond == nil {
   172				continue
   173			}
   174			p.Pcond = brloop(p.Pcond)
   175			if p.Pcond != nil && p.To.Type == TYPE_BRANCH {
   176				p.To.Offset = p.Pcond.Pc
   177			}
   178		}
   179	}
   180	

View as plain text