github.com/dearplain/goloader@v0.0.0-20190107071432-2b1e47d74273/dymcode.go (about)

     1  package goloader
     2  
     3  import (
     4  	"bytes"
     5  	"cmd/objfile/goobj"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"runtime"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  	"unsafe"
    16  )
    17  
    18  func mustOK(err error) {
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  }
    23  
    24  // copy from $GOROOT/src/cmd/internal/objabi/reloctype.go
    25  const (
    26  	// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
    27  	// thread-local symbol from the thread local base and is used to implement the
    28  	// "local exec" model for tls access (r.Sym is not set on intel platforms but is
    29  	// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
    30  	R_TLS_LE    = 16
    31  	R_CALL      = 8
    32  	R_CALLARM   = 9
    33  	R_CALLARM64 = 10
    34  	R_CALLIND   = 11
    35  	R_PCREL     = 15
    36  	R_ADDR      = 1
    37  	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
    38  	// referenced symbol.
    39  	R_ADDRARM64 = 3
    40  	// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
    41  	// holding the data being relocated to the referenced symbol.
    42  	R_ADDROFF = 5
    43  	// R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
    44  	// A weak relocation does not make the symbol it refers to reachable,
    45  	// and is only honored by the linker if the symbol is in some other way
    46  	// reachable.
    47  	R_WEAKADDROFF = 6
    48  	// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
    49  	// holding the data being relocated to the referenced symbol.
    50  	// It is a variant of R_ADDROFF used when linking from the uncommonType of a
    51  	// *rtype, and may be set to zero by the linker if it determines the method
    52  	// text is unreachable by the linked program.
    53  	R_METHODOFF = 24
    54  )
    55  
    56  // copy from $GOROOT/src/cmd/internal/objabi/symkind.go
    57  const (
    58  	// An otherwise invalid zero value for the type
    59  	Sxxx = iota
    60  	// Executable instructions
    61  	STEXT
    62  	// Read only static data
    63  	SRODATA
    64  	// Static data that does not contain any pointers
    65  	SNOPTRDATA
    66  	// Static data
    67  	SDATA
    68  	// Statically data that is initially all 0s
    69  	SBSS
    70  	// Statically data that is initially all 0s and does not contain pointers
    71  	SNOPTRBSS
    72  	// Thread-local data that is initally all 0s
    73  	STLSBSS
    74  	// Debugging data
    75  	SDWARFINFO
    76  	SDWARFRANGE
    77  )
    78  
    79  type SymData struct {
    80  	Name   string
    81  	Kind   int
    82  	Offset int
    83  	Reloc  []Reloc
    84  }
    85  
    86  type Reloc struct {
    87  	Offset int
    88  	SymOff int
    89  	Size   int
    90  	Type   int
    91  	Add    int
    92  }
    93  
    94  // CodeReloc dispatch and load CodeReloc struct via network is OK
    95  type CodeReloc struct {
    96  	Code []byte
    97  	Data []byte
    98  	Mod  Module
    99  	Syms []SymData
   100  }
   101  
   102  type CodeModule struct {
   103  	Syms       map[string]uintptr
   104  	CodeByte   []byte
   105  	Module     interface{}
   106  	pcfuncdata []findfuncbucket
   107  	stkmaps    [][]byte
   108  	itabs      []itabReloc
   109  	itabSyms   []itabSym
   110  	typemap    map[typeOff]uintptr
   111  }
   112  
   113  type itabSym struct {
   114  	ptr   int
   115  	inter int
   116  	_type int
   117  }
   118  
   119  type itabReloc struct {
   120  	locOff  int
   121  	symOff  int
   122  	size    int
   123  	locType int
   124  	add     int
   125  }
   126  
   127  type symFile struct {
   128  	sym  *goobj.Sym
   129  	file *os.File
   130  }
   131  
   132  var (
   133  	tmpModule   interface{}
   134  	modules     = make(map[interface{}]bool)
   135  	modulesLock sync.Mutex
   136  	mov32bit    = [8]byte{0x00, 0x00, 0x80, 0xD2, 0x00, 0x00, 0xA0, 0xF2}
   137  )
   138  
   139  func ReadObj(f *os.File) (*CodeReloc, error) {
   140  	obj, err := goobj.Parse(f, "main")
   141  	if err != nil {
   142  		return nil, fmt.Errorf("read error: %v", err)
   143  	}
   144  
   145  	var syms = make(map[string]symFile)
   146  	for _, sym := range obj.Syms {
   147  		syms[sym.Name] = symFile{
   148  			sym:  sym,
   149  			file: f,
   150  		}
   151  	}
   152  
   153  	var symMap = make(map[string]int)
   154  	var gcObjs = make(map[string]uintptr)
   155  	var fileTabOffsetMap = make(map[string]int)
   156  
   157  	var reloc CodeReloc
   158  
   159  	for _, sym := range obj.Syms {
   160  		if sym.Kind == STEXT {
   161  			relocSym(&reloc, symFile{sym: sym,
   162  				file: f}, syms, symMap,
   163  				gcObjs, fileTabOffsetMap)
   164  		}
   165  	}
   166  
   167  	return &reloc, nil
   168  }
   169  
   170  func ReadObjs(files []string, pkgPath []string) (*CodeReloc, error) {
   171  
   172  	var fs []*os.File
   173  	for _, file := range files {
   174  		f, err := os.Open(file)
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  		fs = append(fs, f)
   179  		defer f.Close()
   180  	}
   181  
   182  	var allSyms = make(map[string]symFile)
   183  
   184  	var symMap = make(map[string]int)
   185  	var gcObjs = make(map[string]uintptr)
   186  	var fileTabOffsetMap = make(map[string]int)
   187  
   188  	var reloc CodeReloc
   189  
   190  	var goObjs []*goobj.Package
   191  	for i, f := range fs {
   192  		if pkgPath[i] == "" {
   193  			pkgPath[i] = "main"
   194  		}
   195  		obj, err := goobj.Parse(f, pkgPath[i])
   196  		if err != nil {
   197  			return nil, fmt.Errorf("read error: %v", err)
   198  		}
   199  
   200  		for _, sym := range obj.Syms {
   201  			allSyms[sym.Name] = symFile{
   202  				sym:  sym,
   203  				file: f,
   204  			}
   205  		}
   206  		goObjs = append(goObjs, obj)
   207  	}
   208  
   209  	for i, obj := range goObjs {
   210  		for _, sym := range obj.Syms {
   211  			if sym.Kind == STEXT {
   212  				relocSym(&reloc, symFile{sym: sym,
   213  					file: fs[i]}, allSyms, symMap,
   214  					gcObjs, fileTabOffsetMap)
   215  			}
   216  		}
   217  	}
   218  
   219  	return &reloc, nil
   220  }
   221  
   222  func addSym(symMap map[string]int, symArray *[]SymData, rsym *SymData) int {
   223  	var offset int
   224  	if of, ok := symMap[rsym.Name]; !ok {
   225  		offset = len(*symArray)
   226  		*symArray = append(*symArray, *rsym)
   227  		symMap[rsym.Name] = offset
   228  	} else {
   229  		offset = of
   230  		(*symArray)[offset] = *rsym
   231  	}
   232  	return offset
   233  }
   234  
   235  type readAtSeeker struct {
   236  	io.ReadSeeker
   237  }
   238  
   239  func (r *readAtSeeker) ReadAt(p []byte, offset int64) (n int, err error) {
   240  	_, err = r.Seek(offset, io.SeekStart)
   241  	if err != nil {
   242  		return
   243  	}
   244  	return r.Read(p)
   245  }
   246  
   247  func relocSym(reloc *CodeReloc, curSym symFile,
   248  	allSyms map[string]symFile, symMap map[string]int,
   249  	gcObjs map[string]uintptr, fileTabOffsetMap map[string]int) int {
   250  
   251  	if curSymOffset, ok := symMap[curSym.sym.Name]; ok {
   252  		return curSymOffset
   253  	}
   254  
   255  	var rsym SymData
   256  	rsym.Name = curSym.sym.Name
   257  	rsym.Kind = int(curSym.sym.Kind)
   258  	curSymOffset := addSym(symMap, &reloc.Syms, &rsym)
   259  
   260  	code := make([]byte, curSym.sym.Data.Size)
   261  	curSym.file.Seek(curSym.sym.Data.Offset, io.SeekStart)
   262  	_, err := curSym.file.Read(code)
   263  	mustOK(err)
   264  	switch int(curSym.sym.Kind) {
   265  	case STEXT:
   266  		rsym.Offset = len(reloc.Code)
   267  		reloc.Code = append(reloc.Code, code...)
   268  		readFuncData(&reloc.Mod, curSym, allSyms, gcObjs,
   269  			fileTabOffsetMap, curSymOffset, rsym.Offset)
   270  	default:
   271  		rsym.Offset = len(reloc.Data)
   272  		reloc.Data = append(reloc.Data, code...)
   273  	}
   274  	addSym(symMap, &reloc.Syms, &rsym)
   275  
   276  	for _, re := range curSym.sym.Reloc {
   277  		symOff := -1
   278  		if s, ok := allSyms[re.Sym.Name]; ok {
   279  			symOff = relocSym(reloc, s, allSyms, symMap,
   280  				gcObjs, fileTabOffsetMap)
   281  		} else {
   282  			var exSym SymData
   283  			exSym.Name = re.Sym.Name
   284  			exSym.Offset = -1
   285  			if re.Type == R_TLS_LE {
   286  				exSym.Name = TLSNAME
   287  				exSym.Offset = int(re.Offset)
   288  			}
   289  			if re.Type == R_CALLIND {
   290  				exSym.Offset = 0
   291  				exSym.Name = R_CALLIND_NAME
   292  			}
   293  			if strings.HasPrefix(exSym.Name, "type..importpath.") {
   294  				path := strings.TrimLeft(exSym.Name, "type..importpath.")
   295  				path = strings.Trim(path, ".")
   296  				pathb := []byte(path)
   297  				pathb = append(pathb, 0)
   298  				exSym.Offset = len(reloc.Data)
   299  				reloc.Data = append(reloc.Data, pathb...)
   300  			}
   301  			symOff = addSym(symMap, &reloc.Syms, &exSym)
   302  		}
   303  		rsym.Reloc = append(rsym.Reloc,
   304  			Reloc{Offset: int(re.Offset) + rsym.Offset, SymOff: symOff,
   305  				Type: int(re.Type),
   306  				Size: int(re.Size), Add: int(re.Add)})
   307  	}
   308  	reloc.Syms[curSymOffset].Reloc = rsym.Reloc
   309  
   310  	return curSymOffset
   311  }
   312  
   313  func strWrite(buf *bytes.Buffer, str ...string) {
   314  	for _, s := range str {
   315  		buf.WriteString(s)
   316  		if s != "\n" {
   317  			buf.WriteString(" ")
   318  		}
   319  	}
   320  }
   321  
   322  func Load(code *CodeReloc, symPtr map[string]uintptr) (*CodeModule, error) {
   323  	pCodeLen := len(code.Code) + len(code.Data)
   324  	codeLen := int(float32(pCodeLen) * 1.5)
   325  	codeByte, err := Mmap(codeLen)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	var codeModule = CodeModule{
   331  		Syms:    make(map[string]uintptr),
   332  		typemap: make(map[typeOff]uintptr),
   333  	}
   334  	var errBuf bytes.Buffer
   335  
   336  	base := int((*sliceHeader)(unsafe.Pointer(&codeByte)).Data)
   337  	dataBase := base + len(code.Code)
   338  
   339  	var symAddrs = make([]int, len(code.Syms))
   340  	var itabIndexs []int
   341  	var funcTypeMap = make(map[string]*int)
   342  	for i, sym := range code.Syms {
   343  		if sym.Offset == -1 {
   344  			if ptr, ok := symPtr[sym.Name]; ok {
   345  				symAddrs[i] = int(ptr)
   346  			} else {
   347  				symAddrs[i] = -1
   348  				strWrite(&errBuf, "unresolve external:", sym.Name, "\n")
   349  			}
   350  		} else if sym.Name == TLSNAME {
   351  			RegTLS(symPtr, sym.Offset)
   352  		} else if sym.Kind == STEXT {
   353  			symAddrs[i] = code.Syms[i].Offset + base
   354  			codeModule.Syms[sym.Name] = uintptr(symAddrs[i])
   355  		} else if strings.HasPrefix(sym.Name, "go.itab") {
   356  			if ptr, ok := symPtr[sym.Name]; ok {
   357  				symAddrs[i] = int(ptr)
   358  			} else {
   359  				itabIndexs = append(itabIndexs, i)
   360  			}
   361  		} else {
   362  			symAddrs[i] = code.Syms[i].Offset + dataBase
   363  
   364  			if strings.HasPrefix(sym.Name, "type.func") {
   365  				funcTypeMap[sym.Name] = &symAddrs[i]
   366  			}
   367  			if strings.HasPrefix(sym.Name, "type.") {
   368  				if ptr, ok := symPtr[sym.Name]; ok {
   369  					symAddrs[i] = int(ptr)
   370  				}
   371  			}
   372  		}
   373  	}
   374  
   375  	var itabSymMap = make(map[string]int)
   376  	for _, itabIndex := range itabIndexs {
   377  		curSym := code.Syms[itabIndex]
   378  		sym1 := symAddrs[curSym.Reloc[0].SymOff]
   379  		sym2 := symAddrs[curSym.Reloc[1].SymOff]
   380  		itabSymMap[curSym.Name] = len(codeModule.itabSyms)
   381  		codeModule.itabSyms = append(codeModule.itabSyms, itabSym{inter: sym1, _type: sym2})
   382  
   383  		if sym1 == -1 || sym2 == -1 {
   384  			continue
   385  		}
   386  		addIFaceSubFuncType(funcTypeMap, codeModule.typemap,
   387  			(*interfacetype)(unsafe.Pointer(uintptr(sym1))), base)
   388  	}
   389  
   390  	var armcode = []byte{0x04, 0xF0, 0x1F, 0xE5, 0x00, 0x00, 0x00, 0x00}
   391  	var arm64code = []byte{0x43, 0x00, 0x00, 0x58, 0x60, 0x00, 0x1F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
   392  	var x86code = []byte{0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
   393  	var movcode byte = 0x8b
   394  	var leacode byte = 0x8d
   395  	var jmpOff = pCodeLen
   396  	for _, curSym := range code.Syms {
   397  		for _, loc := range curSym.Reloc {
   398  			sym := code.Syms[loc.SymOff]
   399  			if symAddrs[loc.SymOff] == -1 {
   400  				continue
   401  			}
   402  			if symAddrs[loc.SymOff] == 0 && strings.HasPrefix(sym.Name, "go.itab") {
   403  				codeModule.itabs = append(codeModule.itabs,
   404  					itabReloc{locOff: loc.Offset, symOff: itabSymMap[sym.Name],
   405  						size: loc.Size, locType: loc.Type, add: loc.Add})
   406  				continue
   407  			}
   408  
   409  			var offset int
   410  			switch loc.Type {
   411  			case R_TLS_LE:
   412  				binary.LittleEndian.PutUint32(code.Code[loc.Offset:], uint32(symPtr[TLSNAME]))
   413  				continue
   414  			case R_CALL, R_PCREL:
   415  				var relocByte = code.Data
   416  				var addrBase = dataBase
   417  				if curSym.Kind == STEXT {
   418  					addrBase = base
   419  					relocByte = code.Code
   420  				}
   421  				offset = symAddrs[loc.SymOff] - (addrBase + loc.Offset + loc.Size) + loc.Add
   422  				if offset > 0x7fffffff || offset < -0x7fffffff {
   423  					if jmpOff+8 > codeLen {
   424  						strWrite(&errBuf, "len overflow", "sym:", sym.Name, "\n")
   425  						continue
   426  					}
   427  					rb := relocByte[loc.Offset-2:]
   428  					if loc.Type == R_CALL {
   429  						offset = (base + jmpOff) - (addrBase + loc.Offset + loc.Size)
   430  						copy(codeByte[jmpOff:], x86code)
   431  						binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
   432  						binary.LittleEndian.PutUint32(codeByte[jmpOff+6:], uint32(symAddrs[loc.SymOff]+loc.Add))
   433  						jmpOff += len(x86code)
   434  					} else if rb[0] == leacode || rb[0] == movcode {
   435  						offset = (base + jmpOff) - (addrBase + loc.Offset + loc.Size)
   436  						binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
   437  						rb[0] = movcode
   438  						binary.LittleEndian.PutUint32(codeByte[jmpOff:], uint32(symAddrs[loc.SymOff]+loc.Add))
   439  						jmpOff += 8
   440  					} else {
   441  						strWrite(&errBuf, "offset overflow sym:", sym.Name, "\n")
   442  						binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
   443  					}
   444  					continue
   445  				}
   446  				binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
   447  			case R_CALLARM, R_CALLARM64:
   448  				var add = loc.Add
   449  				var pcOff = 0
   450  				if loc.Type == R_CALLARM {
   451  					add = loc.Add & 0xffffff
   452  					if add > 256 {
   453  						add = 0
   454  					} else {
   455  						add += 2
   456  					}
   457  					pcOff = 8
   458  				}
   459  				offset = (symAddrs[loc.SymOff] - (base + loc.Offset + pcOff) + add) / 4
   460  				if offset > 0x7fffff || offset < -0x7fffff {
   461  					if jmpOff+4 > codeLen {
   462  						strWrite(&errBuf, "len overflow", "sym:", sym.Name, "\n")
   463  						continue
   464  					}
   465  					align := jmpOff % 4
   466  					if align != 0 {
   467  						jmpOff += (4 - align)
   468  					}
   469  					offset = (jmpOff - (loc.Offset + pcOff)) / 4
   470  					var v = uint32(offset)
   471  					b := code.Code[loc.Offset:]
   472  					b[0] = byte(v)
   473  					b[1] = byte(v >> 8)
   474  					b[2] = byte(v >> 16)
   475  					var jmpLocOff = 0
   476  					var jmpLen = 0
   477  					if loc.Type == R_CALLARM64 {
   478  						copy(codeByte[jmpOff:], arm64code)
   479  						jmpLen = len(arm64code)
   480  						jmpLocOff = 8
   481  					} else {
   482  						copy(codeByte[jmpOff:], armcode)
   483  						jmpLen = len(armcode)
   484  						jmpLocOff = 4
   485  					}
   486  					*(*uintptr)(unsafe.Pointer(&(codeByte[jmpOff+jmpLocOff:][0]))) = uintptr(symAddrs[loc.SymOff] + add*4)
   487  					jmpOff += jmpLen
   488  					continue
   489  				}
   490  				var v = uint32(offset)
   491  				b := code.Code[loc.Offset:]
   492  				b[0] = byte(v)
   493  				b[1] = byte(v >> 8)
   494  				b[2] = byte(v >> 16)
   495  			case R_ADDRARM64:
   496  				if curSym.Kind != STEXT {
   497  					strWrite(&errBuf, "not in code?\n")
   498  				}
   499  				relocADRP(code.Code[loc.Offset:], base+loc.Offset, symAddrs[loc.SymOff], sym.Name)
   500  			case R_ADDR:
   501  				var relocByte = code.Data
   502  				if curSym.Kind == STEXT {
   503  					relocByte = code.Code
   504  				}
   505  				offset = symAddrs[loc.SymOff] + loc.Add
   506  				*(*uintptr)(unsafe.Pointer(&(relocByte[loc.Offset:][0]))) = uintptr(offset)
   507  			case R_CALLIND:
   508  
   509  			case R_ADDROFF, R_WEAKADDROFF, R_METHODOFF:
   510  				var relocByte = code.Data
   511  				var addrBase = base
   512  				if curSym.Kind == STEXT {
   513  					strWrite(&errBuf, "impossible!", sym.Name, "locate on code segment", "\n")
   514  				}
   515  				offset = symAddrs[loc.SymOff] - addrBase + loc.Add
   516  				binary.LittleEndian.PutUint32(relocByte[loc.Offset:], uint32(offset))
   517  			default:
   518  				strWrite(&errBuf, "unknown reloc type:", strconv.Itoa(loc.Type), sym.Name, "\n")
   519  			}
   520  
   521  		}
   522  	}
   523  
   524  	var module moduledata
   525  	module.ftab = make([]functab, len(code.Mod.ftab))
   526  	copy(module.ftab, code.Mod.ftab)
   527  	pclnOff := len(code.Mod.pclntable)
   528  	module.pclntable = make([]byte, len(code.Mod.pclntable)+
   529  		(_funcSize+100)*len(code.Mod.ftab))
   530  	copy(module.pclntable, code.Mod.pclntable)
   531  	module.findfunctab = (uintptr)(unsafe.Pointer(&code.Mod.pcfunc[0]))
   532  	module.minpc = (uintptr)(unsafe.Pointer(&codeByte[0]))
   533  	module.maxpc = (uintptr)(unsafe.Pointer(&codeByte[len(code.Code)-1])) + 2
   534  	module.filetab = code.Mod.filetab
   535  	module.typemap = codeModule.typemap
   536  	module.types = uintptr(base)
   537  	module.etypes = uintptr(base + codeLen)
   538  	module.text = uintptr(base)
   539  	module.etext = uintptr(base + len(code.Code))
   540  	codeModule.pcfuncdata = code.Mod.pcfunc // hold reference
   541  	codeModule.stkmaps = code.Mod.stkmaps
   542  	for i := range module.ftab {
   543  		if i == 0 {
   544  			continue
   545  		}
   546  
   547  		module.ftab[i].entry = uintptr(symAddrs[int(code.Mod.ftab[i].entry)])
   548  
   549  		ptr2 := (uintptr)(unsafe.Pointer(&module.pclntable[pclnOff]))
   550  		if PtrSize == 8 && ptr2&4 != 0 {
   551  			pclnOff += 4
   552  		}
   553  		module.ftab[i].funcoff = uintptr(pclnOff)
   554  		fi := code.Mod.funcinfo[i-1]
   555  		fi.entry = module.ftab[i].entry
   556  		copy2Slice(module.pclntable[pclnOff:],
   557  			unsafe.Pointer(&fi._func), _funcSize)
   558  		pclnOff += _funcSize
   559  
   560  		if len(fi.pcdata) > 0 {
   561  			size := int(4 * fi.npcdata)
   562  			copy2Slice(module.pclntable[pclnOff:],
   563  				unsafe.Pointer(&fi.pcdata[0]), size)
   564  			pclnOff += size
   565  		}
   566  
   567  		var funcdata = make([]uintptr, len(fi.funcdata))
   568  		copy(funcdata, fi.funcdata)
   569  		for i, v := range funcdata {
   570  			funcdata[i] = (uintptr)(unsafe.Pointer(&(code.Mod.stkmaps[v][0])))
   571  		}
   572  		ptr := (uintptr)(unsafe.Pointer(&module.pclntable[pclnOff-1])) + 1
   573  		if PtrSize == 8 && ptr&4 != 0 {
   574  			t := [4]byte{}
   575  			copy(module.pclntable[pclnOff:], t[:])
   576  			pclnOff += len(t)
   577  		}
   578  		funcDataSize := int(PtrSize * fi.nfuncdata)
   579  		copy2Slice(module.pclntable[pclnOff:],
   580  			unsafe.Pointer(&funcdata[0]), funcDataSize)
   581  		pclnOff += funcDataSize
   582  
   583  	}
   584  	module.pclntable = module.pclntable[:pclnOff]
   585  	if len(module.ftab) >= 2 {
   586  		module.ftab[0] = module.ftab[1]
   587  	}
   588  
   589  	modulesLock.Lock()
   590  	addModule(&codeModule, &module, runtime.Version())
   591  	modulesLock.Unlock()
   592  
   593  	copy(codeByte, code.Code)
   594  	copy(codeByte[len(code.Code):], code.Data)
   595  	codeModule.CodeByte = codeByte
   596  
   597  	for i := range codeModule.itabSyms {
   598  		it := &codeModule.itabSyms[i]
   599  		if it.inter == -1 || it._type == -1 {
   600  			continue
   601  		}
   602  		it.ptr = getitab(it.inter, it._type, false)
   603  	}
   604  	for _, it := range codeModule.itabs {
   605  		symAddr := codeModule.itabSyms[it.symOff].ptr
   606  		if symAddr == 0 {
   607  			continue
   608  		}
   609  		switch it.locType {
   610  		case R_PCREL:
   611  			pc := base + it.locOff + it.size
   612  			offset := symAddr - pc + it.add
   613  			if offset > 2147483647 || offset < -2147483647 {
   614  				offset = (base + jmpOff) - pc + it.add
   615  				binary.LittleEndian.PutUint32(codeByte[it.locOff:], uint32(offset))
   616  				codeByte[it.locOff-2:][0] = movcode
   617  				*(*uintptr)(unsafe.Pointer(&(codeByte[jmpOff:][0]))) = uintptr(symAddr)
   618  				jmpOff += PtrSize
   619  				continue
   620  			}
   621  			binary.LittleEndian.PutUint32(codeByte[it.locOff:], uint32(offset))
   622  		case R_ADDRARM64:
   623  			relocADRP(codeByte[it.locOff:], base+it.locOff, symAddr, "unknown")
   624  		}
   625  	}
   626  
   627  	if errBuf.Len() > 0 {
   628  		return &codeModule, errors.New(errBuf.String())
   629  	}
   630  	return &codeModule, nil
   631  }
   632  
   633  func relocADRP(mCode []byte, pc int, symAddr int, symName string) {
   634  	pcPage := pc - pc&0xfff
   635  	lowOff := symAddr & 0xfff
   636  	symPage := symAddr - lowOff
   637  	pageOff := symPage - pcPage
   638  	if pageOff > 1<<31 || pageOff < -1<<31 {
   639  		// fmt.Println("adrp overflow!", symName, symAddr, symAddr < (1<<31))
   640  		movlow := binary.LittleEndian.Uint32(mov32bit[:4])
   641  		movhigh := binary.LittleEndian.Uint32(mov32bit[4:])
   642  		adrp := binary.LittleEndian.Uint32(mCode)
   643  		symAddrUint32 := uint32(symAddr)
   644  		movlow = (((adrp & 0x1f) | movlow) | ((symAddrUint32 & 0xffff) << 5))
   645  		movhigh = (((adrp & 0x1f) | movhigh) | ((symAddrUint32 & 0xffff0000) >> 16 << 5))
   646  		// fmt.Println(adrp, movlow, movhigh)
   647  		binary.LittleEndian.PutUint32(mCode, movlow)
   648  		binary.LittleEndian.PutUint32(mCode[4:], movhigh)
   649  		return
   650  	}
   651  	fmt.Println("pageOff<0:", pageOff < 0)
   652  	// 2bit + 19bit + low(12bit) = 33bit
   653  	pageAnd := (uint32((pageOff>>12)&3) << 29) | (uint32((pageOff>>15)&0x7ffff) << 5)
   654  
   655  	adrp := binary.LittleEndian.Uint32(mCode)
   656  	adrp = adrp | pageAnd
   657  	binary.LittleEndian.PutUint32(mCode, adrp)
   658  
   659  	lowOff = lowOff << 10
   660  	adrpAdd := binary.LittleEndian.Uint32(mCode[4:])
   661  	adrpAdd = adrpAdd | uint32(lowOff)
   662  	binary.LittleEndian.PutUint32(mCode[4:], adrpAdd)
   663  }
   664  
   665  func copy2Slice(dst []byte, src unsafe.Pointer, size int) {
   666  	var s = sliceHeader{
   667  		Data: (uintptr)(src),
   668  		Len:  size,
   669  		Cap:  size,
   670  	}
   671  	copy(dst, *(*[]byte)(unsafe.Pointer(&s)))
   672  }
   673  
   674  func (cm *CodeModule) Unload() {
   675  	runtime.GC()
   676  	modulesLock.Lock()
   677  	removeModule(cm.Module, runtime.Version())
   678  	modulesLock.Unlock()
   679  	Munmap(cm.CodeByte)
   680  }