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