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