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 }