1 package ld 2 3 import ( 4 "cmd/internal/obj" 5 "encoding/binary" 6 "fmt" 7 "log" 8 "sort" 9 ) 10 11 /* 12 Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c 13 http://code.swtch.com/plan9port/src/tip/src/libmach/ 14 15 Copyright 2004 Russ Cox. 16 Portions Copyright 2008-2010 Google Inc. 17 Portions Copyright 2010 The Go Authors. 18 19 Permission is hereby granted, free of charge, to any person obtaining a copy 20 of this software and associated documentation files (the "Software"), to deal 21 in the Software without restriction, including without limitation the rights 22 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 copies of the Software, and to permit persons to whom the Software is 24 furnished to do so, subject to the following conditions: 25 26 The above copyright notice and this permission notice shall be included in 27 all copies or substantial portions of the Software. 28 29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 THE SOFTWARE. 36 */ 37 const ( 38 N_EXT = 0x01 39 N_TYPE = 0x1e 40 N_STAB = 0xe0 41 ) 42 43 type LdMachoObj struct { 44 f *obj.Biobuf 45 base int64 // off in f where Mach-O begins 46 length int64 // length of Mach-O 47 is64 bool 48 name string 49 e binary.ByteOrder 50 cputype uint 51 subcputype uint 52 filetype uint32 53 flags uint32 54 cmd []LdMachoCmd 55 ncmd uint 56 } 57 58 type LdMachoCmd struct { 59 type_ int 60 off uint32 61 size uint32 62 seg LdMachoSeg 63 sym LdMachoSymtab 64 dsym LdMachoDysymtab 65 } 66 67 type LdMachoSeg struct { 68 name string 69 vmaddr uint64 70 vmsize uint64 71 fileoff uint32 72 filesz uint32 73 maxprot uint32 74 initprot uint32 75 nsect uint32 76 flags uint32 77 sect []LdMachoSect 78 } 79 80 type LdMachoSect struct { 81 name string 82 segname string 83 addr uint64 84 size uint64 85 off uint32 86 align uint32 87 reloff uint32 88 nreloc uint32 89 flags uint32 90 res1 uint32 91 res2 uint32 92 sym *LSym 93 rel []LdMachoRel 94 } 95 96 type LdMachoRel struct { 97 addr uint32 98 symnum uint32 99 pcrel uint8 100 length uint8 101 extrn uint8 102 type_ uint8 103 scattered uint8 104 value uint32 105 } 106 107 type LdMachoSymtab struct { 108 symoff uint32 109 nsym uint32 110 stroff uint32 111 strsize uint32 112 str []byte 113 sym []LdMachoSym 114 } 115 116 type LdMachoSym struct { 117 name string 118 type_ uint8 119 sectnum uint8 120 desc uint16 121 kind int8 122 value uint64 123 sym *LSym 124 } 125 126 type LdMachoDysymtab struct { 127 ilocalsym uint32 128 nlocalsym uint32 129 iextdefsym uint32 130 nextdefsym uint32 131 iundefsym uint32 132 nundefsym uint32 133 tocoff uint32 134 ntoc uint32 135 modtaboff uint32 136 nmodtab uint32 137 extrefsymoff uint32 138 nextrefsyms uint32 139 indirectsymoff uint32 140 nindirectsyms uint32 141 extreloff uint32 142 nextrel uint32 143 locreloff uint32 144 nlocrel uint32 145 indir []uint32 146 } 147 148 const ( 149 LdMachoCpuVax = 1 150 LdMachoCpu68000 = 6 151 LdMachoCpu386 = 7 152 LdMachoCpuAmd64 = 0x1000007 153 LdMachoCpuMips = 8 154 LdMachoCpu98000 = 10 155 LdMachoCpuHppa = 11 156 LdMachoCpuArm = 12 157 LdMachoCpu88000 = 13 158 LdMachoCpuSparc = 14 159 LdMachoCpu860 = 15 160 LdMachoCpuAlpha = 16 161 LdMachoCpuPower = 18 162 LdMachoCmdSegment = 1 163 LdMachoCmdSymtab = 2 164 LdMachoCmdSymseg = 3 165 LdMachoCmdThread = 4 166 LdMachoCmdDysymtab = 11 167 LdMachoCmdSegment64 = 25 168 LdMachoFileObject = 1 169 LdMachoFileExecutable = 2 170 LdMachoFileFvmlib = 3 171 LdMachoFileCore = 4 172 LdMachoFilePreload = 5 173 ) 174 175 func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int { 176 e4 := m.e.Uint32 177 e8 := m.e.Uint64 178 179 c.type_ = int(type_) 180 c.size = uint32(sz) 181 switch type_ { 182 default: 183 return -1 184 185 case LdMachoCmdSegment: 186 if sz < 56 { 187 return -1 188 } 189 c.seg.name = cstring(p[8:24]) 190 c.seg.vmaddr = uint64(e4(p[24:])) 191 c.seg.vmsize = uint64(e4(p[28:])) 192 c.seg.fileoff = e4(p[32:]) 193 c.seg.filesz = e4(p[36:]) 194 c.seg.maxprot = e4(p[40:]) 195 c.seg.initprot = e4(p[44:]) 196 c.seg.nsect = e4(p[48:]) 197 c.seg.flags = e4(p[52:]) 198 c.seg.sect = make([]LdMachoSect, c.seg.nsect) 199 if uint32(sz) < 56+c.seg.nsect*68 { 200 return -1 201 } 202 p = p[56:] 203 var s *LdMachoSect 204 for i := 0; uint32(i) < c.seg.nsect; i++ { 205 s = &c.seg.sect[i] 206 s.name = cstring(p[0:16]) 207 s.segname = cstring(p[16:32]) 208 s.addr = uint64(e4(p[32:])) 209 s.size = uint64(e4(p[36:])) 210 s.off = e4(p[40:]) 211 s.align = e4(p[44:]) 212 s.reloff = e4(p[48:]) 213 s.nreloc = e4(p[52:]) 214 s.flags = e4(p[56:]) 215 s.res1 = e4(p[60:]) 216 s.res2 = e4(p[64:]) 217 p = p[68:] 218 } 219 220 case LdMachoCmdSegment64: 221 if sz < 72 { 222 return -1 223 } 224 c.seg.name = cstring(p[8:24]) 225 c.seg.vmaddr = e8(p[24:]) 226 c.seg.vmsize = e8(p[32:]) 227 c.seg.fileoff = uint32(e8(p[40:])) 228 c.seg.filesz = uint32(e8(p[48:])) 229 c.seg.maxprot = e4(p[56:]) 230 c.seg.initprot = e4(p[60:]) 231 c.seg.nsect = e4(p[64:]) 232 c.seg.flags = e4(p[68:]) 233 c.seg.sect = make([]LdMachoSect, c.seg.nsect) 234 if uint32(sz) < 72+c.seg.nsect*80 { 235 return -1 236 } 237 p = p[72:] 238 var s *LdMachoSect 239 for i := 0; uint32(i) < c.seg.nsect; i++ { 240 s = &c.seg.sect[i] 241 s.name = cstring(p[0:16]) 242 s.segname = cstring(p[16:32]) 243 s.addr = e8(p[32:]) 244 s.size = e8(p[40:]) 245 s.off = e4(p[48:]) 246 s.align = e4(p[52:]) 247 s.reloff = e4(p[56:]) 248 s.nreloc = e4(p[60:]) 249 s.flags = e4(p[64:]) 250 s.res1 = e4(p[68:]) 251 s.res2 = e4(p[72:]) 252 253 // p+76 is reserved 254 p = p[80:] 255 } 256 257 case LdMachoCmdSymtab: 258 if sz < 24 { 259 return -1 260 } 261 c.sym.symoff = e4(p[8:]) 262 c.sym.nsym = e4(p[12:]) 263 c.sym.stroff = e4(p[16:]) 264 c.sym.strsize = e4(p[20:]) 265 266 case LdMachoCmdDysymtab: 267 if sz < 80 { 268 return -1 269 } 270 c.dsym.ilocalsym = e4(p[8:]) 271 c.dsym.nlocalsym = e4(p[12:]) 272 c.dsym.iextdefsym = e4(p[16:]) 273 c.dsym.nextdefsym = e4(p[20:]) 274 c.dsym.iundefsym = e4(p[24:]) 275 c.dsym.nundefsym = e4(p[28:]) 276 c.dsym.tocoff = e4(p[32:]) 277 c.dsym.ntoc = e4(p[36:]) 278 c.dsym.modtaboff = e4(p[40:]) 279 c.dsym.nmodtab = e4(p[44:]) 280 c.dsym.extrefsymoff = e4(p[48:]) 281 c.dsym.nextrefsyms = e4(p[52:]) 282 c.dsym.indirectsymoff = e4(p[56:]) 283 c.dsym.nindirectsyms = e4(p[60:]) 284 c.dsym.extreloff = e4(p[64:]) 285 c.dsym.nextrel = e4(p[68:]) 286 c.dsym.locreloff = e4(p[72:]) 287 c.dsym.nlocrel = e4(p[76:]) 288 } 289 290 return 0 291 } 292 293 func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int { 294 if sect.rel != nil || sect.nreloc == 0 { 295 return 0 296 } 297 rel := make([]LdMachoRel, sect.nreloc) 298 n := int(sect.nreloc * 8) 299 buf := make([]byte, n) 300 if obj.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || obj.Bread(m.f, buf) != n { 301 return -1 302 } 303 var p []byte 304 var r *LdMachoRel 305 var v uint32 306 for i := 0; uint32(i) < sect.nreloc; i++ { 307 r = &rel[i] 308 p = buf[i*8:] 309 r.addr = m.e.Uint32(p) 310 311 // TODO(rsc): Wrong interpretation for big-endian bitfields? 312 if r.addr&0x80000000 != 0 { 313 // scatterbrained relocation 314 r.scattered = 1 315 316 v = r.addr >> 24 317 r.addr &= 0xFFFFFF 318 r.type_ = uint8(v & 0xF) 319 v >>= 4 320 r.length = 1 << (v & 3) 321 v >>= 2 322 r.pcrel = uint8(v & 1) 323 r.value = m.e.Uint32(p[4:]) 324 } else { 325 v = m.e.Uint32(p[4:]) 326 r.symnum = v & 0xFFFFFF 327 v >>= 24 328 r.pcrel = uint8(v & 1) 329 v >>= 1 330 r.length = 1 << (v & 3) 331 v >>= 2 332 r.extrn = uint8(v & 1) 333 v >>= 1 334 r.type_ = uint8(v) 335 } 336 } 337 338 sect.rel = rel 339 return 0 340 } 341 342 func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int { 343 n := int(d.nindirectsyms) 344 345 p := make([]byte, n*4) 346 if obj.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || obj.Bread(m.f, p) != len(p) { 347 return -1 348 } 349 350 d.indir = make([]uint32, n) 351 for i := 0; i < n; i++ { 352 d.indir[i] = m.e.Uint32(p[4*i:]) 353 } 354 return 0 355 } 356 357 func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { 358 if symtab.sym != nil { 359 return 0 360 } 361 362 strbuf := make([]byte, symtab.strsize) 363 if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) { 364 return -1 365 } 366 367 symsize := 12 368 if m.is64 { 369 symsize = 16 370 } 371 n := int(symtab.nsym * uint32(symsize)) 372 symbuf := make([]byte, n) 373 if obj.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || obj.Bread(m.f, symbuf) != len(symbuf) { 374 return -1 375 } 376 sym := make([]LdMachoSym, symtab.nsym) 377 p := symbuf 378 var s *LdMachoSym 379 var v uint32 380 for i := 0; uint32(i) < symtab.nsym; i++ { 381 s = &sym[i] 382 v = m.e.Uint32(p) 383 if v >= symtab.strsize { 384 return -1 385 } 386 s.name = cstring(strbuf[v:]) 387 s.type_ = uint8(p[4]) 388 s.sectnum = uint8(p[5]) 389 s.desc = m.e.Uint16(p[6:]) 390 if m.is64 { 391 s.value = m.e.Uint64(p[8:]) 392 } else { 393 s.value = uint64(m.e.Uint32(p[8:])) 394 } 395 p = p[symsize:] 396 } 397 398 symtab.str = strbuf 399 symtab.sym = sym 400 return 0 401 } 402 403 func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { 404 var err error 405 var j int 406 var is64 bool 407 var secaddr uint64 408 var hdr [7 * 4]uint8 409 var cmdp []byte 410 var dat []byte 411 var ncmd uint32 412 var cmdsz uint32 413 var ty uint32 414 var sz uint32 415 var off uint32 416 var m *LdMachoObj 417 var e binary.ByteOrder 418 var sect *LdMachoSect 419 var rel *LdMachoRel 420 var rpi int 421 var s *LSym 422 var s1 *LSym 423 var outer *LSym 424 var c *LdMachoCmd 425 var symtab *LdMachoSymtab 426 var dsymtab *LdMachoDysymtab 427 var sym *LdMachoSym 428 var r []Reloc 429 var rp *Reloc 430 var name string 431 432 Ctxt.Version++ 433 base := obj.Boffset(f) 434 if obj.Bread(f, hdr[:]) != len(hdr) { 435 goto bad 436 } 437 438 if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { 439 e = binary.BigEndian 440 } else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE { 441 e = binary.LittleEndian 442 } else { 443 err = fmt.Errorf("bad magic - not mach-o file") 444 goto bad 445 } 446 447 is64 = e.Uint32(hdr[:]) == 0xFEEDFACF 448 ncmd = e.Uint32([]byte(hdr[4*4:])) 449 cmdsz = e.Uint32([]byte(hdr[5*4:])) 450 if ncmd > 0x10000 || cmdsz >= 0x01000000 { 451 err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz) 452 goto bad 453 } 454 455 if is64 { 456 var tmp [4]uint8 457 obj.Bread(f, tmp[:4]) // skip reserved word in header 458 } 459 460 m = new(LdMachoObj) 461 462 m.f = f 463 m.e = e 464 m.cputype = uint(e.Uint32([]byte(hdr[1*4:]))) 465 m.subcputype = uint(e.Uint32([]byte(hdr[2*4:]))) 466 m.filetype = e.Uint32([]byte(hdr[3*4:])) 467 m.ncmd = uint(ncmd) 468 m.flags = e.Uint32([]byte(hdr[6*4:])) 469 m.is64 = is64 470 m.base = base 471 m.length = length 472 m.name = pn 473 474 switch Thearch.Thechar { 475 default: 476 Diag("%s: mach-o %s unimplemented", pn, Thestring) 477 return 478 479 case '6': 480 if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 { 481 Diag("%s: mach-o object but not amd64", pn) 482 return 483 } 484 485 case '8': 486 if e != binary.LittleEndian || m.cputype != LdMachoCpu386 { 487 Diag("%s: mach-o object but not 386", pn) 488 return 489 } 490 } 491 492 m.cmd = make([]LdMachoCmd, ncmd) 493 off = uint32(len(hdr)) 494 cmdp = make([]byte, cmdsz) 495 if obj.Bread(f, cmdp) != len(cmdp) { 496 err = fmt.Errorf("reading cmds: %v", err) 497 goto bad 498 } 499 500 // read and parse load commands 501 c = nil 502 503 symtab = nil 504 dsymtab = nil 505 506 for i := 0; uint32(i) < ncmd; i++ { 507 ty = e.Uint32(cmdp) 508 sz = e.Uint32(cmdp[4:]) 509 m.cmd[i].off = off 510 unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz)) 511 cmdp = cmdp[sz:] 512 off += sz 513 if ty == LdMachoCmdSymtab { 514 if symtab != nil { 515 err = fmt.Errorf("multiple symbol tables") 516 goto bad 517 } 518 519 symtab = &m.cmd[i].sym 520 macholoadsym(m, symtab) 521 } 522 523 if ty == LdMachoCmdDysymtab { 524 dsymtab = &m.cmd[i].dsym 525 macholoaddsym(m, dsymtab) 526 } 527 528 if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) { 529 if c != nil { 530 err = fmt.Errorf("multiple load commands") 531 goto bad 532 } 533 534 c = &m.cmd[i] 535 } 536 } 537 538 // load text and data segments into memory. 539 // they are not as small as the load commands, but we'll need 540 // the memory anyway for the symbol images, so we might 541 // as well use one large chunk. 542 if c == nil { 543 err = fmt.Errorf("no load command") 544 goto bad 545 } 546 547 if symtab == nil { 548 // our work is done here - no symbols means nothing can refer to this file 549 return 550 } 551 552 if int64(c.seg.fileoff+c.seg.filesz) >= length { 553 err = fmt.Errorf("load segment out of range") 554 goto bad 555 } 556 557 dat = make([]byte, c.seg.filesz) 558 if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) { 559 err = fmt.Errorf("cannot load object data: %v", err) 560 goto bad 561 } 562 563 for i := 0; uint32(i) < c.seg.nsect; i++ { 564 sect = &c.seg.sect[i] 565 if sect.segname != "__TEXT" && sect.segname != "__DATA" { 566 continue 567 } 568 if sect.name == "__eh_frame" { 569 continue 570 } 571 name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name) 572 s = Linklookup(Ctxt, name, Ctxt.Version) 573 if s.Type != 0 { 574 err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name) 575 goto bad 576 } 577 578 if sect.flags&0xff == 1 { // S_ZEROFILL 579 s.P = make([]byte, sect.size) 580 } else { 581 s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size] 582 } 583 s.Size = int64(len(s.P)) 584 585 if sect.segname == "__TEXT" { 586 if sect.name == "__text" { 587 s.Type = obj.STEXT 588 } else { 589 s.Type = obj.SRODATA 590 } 591 } else { 592 if sect.name == "__bss" { 593 s.Type = obj.SNOPTRBSS 594 s.P = s.P[:0] 595 } else { 596 s.Type = obj.SNOPTRDATA 597 } 598 } 599 600 sect.sym = s 601 } 602 603 // enter sub-symbols into symbol table. 604 // have to guess sizes from next symbol. 605 for i := 0; uint32(i) < symtab.nsym; i++ { 606 sym = &symtab.sym[i] 607 if sym.type_&N_STAB != 0 { 608 continue 609 } 610 611 // TODO: check sym->type against outer->type. 612 name = sym.name 613 614 if name[0] == '_' && name[1] != '\x00' { 615 name = name[1:] 616 } 617 v := 0 618 if sym.type_&N_EXT == 0 { 619 v = Ctxt.Version 620 } 621 s = Linklookup(Ctxt, name, v) 622 if sym.type_&N_EXT == 0 { 623 s.Dupok = 1 624 } 625 sym.sym = s 626 if sym.sectnum == 0 { // undefined 627 continue 628 } 629 if uint32(sym.sectnum) > c.seg.nsect { 630 err = fmt.Errorf("reference to invalid section %d", sym.sectnum) 631 goto bad 632 } 633 634 sect = &c.seg.sect[sym.sectnum-1] 635 outer = sect.sym 636 if outer == nil { 637 err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name) 638 continue 639 } 640 641 if s.Outer != nil { 642 if s.Dupok != 0 { 643 continue 644 } 645 Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name) 646 } 647 648 s.Type = outer.Type | obj.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 == obj.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 == obj.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 = obj.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 } 894