Skip to content
Snippets Groups Projects
loader.go 67.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
    
    		// A symbol may be a dup or overwritten. In this case, its
    		// content will actually be provided by a different object
    		// (to which its global index points). Skip those symbols.
    		gi := l.toGlobal(r, i)
    		var isdup bool
    		if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
    			isdup = true
    		}
    
    
    		osym.ReadWithoutName(r.Reader, r.SymOff(i))
    
    		if dupok && isdup {
    			if l.attrReachable.has(gi) {
    				// 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[gi]
    				if s.Type == sym.STEXT {
    					lib.DupTextSyms = append(lib.DupTextSyms, s)
    					lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
    
    			continue // come from a different object
    		}
    		s := l.Syms[gi]
    
    		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:]
    
    		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)
    
    			lib.Textp2 = append(lib.Textp2, sym.LoaderSym(isym))
    
    			// there may be a dup in another package
    
    			// put into a temp list and add to text later
    			lib.DupTextSyms = append(lib.DupTextSyms, s)
    
    			lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(isym))
    
    // convertRelocations takes a vector of loader.Reloc relocations and
    // translates them into an equivalent set of sym.Reloc relocations on
    // the symbol "dst", performing fixups along the way for ABI aliases,
    // etc. It is assumed that the called has pre-allocated the dst symbol
    // relocations slice.
    func (l *Loader) convertRelocations(src []Reloc, dst *sym.Symbol) {
    	for j := range dst.R {
    		r := src[j]
    		rs := r.Sym
    		sz := r.Size
    		rt := r.Type
    		if rt == objabi.R_METHODOFF {
    			if l.attrReachable.has(rs) {
    				rt = objabi.R_ADDROFF
    			} else {
    				sz = 0
    				rs = 0
    			}
    		}
    		if rt == objabi.R_WEAKADDROFF && !l.attrReachable.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
    		}
    		dst.R[j] = sym.Reloc{
    			Off:  r.Off,
    			Siz:  sz,
    			Type: rt,
    			Add:  r.Add,
    			Sym:  l.Syms[rs],
    		}
    	}
    }
    
    
    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)
    		}
    	}
    }
    
    // UndefinedRelocTargets iterates through the global symbol index
    // space, looking for symbols with relocations targeting undefined
    // references. The linker's loadlib method uses this to determine if
    // there are unresolved references to functions in system libraries
    // (for example, libgcc.a), presumably due to CGO code. Return
    // value is a list of loader.Sym's corresponding to the undefined
    // cross-refs. The "limit" param controls the maximum number of
    // results returned; if "limit" is -1, then all undefs are returned.
    func (l *Loader) UndefinedRelocTargets(limit int) []Sym {
    	result := []Sym{}
    	rslice := []Reloc{}
    
    	for si := Sym(1); si < Sym(len(l.objSyms)); si++ {
    
    		rslice = relocs.ReadSyms(rslice)
    
    		for ri := 0; ri < relocs.Count; ri++ {
    			r := &rslice[ri]
    			if r.Sym != 0 && l.SymType(r.Sym) == sym.SXREF && l.RawSymName(r.Sym) != ".got" {
    				result = append(result, r.Sym)
    				if limit != -1 && len(result) >= limit {
    					break
    				}
    			}
    		}
    	}
    	return result
    }
    
    
    // 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("Nsyms:", len(l.objSyms))
    
    	for i := Sym(1); i <= Sym(len(l.objSyms)); i++ {
    
    		pi := interface{}("")
    		if l.IsExternal(i) {
    			pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
    		}
    		var s *sym.Symbol
    		if int(i) < len(l.Syms) {
    			s = l.Syms[i]
    
    			fmt.Println(i, s, s.Type, pi)
    
    			fmt.Println(i, l.SymName(i), "<not loaded>", pi)
    
    	for name, i := range l.symsByName[0] {
    		fmt.Println(i, name, 0)
    	}
    	for name, i := range l.symsByName[1] {
    		fmt.Println(i, name, 1)
    
    	fmt.Println("payloads:")
    	for i := range l.payloads {
    		pp := l.payloads[i]
    		fmt.Println(i, pp.name, pp.ver, pp.kind)
    	}