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