github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/internal/obj/plist.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package obj
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"strings"
    11  )
    12  
    13  type Plist struct {
    14  	Firstpc *Prog
    15  }
    16  
    17  /*
    18   * start a new Prog list.
    19   */
    20  func Linknewplist(ctxt *Link) *Plist {
    21  	pl := new(Plist)
    22  	ctxt.Plists = append(ctxt.Plists, pl)
    23  	return pl
    24  }
    25  
    26  func Flushplist(ctxt *Link) {
    27  	flushplist(ctxt, ctxt.Debugasm == 0)
    28  }
    29  func FlushplistNoFree(ctxt *Link) {
    30  	flushplist(ctxt, false)
    31  }
    32  func flushplist(ctxt *Link, freeProgs bool) {
    33  	// Build list of symbols, and assign instructions to lists.
    34  	// Ignore ctxt->plist boundaries. There are no guarantees there,
    35  	// and the assemblers just use one big list.
    36  	var curtext *LSym
    37  	var etext *Prog
    38  	var text []*LSym
    39  
    40  	for _, pl := range ctxt.Plists {
    41  		var plink *Prog
    42  		for p := pl.Firstpc; p != nil; p = plink {
    43  			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
    44  				fmt.Printf("obj: %v\n", p)
    45  			}
    46  			plink = p.Link
    47  			p.Link = nil
    48  
    49  			switch p.As {
    50  			case AEND:
    51  				continue
    52  
    53  			case ATYPE:
    54  				// Assume each TYPE instruction describes
    55  				// a different local variable or parameter,
    56  				// so no dedup.
    57  				// Using only the TYPE instructions means
    58  				// that we discard location information about local variables
    59  				// in C and assembly functions; that information is inferred
    60  				// from ordinary references, because there are no TYPE
    61  				// instructions there. Without the type information, gdb can't
    62  				// use the locations, so we don't bother to save them.
    63  				// If something else could use them, we could arrange to
    64  				// preserve them.
    65  				if curtext == nil {
    66  					continue
    67  				}
    68  				a := new(Auto)
    69  				a.Asym = p.From.Sym
    70  				a.Aoffset = int32(p.From.Offset)
    71  				a.Name = int16(p.From.Name)
    72  				a.Gotype = p.To.Sym
    73  				a.Link = curtext.Autom
    74  				curtext.Autom = a
    75  				continue
    76  
    77  			case ATEXT:
    78  				s := p.From.Sym
    79  				if s == nil {
    80  					// func _() { }
    81  					curtext = nil
    82  
    83  					continue
    84  				}
    85  
    86  				if s.Text != nil {
    87  					log.Fatalf("duplicate TEXT for %s", s.Name)
    88  				}
    89  				if s.OnList() {
    90  					log.Fatalf("symbol %s listed multiple times", s.Name)
    91  				}
    92  				s.Set(AttrOnList, true)
    93  				text = append(text, s)
    94  				flag := int(p.From3Offset())
    95  				if flag&DUPOK != 0 {
    96  					s.Set(AttrDuplicateOK, true)
    97  				}
    98  				if flag&NOSPLIT != 0 {
    99  					s.Set(AttrNoSplit, true)
   100  				}
   101  				if flag&REFLECTMETHOD != 0 {
   102  					s.Set(AttrReflectMethod, true)
   103  				}
   104  				s.Type = STEXT
   105  				s.Text = p
   106  				etext = p
   107  				curtext = s
   108  				continue
   109  
   110  			case AFUNCDATA:
   111  				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
   112  				if curtext == nil { // func _() {}
   113  					continue
   114  				}
   115  				if p.To.Sym.Name == "go_args_stackmap" {
   116  					if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
   117  						ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
   118  					}
   119  					p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
   120  				}
   121  
   122  			}
   123  
   124  			if curtext == nil {
   125  				etext = nil
   126  				continue
   127  			}
   128  			etext.Link = p
   129  			etext = p
   130  		}
   131  	}
   132  
   133  	// Add reference to Go arguments for C or assembly functions without them.
   134  	for _, s := range text {
   135  		if !strings.HasPrefix(s.Name, "\"\".") {
   136  			continue
   137  		}
   138  		found := false
   139  		var p *Prog
   140  		for p = s.Text; p != nil; p = p.Link {
   141  			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
   142  				found = true
   143  				break
   144  			}
   145  		}
   146  
   147  		if !found {
   148  			p = Appendp(ctxt, s.Text)
   149  			p.As = AFUNCDATA
   150  			p.From.Type = TYPE_CONST
   151  			p.From.Offset = FUNCDATA_ArgsPointerMaps
   152  			p.To.Type = TYPE_MEM
   153  			p.To.Name = NAME_EXTERN
   154  			p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
   155  		}
   156  	}
   157  
   158  	// Turn functions into machine code images.
   159  	for _, s := range text {
   160  		mkfwd(s)
   161  		linkpatch(ctxt, s)
   162  		if ctxt.Flag_optimize {
   163  			ctxt.Arch.Follow(ctxt, s)
   164  		}
   165  		ctxt.Arch.Preprocess(ctxt, s)
   166  		ctxt.Arch.Assemble(ctxt, s)
   167  		fieldtrack(ctxt, s)
   168  		linkpcln(ctxt, s)
   169  		if freeProgs {
   170  			s.Text = nil
   171  		}
   172  	}
   173  
   174  	// Add to running list in ctxt.
   175  	ctxt.Text = append(ctxt.Text, text...)
   176  	ctxt.Data = append(ctxt.Data, gendwarf(ctxt, text)...)
   177  	ctxt.Plists = nil
   178  	ctxt.Curp = nil
   179  	if freeProgs {
   180  		ctxt.freeProgs()
   181  	}
   182  }
   183  
   184  func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
   185  	if s.SeenGlobl() {
   186  		fmt.Printf("duplicate %v\n", s)
   187  	}
   188  	s.Set(AttrSeenGlobl, true)
   189  	if s.OnList() {
   190  		log.Fatalf("symbol %s listed multiple times", s.Name)
   191  	}
   192  	s.Set(AttrOnList, true)
   193  	ctxt.Data = append(ctxt.Data, s)
   194  	s.Size = size
   195  	if s.Type == 0 || s.Type == SXREF {
   196  		s.Type = SBSS
   197  	}
   198  	if flag&DUPOK != 0 {
   199  		s.Set(AttrDuplicateOK, true)
   200  	}
   201  	if flag&RODATA != 0 {
   202  		s.Type = SRODATA
   203  	} else if flag&NOPTR != 0 {
   204  		s.Type = SNOPTRBSS
   205  	} else if flag&TLSBSS != 0 {
   206  		s.Type = STLSBSS
   207  	}
   208  }