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