github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/cmd/link/scan.go (about) 1 // Copyright 2014 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 // Initial scan of packages making up a program. 6 7 // TODO(rsc): Rename goobj.SymID.Version to StaticID to avoid confusion with the ELF meaning of version. 8 // TODO(rsc): Fix file format so that SBSS/SNOPTRBSS with data is listed as SDATA/SNOPTRDATA. 9 // TODO(rsc): Parallelize scan to overlap file i/o where possible. 10 11 package main 12 13 import ( 14 "cmd/internal/goobj" 15 "os" 16 "sort" 17 "strings" 18 ) 19 20 // scan scans all packages making up the program, starting with package main defined in mainfile. 21 func (p *Prog) scan(mainfile string) { 22 p.initScan() 23 p.scanFile("main", mainfile) 24 if len(p.Missing) > 0 && !p.omitRuntime { 25 p.scanImport("runtime") 26 } 27 28 var missing []string 29 for sym := range p.Missing { 30 if !p.isAuto(sym) { 31 missing = append(missing, sym.String()) 32 } 33 } 34 35 if missing != nil { 36 sort.Strings(missing) 37 for _, sym := range missing { 38 p.errorf("undefined: %s", sym) 39 } 40 } 41 42 // TODO(rsc): Walk import graph to diagnose cycles. 43 } 44 45 // initScan initializes the Prog fields needed by scan. 46 func (p *Prog) initScan() { 47 p.Packages = make(map[string]*Package) 48 p.Syms = make(map[goobj.SymID]*Sym) 49 p.Missing = make(map[goobj.SymID]bool) 50 p.Missing[p.startSym] = true 51 } 52 53 // scanFile reads file to learn about the package with the given import path. 54 func (p *Prog) scanFile(pkgpath string, file string) { 55 pkg := &Package{ 56 File: file, 57 } 58 p.Packages[pkgpath] = pkg 59 60 f, err := os.Open(file) 61 if err != nil { 62 p.errorf("%v", err) 63 return 64 } 65 gp, err := goobj.Parse(f, pkgpath) 66 f.Close() 67 if err != nil { 68 p.errorf("reading %s: %v", file, err) 69 return 70 } 71 72 // TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name. 73 // TODO(rsc): If pkgpath == "main", check that gp.Name == "main". 74 75 pkg.Package = gp 76 77 for _, gs := range gp.Syms { 78 // TODO(rsc): Fix file format instead of this workaround. 79 if gs.Data.Size > 0 { 80 switch gs.Kind { 81 case goobj.SBSS: 82 gs.Kind = goobj.SDATA 83 case goobj.SNOPTRBSS: 84 gs.Kind = goobj.SNOPTRDATA 85 } 86 } 87 88 if gs.Version != 0 { 89 gs.Version += p.MaxVersion 90 } 91 for i := range gs.Reloc { 92 r := &gs.Reloc[i] 93 if r.Sym.Version != 0 { 94 r.Sym.Version += p.MaxVersion 95 } 96 if p.Syms[r.Sym] == nil { 97 p.Missing[r.Sym] = true 98 } 99 } 100 if gs.Func != nil { 101 for i := range gs.Func.FuncData { 102 fdata := &gs.Func.FuncData[i] 103 if fdata.Sym.Name != "" { 104 if fdata.Sym.Version != 0 { 105 fdata.Sym.Version += p.MaxVersion 106 } 107 if p.Syms[fdata.Sym] == nil { 108 p.Missing[fdata.Sym] = true 109 } 110 } 111 } 112 } 113 if old := p.Syms[gs.SymID]; old != nil { 114 // Duplicate definition of symbol. Is it okay? 115 // TODO(rsc): Write test for this code. 116 switch { 117 // If both symbols are BSS (no data), take max of sizes 118 // but otherwise ignore second symbol. 119 case old.Data.Size == 0 && gs.Data.Size == 0: 120 if old.Size < gs.Size { 121 old.Size = gs.Size 122 } 123 continue 124 125 // If one is in BSS and one is not, use the one that is not. 126 case old.Data.Size > 0 && gs.Data.Size == 0: 127 continue 128 case gs.Data.Size > 0 && old.Data.Size == 0: 129 break // install gs as new symbol below 130 131 // If either is marked as DupOK, we can keep either one. 132 // Keep the one that we saw first. 133 case old.DupOK || gs.DupOK: 134 continue 135 136 // Otherwise, there's an actual conflict: 137 default: 138 p.errorf("symbol %s defined in both %s and %s %v %v", gs.SymID, old.Package.File, file, old.Data, gs.Data) 139 continue 140 } 141 } 142 s := &Sym{ 143 Sym: gs, 144 Package: pkg, 145 } 146 p.addSym(s) 147 delete(p.Missing, gs.SymID) 148 149 if s.Data.Size > int64(s.Size) { 150 p.errorf("%s: initialized data larger than symbol (%d > %d)", s, s.Data.Size, s.Size) 151 } 152 } 153 p.MaxVersion += pkg.MaxVersion 154 155 for i, pkgpath := range pkg.Imports { 156 // TODO(rsc): Fix file format to drop .a from recorded import path. 157 pkgpath = strings.TrimSuffix(pkgpath, ".a") 158 pkg.Imports[i] = pkgpath 159 160 p.scanImport(pkgpath) 161 } 162 } 163 164 func (p *Prog) addSym(s *Sym) { 165 pkg := s.Package 166 if pkg == nil { 167 pkg = p.Packages[""] 168 if pkg == nil { 169 pkg = &Package{} 170 p.Packages[""] = pkg 171 } 172 s.Package = pkg 173 } 174 pkg.Syms = append(pkg.Syms, s) 175 p.Syms[s.SymID] = s 176 p.SymOrder = append(p.SymOrder, s) 177 } 178 179 // scanImport finds the object file for the given import path and then scans it. 180 func (p *Prog) scanImport(pkgpath string) { 181 if p.Packages[pkgpath] != nil { 182 return // already loaded 183 } 184 185 // TODO(rsc): Implement correct search to find file. 186 p.scanFile(pkgpath, p.pkgdir+"/"+pkgpath+".a") 187 }