github.com/bir3/gocompiler@v0.9.2202/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 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 9 "github.com/bir3/gocompiler/src/cmd/internal/src" 10 "fmt" 11 "github.com/bir3/gocompiler/src/internal/abi" 12 "strings" 13 ) 14 15 type Plist struct { 16 Firstpc *Prog 17 Curfn Func 18 } 19 20 // ProgAlloc is a function that allocates Progs. 21 // It is used to provide access to cached/bulk-allocated Progs to the assemblers. 22 type ProgAlloc func() *Prog 23 24 func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc) { 25 if ctxt.Pkgpath == "" { 26 panic("Flushplist called without Pkgpath") 27 } 28 29 // Build list of symbols, and assign instructions to lists. 30 var curtext *LSym 31 var etext *Prog 32 var text []*LSym 33 34 var plink *Prog 35 for p := plist.Firstpc; p != nil; p = plink { 36 if ctxt.Debugasm > 0 && ctxt.Debugvlog { 37 fmt.Printf("obj: %v\n", p) 38 } 39 plink = p.Link 40 p.Link = nil 41 42 switch p.As { 43 case AEND: 44 continue 45 46 case ATEXT: 47 s := p.From.Sym 48 if s == nil { 49 // func _() { } 50 curtext = nil 51 continue 52 } 53 text = append(text, s) 54 etext = p 55 curtext = s 56 continue 57 58 case AFUNCDATA: 59 // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information. 60 if curtext == nil { // func _() {} 61 continue 62 } 63 switch p.To.Sym.Name { 64 case "go_args_stackmap": 65 if p.From.Type != TYPE_CONST || p.From.Offset != abi.FUNCDATA_ArgsPointerMaps { 66 ctxt.Diag("%s: FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps", p.Pos) 67 } 68 p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap") 69 case "no_pointers_stackmap": 70 if p.From.Type != TYPE_CONST || p.From.Offset != abi.FUNCDATA_LocalsPointerMaps { 71 ctxt.Diag("%s: FUNCDATA use of no_pointers_stackmap(SB) without FUNCDATA_LocalsPointerMaps", p.Pos) 72 } 73 // funcdata for functions with no local variables in frame. 74 // Define two zero-length bitmaps, because the same index is used 75 // for the local variables as for the argument frame, and assembly 76 // frames have two argument bitmaps, one without results and one with results. 77 // Write []uint32{2, 0}. 78 b := make([]byte, 8) 79 ctxt.Arch.ByteOrder.PutUint32(b, 2) 80 s := ctxt.GCLocalsSym(b) 81 if !s.OnList() { 82 ctxt.Globl(s, int64(len(s.P)), int(RODATA|DUPOK)) 83 } 84 p.To.Sym = s 85 } 86 87 } 88 89 if curtext == nil { 90 etext = nil 91 continue 92 } 93 etext.Link = p 94 etext = p 95 } 96 97 if newprog == nil { 98 newprog = ctxt.NewProg 99 } 100 101 // Add reference to Go arguments for assembly functions without them. 102 if ctxt.IsAsm { 103 pkgPrefix := objabi.PathToPrefix(ctxt.Pkgpath) + "." 104 for _, s := range text { 105 if !strings.HasPrefix(s.Name, pkgPrefix) { 106 continue 107 } 108 // The current args_stackmap generation in the compiler assumes 109 // that the function in question is ABI0, so avoid introducing 110 // an args_stackmap reference if the func is not ABI0 (better to 111 // have no stackmap than an incorrect/lying stackmap). 112 if s.ABI() != ABI0 { 113 continue 114 } 115 // runtime.addmoduledata is a host ABI function, so it doesn't 116 // need FUNCDATA anyway. Moreover, cmd/link has special logic 117 // for linking it in eccentric build modes, which breaks if it 118 // has FUNCDATA references (e.g., cmd/cgo/internal/testplugin). 119 // 120 // TODO(cherryyz): Fix cmd/link's handling of plugins (see 121 // discussion on CL 523355). 122 if s.Name == "runtime.addmoduledata" { 123 continue 124 } 125 foundArgMap, foundArgInfo := false, false 126 for p := s.Func().Text; p != nil; p = p.Link { 127 if p.As == AFUNCDATA && p.From.Type == TYPE_CONST { 128 if p.From.Offset == abi.FUNCDATA_ArgsPointerMaps { 129 foundArgMap = true 130 } 131 if p.From.Offset == abi.FUNCDATA_ArgInfo { 132 foundArgInfo = true 133 } 134 if foundArgMap && foundArgInfo { 135 break 136 } 137 } 138 } 139 if !foundArgMap { 140 p := Appendp(s.Func().Text, newprog) 141 p.As = AFUNCDATA 142 p.From.Type = TYPE_CONST 143 p.From.Offset = abi.FUNCDATA_ArgsPointerMaps 144 p.To.Type = TYPE_MEM 145 p.To.Name = NAME_EXTERN 146 p.To.Sym = ctxt.LookupDerived(s, s.Name+".args_stackmap") 147 } 148 if !foundArgInfo { 149 p := Appendp(s.Func().Text, newprog) 150 p.As = AFUNCDATA 151 p.From.Type = TYPE_CONST 152 p.From.Offset = abi.FUNCDATA_ArgInfo 153 p.To.Type = TYPE_MEM 154 p.To.Name = NAME_EXTERN 155 p.To.Sym = ctxt.LookupDerived(s, fmt.Sprintf("%s.arginfo%d", s.Name, s.ABI())) 156 } 157 } 158 } 159 160 // Turn functions into machine code images. 161 for _, s := range text { 162 mkfwd(s) 163 if ctxt.Arch.ErrorCheck != nil { 164 ctxt.Arch.ErrorCheck(ctxt, s) 165 } 166 linkpatch(ctxt, s, newprog) 167 ctxt.Arch.Preprocess(ctxt, s, newprog) 168 ctxt.Arch.Assemble(ctxt, s, newprog) 169 if ctxt.Errors > 0 { 170 continue 171 } 172 linkpcln(ctxt, s) 173 ctxt.populateDWARF(plist.Curfn, s) 174 if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.SEH != nil { 175 s.Func().sehUnwindInfoSym = ctxt.Arch.SEH(ctxt, s) 176 } 177 } 178 } 179 180 func (ctxt *Link) InitTextSym(s *LSym, flag int, start src.XPos) { 181 if s == nil { 182 // func _() { } 183 return 184 } 185 if s.Func() != nil { 186 ctxt.Diag("%s: symbol %s redeclared\n\t%s: other declaration of symbol %s", ctxt.PosTable.Pos(start), s.Name, ctxt.PosTable.Pos(s.Func().Text.Pos), s.Name) 187 return 188 } 189 s.NewFuncInfo() 190 if s.OnList() { 191 ctxt.Diag("%s: symbol %s redeclared", ctxt.PosTable.Pos(start), s.Name) 192 return 193 } 194 if strings.HasPrefix(s.Name, `"".`) { 195 ctxt.Diag("%s: unqualified symbol name: %s", ctxt.PosTable.Pos(start), s.Name) 196 } 197 198 // startLine should be the same line number that would be displayed via 199 // pcln, etc for the declaration (i.e., relative line number, as 200 // adjusted by //line). 201 _, startLine := ctxt.getFileIndexAndLine(start) 202 203 s.Func().FuncID = objabi.GetFuncID(s.Name, flag&WRAPPER != 0 || flag&ABIWRAPPER != 0) 204 s.Func().FuncFlag = ctxt.toFuncFlag(flag) 205 s.Func().StartLine = startLine 206 s.Set(AttrOnList, true) 207 s.Set(AttrDuplicateOK, flag&DUPOK != 0) 208 s.Set(AttrNoSplit, flag&NOSPLIT != 0) 209 s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0) 210 s.Set(AttrWrapper, flag&WRAPPER != 0) 211 s.Set(AttrABIWrapper, flag&ABIWRAPPER != 0) 212 s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0) 213 s.Set(AttrNoFrame, flag&NOFRAME != 0) 214 s.Set(AttrPkgInit, flag&PKGINIT != 0) 215 s.Type = objabi.STEXT 216 ctxt.Text = append(ctxt.Text, s) 217 218 // Set up DWARF entries for s 219 ctxt.dwarfSym(s) 220 } 221 222 func (ctxt *Link) toFuncFlag(flag int) abi.FuncFlag { 223 var out abi.FuncFlag 224 if flag&TOPFRAME != 0 { 225 out |= abi.FuncFlagTopFrame 226 } 227 if ctxt.IsAsm { 228 out |= abi.FuncFlagAsm 229 } 230 return out 231 } 232 233 func (ctxt *Link) Globl(s *LSym, size int64, flag int) { 234 ctxt.GloblPos(s, size, flag, src.NoXPos) 235 } 236 func (ctxt *Link) GloblPos(s *LSym, size int64, flag int, pos src.XPos) { 237 if s.OnList() { 238 // TODO: print where the first declaration was. 239 ctxt.Diag("%s: symbol %s redeclared", ctxt.PosTable.Pos(pos), s.Name) 240 } 241 s.Set(AttrOnList, true) 242 ctxt.Data = append(ctxt.Data, s) 243 s.Size = size 244 if s.Type == 0 { 245 s.Type = objabi.SBSS 246 } 247 if flag&DUPOK != 0 { 248 s.Set(AttrDuplicateOK, true) 249 } 250 if flag&RODATA != 0 { 251 s.Type = objabi.SRODATA 252 } else if flag&NOPTR != 0 { 253 if s.Type == objabi.SDATA { 254 s.Type = objabi.SNOPTRDATA 255 } else { 256 s.Type = objabi.SNOPTRBSS 257 } 258 } else if flag&TLSBSS != 0 { 259 s.Type = objabi.STLSBSS 260 } 261 } 262 263 // EmitEntryLiveness generates PCDATA Progs after p to switch to the 264 // liveness map active at the entry of function s. It returns the last 265 // Prog generated. 266 func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog { 267 pcdata := ctxt.EmitEntryStackMap(s, p, newprog) 268 pcdata = ctxt.EmitEntryUnsafePoint(s, pcdata, newprog) 269 return pcdata 270 } 271 272 // Similar to EmitEntryLiveness, but just emit stack map. 273 func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog { 274 pcdata := Appendp(p, newprog) 275 pcdata.Pos = s.Func().Text.Pos 276 pcdata.As = APCDATA 277 pcdata.From.Type = TYPE_CONST 278 pcdata.From.Offset = abi.PCDATA_StackMapIndex 279 pcdata.To.Type = TYPE_CONST 280 pcdata.To.Offset = -1 // pcdata starts at -1 at function entry 281 282 return pcdata 283 } 284 285 // Similar to EmitEntryLiveness, but just emit unsafe point map. 286 func (ctxt *Link) EmitEntryUnsafePoint(s *LSym, p *Prog, newprog ProgAlloc) *Prog { 287 pcdata := Appendp(p, newprog) 288 pcdata.Pos = s.Func().Text.Pos 289 pcdata.As = APCDATA 290 pcdata.From.Type = TYPE_CONST 291 pcdata.From.Offset = abi.PCDATA_UnsafePoint 292 pcdata.To.Type = TYPE_CONST 293 pcdata.To.Offset = -1 294 295 return pcdata 296 } 297 298 // StartUnsafePoint generates PCDATA Progs after p to mark the 299 // beginning of an unsafe point. The unsafe point starts immediately 300 // after p. 301 // It returns the last Prog generated. 302 func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog { 303 pcdata := Appendp(p, newprog) 304 pcdata.As = APCDATA 305 pcdata.From.Type = TYPE_CONST 306 pcdata.From.Offset = abi.PCDATA_UnsafePoint 307 pcdata.To.Type = TYPE_CONST 308 pcdata.To.Offset = abi.UnsafePointUnsafe 309 310 return pcdata 311 } 312 313 // EndUnsafePoint generates PCDATA Progs after p to mark the end of an 314 // unsafe point, restoring the register map index to oldval. 315 // The unsafe point ends right after p. 316 // It returns the last Prog generated. 317 func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog { 318 pcdata := Appendp(p, newprog) 319 pcdata.As = APCDATA 320 pcdata.From.Type = TYPE_CONST 321 pcdata.From.Offset = abi.PCDATA_UnsafePoint 322 pcdata.To.Type = TYPE_CONST 323 pcdata.To.Offset = oldval 324 325 return pcdata 326 } 327 328 // MarkUnsafePoints inserts PCDATAs to mark nonpreemptible and restartable 329 // instruction sequences, based on isUnsafePoint and isRestartable predicate. 330 // p0 is the start of the instruction stream. 331 // isUnsafePoint(p) returns true if p is not safe for async preemption. 332 // isRestartable(p) returns true if we can restart at the start of p (this Prog) 333 // upon async preemption. (Currently multi-Prog restartable sequence is not 334 // supported.) 335 // isRestartable can be nil. In this case it is treated as always returning false. 336 // If isUnsafePoint(p) and isRestartable(p) are both true, it is treated as 337 // an unsafe point. 338 func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, isRestartable func(*Prog) bool) { 339 if isRestartable == nil { 340 // Default implementation: nothing is restartable. 341 isRestartable = func(*Prog) bool { return false } 342 } 343 prev := p0 344 prevPcdata := int64(-1) // entry PC data value 345 prevRestart := int64(0) 346 for p := prev.Link; p != nil; p, prev = p.Link, p { 347 if p.As == APCDATA && p.From.Offset == abi.PCDATA_UnsafePoint { 348 prevPcdata = p.To.Offset 349 continue 350 } 351 if prevPcdata == abi.UnsafePointUnsafe { 352 continue // already unsafe 353 } 354 if isUnsafePoint(p) { 355 q := ctxt.StartUnsafePoint(prev, newprog) 356 q.Pc = p.Pc 357 q.Link = p 358 // Advance to the end of unsafe point. 359 for p.Link != nil && isUnsafePoint(p.Link) { 360 p = p.Link 361 } 362 if p.Link == nil { 363 break // Reached the end, don't bother marking the end 364 } 365 p = ctxt.EndUnsafePoint(p, newprog, prevPcdata) 366 p.Pc = p.Link.Pc 367 continue 368 } 369 if isRestartable(p) { 370 val := int64(abi.UnsafePointRestart1) 371 if val == prevRestart { 372 val = abi.UnsafePointRestart2 373 } 374 prevRestart = val 375 q := Appendp(prev, newprog) 376 q.As = APCDATA 377 q.From.Type = TYPE_CONST 378 q.From.Offset = abi.PCDATA_UnsafePoint 379 q.To.Type = TYPE_CONST 380 q.To.Offset = val 381 q.Pc = p.Pc 382 q.Link = p 383 384 if p.Link == nil { 385 break // Reached the end, don't bother marking the end 386 } 387 if isRestartable(p.Link) { 388 // Next Prog is also restartable. No need to mark the end 389 // of this sequence. We'll just go ahead mark the next one. 390 continue 391 } 392 p = Appendp(p, newprog) 393 p.As = APCDATA 394 p.From.Type = TYPE_CONST 395 p.From.Offset = abi.PCDATA_UnsafePoint 396 p.To.Type = TYPE_CONST 397 p.To.Offset = prevPcdata 398 p.Pc = p.Link.Pc 399 } 400 } 401 }