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