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