Home | History | Annotate | Download | only in obj
      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 }
    209