github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/loadmacho/ldmacho.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package loadmacho implements a Mach-O file reader. 6 package loadmacho 7 8 import ( 9 "bytes" 10 "github.com/bir3/gocompiler/src/cmd/internal/bio" 11 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 12 "github.com/bir3/gocompiler/src/cmd/internal/sys" 13 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 14 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 15 "encoding/binary" 16 "fmt" 17 ) 18 19 /* 20 Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c 21 https://github.com/9fans/plan9port/tree/master/src/libmach/ 22 23 Copyright © 2004 Russ Cox. 24 Portions Copyright © 2008-2010 Google Inc. 25 Portions Copyright © 2010 The Go Authors. 26 27 Permission is hereby granted, free of charge, to any person obtaining a copy 28 of this software and associated documentation files (the "Software"), to deal 29 in the Software without restriction, including without limitation the rights 30 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31 copies of the Software, and to permit persons to whom the Software is 32 furnished to do so, subject to the following conditions: 33 34 The above copyright notice and this permission notice shall be included in 35 all copies or substantial portions of the Software. 36 37 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 40 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 43 THE SOFTWARE. 44 */ 45 46 // TODO(crawshaw): de-duplicate these symbols with cmd/link/internal/ld 47 const ( 48 MACHO_X86_64_RELOC_UNSIGNED = 0 49 MACHO_X86_64_RELOC_SIGNED = 1 50 MACHO_ARM64_RELOC_ADDEND = 10 51 ) 52 53 type ldMachoObj struct { 54 f *bio.Reader 55 base int64 // off in f where Mach-O begins 56 length int64 // length of Mach-O 57 is64 bool 58 name string 59 e binary.ByteOrder 60 cputype uint 61 subcputype uint 62 filetype uint32 63 flags uint32 64 cmd []ldMachoCmd 65 ncmd uint 66 } 67 68 type ldMachoCmd struct { 69 type_ int 70 off uint32 71 size uint32 72 seg ldMachoSeg 73 sym ldMachoSymtab 74 dsym ldMachoDysymtab 75 } 76 77 type ldMachoSeg struct { 78 name string 79 vmaddr uint64 80 vmsize uint64 81 fileoff uint32 82 filesz uint32 83 maxprot uint32 84 initprot uint32 85 nsect uint32 86 flags uint32 87 sect []ldMachoSect 88 } 89 90 type ldMachoSect struct { 91 name string 92 segname string 93 addr uint64 94 size uint64 95 off uint32 96 align uint32 97 reloff uint32 98 nreloc uint32 99 flags uint32 100 res1 uint32 101 res2 uint32 102 sym loader.Sym 103 rel []ldMachoRel 104 } 105 106 type ldMachoRel struct { 107 addr uint32 108 symnum uint32 109 pcrel uint8 110 length uint8 111 extrn uint8 112 type_ uint8 113 scattered uint8 114 value uint32 115 } 116 117 type ldMachoSymtab struct { 118 symoff uint32 119 nsym uint32 120 stroff uint32 121 strsize uint32 122 str []byte 123 sym []ldMachoSym 124 } 125 126 type ldMachoSym struct { 127 name string 128 type_ uint8 129 sectnum uint8 130 desc uint16 131 kind int8 132 value uint64 133 sym loader.Sym 134 } 135 136 type ldMachoDysymtab struct { 137 ilocalsym uint32 138 nlocalsym uint32 139 iextdefsym uint32 140 nextdefsym uint32 141 iundefsym uint32 142 nundefsym uint32 143 tocoff uint32 144 ntoc uint32 145 modtaboff uint32 146 nmodtab uint32 147 extrefsymoff uint32 148 nextrefsyms uint32 149 indirectsymoff uint32 150 nindirectsyms uint32 151 extreloff uint32 152 nextrel uint32 153 locreloff uint32 154 nlocrel uint32 155 indir []uint32 156 } 157 158 // ldMachoSym.type_ 159 const ( 160 N_EXT = 0x01 161 N_TYPE = 0x1e 162 N_STAB = 0xe0 163 ) 164 165 // ldMachoSym.desc 166 const ( 167 N_WEAK_REF = 0x40 168 N_WEAK_DEF = 0x80 169 ) 170 171 const ( 172 LdMachoCpuVax = 1 173 LdMachoCpu68000 = 6 174 LdMachoCpu386 = 7 175 LdMachoCpuAmd64 = 1<<24 | 7 176 LdMachoCpuMips = 8 177 LdMachoCpu98000 = 10 178 LdMachoCpuHppa = 11 179 LdMachoCpuArm = 12 180 LdMachoCpuArm64 = 1<<24 | 12 181 LdMachoCpu88000 = 13 182 LdMachoCpuSparc = 14 183 LdMachoCpu860 = 15 184 LdMachoCpuAlpha = 16 185 LdMachoCpuPower = 18 186 LdMachoCmdSegment = 1 187 LdMachoCmdSymtab = 2 188 LdMachoCmdSymseg = 3 189 LdMachoCmdThread = 4 190 LdMachoCmdDysymtab = 11 191 LdMachoCmdSegment64 = 25 192 LdMachoFileObject = 1 193 LdMachoFileExecutable = 2 194 LdMachoFileFvmlib = 3 195 LdMachoFileCore = 4 196 LdMachoFilePreload = 5 197 ) 198 199 func unpackcmd(p []byte, m *ldMachoObj, c *ldMachoCmd, type_ uint, sz uint) int { 200 e4 := m.e.Uint32 201 e8 := m.e.Uint64 202 203 c.type_ = int(type_) 204 c.size = uint32(sz) 205 switch type_ { 206 default: 207 return -1 208 209 case LdMachoCmdSegment: 210 if sz < 56 { 211 return -1 212 } 213 c.seg.name = cstring(p[8:24]) 214 c.seg.vmaddr = uint64(e4(p[24:])) 215 c.seg.vmsize = uint64(e4(p[28:])) 216 c.seg.fileoff = e4(p[32:]) 217 c.seg.filesz = e4(p[36:]) 218 c.seg.maxprot = e4(p[40:]) 219 c.seg.initprot = e4(p[44:]) 220 c.seg.nsect = e4(p[48:]) 221 c.seg.flags = e4(p[52:]) 222 c.seg.sect = make([]ldMachoSect, c.seg.nsect) 223 if uint32(sz) < 56+c.seg.nsect*68 { 224 return -1 225 } 226 p = p[56:] 227 var s *ldMachoSect 228 for i := 0; uint32(i) < c.seg.nsect; i++ { 229 s = &c.seg.sect[i] 230 s.name = cstring(p[0:16]) 231 s.segname = cstring(p[16:32]) 232 s.addr = uint64(e4(p[32:])) 233 s.size = uint64(e4(p[36:])) 234 s.off = e4(p[40:]) 235 s.align = e4(p[44:]) 236 s.reloff = e4(p[48:]) 237 s.nreloc = e4(p[52:]) 238 s.flags = e4(p[56:]) 239 s.res1 = e4(p[60:]) 240 s.res2 = e4(p[64:]) 241 p = p[68:] 242 } 243 244 case LdMachoCmdSegment64: 245 if sz < 72 { 246 return -1 247 } 248 c.seg.name = cstring(p[8:24]) 249 c.seg.vmaddr = e8(p[24:]) 250 c.seg.vmsize = e8(p[32:]) 251 c.seg.fileoff = uint32(e8(p[40:])) 252 c.seg.filesz = uint32(e8(p[48:])) 253 c.seg.maxprot = e4(p[56:]) 254 c.seg.initprot = e4(p[60:]) 255 c.seg.nsect = e4(p[64:]) 256 c.seg.flags = e4(p[68:]) 257 c.seg.sect = make([]ldMachoSect, c.seg.nsect) 258 if uint32(sz) < 72+c.seg.nsect*80 { 259 return -1 260 } 261 p = p[72:] 262 var s *ldMachoSect 263 for i := 0; uint32(i) < c.seg.nsect; i++ { 264 s = &c.seg.sect[i] 265 s.name = cstring(p[0:16]) 266 s.segname = cstring(p[16:32]) 267 s.addr = e8(p[32:]) 268 s.size = e8(p[40:]) 269 s.off = e4(p[48:]) 270 s.align = e4(p[52:]) 271 s.reloff = e4(p[56:]) 272 s.nreloc = e4(p[60:]) 273 s.flags = e4(p[64:]) 274 s.res1 = e4(p[68:]) 275 s.res2 = e4(p[72:]) 276 277 // p+76 is reserved 278 p = p[80:] 279 } 280 281 case LdMachoCmdSymtab: 282 if sz < 24 { 283 return -1 284 } 285 c.sym.symoff = e4(p[8:]) 286 c.sym.nsym = e4(p[12:]) 287 c.sym.stroff = e4(p[16:]) 288 c.sym.strsize = e4(p[20:]) 289 290 case LdMachoCmdDysymtab: 291 if sz < 80 { 292 return -1 293 } 294 c.dsym.ilocalsym = e4(p[8:]) 295 c.dsym.nlocalsym = e4(p[12:]) 296 c.dsym.iextdefsym = e4(p[16:]) 297 c.dsym.nextdefsym = e4(p[20:]) 298 c.dsym.iundefsym = e4(p[24:]) 299 c.dsym.nundefsym = e4(p[28:]) 300 c.dsym.tocoff = e4(p[32:]) 301 c.dsym.ntoc = e4(p[36:]) 302 c.dsym.modtaboff = e4(p[40:]) 303 c.dsym.nmodtab = e4(p[44:]) 304 c.dsym.extrefsymoff = e4(p[48:]) 305 c.dsym.nextrefsyms = e4(p[52:]) 306 c.dsym.indirectsymoff = e4(p[56:]) 307 c.dsym.nindirectsyms = e4(p[60:]) 308 c.dsym.extreloff = e4(p[64:]) 309 c.dsym.nextrel = e4(p[68:]) 310 c.dsym.locreloff = e4(p[72:]) 311 c.dsym.nlocrel = e4(p[76:]) 312 } 313 314 return 0 315 } 316 317 func macholoadrel(m *ldMachoObj, sect *ldMachoSect) int { 318 if sect.rel != nil || sect.nreloc == 0 { 319 return 0 320 } 321 rel := make([]ldMachoRel, sect.nreloc) 322 m.f.MustSeek(m.base+int64(sect.reloff), 0) 323 buf, _, err := m.f.Slice(uint64(sect.nreloc * 8)) 324 if err != nil { 325 return -1 326 } 327 for i := uint32(0); i < sect.nreloc; i++ { 328 r := &rel[i] 329 p := buf[i*8:] 330 r.addr = m.e.Uint32(p) 331 332 // TODO(rsc): Wrong interpretation for big-endian bitfields? 333 if r.addr&0x80000000 != 0 { 334 // scatterbrained relocation 335 r.scattered = 1 336 337 v := r.addr >> 24 338 r.addr &= 0xFFFFFF 339 r.type_ = uint8(v & 0xF) 340 v >>= 4 341 r.length = 1 << (v & 3) 342 v >>= 2 343 r.pcrel = uint8(v & 1) 344 r.value = m.e.Uint32(p[4:]) 345 } else { 346 v := m.e.Uint32(p[4:]) 347 r.symnum = v & 0xFFFFFF 348 v >>= 24 349 r.pcrel = uint8(v & 1) 350 v >>= 1 351 r.length = 1 << (v & 3) 352 v >>= 2 353 r.extrn = uint8(v & 1) 354 v >>= 1 355 r.type_ = uint8(v) 356 } 357 } 358 359 sect.rel = rel 360 return 0 361 } 362 363 func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int { 364 n := int(d.nindirectsyms) 365 m.f.MustSeek(m.base+int64(d.indirectsymoff), 0) 366 p, _, err := m.f.Slice(uint64(n * 4)) 367 if err != nil { 368 return -1 369 } 370 371 d.indir = make([]uint32, n) 372 for i := 0; i < n; i++ { 373 d.indir[i] = m.e.Uint32(p[4*i:]) 374 } 375 return 0 376 } 377 378 func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int { 379 if symtab.sym != nil { 380 return 0 381 } 382 383 m.f.MustSeek(m.base+int64(symtab.stroff), 0) 384 strbuf, _, err := m.f.Slice(uint64(symtab.strsize)) 385 if err != nil { 386 return -1 387 } 388 389 symsize := 12 390 if m.is64 { 391 symsize = 16 392 } 393 n := int(symtab.nsym * uint32(symsize)) 394 m.f.MustSeek(m.base+int64(symtab.symoff), 0) 395 symbuf, _, err := m.f.Slice(uint64(n)) 396 if err != nil { 397 return -1 398 } 399 sym := make([]ldMachoSym, symtab.nsym) 400 p := symbuf 401 for i := uint32(0); i < symtab.nsym; i++ { 402 s := &sym[i] 403 v := m.e.Uint32(p) 404 if v >= symtab.strsize { 405 return -1 406 } 407 s.name = cstring(strbuf[v:]) 408 s.type_ = p[4] 409 s.sectnum = p[5] 410 s.desc = m.e.Uint16(p[6:]) 411 if m.is64 { 412 s.value = m.e.Uint64(p[8:]) 413 } else { 414 s.value = uint64(m.e.Uint32(p[8:])) 415 } 416 p = p[symsize:] 417 } 418 419 symtab.str = strbuf 420 symtab.sym = sym 421 return 0 422 } 423 424 // Load the Mach-O file pn from f. 425 // Symbols are written into syms, and a slice of the text symbols is returned. 426 func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, err error) { 427 errorf := func(str string, args ...interface{}) ([]loader.Sym, error) { 428 return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...)) 429 } 430 431 base := f.Offset() 432 433 hdr, _, err := f.Slice(7 * 4) 434 if err != nil { 435 return errorf("reading hdr: %v", err) 436 } 437 438 var e binary.ByteOrder 439 if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { 440 e = binary.BigEndian 441 } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { 442 e = binary.LittleEndian 443 } else { 444 return errorf("bad magic - not mach-o file") 445 } 446 447 is64 := e.Uint32(hdr[:]) == 0xFEEDFACF 448 ncmd := e.Uint32(hdr[4*4:]) 449 cmdsz := e.Uint32(hdr[5*4:]) 450 if ncmd > 0x10000 || cmdsz >= 0x01000000 { 451 return errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz) 452 } 453 454 if is64 { 455 f.MustSeek(4, 1) // skip reserved word in header 456 } 457 458 m := &ldMachoObj{ 459 f: f, 460 e: e, 461 cputype: uint(e.Uint32(hdr[1*4:])), 462 subcputype: uint(e.Uint32(hdr[2*4:])), 463 filetype: e.Uint32(hdr[3*4:]), 464 ncmd: uint(ncmd), 465 flags: e.Uint32(hdr[6*4:]), 466 is64: is64, 467 base: base, 468 length: length, 469 name: pn, 470 } 471 472 switch arch.Family { 473 default: 474 return errorf("mach-o %s unimplemented", arch.Name) 475 case sys.AMD64: 476 if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 { 477 return errorf("mach-o object but not amd64") 478 } 479 case sys.ARM64: 480 if e != binary.LittleEndian || m.cputype != LdMachoCpuArm64 { 481 return errorf("mach-o object but not arm64") 482 } 483 } 484 485 m.cmd = make([]ldMachoCmd, ncmd) 486 cmdp, _, err := f.Slice(uint64(cmdsz)) 487 if err != nil { 488 return errorf("reading cmds: %v", err) 489 } 490 491 // read and parse load commands 492 var c *ldMachoCmd 493 494 var symtab *ldMachoSymtab 495 var dsymtab *ldMachoDysymtab 496 497 off := uint32(len(hdr)) 498 for i := uint32(0); i < ncmd; i++ { 499 ty := e.Uint32(cmdp) 500 sz := e.Uint32(cmdp[4:]) 501 m.cmd[i].off = off 502 unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz)) 503 cmdp = cmdp[sz:] 504 off += sz 505 if ty == LdMachoCmdSymtab { 506 if symtab != nil { 507 return errorf("multiple symbol tables") 508 } 509 510 symtab = &m.cmd[i].sym 511 macholoadsym(m, symtab) 512 } 513 514 if ty == LdMachoCmdDysymtab { 515 dsymtab = &m.cmd[i].dsym 516 macholoaddsym(m, dsymtab) 517 } 518 519 if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) { 520 if c != nil { 521 return errorf("multiple load commands") 522 } 523 524 c = &m.cmd[i] 525 } 526 } 527 528 // load text and data segments into memory. 529 // they are not as small as the load commands, but we'll need 530 // the memory anyway for the symbol images, so we might 531 // as well use one large chunk. 532 if c == nil { 533 return errorf("no load command") 534 } 535 536 if symtab == nil { 537 // our work is done here - no symbols means nothing can refer to this file 538 return 539 } 540 541 if int64(c.seg.fileoff+c.seg.filesz) >= length { 542 return errorf("load segment out of range") 543 } 544 545 f.MustSeek(m.base+int64(c.seg.fileoff), 0) 546 dat, readOnly, err := f.Slice(uint64(c.seg.filesz)) 547 if err != nil { 548 return errorf("cannot load object data: %v", err) 549 } 550 551 for i := uint32(0); i < c.seg.nsect; i++ { 552 sect := &c.seg.sect[i] 553 if sect.segname != "__TEXT" && sect.segname != "__DATA" { 554 continue 555 } 556 if sect.name == "__eh_frame" { 557 continue 558 } 559 name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name) 560 s := l.LookupOrCreateSym(name, localSymVersion) 561 bld := l.MakeSymbolUpdater(s) 562 if bld.Type() != 0 { 563 return errorf("duplicate %s/%s", sect.segname, sect.name) 564 } 565 566 if sect.flags&0xff == 1 { // S_ZEROFILL 567 bld.SetData(make([]byte, sect.size)) 568 } else { 569 bld.SetReadOnly(readOnly) 570 bld.SetData(dat[sect.addr-c.seg.vmaddr:][:sect.size]) 571 } 572 bld.SetSize(int64(len(bld.Data()))) 573 574 if sect.segname == "__TEXT" { 575 if sect.name == "__text" { 576 bld.SetType(sym.STEXT) 577 } else { 578 bld.SetType(sym.SRODATA) 579 } 580 } else { 581 if sect.name == "__bss" { 582 bld.SetType(sym.SNOPTRBSS) 583 bld.SetData(nil) 584 } else { 585 bld.SetType(sym.SNOPTRDATA) 586 } 587 } 588 589 sect.sym = s 590 } 591 592 // enter sub-symbols into symbol table. 593 // have to guess sizes from next symbol. 594 for i := uint32(0); i < symtab.nsym; i++ { 595 machsym := &symtab.sym[i] 596 if machsym.type_&N_STAB != 0 { 597 continue 598 } 599 600 // TODO: check sym->type against outer->type. 601 name := machsym.name 602 603 if name[0] == '_' && name[1] != '\x00' { 604 name = name[1:] 605 } 606 v := 0 607 if machsym.type_&N_EXT == 0 { 608 v = localSymVersion 609 } 610 s := l.LookupOrCreateCgoExport(name, v) 611 if machsym.type_&N_EXT == 0 { 612 l.SetAttrDuplicateOK(s, true) 613 } 614 if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 { 615 l.SetAttrDuplicateOK(s, true) 616 } 617 machsym.sym = s 618 if machsym.sectnum == 0 { // undefined 619 continue 620 } 621 if uint32(machsym.sectnum) > c.seg.nsect { 622 return errorf("reference to invalid section %d", machsym.sectnum) 623 } 624 625 sect := &c.seg.sect[machsym.sectnum-1] 626 bld := l.MakeSymbolUpdater(s) 627 outer := sect.sym 628 if outer == 0 { 629 continue // ignore reference to invalid section 630 } 631 632 if osym := l.OuterSym(s); osym != 0 { 633 if l.AttrDuplicateOK(s) { 634 continue 635 } 636 return errorf("duplicate symbol reference: %s in both %s and %s", l.SymName(s), l.SymName(osym), l.SymName(sect.sym)) 637 } 638 639 bld.SetType(l.SymType(outer)) 640 if l.SymSize(outer) != 0 { // skip empty section (0-sized symbol) 641 l.AddInteriorSym(outer, s) 642 } 643 644 bld.SetValue(int64(machsym.value - sect.addr)) 645 if !l.AttrCgoExportDynamic(s) { 646 bld.SetDynimplib("") // satisfy dynimport 647 } 648 if l.SymType(outer) == sym.STEXT { 649 if bld.External() && !bld.DuplicateOK() { 650 return errorf("%v: duplicate symbol definition", s) 651 } 652 bld.SetExternal(true) 653 } 654 } 655 656 // Sort outer lists by address, adding to textp. 657 // This keeps textp in increasing address order. 658 for i := 0; uint32(i) < c.seg.nsect; i++ { 659 sect := &c.seg.sect[i] 660 s := sect.sym 661 if s == 0 { 662 continue 663 } 664 bld := l.MakeSymbolUpdater(s) 665 if bld.SubSym() != 0 { 666 667 bld.SortSub() 668 669 // assign sizes, now that we know symbols in sorted order. 670 for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) { 671 s1Bld := l.MakeSymbolUpdater(s1) 672 if sub := l.SubSym(s1); sub != 0 { 673 s1Bld.SetSize(l.SymValue(sub) - l.SymValue(s1)) 674 } else { 675 dlen := int64(len(l.Data(s))) 676 s1Bld.SetSize(l.SymValue(s) + dlen - l.SymValue(s1)) 677 } 678 } 679 } 680 681 if bld.Type() == sym.STEXT { 682 if bld.OnList() { 683 return errorf("symbol %s listed multiple times", bld.Name()) 684 } 685 bld.SetOnList(true) 686 textp = append(textp, s) 687 for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) { 688 if l.AttrOnList(s1) { 689 return errorf("symbol %s listed multiple times", l.SymName(s1)) 690 } 691 l.SetAttrOnList(s1, true) 692 textp = append(textp, s1) 693 } 694 } 695 } 696 697 // load relocations 698 for i := 0; uint32(i) < c.seg.nsect; i++ { 699 sect := &c.seg.sect[i] 700 s := sect.sym 701 if s == 0 { 702 continue 703 } 704 macholoadrel(m, sect) 705 if sect.rel == nil { 706 continue 707 } 708 709 sb := l.MakeSymbolUpdater(sect.sym) 710 var rAdd int64 711 for j := uint32(0); j < sect.nreloc; j++ { 712 var ( 713 rOff int32 714 rSize uint8 715 rType objabi.RelocType 716 rSym loader.Sym 717 ) 718 rel := §.rel[j] 719 if rel.scattered != 0 { 720 // mach-o only uses scattered relocation on 32-bit platforms, 721 // which are no longer supported. 722 return errorf("%v: unexpected scattered relocation", s) 723 } 724 725 if arch.Family == sys.ARM64 && rel.type_ == MACHO_ARM64_RELOC_ADDEND { 726 // Two relocations. This addend will be applied to the next one. 727 rAdd = int64(rel.symnum) << 40 >> 40 // convert unsigned 24-bit to signed 24-bit 728 continue 729 } 730 731 rSize = rel.length 732 rType = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel) 733 rOff = int32(rel.addr) 734 735 // Handle X86_64_RELOC_SIGNED referencing a section (rel.extrn == 0). 736 p := l.Data(s) 737 if arch.Family == sys.AMD64 { 738 if rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED { 739 // Calculate the addend as the offset into the section. 740 // 741 // The rip-relative offset stored in the object file is encoded 742 // as follows: 743 // 744 // movsd 0x00000360(%rip),%xmm0 745 // 746 // To get the absolute address of the value this rip-relative address is pointing 747 // to, we must add the address of the next instruction to it. This is done by 748 // taking the address of the relocation and adding 4 to it (since the rip-relative 749 // offset can at most be 32 bits long). To calculate the offset into the section the 750 // relocation is referencing, we subtract the vaddr of the start of the referenced 751 // section found in the original object file. 752 // 753 // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] 754 secaddr := c.seg.sect[rel.symnum-1].addr 755 rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr) 756 } else { 757 rAdd = int64(int32(e.Uint32(p[rOff:]))) 758 } 759 } 760 761 // An unsigned internal relocation has a value offset 762 // by the section address. 763 if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED { 764 secaddr := c.seg.sect[rel.symnum-1].addr 765 rAdd -= int64(secaddr) 766 } 767 768 if rel.extrn == 0 { 769 if rel.symnum < 1 || rel.symnum > c.seg.nsect { 770 return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect) 771 } 772 773 rSym = c.seg.sect[rel.symnum-1].sym 774 if rSym == 0 { 775 return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name) 776 } 777 } else { 778 if rel.symnum >= symtab.nsym { 779 return errorf("invalid relocation: symbol reference out of range") 780 } 781 782 rSym = symtab.sym[rel.symnum].sym 783 } 784 785 r, _ := sb.AddRel(rType) 786 r.SetOff(rOff) 787 r.SetSiz(rSize) 788 r.SetSym(rSym) 789 r.SetAdd(rAdd) 790 791 rAdd = 0 // clear rAdd for next iteration 792 } 793 794 sb.SortRelocs() 795 } 796 797 return textp, nil 798 } 799 800 func cstring(x []byte) string { 801 i := bytes.IndexByte(x, '\x00') 802 if i >= 0 { 803 x = x[:i] 804 } 805 return string(x) 806 }