github.com/eh-steve/goloader@v0.0.0-20240111193454-90ff3cfdae39/ld.go (about)

     1  package goloader
     2  
     3  import (
     4  	"bytes"
     5  	"cmd/objfile/objabi"
     6  	"cmd/objfile/sys"
     7  	"encoding/binary"
     8  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"reflect"
    12  	"runtime"
    13  	"sort"
    14  	"strings"
    15  	"sync"
    16  	"unsafe"
    17  
    18  	"github.com/eh-steve/goloader/obj"
    19  	"github.com/eh-steve/goloader/objabi/reloctype"
    20  	"github.com/eh-steve/goloader/objabi/symkind"
    21  	"github.com/eh-steve/goloader/stackobject"
    22  )
    23  
    24  // ourself defined struct
    25  // code segment
    26  type segment struct {
    27  	codeByte      []byte
    28  	dataByte      []byte
    29  	codeBase      int
    30  	dataBase      int
    31  	sumDataLen    int
    32  	dataLen       int
    33  	noptrdataLen  int
    34  	bssLen        int
    35  	noptrbssLen   int
    36  	codeLen       int
    37  	maxCodeLength int
    38  	maxDataLength int
    39  	codeOff       int
    40  	dataOff       int
    41  }
    42  
    43  type Linker struct {
    44  	code                   []byte
    45  	data                   []byte
    46  	noptrdata              []byte
    47  	bss                    []byte
    48  	noptrbss               []byte
    49  	cuFiles                []obj.CompilationUnitFiles
    50  	symMap                 map[string]*obj.Sym
    51  	objsymbolMap           map[string]*obj.ObjSymbol
    52  	namemap                map[string]int
    53  	fileNameMap            map[string]int
    54  	cutab                  []uint32
    55  	filetab                []byte
    56  	funcnametab            []byte
    57  	functab                []byte
    58  	pctab                  []byte
    59  	_func                  []*_func
    60  	initFuncs              []string
    61  	symNameOrder           []string
    62  	Arch                   *sys.Arch
    63  	options                LinkerOptions
    64  	heapStringMap          map[string]*string
    65  	appliedADRPRelocs      map[*byte][]byte
    66  	appliedPCRelRelocs     map[*byte][]byte
    67  	pkgNamesWithUnresolved map[string]struct{}
    68  	pkgNamesToForceRebuild map[string]struct{}
    69  	reachableTypes         map[string]struct{}
    70  	reachableSymbols       map[string]struct{}
    71  	pkgs                   []*obj.Pkg
    72  	pkgsByName             map[string]*obj.Pkg
    73  }
    74  
    75  type CodeModule struct {
    76  	segment
    77  	SymbolsByPkg           map[string]map[string]interface{}
    78  	Syms                   map[string]uintptr
    79  	module                 *moduledata
    80  	gcdata                 []byte
    81  	gcbss                  []byte
    82  	patchedTypeMethodsIfn  map[*_type]map[int]struct{}
    83  	patchedTypeMethodsTfn  map[*_type]map[int]struct{}
    84  	patchedTypeMethodsMtyp map[*_type]map[int]typeOff
    85  	deduplicatedTypes      map[string]uintptr
    86  	heapStrings            map[string]*string
    87  }
    88  
    89  var (
    90  	modules     = make(map[*CodeModule]bool)
    91  	modulesLock sync.Mutex
    92  )
    93  
    94  // initialize Linker
    95  func initLinker(opts []LinkerOptFunc) (*Linker, error) {
    96  
    97  	linker := &Linker{
    98  		// Pad these tabs out so offsets don't start at 0, which is often used in runtime as a special value for "missing"
    99  		// e.g. runtime/traceback.go and runtime/symtab.go both contain checks like:
   100  		// if f.pcsp == 0 ...
   101  		// and
   102  		// if f.nameoff == 0
   103  		funcnametab:            make([]byte, PtrSize),
   104  		pctab:                  make([]byte, PtrSize),
   105  		symMap:                 make(map[string]*obj.Sym),
   106  		objsymbolMap:           make(map[string]*obj.ObjSymbol),
   107  		namemap:                make(map[string]int),
   108  		fileNameMap:            make(map[string]int),
   109  		heapStringMap:          make(map[string]*string),
   110  		appliedADRPRelocs:      make(map[*byte][]byte),
   111  		appliedPCRelRelocs:     make(map[*byte][]byte),
   112  		pkgNamesWithUnresolved: make(map[string]struct{}),
   113  		pkgNamesToForceRebuild: make(map[string]struct{}),
   114  		reachableTypes:         make(map[string]struct{}),
   115  		reachableSymbols:       make(map[string]struct{}),
   116  	}
   117  	if os.Getenv("GOLOADER_FORCE_TEST_RELOCATION_EPILOGUES") == "1" {
   118  		opts = append(opts, WithForceTestRelocationEpilogues())
   119  	}
   120  	linker.Opts(opts...)
   121  
   122  	head := make([]byte, unsafe.Sizeof(pcHeader{}))
   123  	copy(head, obj.ModuleHeadx86)
   124  	linker.functab = append(linker.functab, head...)
   125  	linker.functab[len(obj.ModuleHeadx86)-1] = PtrSize
   126  	return linker, nil
   127  }
   128  
   129  func (linker *Linker) Autolib() []string {
   130  	// Sort dependent packages into autolib order via depth first recursion
   131  	if len(linker.pkgs) == 0 {
   132  		return nil
   133  	}
   134  	seen := map[string]struct{}{}
   135  	var autolibsByPkg = map[string][]string{}
   136  	for _, pkg := range linker.pkgs {
   137  		autolibsByPkg[pkg.PkgPath] = pkg.AutoLib
   138  	}
   139  	// The last package is the main package, so start there
   140  	mainPkg := linker.pkgs[len(linker.pkgs)-1]
   141  	var autolibs []string
   142  	recurseAutolibs(autolibsByPkg, mainPkg.PkgPath, &autolibs, seen)
   143  
   144  	return autolibs
   145  }
   146  
   147  func recurseAutolibs(autolibsByPkg map[string][]string, targetPkg string, autolibs *[]string, seen map[string]struct{}) {
   148  	if _, ok := seen[targetPkg]; ok {
   149  		return
   150  	}
   151  	seen[targetPkg] = struct{}{}
   152  	for _, imported := range autolibsByPkg[targetPkg] {
   153  		recurseAutolibs(autolibsByPkg, imported, autolibs, seen)
   154  		newLibs := autolibsByPkg[imported]
   155  		for _, newLib := range newLibs {
   156  			if _, ok := seen[newLib]; !ok {
   157  				*autolibs = append(*autolibs, newLib)
   158  			}
   159  		}
   160  	}
   161  	*autolibs = append(*autolibs, targetPkg)
   162  }
   163  
   164  func (linker *Linker) Opts(linkerOpts ...LinkerOptFunc) {
   165  	for _, opt := range linkerOpts {
   166  		opt(&linker.options)
   167  	}
   168  }
   169  
   170  func (linker *Linker) addSymbols(symbolNames []string, globalSymPtr map[string]uintptr) error {
   171  	// static_tmp is 0, golang compile not allocate memory.
   172  	linker.noptrdata = append(linker.noptrdata, make([]byte, IntSize)...)
   173  
   174  	for _, cuFileSet := range linker.cuFiles {
   175  		for _, fileName := range cuFileSet.Files {
   176  			if offset, ok := linker.fileNameMap[fileName]; !ok {
   177  				linker.cutab = append(linker.cutab, (uint32)(len(linker.filetab)))
   178  				linker.fileNameMap[fileName] = len(linker.filetab)
   179  				fileName = expandGoroot(strings.TrimPrefix(fileName, FileSymPrefix))
   180  				linker.filetab = append(linker.filetab, []byte(fileName)...)
   181  				linker.filetab = append(linker.filetab, ZeroByte)
   182  			} else {
   183  				linker.cutab = append(linker.cutab, uint32(offset))
   184  			}
   185  		}
   186  	}
   187  
   188  	for _, objSymName := range symbolNames {
   189  		if _, ok := linker.symMap[objSymName]; ok {
   190  			continue
   191  		}
   192  		if !linker.isSymbolReachable(objSymName) {
   193  			continue
   194  		}
   195  
   196  		objSym := linker.objsymbolMap[objSymName]
   197  		if objSym == nil {
   198  			// Might have been added as an ABI wrapper without the actual implementation
   199  			objSym = linker.objsymbolMap[objSymName+obj.ABI0Suffix]
   200  			if objSym != nil {
   201  				panic("missing a symbol " + objSymName + " but found its ABI0 wrapper")
   202  			} else {
   203  				objSym = linker.objsymbolMap[objSymName+obj.ABIInternalSuffix]
   204  				if objSym != nil {
   205  					panic("missing a symbol " + objSymName + " but found its ABIInternal wrapper")
   206  				}
   207  			}
   208  		}
   209  		if objSym.Kind == symkind.STEXT && objSym.DupOK == false {
   210  			_, err := linker.addSymbol(objSym.Name, globalSymPtr)
   211  			if err != nil {
   212  				return err
   213  			}
   214  		} else if objSym.Kind == symkind.STEXT && objSym.DupOK {
   215  			// This might be an asm func ABIWRAPPER. Check if one of its relocs points to itself
   216  			// (the abi0 version of itself, without the .abiinternal suffix)
   217  			isAsmWrapper := false
   218  
   219  			if objSym.Func != nil && objSym.Func.FuncID == uint8(obj.FuncIDWrapper) {
   220  				for _, reloc := range objSym.Reloc {
   221  					if reloc.Sym.Name+obj.ABIInternalSuffix == objSym.Name {
   222  						// Relocation pointing at itself (the ABI0 ASM version)
   223  						isAsmWrapper = true
   224  					}
   225  				}
   226  			}
   227  			if isAsmWrapper {
   228  				// This wrapper's symbol has a suffix of .abiinternal to distinguish it from the abi0 ASM func
   229  				_, err := linker.addSymbol(objSym.Name, globalSymPtr)
   230  				if err != nil {
   231  					return err
   232  				}
   233  			}
   234  		}
   235  		switch objSym.Kind {
   236  		case symkind.SNOPTRDATA, symkind.SRODATA, symkind.SDATA, symkind.SBSS, symkind.SNOPTRBSS:
   237  			_, err := linker.addSymbol(objSym.Name, globalSymPtr)
   238  			if err != nil {
   239  				return err
   240  			}
   241  		}
   242  	}
   243  	for _, sym := range linker.symMap {
   244  		offset := 0
   245  		switch sym.Kind {
   246  		case symkind.SNOPTRDATA, symkind.SRODATA:
   247  			if strings.HasPrefix(sym.Name, TypeStringPrefix) {
   248  				// nothing todo
   249  			} else {
   250  				offset += len(linker.data)
   251  			}
   252  		case symkind.SBSS:
   253  			offset += len(linker.data) + len(linker.noptrdata)
   254  		case symkind.SNOPTRBSS:
   255  			offset += len(linker.data) + len(linker.noptrdata) + len(linker.bss)
   256  		}
   257  		sym.Offset += offset
   258  		if offset != 0 {
   259  			for index := range sym.Reloc {
   260  				sym.Reloc[index].Offset += offset
   261  				if sym.Reloc[index].EpilogueOffset > 0 {
   262  					sym.Reloc[index].EpilogueOffset += offset
   263  				}
   264  			}
   265  		}
   266  	}
   267  	linker.symNameOrder = symbolNames
   268  	return nil
   269  }
   270  
   271  func (linker *Linker) SymbolOrder() []string {
   272  	return linker.symNameOrder
   273  }
   274  
   275  func (linker *Linker) addSymbol(name string, globalSymPtr map[string]uintptr) (symbol *obj.Sym, err error) {
   276  	if symbol, ok := linker.symMap[name]; ok {
   277  		return symbol, nil
   278  	}
   279  	objsym := linker.objsymbolMap[name]
   280  	symbol = &obj.Sym{Name: objsym.Name, Kind: objsym.Kind, Pkg: objsym.Pkg}
   281  	linker.symMap[symbol.Name] = symbol
   282  
   283  	switch symbol.Kind {
   284  	case symkind.STEXT:
   285  		symbol.Offset = len(linker.code)
   286  		linker.code = append(linker.code, objsym.Data...)
   287  		bytearrayAlignNops(linker.Arch, &linker.code, PtrSize)
   288  		for i, reloc := range objsym.Reloc {
   289  			// Pessimistically pad the function text with extra bytes for any relocations which might add extra
   290  			// instructions at the end in the case of a 32 bit overflow. These epilogue PCs need to be added to
   291  			// the PCData, PCLine, PCFile, PCSP etc in case of pre-emption or stack unwinding while the PC is running these hacked instructions.
   292  			// We find the relevant PCValues for the offset of the reloc, and reuse the values for the reloc's epilogue
   293  
   294  			if linker.options.NoRelocationEpilogues && !strings.HasPrefix(reloc.Sym.Name, TypeStringPrefix) {
   295  				continue
   296  			}
   297  			switch reloc.Type {
   298  			case reloctype.R_ADDRARM64:
   299  				objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset
   300  				objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesADRP
   301  				linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesADRP)...)
   302  			case reloctype.R_ARM64_PCREL_LDST8, reloctype.R_ARM64_PCREL_LDST16, reloctype.R_ARM64_PCREL_LDST32, reloctype.R_ARM64_PCREL_LDST64:
   303  				objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset
   304  				objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesADRPLDST
   305  				linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesADRPLDST)...)
   306  			case reloctype.R_CALLARM64, reloctype.R_CALLARM64 | reloctype.R_WEAK:
   307  				objsym.Reloc[i].EpilogueOffset = alignof(len(linker.code)-symbol.Offset, PtrSize)
   308  				objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesCALLARM64
   309  				alignment := alignof(len(linker.code)-symbol.Offset, PtrSize) - (len(linker.code) - symbol.Offset)
   310  				linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesCALLARM64+alignment)...)
   311  			case reloctype.R_PCREL:
   312  				objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset
   313  				var epilogueSize int
   314  				offset := reloc.Offset
   315  				if reloc.Offset == 1 {
   316  					// This might happen if a CGo E9 JMP is right at the beginning of a function, so we want to avoid slicing before the start of the text
   317  					offset += 1
   318  				}
   319  				instructionBytes := objsym.Data[offset-2 : reloc.Offset+reloc.Size]
   320  				opcode := instructionBytes[0]
   321  				switch opcode {
   322  				case x86amd64LEAcode:
   323  					epilogueSize = maxExtraInstructionBytesPCRELxLEAQ
   324  				case x86amd64MOVcode:
   325  					epilogueSize = maxExtraInstructionBytesPCRELxMOVNear
   326  				case x86amd64CMPLcode:
   327  					epilogueSize = maxExtraInstructionBytesPCRELxCMPLNear
   328  				case x86amd64JMPcode:
   329  					epilogueSize = maxExtraInstructionBytesPCRELxJMP
   330  				case x86amd64CALL2code: // CGo FF 15 PCREL call
   331  					if instructionBytes[1] == 0x15 {
   332  						epilogueSize = maxExtraInstructionBytesPCRELxCALL2
   333  						break
   334  					}
   335  					fallthrough // Might be FF XX E8/E9 ...
   336  				default:
   337  					switch instructionBytes[1] {
   338  					case x86amd64CALLcode:
   339  						opcode = x86amd64CALLcode
   340  						epilogueSize = maxExtraInstructionBytesCALLNear
   341  					case x86amd64JMPcode:
   342  						epilogueSize = maxExtraInstructionBytesPCRELxJMP
   343  					}
   344  				}
   345  				returnOffset := (reloc.Offset + reloc.Size) - (objsym.Reloc[i].EpilogueOffset + epilogueSize) - len(x86amd64JMPShortCode) //  assumes short jump, adjusts if not
   346  				shortJmp := returnOffset < 0 && returnOffset > -0x80
   347  				switch opcode {
   348  				case x86amd64MOVcode:
   349  					if shortJmp {
   350  						epilogueSize = maxExtraInstructionBytesPCRELxMOVShort
   351  					}
   352  				case x86amd64CMPLcode:
   353  					if shortJmp {
   354  						epilogueSize = maxExtraInstructionBytesPCRELxCMPLShort
   355  					}
   356  				case x86amd64CALLcode:
   357  					if shortJmp {
   358  						epilogueSize = maxExtraInstructionBytesCALLShort
   359  					}
   360  				}
   361  				objsym.Reloc[i].EpilogueSize = epilogueSize
   362  				linker.code = append(linker.code, createArchNops(linker.Arch, epilogueSize)...)
   363  			case reloctype.R_GOTPCREL, reloctype.R_TLS_IE:
   364  				objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset
   365  				objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesGOTPCREL
   366  				linker.code = append(linker.code, createArchNops(linker.Arch, objsym.Reloc[i].EpilogueSize)...)
   367  			case reloctype.R_ARM64_GOTPCREL, reloctype.R_ARM64_TLS_IE:
   368  				objsym.Reloc[i].EpilogueOffset = alignof(len(linker.code)-symbol.Offset, PtrSize)
   369  				objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesARM64GOTPCREL
   370  				// need to be able to pad to align to multiple of 8
   371  				alignment := alignof(len(linker.code)-symbol.Offset, PtrSize) - (len(linker.code) - symbol.Offset)
   372  				linker.code = append(linker.code, createArchNops(linker.Arch, objsym.Reloc[i].EpilogueSize+alignment)...)
   373  			case reloctype.R_CALL, reloctype.R_CALL | reloctype.R_WEAK:
   374  				epilogueSize := maxExtraInstructionBytesCALLNear
   375  				returnOffset := (reloc.Offset + reloc.Size) - (objsym.Reloc[i].EpilogueOffset + epilogueSize) - len(x86amd64JMPShortCode) //  assumes short jump, adjusts if not
   376  				shortJmp := returnOffset < 0 && returnOffset > -0x80
   377  				objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset
   378  				if shortJmp {
   379  					epilogueSize = maxExtraInstructionBytesCALLShort
   380  				}
   381  				objsym.Reloc[i].EpilogueSize = epilogueSize
   382  				linker.code = append(linker.code, createArchNops(linker.Arch, epilogueSize)...)
   383  			}
   384  			bytearrayAlignNops(linker.Arch, &linker.code, PtrSize)
   385  		}
   386  
   387  		symbol.Func = &obj.Func{}
   388  		if err := linker.readFuncData(linker.objsymbolMap[name], symbol.Offset); err != nil {
   389  			return nil, err
   390  		}
   391  	case symkind.SDATA:
   392  		symbol.Offset = len(linker.data)
   393  		linker.data = append(linker.data, objsym.Data...)
   394  		bytearrayAlign(&linker.data, PtrSize)
   395  	case symkind.SNOPTRDATA, symkind.SRODATA:
   396  		// because golang string assignment is pointer assignment, so store go.string constants
   397  		// in a separate segment and not unload when module unload.
   398  		if strings.HasPrefix(symbol.Name, TypeStringPrefix) {
   399  			data := make([]byte, len(objsym.Data))
   400  			copy(data, objsym.Data)
   401  			stringVal := string(data)
   402  			linker.heapStringMap[symbol.Name] = &stringVal
   403  		} else {
   404  			symbol.Offset = len(linker.noptrdata)
   405  			linker.noptrdata = append(linker.noptrdata, objsym.Data...)
   406  			bytearrayAlign(&linker.noptrdata, PtrSize)
   407  		}
   408  	case symkind.SBSS:
   409  		symbol.Offset = len(linker.bss)
   410  		linker.bss = append(linker.bss, objsym.Data...)
   411  		bytearrayAlign(&linker.bss, PtrSize)
   412  	case symkind.SNOPTRBSS:
   413  		symbol.Offset = len(linker.noptrbss)
   414  		linker.noptrbss = append(linker.noptrbss, objsym.Data...)
   415  		bytearrayAlign(&linker.noptrbss, PtrSize)
   416  	case symkind.STLSBSS:
   417  		// Nothing to do, since runtime.tls_g should be resolved from the host binary
   418  	default:
   419  		return nil, fmt.Errorf("invalid symbol:%s kind:%d", symbol.Name, symbol.Kind)
   420  	}
   421  
   422  	if symbol.Kind == symkind.STEXT {
   423  		symbol.Size = len(linker.code) - symbol.Offset // includes epilogue
   424  	} else {
   425  		symbol.Size = int(objsym.Size)
   426  	}
   427  	for _, loc := range objsym.Reloc {
   428  		reloc := loc
   429  		reloc.Offset = reloc.Offset + symbol.Offset
   430  		reloc.EpilogueOffset = reloc.EpilogueOffset + symbol.Offset
   431  		if _, ok := linker.objsymbolMap[reloc.Sym.Name]; ok {
   432  			reloc.Sym, err = linker.addSymbol(reloc.Sym.Name, globalSymPtr)
   433  			if err != nil {
   434  				return nil, err
   435  			}
   436  			if len(linker.objsymbolMap[reloc.Sym.Name].Data) == 0 && reloc.Size > 0 {
   437  				// static_tmp is 0, golang compile not allocate memory.
   438  				// goloader add IntSize bytes on linker.noptrdata[0]
   439  				if reloc.Size <= IntSize {
   440  					reloc.Sym.Offset = 0
   441  				} else {
   442  					return nil, fmt.Errorf("Symbol: %s size: %d > IntSize: %d\n", reloc.Sym.Name, reloc.Size, IntSize)
   443  				}
   444  			}
   445  		} else {
   446  			if reloc.Type == reloctype.R_TLS_LE || reloc.Type == reloctype.R_TLS_IE {
   447  				reloc.Sym.Name = TLSNAME
   448  				reloc.Sym.Offset = loc.Offset
   449  			}
   450  			if reloc.Type == reloctype.R_CALLIND {
   451  				reloc.Sym.Offset = 0
   452  			}
   453  			_, exist := linker.symMap[reloc.Sym.Name]
   454  			if strings.HasPrefix(reloc.Sym.Name, TypeImportPathPrefix) {
   455  				if exist {
   456  					reloc.Sym = linker.symMap[reloc.Sym.Name]
   457  				} else {
   458  					path := strings.Trim(strings.TrimPrefix(reloc.Sym.Name, TypeImportPathPrefix), ".")
   459  					reloc.Sym.Kind = symkind.SNOPTRDATA
   460  					reloc.Sym.Offset = len(linker.noptrdata)
   461  					// name memory layout
   462  					// name { tagLen(byte), len(uint16), str*}
   463  					nameLen := []byte{0, 0, 0}
   464  					binary.PutUvarint(nameLen[1:], uint64(len(path)))
   465  					linker.noptrdata = append(linker.noptrdata, nameLen...)
   466  					linker.noptrdata = append(linker.noptrdata, path...)
   467  					linker.noptrdata = append(linker.noptrdata, ZeroByte)
   468  					bytearrayAlign(&linker.noptrdata, PtrSize)
   469  				}
   470  			}
   471  			if ispreprocesssymbol(reloc.Sym.Name) {
   472  				bytes := make([]byte, UInt64Size)
   473  				if err := preprocesssymbol(linker.Arch.ByteOrder, reloc.Sym.Name, bytes); err != nil {
   474  					return nil, err
   475  				} else {
   476  					if exist {
   477  						reloc.Sym = linker.symMap[reloc.Sym.Name]
   478  					} else {
   479  						reloc.Sym.Kind = symkind.SNOPTRDATA
   480  						reloc.Sym.Offset = len(linker.noptrdata)
   481  						linker.noptrdata = append(linker.noptrdata, bytes...)
   482  						bytearrayAlign(&linker.noptrdata, PtrSize)
   483  					}
   484  				}
   485  			}
   486  			if !exist {
   487  				// golang1.8, some function generates more than one (MOVQ (TLS), CX)
   488  				// so when same name symbol in linker.symMap, do not update it
   489  				if reloc.Sym.Name != "" {
   490  					linker.symMap[reloc.Sym.Name] = reloc.Sym
   491  				}
   492  			}
   493  		}
   494  		symbol.Reloc = append(symbol.Reloc, reloc)
   495  	}
   496  
   497  	if objsym.Type != EmptyString {
   498  		if _, ok := linker.symMap[objsym.Type]; !ok {
   499  			if _, ok := linker.objsymbolMap[objsym.Type]; !ok {
   500  				linker.symMap[objsym.Type] = &obj.Sym{Name: objsym.Type, Offset: InvalidOffset, Pkg: objsym.Pkg}
   501  			}
   502  		}
   503  	}
   504  	return symbol, nil
   505  }
   506  
   507  func (linker *Linker) readFuncData(symbol *obj.ObjSymbol, codeLen int) (err error) {
   508  	nameOff := len(linker.funcnametab)
   509  	if offset, ok := linker.namemap[symbol.Name]; !ok {
   510  		linker.namemap[symbol.Name] = len(linker.funcnametab)
   511  		linker.funcnametab = append(linker.funcnametab, []byte(symbol.Name)...)
   512  		linker.funcnametab = append(linker.funcnametab, ZeroByte)
   513  	} else {
   514  		nameOff = offset
   515  	}
   516  
   517  	for _, reloc := range symbol.Reloc {
   518  		if reloc.EpilogueOffset > 0 {
   519  			if len(symbol.Func.PCSP) > 0 {
   520  				linker.patchPCValuesForReloc(&symbol.Func.PCSP, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize)
   521  			}
   522  			if len(symbol.Func.PCFile) > 0 {
   523  				linker.patchPCValuesForReloc(&symbol.Func.PCFile, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize)
   524  			}
   525  			if len(symbol.Func.PCLine) > 0 {
   526  				linker.patchPCValuesForReloc(&symbol.Func.PCLine, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize)
   527  			}
   528  			for i, pcdata := range symbol.Func.PCData {
   529  				if len(pcdata) > 0 {
   530  					linker.patchPCValuesForReloc(&symbol.Func.PCData[i], reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize)
   531  				}
   532  			}
   533  		}
   534  	}
   535  	pcspOff := len(linker.pctab)
   536  	linker.pctab = append(linker.pctab, symbol.Func.PCSP...)
   537  
   538  	pcfileOff := len(linker.pctab)
   539  	linker.pctab = append(linker.pctab, symbol.Func.PCFile...)
   540  
   541  	pclnOff := len(linker.pctab)
   542  	linker.pctab = append(linker.pctab, symbol.Func.PCLine...)
   543  
   544  	_func := initfunc(symbol, nameOff, pcspOff, pcfileOff, pclnOff, symbol.Func.CUOffset)
   545  	linker._func = append(linker._func, &_func)
   546  	Func := linker.symMap[symbol.Name].Func
   547  	for _, pcdata := range symbol.Func.PCData {
   548  		if len(pcdata) == 0 {
   549  			Func.PCData = append(Func.PCData, 0)
   550  		} else {
   551  			Func.PCData = append(Func.PCData, uint32(len(linker.pctab)))
   552  			linker.pctab = append(linker.pctab, pcdata...)
   553  		}
   554  	}
   555  
   556  	for _, name := range symbol.Func.FuncData {
   557  		if name == EmptyString {
   558  			Func.FuncData = append(Func.FuncData, (uintptr)(0))
   559  		} else {
   560  			if _, ok := linker.symMap[name]; !ok {
   561  				if _, ok := linker.objsymbolMap[name]; ok {
   562  					if _, err = linker.addSymbol(name, nil); err != nil {
   563  						return err
   564  					}
   565  				} else {
   566  					return errors.New("unknown gcobj:" + name)
   567  				}
   568  			}
   569  			if sym, ok := linker.symMap[name]; ok {
   570  				Func.FuncData = append(Func.FuncData, (uintptr)(sym.Offset))
   571  			} else {
   572  				Func.FuncData = append(Func.FuncData, (uintptr)(0))
   573  			}
   574  		}
   575  	}
   576  
   577  	if err = linker.addInlineTree(&_func, symbol); err != nil {
   578  		return err
   579  	}
   580  
   581  	grow(&linker.pctab, alignof(len(linker.pctab), PtrSize))
   582  	return
   583  }
   584  
   585  func (linker *Linker) addSymbolMap(symPtr map[string]uintptr, codeModule *CodeModule) (symbolMap map[string]uintptr, err error) {
   586  	symbolMap = make(map[string]uintptr)
   587  	segment := &codeModule.segment
   588  	for name, sym := range linker.symMap {
   589  		if !linker.isSymbolReachable(name) {
   590  			continue
   591  		}
   592  		if sym.Offset == InvalidOffset {
   593  			if ptr, ok := symPtr[sym.Name]; ok {
   594  				symbolMap[name] = ptr
   595  				// Mark the symbol as a duplicate
   596  				symbolMap[FirstModulePrefix+name] = ptr
   597  			} else {
   598  				symbolMap[name] = InvalidHandleValue
   599  				return nil, fmt.Errorf("unresolved external symbol: %s", sym.Name)
   600  			}
   601  		} else if sym.Name == TLSNAME {
   602  			// nothing todo
   603  		} else if sym.Kind == symkind.STEXT {
   604  			symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.codeBase)
   605  			codeModule.Syms[sym.Name] = symbolMap[name]
   606  			if _, ok := symPtr[name]; ok {
   607  				// Mark the symbol as a duplicate, and store the original entrypoint
   608  				symbolMap[FirstModulePrefix+name] = symPtr[name]
   609  			}
   610  		} else if strings.HasPrefix(sym.Name, ItabPrefix) {
   611  			if ptr, ok := symPtr[sym.Name]; ok {
   612  				symbolMap[name] = ptr
   613  				symbolMap[FirstModulePrefix+name] = ptr
   614  			}
   615  		} else {
   616  			if _, ok := symPtr[name]; !ok {
   617  				if strings.HasPrefix(name, TypeStringPrefix) {
   618  					strPtr := linker.heapStringMap[name]
   619  					if strPtr == nil {
   620  						return nil, fmt.Errorf("impossible! got a nil string for symbol %s", name)
   621  					}
   622  					if len(*strPtr) == 0 {
   623  						// Any address will do, the length is 0, so it should never be read
   624  						symbolMap[name] = uintptr(unsafe.Pointer(linker))
   625  					} else {
   626  						x := (*reflect.StringHeader)(unsafe.Pointer(strPtr))
   627  						symbolMap[name] = x.Data
   628  					}
   629  				} else {
   630  					symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase)
   631  					if strings.HasSuffix(sym.Name, "·f") {
   632  						codeModule.Syms[sym.Name] = symbolMap[name]
   633  					}
   634  					if strings.HasPrefix(name, TypePrefix) {
   635  						if variant, ok := symbolIsVariant(name); ok && symPtr[variant] != 0 {
   636  							symbolMap[FirstModulePrefix+name] = symPtr[variant]
   637  						}
   638  					}
   639  				}
   640  			} else {
   641  				if strings.HasPrefix(name, MainPkgPrefix) || strings.HasPrefix(name, TypePrefix) {
   642  					symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase)
   643  					// Record the presence of a duplicate symbol by adding a prefix
   644  					symbolMap[FirstModulePrefix+name] = symPtr[name]
   645  				} else {
   646  					shouldSkipDedup := false
   647  					for _, pkgPath := range linker.options.SkipTypeDeduplicationForPackages {
   648  						if strings.HasPrefix(name, pkgPath) {
   649  							shouldSkipDedup = true
   650  						}
   651  					}
   652  					if shouldSkipDedup {
   653  						// Use the new version of the symbol
   654  						symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase)
   655  					} else {
   656  						symbolMap[name] = symPtr[name]
   657  						// Mark the symbol as a duplicate
   658  						symbolMap[FirstModulePrefix+name] = symPtr[name]
   659  					}
   660  				}
   661  			}
   662  		}
   663  	}
   664  	if tlsG, ok := symPtr[TLSNAME]; ok {
   665  		symbolMap[TLSNAME] = tlsG
   666  	}
   667  	codeModule.heapStrings = linker.heapStringMap
   668  	return symbolMap, err
   669  }
   670  
   671  func (linker *Linker) addFuncTab(module *moduledata, _func *_func, symbolMap map[string]uintptr) (err error) {
   672  	funcname := gostringnocopy(&linker.funcnametab[_func.nameoff])
   673  	setfuncentry(_func, symbolMap[funcname], module.text)
   674  	Func := linker.symMap[funcname].Func
   675  
   676  	if err = stackobject.AddStackObject(funcname, linker.symMap, symbolMap, module.noptrdata); err != nil {
   677  		return err
   678  	}
   679  	if err = linker.addDeferReturn(_func); err != nil {
   680  		return err
   681  	}
   682  
   683  	append2Slice(&module.pclntable, uintptr(unsafe.Pointer(_func)), _FuncSize)
   684  
   685  	if _func.npcdata > 0 {
   686  		append2Slice(&module.pclntable, uintptr(unsafe.Pointer(&(Func.PCData[0]))), Uint32Size*int(_func.npcdata))
   687  	}
   688  
   689  	if _func.nfuncdata > 0 {
   690  		addfuncdata(module, Func, _func)
   691  	}
   692  
   693  	return err
   694  }
   695  
   696  func readPCData(p []byte, startPC uintptr) (pcs []uintptr, vals []int32) {
   697  	pc := startPC
   698  	val := int32(-1)
   699  	if len(p) == 0 {
   700  		return nil, nil
   701  	}
   702  	for {
   703  		var ok bool
   704  		p, ok = step(p, &pc, &val, pc == startPC)
   705  		if !ok {
   706  			break
   707  		}
   708  		pcs = append(pcs, pc)
   709  		vals = append(vals, val)
   710  		if len(p) == 0 {
   711  			break
   712  		}
   713  	}
   714  	return
   715  }
   716  
   717  func formatPCData(p []byte, startPC uintptr) string {
   718  	pcs, vals := readPCData(p, startPC)
   719  	var result string
   720  	if len(pcs) == 0 {
   721  		return "()"
   722  	}
   723  	prevPC := startPC
   724  	for i := range pcs {
   725  		result += fmt.Sprintf("(%d-%d => %d), ", prevPC, pcs[i], vals[i])
   726  		prevPC = startPC + pcs[i]
   727  	}
   728  	return result
   729  }
   730  
   731  func pcValue(p []byte, targetOffset uintptr) (int32, uintptr) {
   732  	startPC := uintptr(0)
   733  	pc := uintptr(0)
   734  	val := int32(-1)
   735  	if len(p) == 0 {
   736  		return -1, 1<<64 - 1
   737  	}
   738  	prevpc := pc
   739  	for {
   740  		var ok bool
   741  		p, ok = step(p, &pc, &val, pc == startPC)
   742  		if !ok {
   743  			break
   744  		}
   745  		if len(p) == 0 {
   746  			break
   747  		}
   748  		if targetOffset < pc {
   749  			return val, prevpc
   750  		}
   751  		prevpc = pc
   752  	}
   753  	return -1, 1<<64 - 1
   754  }
   755  
   756  func (linker *Linker) patchPCValuesForReloc(pcvalues *[]byte, relocOffet int, epilogueOffset int, epilogueSize int) {
   757  	// Use the pcvalue at the offset of the reloc for the entire of that reloc's epilogue.
   758  	// This ensures that if the code is pre-empted or the stack unwound while we're inside the epilogue, the runtime behaves correctly
   759  
   760  	var pcQuantum uintptr = 1
   761  	if linker.Arch.Family == sys.ARM64 {
   762  		pcQuantum = 4
   763  	}
   764  	p := *pcvalues
   765  	if len(p) == 0 {
   766  		panic("trying to patch a zero sized pcvalue table. This shouldn't be possible...")
   767  	}
   768  	valAtRelocSite, startPC := pcValue(p, uintptr(relocOffet))
   769  	if startPC == 1<<64-1 && valAtRelocSite == -1 {
   770  		panic(fmt.Sprintf("couldn't interpret pcvalue data when trying to patch it... relocOffset: %d, pcdata: %v\n %s", relocOffet, p, formatPCData(p, 0)))
   771  	}
   772  	if p[len(p)-1] != 0 {
   773  		panic(fmt.Sprintf("got a pcvalue table with an unexpected ending (%d)...\n%s ", p[len(p)-1], formatPCData(p, 0)))
   774  	}
   775  	p = p[:len(p)-1] // Remove the terminating 0
   776  
   777  	// Table is (value, PC), (value, PC), (value, PC)... etc
   778  	// Each value is delta encoded (signed) relative to the last, and each PC is delta encoded (unsigned)
   779  
   780  	pcs, vals := readPCData(p, 0)
   781  	lastValue := vals[len(vals)-1]
   782  	lastPC := pcs[len(pcs)-1]
   783  	if lastValue == valAtRelocSite {
   784  		// Extend the lastPC delta to absorb our epilogue, keep the value the same
   785  		var pcDelta uintptr
   786  		if len(pcs) > 1 {
   787  			pcDelta = (lastPC - pcs[len(pcs)-2]) / pcQuantum
   788  		} else {
   789  			pcDelta = lastPC / pcQuantum
   790  		}
   791  
   792  		buf := make([]byte, 10)
   793  		n := binary.PutUvarint(buf, uint64(pcDelta))
   794  		buf = buf[:n]
   795  		index := bytes.LastIndex(p, buf)
   796  		if index == -1 {
   797  			panic(fmt.Sprintf("could not find varint PC delta of %d (%v)", pcDelta, buf))
   798  		}
   799  		p = p[:index]
   800  		if len(pcs) > 1 {
   801  			pcDelta = (uintptr(epilogueOffset+epilogueSize) - pcs[len(pcs)-2]) / pcQuantum
   802  		} else {
   803  			pcDelta = (uintptr(epilogueOffset + epilogueSize)) / pcQuantum
   804  		}
   805  
   806  		buf = make([]byte, 10)
   807  		n = binary.PutUvarint(buf, uint64(pcDelta))
   808  		p = append(p, buf[:n]...)
   809  	} else {
   810  		// Append a new (value, PC) pair
   811  		pcDelta := (epilogueOffset + epilogueSize - int(lastPC)) / int(pcQuantum)
   812  		if pcDelta < 0 {
   813  			panic(fmt.Sprintf("somehow the epilogue is not at the end?? lastPC %d, epilogue offset %d", lastPC, epilogueOffset))
   814  		}
   815  		valDelta := valAtRelocSite - lastValue
   816  
   817  		buf := make([]byte, 10)
   818  		n := binary.PutVarint(buf, int64(valDelta))
   819  		p = append(p, buf[:n]...)
   820  
   821  		n = binary.PutUvarint(buf, uint64(pcDelta))
   822  		p = append(p, buf[:n]...)
   823  	}
   824  
   825  	// Re-add the terminating 0 we stripped off
   826  	p = append(p, 0)
   827  
   828  	*pcvalues = p
   829  }
   830  
   831  func (linker *Linker) buildModule(codeModule *CodeModule, symbolMap map[string]uintptr) (err error) {
   832  	segment := &codeModule.segment
   833  	module := codeModule.module
   834  	module.pclntable = append(module.pclntable, linker.functab...)
   835  	module.minpc = uintptr(segment.codeBase)
   836  	module.maxpc = uintptr(segment.codeBase + segment.codeOff)
   837  	module.text = uintptr(segment.codeBase)
   838  	module.etext = module.maxpc
   839  	module.data = uintptr(segment.dataBase)
   840  	module.edata = uintptr(segment.dataBase) + uintptr(segment.dataLen)
   841  	module.noptrdata = module.edata
   842  	module.enoptrdata = module.noptrdata + uintptr(segment.noptrdataLen)
   843  	module.bss = module.enoptrdata
   844  	module.ebss = module.bss + uintptr(segment.bssLen)
   845  	module.noptrbss = module.ebss
   846  	module.enoptrbss = module.noptrbss + uintptr(segment.noptrbssLen)
   847  	module.end = module.enoptrbss
   848  	module.types = module.data
   849  	module.etypes = module.enoptrbss
   850  
   851  	module.ftab = append(module.ftab, initfunctab(module.minpc, uintptr(len(module.pclntable)), module.text))
   852  	for index, _func := range linker._func {
   853  		funcname := gostringnocopy(&linker.funcnametab[_func.nameoff])
   854  		module.ftab = append(module.ftab, initfunctab(symbolMap[funcname], uintptr(len(module.pclntable)), module.text))
   855  		if err = linker.addFuncTab(module, linker._func[index], symbolMap); err != nil {
   856  			return err
   857  		}
   858  	}
   859  	module.ftab = append(module.ftab, initfunctab(module.maxpc, uintptr(len(module.pclntable)), module.text))
   860  
   861  	// see:^src/cmd/link/internal/ld/pcln.go findfunctab
   862  	funcbucket := []findfuncbucket{}
   863  	for k := 0; k < len(linker._func); k++ {
   864  		lEntry := int(getfuncentry(linker._func[k], module.text) - module.text)
   865  		lb := lEntry / pcbucketsize
   866  		li := lEntry % pcbucketsize / (pcbucketsize / nsub)
   867  
   868  		entry := int(module.maxpc - module.text)
   869  		if k < len(linker._func)-1 {
   870  			entry = int(getfuncentry(linker._func[k+1], module.text) - module.text)
   871  		}
   872  		b := entry / pcbucketsize
   873  		i := entry % pcbucketsize / (pcbucketsize / nsub)
   874  
   875  		for m := b - len(funcbucket); m >= 0; m-- {
   876  			funcbucket = append(funcbucket, findfuncbucket{idx: uint32(k)})
   877  		}
   878  		if lb < b {
   879  			i = nsub - 1
   880  		}
   881  		for n := li + 1; n <= i; n++ {
   882  			if funcbucket[lb].subbuckets[n] == 0 {
   883  				funcbucket[lb].subbuckets[n] = byte(k - int(funcbucket[lb].idx))
   884  			}
   885  		}
   886  	}
   887  	length := len(funcbucket) * FindFuncBucketSize
   888  	append2Slice(&module.pclntable, uintptr(unsafe.Pointer(&funcbucket[0])), length)
   889  	module.findfunctab = (uintptr)(unsafe.Pointer(&module.pclntable[len(module.pclntable)-length]))
   890  
   891  	if err = linker.addgcdata(codeModule, symbolMap); err != nil {
   892  		return err
   893  	}
   894  	for name, addr := range symbolMap {
   895  		if strings.HasPrefix(name, TypePrefix) &&
   896  			!strings.HasPrefix(name, TypeDoubleDotPrefix) &&
   897  			addr >= module.types && addr < module.etypes {
   898  			module.typelinks = append(module.typelinks, int32(addr-module.types))
   899  			module.typemap[typeOff(addr-module.types)] = (*_type)(unsafe.Pointer(addr))
   900  		}
   901  	}
   902  	initmodule(codeModule.module, linker)
   903  
   904  	modulesLock.Lock()
   905  	addModule(codeModule)
   906  	modulesLock.Unlock()
   907  	additabs(codeModule.module)
   908  	moduledataverify1(codeModule.module)
   909  	modulesinit()
   910  	typelinksinit() // Deduplicate typelinks across all modules
   911  	return err
   912  }
   913  
   914  func (linker *Linker) deduplicateTypeDescriptors(codeModule *CodeModule, symbolMap map[string]uintptr) (err error) {
   915  	// Having called addModule and runtime.modulesinit(), we can now safely use typesEqual()
   916  	// (which depended on the module being in the linked list for safe name resolution of types).
   917  	// This means we can now deduplicate type descriptors in the actual code
   918  	// by relocating their addresses to the equivalent *_type in the main module
   919  
   920  	// We need to deduplicate type symbols with the main module according to type hash, since type assertion
   921  	// uses *_type pointer equality and many overlapping or builtin types may be included twice
   922  	// We have to do this after adding the module to the linked list since deduplication
   923  	// depends on symbol resolution across all modules
   924  	typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
   925  	buildModuleTypeHash(activeModules()[0], typehash)
   926  
   927  	patchedTypeMethodsIfn := make(map[*_type]map[int]struct{})
   928  	patchedTypeMethodsTfn := make(map[*_type]map[int]struct{})
   929  	patchedTypeMethodsMtyp := make(map[*_type]map[int]typeOff)
   930  	segment := &codeModule.segment
   931  	byteorder := linker.Arch.ByteOrder
   932  	dedupedTypes := map[string]uintptr{}
   933  	for _, symbol := range linker.symMap {
   934  		if linker.options.DumpTextBeforeAndAfterRelocs && linker.options.RelocationDebugWriter != nil && symbol.Kind == symkind.STEXT && symbol.Offset >= 0 {
   935  			_, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, "BEFORE DEDUPE (%x - %x) %142s: %x\n", codeModule.codeBase+symbol.Offset, codeModule.codeBase+symbol.Offset+symbol.Size, symbol.Name, codeModule.codeByte[symbol.Offset:symbol.Offset+symbol.Size])
   936  		}
   937  	relocLoop:
   938  		for _, loc := range symbol.Reloc {
   939  			addr := symbolMap[loc.Sym.Name]
   940  			sym := loc.Sym
   941  			relocByte := segment.dataByte
   942  			addrBase := segment.dataBase
   943  			if symbol.Kind == symkind.STEXT {
   944  				addrBase = segment.codeBase
   945  				relocByte = segment.codeByte
   946  			}
   947  			if addr != InvalidHandleValue && sym.Kind == symkind.SRODATA &&
   948  				strings.HasPrefix(sym.Name, TypePrefix) &&
   949  				!strings.HasPrefix(sym.Name, TypeDoubleDotPrefix) && sym.Offset != -1 {
   950  
   951  				// if this is pointing to a type descriptor at an offset inside this binary, we should deduplicate it against
   952  				// already known types from other modules to allow fast type assertion using *_type pointer equality
   953  				t := (*_type)(unsafe.Pointer(addr))
   954  				prevT := (*_type)(unsafe.Pointer(addr))
   955  				for _, candidate := range typehash[t.hash] {
   956  					seen := map[_typePair]struct{}{}
   957  					if typesEqual(t, candidate, seen) {
   958  						t = candidate
   959  						break
   960  					}
   961  				}
   962  
   963  				// Only relocate code if the type is a duplicate
   964  				if t != prevT {
   965  					_, isVariant := symbolIsVariant(loc.Sym.Name)
   966  					if uintptr(unsafe.Pointer(t)) != symbolMap[FirstModulePrefix+loc.Sym.Name] && !isVariant {
   967  						// This shouldn't be possible and indicates a registration bug
   968  						panic(fmt.Sprintf("found another firstmodule type that wasn't registered by goloader. Symbol name: %s, type name: %s. This shouldn't be possible and indicates a bug in firstmodule type registration\n", loc.Sym.Name, t.nameOff(t.str).name()))
   969  					}
   970  					// Store this for later so we know which types were deduplicated
   971  					dedupedTypes[loc.Sym.Name] = uintptr(unsafe.Pointer(t))
   972  
   973  					for _, pkgPathToSkip := range linker.options.SkipTypeDeduplicationForPackages {
   974  						if t.PkgPath() == pkgPathToSkip {
   975  							continue relocLoop
   976  						}
   977  					}
   978  					u := t.uncommon()
   979  					prevU := prevT.uncommon()
   980  					err2 := codeModule.patchTypeMethodOffsets(t, u, prevU, patchedTypeMethodsIfn, patchedTypeMethodsTfn, patchedTypeMethodsMtyp)
   981  					if err2 != nil {
   982  						return err2
   983  					}
   984  
   985  					addr = uintptr(unsafe.Pointer(t))
   986  					if linker.options.RelocationDebugWriter != nil && loc.Offset != InvalidOffset {
   987  						var weakness string
   988  						if loc.Type&reloctype.R_WEAK > 0 {
   989  							weakness = "WEAK|"
   990  						}
   991  						relocType := weakness + objabi.RelocType(loc.Type&^reloctype.R_WEAK).String()
   992  						_, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, "DEDUPLICATING   %10s %10s %18s Base: 0x%x Pos: 0x%08x, Addr: 0x%016x AddrFromBase: %12d %s   to    %s\n",
   993  							objabi.SymKind(symbol.Kind), objabi.SymKind(sym.Kind), relocType, addrBase, uintptr(unsafe.Pointer(&relocByte[loc.Offset])),
   994  							addr, int(addr)-addrBase, symbol.Name, sym.Name)
   995  					}
   996  					switch loc.Type {
   997  					case reloctype.R_GOTPCREL:
   998  						linker.relocateGOTPCREL(addr, loc, relocByte)
   999  					case reloctype.R_PCREL:
  1000  						err2 := linker.relocatePCREL(addr, loc, &codeModule.segment, relocByte, addrBase)
  1001  						if err2 != nil {
  1002  							err = err2
  1003  						}
  1004  					case reloctype.R_CALLARM, reloctype.R_CALLARM64, reloctype.R_CALL:
  1005  						panic("This should not be possible")
  1006  					case reloctype.R_ADDRARM64, reloctype.R_ARM64_PCREL_LDST8, reloctype.R_ARM64_PCREL_LDST16, reloctype.R_ARM64_PCREL_LDST32, reloctype.R_ARM64_PCREL_LDST64, reloctype.R_ARM64_GOTPCREL:
  1007  						err2 := linker.relocateADRP(relocByte[loc.Offset:], loc, segment, addr)
  1008  						if err2 != nil {
  1009  							err = err2
  1010  						}
  1011  					case reloctype.R_ADDR, reloctype.R_WEAKADDR:
  1012  						// TODO - sanity check this
  1013  						address := uintptr(int(addr) + loc.Add)
  1014  						putAddress(byteorder, relocByte[loc.Offset:], uint64(address))
  1015  					case reloctype.R_ADDROFF, reloctype.R_WEAKADDROFF:
  1016  						offset := int(addr) - addrBase + loc.Add
  1017  						if offset > 0x7FFFFFFF || offset < -0x80000000 {
  1018  							err = fmt.Errorf("symName: %s %s offset: %d overflows!\n", objabi.RelocType(loc.Type), sym.Name, offset)
  1019  						}
  1020  						byteorder.PutUint32(relocByte[loc.Offset:], uint32(offset))
  1021  					case reloctype.R_METHODOFF:
  1022  						if loc.Sym.Kind == symkind.STEXT {
  1023  							addrBase = segment.codeBase
  1024  						}
  1025  						offset := int(addr) - addrBase + loc.Add
  1026  						if offset > 0x7FFFFFFF || offset < -0x80000000 {
  1027  							err = fmt.Errorf("symName: %s %s offset: %d overflows!\n", objabi.RelocType(loc.Type), sym.Name, offset)
  1028  						}
  1029  						byteorder.PutUint32(relocByte[loc.Offset:], uint32(offset))
  1030  					case reloctype.R_USETYPE, reloctype.R_USEIFACE, reloctype.R_USEIFACEMETHOD, reloctype.R_ADDRCUOFF, reloctype.R_KEEP:
  1031  						// nothing to do
  1032  					default:
  1033  						panic(fmt.Sprintf("unhandled reloc %s", objabi.RelocType(loc.Type)))
  1034  						// TODO - should we attempt to rewrite other relocations which point at *_types too?
  1035  					}
  1036  				}
  1037  			}
  1038  		}
  1039  		if linker.options.DumpTextBeforeAndAfterRelocs && linker.options.RelocationDebugWriter != nil && symbol.Kind == symkind.STEXT && symbol.Offset >= 0 {
  1040  			_, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, " AFTER DEDUPE (%x - %x) %142s: %x\n", codeModule.codeBase+symbol.Offset, codeModule.codeBase+symbol.Offset+symbol.Size, symbol.Name, codeModule.codeByte[symbol.Offset:symbol.Offset+symbol.Size])
  1041  		}
  1042  	}
  1043  	codeModule.patchedTypeMethodsIfn = patchedTypeMethodsIfn
  1044  	codeModule.patchedTypeMethodsTfn = patchedTypeMethodsTfn
  1045  	codeModule.patchedTypeMethodsMtyp = patchedTypeMethodsMtyp
  1046  	codeModule.deduplicatedTypes = dedupedTypes
  1047  
  1048  	if err != nil {
  1049  		return err
  1050  	}
  1051  	err = patchTypeMethodTextPtrs(uintptr(codeModule.codeBase), codeModule.patchedTypeMethodsIfn, codeModule.patchedTypeMethodsTfn)
  1052  
  1053  	return err
  1054  }
  1055  
  1056  func (linker *Linker) buildExports(codeModule *CodeModule, symbolMap map[string]uintptr) {
  1057  	codeModule.SymbolsByPkg = map[string]map[string]interface{}{}
  1058  	for _, pkg := range linker.pkgs {
  1059  		pkgSyms := map[string]interface{}{}
  1060  		for name, info := range pkg.Exports {
  1061  			reachable := linker.isSymbolReachable(info.SymName)
  1062  			typeAddr, ok := symbolMap[info.TypeName]
  1063  			if !ok {
  1064  				if !reachable {
  1065  					// Doesn't matter
  1066  					continue
  1067  				}
  1068  				// Only panic if a type is missing from the main JIT package - types might not be included for //go:linkname'd symbols, and that's ok
  1069  				if linker.pkgs[len(linker.pkgs)-1] == pkg {
  1070  					panic("could not find type symbol " + info.TypeName + " needed for " + info.SymName)
  1071  				} else {
  1072  					continue
  1073  				}
  1074  			}
  1075  			fmTypeAddr, ok := symbolMap[FirstModulePrefix+info.TypeName]
  1076  			if ok && fmTypeAddr != typeAddr {
  1077  				// Prefer firstmodule types if equal (i.e. deduplicate)
  1078  				seen := map[_typePair]struct{}{}
  1079  				fmTyp := (*_type)(unsafe.Pointer(fmTypeAddr))
  1080  				newTyp := (*_type)(unsafe.Pointer(typeAddr))
  1081  				if fmTyp.hash == newTyp.hash && typesEqual(fmTyp, newTyp, seen) {
  1082  					typeAddr = fmTypeAddr
  1083  				}
  1084  			}
  1085  			addr, ok := symbolMap[info.SymName]
  1086  			if !ok {
  1087  				if !reachable {
  1088  					continue
  1089  				}
  1090  				panic(fmt.Sprintf("could not find symbol %s in package %s", info.SymName, pkg.PkgPath))
  1091  			}
  1092  			t := (*_type)(unsafe.Pointer(typeAddr))
  1093  			if dup, ok := codeModule.deduplicatedTypes[info.TypeName]; ok {
  1094  				t = (*_type)(unsafe.Pointer(dup))
  1095  			}
  1096  
  1097  			var val interface{}
  1098  			valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val))
  1099  			(*valp)[0] = unsafe.Pointer(t)
  1100  
  1101  			if t.Kind() == reflect.Func {
  1102  				(*valp)[1] = unsafe.Pointer(&addr)
  1103  			} else {
  1104  				(*valp)[1] = unsafe.Pointer(addr)
  1105  			}
  1106  
  1107  			pkgSyms[name] = val
  1108  		}
  1109  		if len(pkgSyms) > 0 {
  1110  			codeModule.SymbolsByPkg[pkg.PkgPath] = pkgSyms
  1111  		}
  1112  	}
  1113  }
  1114  
  1115  func (linker *Linker) UnresolvedExternalSymbols(symbolMap map[string]uintptr, ignorePackages []string, stdLibPkgs map[string]struct{}, unsafeBlindlyUseFirstModuleTypes bool) map[string]*obj.Sym {
  1116  	symMap := make(map[string]*obj.Sym)
  1117  	for symName, sym := range linker.symMap {
  1118  		shouldSkipDedup := false
  1119  		for _, pkgPath := range ignorePackages {
  1120  			if sym.Pkg == pkgPath {
  1121  				shouldSkipDedup = true
  1122  			}
  1123  		}
  1124  		if sym.Offset == InvalidOffset || shouldSkipDedup {
  1125  			if strings.HasPrefix(symName, TypePrefix) &&
  1126  				!strings.HasPrefix(symName, TypeDoubleDotPrefix) {
  1127  				// Always force the rebuild of non-std lib types in case they've changed between firstmodule and JIT code
  1128  				// They can be checked for structural equality if the JIT code builds it, but not if we blindly use the firstmodule version of a _type
  1129  				if typeSym, ok := symbolMap[symName]; ok {
  1130  					t := (*_type)(unsafe.Pointer(typeSym))
  1131  					firstModuleTypeHasUnreachableMethods := false
  1132  					if u := t.uncommon(); u != nil && linker.isTypeReachable(symName) {
  1133  						for _, method := range u.methods() {
  1134  							if method.tfn == -1 || method.ifn == -1 {
  1135  								// This first module method is unreachable, so check if JIT code calls this method,
  1136  								// and if it does, then mark the whole type as an unresolved symbol
  1137  								if linker.isSymbolReachable(fullyQualifiedMethodName(t, method)) {
  1138  									firstModuleTypeHasUnreachableMethods = true
  1139  									break
  1140  								}
  1141  							}
  1142  						}
  1143  					}
  1144  					_, isStdLibPkg := stdLibPkgs[t.PkgPath()]
  1145  					// Don't rebuild types in the stdlib, as these shouldn't be different (assuming same toolchain version for host and JIT)
  1146  					if t.PkgPath() != "" && (!isStdLibPkg || firstModuleTypeHasUnreachableMethods) {
  1147  						// Only rebuild types which are reachable (via relocs) from the main package, otherwise we'll end up building everything unnecessarily
  1148  						if (linker.isTypeReachable(symName) && !unsafeBlindlyUseFirstModuleTypes) || firstModuleTypeHasUnreachableMethods {
  1149  							symMap[symName] = sym
  1150  						}
  1151  					}
  1152  				}
  1153  			}
  1154  			if _, ok := symbolMap[symName]; !ok || shouldSkipDedup {
  1155  				if _, ok := linker.objsymbolMap[symName]; !ok || shouldSkipDedup {
  1156  					if linker.isSymbolReachable(symName) {
  1157  						symMap[symName] = sym
  1158  					}
  1159  				}
  1160  			}
  1161  		}
  1162  	}
  1163  
  1164  	for _, sym := range symMap {
  1165  		_, alreadyBuiltPkg := linker.pkgsByName[sym.Pkg]
  1166  		if alreadyBuiltPkg {
  1167  			// If we already built and loaded the package which this symbol came from, it's probably linknamed and implemented in runtime
  1168  			if sym.Pkg != "runtime" {
  1169  				sym.Pkg = "runtime"
  1170  			} else {
  1171  				// If we already built runtime and still can't find this sym, it may be a runtime/internal/* type
  1172  				// TODO - this doesn't seem robust
  1173  				if strings.HasPrefix(sym.Name, TypePrefix+"runtime/internal") {
  1174  					sym.Pkg = strings.Split(strings.TrimPrefix(sym.Name, TypePrefix), ".")[0]
  1175  				}
  1176  			}
  1177  		}
  1178  	}
  1179  	return symMap
  1180  }
  1181  
  1182  func (linker *Linker) UnresolvedPackageReferences(existingPkgs []string) []string {
  1183  	var pkgList []string
  1184  outer:
  1185  	for pkgName := range linker.pkgNamesWithUnresolved {
  1186  		for _, existing := range existingPkgs {
  1187  			if pkgName == existing {
  1188  				continue outer
  1189  			}
  1190  		}
  1191  		pkgList = append(pkgList, pkgName)
  1192  	}
  1193  outer2:
  1194  	for pkgName := range linker.pkgNamesToForceRebuild {
  1195  		for _, alreadyAdded := range pkgList {
  1196  			if alreadyAdded == pkgName {
  1197  				continue outer2
  1198  			}
  1199  		}
  1200  		pkgList = append(pkgList, pkgName)
  1201  	}
  1202  	return pkgList
  1203  }
  1204  
  1205  func (linker *Linker) UnresolvedExternalSymbolUsers(symbolMap map[string]uintptr) map[string][]string {
  1206  	requiredBy := map[string][]string{}
  1207  	for symName, sym := range linker.symMap {
  1208  		if sym.Offset == InvalidOffset {
  1209  			if _, ok := symbolMap[symName]; !ok {
  1210  				if _, ok := linker.objsymbolMap[symName]; !ok {
  1211  					if linker.isSymbolReachable(symName) {
  1212  						var requiredBySet = map[string]struct{}{}
  1213  						for _, otherSym := range linker.symMap {
  1214  							for _, reloc := range otherSym.Reloc {
  1215  								if reloc.Sym.Name == symName {
  1216  									requiredBySet[otherSym.Name] = struct{}{}
  1217  								}
  1218  							}
  1219  						}
  1220  						requiredByList := make([]string, 0, len(requiredBySet))
  1221  						for k := range requiredBySet {
  1222  							requiredByList = append(requiredByList, k)
  1223  						}
  1224  						sort.Strings(requiredByList)
  1225  						requiredBy[sym.Name] = requiredByList
  1226  					}
  1227  				}
  1228  			}
  1229  		}
  1230  	}
  1231  	return requiredBy
  1232  }
  1233  
  1234  func (linker *Linker) UnloadStrings() {
  1235  	linker.heapStringMap = nil
  1236  }
  1237  
  1238  func Load(linker *Linker, symPtr map[string]uintptr) (codeModule *CodeModule, err error) {
  1239  	codeModule = &CodeModule{
  1240  		Syms:   make(map[string]uintptr),
  1241  		module: &moduledata{typemap: make(map[typeOff]*_type)},
  1242  	}
  1243  	codeModule.codeLen = len(linker.code)
  1244  	codeModule.dataLen = len(linker.data)
  1245  	codeModule.noptrdataLen = len(linker.noptrdata)
  1246  	codeModule.bssLen = len(linker.bss)
  1247  	codeModule.noptrbssLen = len(linker.noptrbss)
  1248  	codeModule.sumDataLen = codeModule.dataLen + codeModule.noptrdataLen + codeModule.bssLen + codeModule.noptrbssLen
  1249  	codeModule.maxCodeLength = alignof(codeModule.codeLen, PageSize)
  1250  	codeModule.maxDataLength = alignof(codeModule.sumDataLen, PageSize)
  1251  	codeByte, err := Mmap(codeModule.maxCodeLength)
  1252  	if err != nil {
  1253  		return nil, err
  1254  	}
  1255  	dataByte, err := MmapData(codeModule.maxDataLength)
  1256  	if err != nil {
  1257  		return nil, err
  1258  	}
  1259  
  1260  	codeModule.codeByte = codeByte
  1261  	codeModule.codeBase = int((*sliceHeader)(unsafe.Pointer(&codeByte)).Data)
  1262  	copy(codeModule.codeByte, linker.code)
  1263  	codeModule.codeOff = codeModule.codeLen
  1264  
  1265  	codeModule.dataByte = dataByte
  1266  	codeModule.dataBase = int((*sliceHeader)(unsafe.Pointer(&dataByte)).Data)
  1267  	copy(codeModule.dataByte[codeModule.dataOff:], linker.data)
  1268  	codeModule.dataOff = codeModule.dataLen
  1269  	copy(codeModule.dataByte[codeModule.dataOff:], linker.noptrdata)
  1270  	codeModule.dataOff += codeModule.noptrdataLen
  1271  	copy(codeModule.dataByte[codeModule.dataOff:], linker.bss)
  1272  	codeModule.dataOff += codeModule.bssLen
  1273  	copy(codeModule.dataByte[codeModule.dataOff:], linker.noptrbss)
  1274  	codeModule.dataOff += codeModule.noptrbssLen
  1275  
  1276  	var symbolMap map[string]uintptr
  1277  	if symbolMap, err = linker.addSymbolMap(symPtr, codeModule); err == nil {
  1278  		if err = linker.relocate(codeModule, symbolMap); err == nil {
  1279  			if err = linker.buildModule(codeModule, symbolMap); err == nil {
  1280  				if err = linker.deduplicateTypeDescriptors(codeModule, symbolMap); err == nil {
  1281  					linker.buildExports(codeModule, symbolMap)
  1282  					MakeThreadJITCodeExecutable(uintptr(codeModule.codeBase), codeModule.maxCodeLength)
  1283  					if err = linker.doInitialize(codeModule, symbolMap); err == nil {
  1284  						return codeModule, err
  1285  					}
  1286  				}
  1287  			}
  1288  		}
  1289  	}
  1290  	if err != nil {
  1291  		err2 := Munmap(codeByte)
  1292  		err3 := Munmap(dataByte)
  1293  		if err2 != nil {
  1294  			err = fmt.Errorf("failed to munmap (%s) after linker error: %w", err2, err)
  1295  		}
  1296  		if err3 != nil {
  1297  			err = fmt.Errorf("failed to munmap (%s) after linker error: %w", err3, err)
  1298  		}
  1299  	}
  1300  	return nil, err
  1301  }
  1302  
  1303  func (cm *CodeModule) Unload() error {
  1304  	err := cm.revertPatchedTypeMethods()
  1305  	if err != nil {
  1306  		return err
  1307  	}
  1308  	removeitabs(cm.module)
  1309  	runtime.GC()
  1310  	modulesLock.Lock()
  1311  	removeModule(cm)
  1312  	modulesLock.Unlock()
  1313  	modulesinit()
  1314  	err1 := Munmap(cm.codeByte)
  1315  	err2 := Munmap(cm.dataByte)
  1316  	if err1 != nil {
  1317  		return err1
  1318  	}
  1319  	cm.heapStrings = nil
  1320  	return err2
  1321  }
  1322  
  1323  func (cm *CodeModule) TextAddr() (start, end uintptr) {
  1324  	if cm.module == nil {
  1325  		return 0, 0
  1326  	}
  1327  	return cm.module.text, cm.module.etext
  1328  }
  1329  
  1330  func (cm *CodeModule) DataAddr() (start, end uintptr) {
  1331  	if cm.module == nil {
  1332  		return 0, 0
  1333  	}
  1334  	return cm.module.data, cm.module.enoptrbss
  1335  }