Skip to content
Snippets Groups Projects
loader.go 37.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		// symbol exists
    		if int(i) < len(l.Syms) && l.Syms[i] != nil {
    
    		}
    		if l.IsExternal(i) {
    			panic("Can't load an external symbol.")
    		}
    
    		return l.loadSymbol(name, version)
    
    	s := l.allocSym(name, version)
    
    // Create creates a symbol with the specified name, returning a
    // sym.Symbol object for it. This method is intended for static/hidden
    // symbols discovered while loading host objects. We can see more than
    // one instance of a given static symbol with the same name/version,
    // so we can't add them to the lookup tables "as is". Instead assign
    // them fictitious (unique) versions, starting at -1 and decreasing by
    // one for each newly created symbol, and record them in the
    // extStaticSyms hash.
    
    func (l *Loader) Create(name string) *sym.Symbol {
    
    	i := l.max + 1
    	l.max++
    	if l.extStart == 0 {
    		l.extStart = i
    	}
    
    
    	// Assign a new unique negative version -- this is to mark the
    	// symbol so that it can be skipped when ExtractSymbols is adding
    	// ext syms to the sym.Symbols hash.
    	l.anonVersion--
    	ver := l.anonVersion
    	l.extSyms = append(l.extSyms, nameVer{name, ver})
    
    	s := l.allocSym(name, ver)
    
    	l.extStaticSyms[nameVer{name, ver}] = i
    
    
    func loadObjFull(l *Loader, r *oReader) {
    	lib := r.unit.Lib
    
    
    	resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
    
    	funcs := []funcInfoSym{}
    	fdsyms := []*sym.Symbol{}
    	var funcAllocCounts funcAllocInfo
    
    	for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
    		osym := goobj2.Sym{}
    		osym.Read(r.Reader, r.SymOff(i))
    		name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
    
    		if name == "" {
    			continue
    		}
    		ver := abiToVer(osym.ABI, r.version)
    
    			if dupsym := l.symsByName[ver][name]; dupsym != istart+Sym(i) {
    
    				if l.Reachable.Has(dupsym) {
    					// A dupok symbol is resolved to another package. We still need
    					// to record its presence in the current package, as the trampoline
    					// pass expects packages are laid out in dependency order.
    					s := l.Syms[dupsym]
    					if s.Type == sym.STEXT {
    						lib.DupTextSyms = append(lib.DupTextSyms, s)
    					}
    
    		if s.Name != name { // Sanity check. We can remove it in the final version.
    			fmt.Println("name mismatch:", lib, i, s.Name, name)
    			panic("name mismatch")
    		}
    
    
    		local := osym.Local()
    		makeTypelink := osym.Typelink()
    
    		size := osym.Siz
    
    		// Symbol data
    		s.P = r.Data(i)
    		s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
    
    		batch := l.relocBatch
    		s.R = batch[:relocs.Count:relocs.Count]
    		l.relocBatch = batch[relocs.Count:]
    
    			if rt == objabi.R_METHODOFF {
    				if l.Reachable.Has(rs) {
    					rt = objabi.R_ADDROFF
    				} else {
    					sz = 0
    					rs = 0
    				}
    			}
    			if rt == objabi.R_WEAKADDROFF && !l.Reachable.Has(rs) {
    				rs = 0
    				sz = 0
    			}
    
    			if rs != 0 && l.Syms[rs] != nil && l.Syms[rs].Type == sym.SABIALIAS {
    
    				rsrelocs := l.Relocs(rs)
    				rs = rsrelocs.At(0).Sym
    
    				Sym:  l.Syms[rs],
    
    		naux := r.NAux(i)
    		for j := 0; j < naux; j++ {
    			a := goobj2.Aux{}
    
    			switch a.Type {
    			case goobj2.AuxGotype:
    				typ := resolveSymRef(a.Sym)
    				if typ != nil {
    					s.Gotype = typ
    				}
    
    				fdsyms = append(fdsyms, resolveSymRef(a.Sym))
    
    			case goobj2.AuxFuncInfo:
    				if a.Sym.PkgIdx != goobj2.PkgIdxSelf {
    					panic("funcinfo symbol not defined in current package")
    				}
    				isym = int(a.Sym.SymIdx)
    
    			case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
    				// ignored for now
    
    		s.File = r.pkgprefix[:len(r.pkgprefix)-1]
    
    		if dupok {
    			s.Attr |= sym.AttrDuplicateOK
    		}
    		if s.Size < int64(size) {
    			s.Size = int64(size)
    		}
    		s.Attr.Set(sym.AttrLocal, local)
    		s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
    
    
    		if s.Type == sym.SDWARFINFO {
    			// For DWARF symbols, replace `"".` to actual package prefix
    			// in the symbol content.
    			// TODO: maybe we should do this in the compiler and get rid
    			// of this.
    			patchDWARFName(s, r)
    		}
    
    
    		if s.Type != sym.STEXT {
    			continue
    		}
    
    		if isym == -1 {
    			continue
    		}
    
    
    		// Record function sym and associated info for additional
    		// processing in the loop below.
    		fwis := funcInfoSym{s: s, isym: isym, osym: osym}
    		funcs = append(funcs, fwis)
    
    		// Read the goobj2.FuncInfo for this text symbol so that we can
    		// collect allocation counts. We'll read it again in the loop
    		// below.
    		b := r.Data(isym)
    		info := goobj2.FuncInfo{}
    		info.Read(b)
    		funcAllocCounts.symPtr += uint32(len(info.File))
    		funcAllocCounts.pcData += uint32(len(info.Pcdata))
    		funcAllocCounts.inlCall += uint32(len(info.InlTree))
    		funcAllocCounts.fdOff += uint32(len(info.Funcdataoff))
    	}
    
    	// At this point we can do batch allocation of the sym.FuncInfo's,
    	// along with the slices of sub-objects they use.
    	fiBatch := make([]sym.FuncInfo, len(funcs))
    	inlCallBatch := make([]sym.InlinedCall, funcAllocCounts.inlCall)
    	symPtrBatch := make([]*sym.Symbol, funcAllocCounts.symPtr)
    	pcDataBatch := make([]sym.Pcdata, funcAllocCounts.pcData)
    	fdOffBatch := make([]int64, funcAllocCounts.fdOff)
    
    	// Populate FuncInfo contents for func symbols.
    	for fi := 0; fi < len(funcs); fi++ {
    		s := funcs[fi].s
    		isym := funcs[fi].isym
    		osym := funcs[fi].osym
    
    		s.FuncInfo = &fiBatch[0]
    		fiBatch = fiBatch[1:]
    
    
    		info := goobj2.FuncInfo{}
    		info.Read(b)
    
    		if info.NoSplit != 0 {
    			s.Attr |= sym.AttrNoSplit
    		}
    
    			s.Attr |= sym.AttrReflectMethod
    		}
    
    		if r.Flags()&goobj2.ObjFlagShared != 0 {
    
    			s.Attr |= sym.AttrShared
    		}
    
    
    		if len(info.Funcdataoff) != 0 {
    			nfd := len(info.Funcdataoff)
    			pc.Funcdata = fdsyms[:nfd:nfd]
    			fdsyms = fdsyms[nfd:]
    
    
    		info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends
    
    		pc.Args = int32(info.Args)
    		pc.Locals = int32(info.Locals)
    
    
    		npc := len(info.Pcdata) - 1 // -1 as we appended one above
    		pc.Pcdata = pcDataBatch[:npc:npc]
    		pcDataBatch = pcDataBatch[npc:]
    
    		nfd := len(info.Funcdataoff)
    		pc.Funcdataoff = fdOffBatch[:nfd:nfd]
    		fdOffBatch = fdOffBatch[nfd:]
    
    		nsp := len(info.File)
    		pc.File = symPtrBatch[:nsp:nsp]
    		symPtrBatch = symPtrBatch[nsp:]
    
    		nic := len(info.InlTree)
    		pc.InlTree = inlCallBatch[:nic:nic]
    		inlCallBatch = inlCallBatch[nic:]
    
    
    		pc.Pcsp.P = r.BytesAt(pcdataBase+info.Pcsp, int(info.Pcfile-info.Pcsp))
    		pc.Pcfile.P = r.BytesAt(pcdataBase+info.Pcfile, int(info.Pcline-info.Pcfile))
    		pc.Pcline.P = r.BytesAt(pcdataBase+info.Pcline, int(info.Pcinline-info.Pcline))
    		pc.Pcinline.P = r.BytesAt(pcdataBase+info.Pcinline, int(info.Pcdata[0]-info.Pcinline))
    		for k := range pc.Pcdata {
    			pc.Pcdata[k].P = r.BytesAt(pcdataBase+info.Pcdata[k], int(info.Pcdata[k+1]-info.Pcdata[k]))
    		}
    
    			pc.Funcdataoff[k] = int64(info.Funcdataoff[k])
    		}
    		for k := range pc.File {
    			pc.File[k] = resolveSymRef(info.File[k])
    		}
    
    		for k := range pc.InlTree {
    			inl := &info.InlTree[k]
    			pc.InlTree[k] = sym.InlinedCall{
    				Parent:   inl.Parent,
    				File:     resolveSymRef(inl.File),
    				Line:     inl.Line,
    
    				Func:     l.SymName(l.resolve(r, inl.Func)),
    
    		if !dupok {
    			if s.Attr.OnList() {
    				log.Fatalf("symbol %s listed multiple times", s.Name)
    			}
    			s.Attr.Set(sym.AttrOnList, true)
    			lib.Textp = append(lib.Textp, s)
    		} else {
    
    			// there may be a dup in another package
    
    			// put into a temp list and add to text later
    			lib.DupTextSyms = append(lib.DupTextSyms, s)
    		}
    
    func patchDWARFName1(p []byte, r *oReader) ([]byte, int) {
    
    	// This is kind of ugly. Really the package name should not
    	// even be included here.
    
    	if len(p) < 1 || p[0] != dwarf.DW_ABRV_FUNCTION {
    		return p, -1
    
    	if !bytes.Contains(p[:e], emptyPkg) {
    		return p, -1
    
    	patched := bytes.Replace(p[:e], emptyPkg, pkgprefix, -1)
    	return append(patched, p[e:]...), e
    }
    
    func patchDWARFName(s *sym.Symbol, r *oReader) {
    	patched, e := patchDWARFName1(s.P, r)
    	if e == -1 {
    		return
    	}
    	s.P = patched
    
    	s.Attr.Set(sym.AttrReadOnly, false)
    	delta := int64(len(s.P)) - s.Size
    	s.Size = int64(len(s.P))
    	for i := range s.R {
    		r := &s.R[i]
    		if r.Off > int32(e) {
    			r.Off += int32(delta)
    		}
    	}
    }
    
    
    // For debugging.
    func (l *Loader) Dump() {
    	fmt.Println("objs")
    	for _, obj := range l.objs {
    		if obj.r != nil {
    			fmt.Println(obj.i, obj.r.unit.Lib)
    		}
    	}
    	fmt.Println("syms")
    	for i, s := range l.Syms {
    		if i == 0 {
    			continue
    		}
    		if s != nil {
    			fmt.Println(i, s, s.Type)
    		} else {
    			fmt.Println(i, l.SymName(Sym(i)), "<not loaded>")
    		}
    	}
    	fmt.Println("overwrite:", l.overwrite)
    	fmt.Println("symsByName")
    
    	for name, i := range l.symsByName[0] {
    		fmt.Println(i, name, 0)
    	}
    	for name, i := range l.symsByName[1] {
    		fmt.Println(i, name, 1)