github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/cmd/link/internal/ld/macho.go (about) 1 // Copyright 2009 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 ld 6 7 import ( 8 "cmd/internal/obj" 9 "cmd/internal/sys" 10 "sort" 11 "strings" 12 ) 13 14 type MachoHdr struct { 15 cpu uint32 16 subcpu uint32 17 } 18 19 type MachoSect struct { 20 name string 21 segname string 22 addr uint64 23 size uint64 24 off uint32 25 align uint32 26 reloc uint32 27 nreloc uint32 28 flag uint32 29 res1 uint32 30 res2 uint32 31 } 32 33 type MachoSeg struct { 34 name string 35 vsize uint64 36 vaddr uint64 37 fileoffset uint64 38 filesize uint64 39 prot1 uint32 40 prot2 uint32 41 nsect uint32 42 msect uint32 43 sect []MachoSect 44 flag uint32 45 } 46 47 type MachoLoad struct { 48 type_ uint32 49 data []uint32 50 } 51 52 /* 53 * Total amount of space to reserve at the start of the file 54 * for Header, PHeaders, and SHeaders. 55 * May waste some. 56 */ 57 const ( 58 INITIAL_MACHO_HEADR = 4 * 1024 59 ) 60 61 const ( 62 MACHO_CPU_AMD64 = 1<<24 | 7 63 MACHO_CPU_386 = 7 64 MACHO_SUBCPU_X86 = 3 65 MACHO_CPU_ARM = 12 66 MACHO_SUBCPU_ARM = 0 67 MACHO_SUBCPU_ARMV7 = 9 68 MACHO_CPU_ARM64 = 1<<24 | 12 69 MACHO_SUBCPU_ARM64_ALL = 0 70 MACHO32SYMSIZE = 12 71 MACHO64SYMSIZE = 16 72 MACHO_X86_64_RELOC_UNSIGNED = 0 73 MACHO_X86_64_RELOC_SIGNED = 1 74 MACHO_X86_64_RELOC_BRANCH = 2 75 MACHO_X86_64_RELOC_GOT_LOAD = 3 76 MACHO_X86_64_RELOC_GOT = 4 77 MACHO_X86_64_RELOC_SUBTRACTOR = 5 78 MACHO_X86_64_RELOC_SIGNED_1 = 6 79 MACHO_X86_64_RELOC_SIGNED_2 = 7 80 MACHO_X86_64_RELOC_SIGNED_4 = 8 81 MACHO_ARM_RELOC_VANILLA = 0 82 MACHO_ARM_RELOC_PAIR = 1 83 MACHO_ARM_RELOC_SECTDIFF = 2 84 MACHO_ARM_RELOC_BR24 = 5 85 MACHO_ARM64_RELOC_UNSIGNED = 0 86 MACHO_ARM64_RELOC_BRANCH26 = 2 87 MACHO_ARM64_RELOC_PAGE21 = 3 88 MACHO_ARM64_RELOC_PAGEOFF12 = 4 89 MACHO_ARM64_RELOC_ADDEND = 10 90 MACHO_GENERIC_RELOC_VANILLA = 0 91 MACHO_FAKE_GOTPCREL = 100 92 ) 93 94 // Copyright 2009 The Go Authors. All rights reserved. 95 // Use of this source code is governed by a BSD-style 96 // license that can be found in the LICENSE file. 97 98 // Mach-O file writing 99 // http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html 100 101 var macho64 bool 102 103 var machohdr MachoHdr 104 105 var load []MachoLoad 106 107 var seg [16]MachoSeg 108 109 var nseg int 110 111 var ndebug int 112 113 var nsect int 114 115 const ( 116 SymKindLocal = 0 + iota 117 SymKindExtdef 118 SymKindUndef 119 NumSymKind 120 ) 121 122 var nkind [NumSymKind]int 123 124 var sortsym []*Symbol 125 126 var nsortsym int 127 128 // Amount of space left for adding load commands 129 // that refer to dynamic libraries. Because these have 130 // to go in the Mach-O header, we can't just pick a 131 // "big enough" header size. The initial header is 132 // one page, the non-dynamic library stuff takes 133 // up about 1300 bytes; we overestimate that as 2k. 134 var loadBudget int = INITIAL_MACHO_HEADR - 2*1024 135 136 func Machoinit() { 137 macho64 = SysArch.RegSize == 8 138 } 139 140 func getMachoHdr() *MachoHdr { 141 return &machohdr 142 } 143 144 func newMachoLoad(type_ uint32, ndata uint32) *MachoLoad { 145 if macho64 && (ndata&1 != 0) { 146 ndata++ 147 } 148 149 load = append(load, MachoLoad{}) 150 l := &load[len(load)-1] 151 l.type_ = type_ 152 l.data = make([]uint32, ndata) 153 return l 154 } 155 156 func newMachoSeg(name string, msect int) *MachoSeg { 157 if nseg >= len(seg) { 158 Exitf("too many segs") 159 } 160 161 s := &seg[nseg] 162 nseg++ 163 s.name = name 164 s.msect = uint32(msect) 165 s.sect = make([]MachoSect, msect) 166 return s 167 } 168 169 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect { 170 if seg.nsect >= seg.msect { 171 Exitf("too many sects in segment %s", seg.name) 172 } 173 174 s := &seg.sect[seg.nsect] 175 seg.nsect++ 176 s.name = name 177 s.segname = segname 178 nsect++ 179 return s 180 } 181 182 // Generic linking code. 183 184 var dylib []string 185 186 var linkoff int64 187 188 func machowrite() int { 189 o1 := coutbuf.Offset() 190 191 loadsize := 4 * 4 * ndebug 192 for i := 0; i < len(load); i++ { 193 loadsize += 4 * (len(load[i].data) + 2) 194 } 195 if macho64 { 196 loadsize += 18 * 4 * nseg 197 loadsize += 20 * 4 * nsect 198 } else { 199 loadsize += 14 * 4 * nseg 200 loadsize += 17 * 4 * nsect 201 } 202 203 if macho64 { 204 Thearch.Lput(0xfeedfacf) 205 } else { 206 Thearch.Lput(0xfeedface) 207 } 208 Thearch.Lput(machohdr.cpu) 209 Thearch.Lput(machohdr.subcpu) 210 if Linkmode == LinkExternal { 211 Thearch.Lput(1) /* file type - mach object */ 212 } else { 213 Thearch.Lput(2) /* file type - mach executable */ 214 } 215 Thearch.Lput(uint32(len(load)) + uint32(nseg) + uint32(ndebug)) 216 Thearch.Lput(uint32(loadsize)) 217 Thearch.Lput(1) /* flags - no undefines */ 218 if macho64 { 219 Thearch.Lput(0) /* reserved */ 220 } 221 222 var j int 223 var s *MachoSeg 224 var t *MachoSect 225 for i := 0; i < nseg; i++ { 226 s = &seg[i] 227 if macho64 { 228 Thearch.Lput(25) /* segment 64 */ 229 Thearch.Lput(72 + 80*s.nsect) 230 strnput(s.name, 16) 231 Thearch.Vput(s.vaddr) 232 Thearch.Vput(s.vsize) 233 Thearch.Vput(s.fileoffset) 234 Thearch.Vput(s.filesize) 235 Thearch.Lput(s.prot1) 236 Thearch.Lput(s.prot2) 237 Thearch.Lput(s.nsect) 238 Thearch.Lput(s.flag) 239 } else { 240 Thearch.Lput(1) /* segment 32 */ 241 Thearch.Lput(56 + 68*s.nsect) 242 strnput(s.name, 16) 243 Thearch.Lput(uint32(s.vaddr)) 244 Thearch.Lput(uint32(s.vsize)) 245 Thearch.Lput(uint32(s.fileoffset)) 246 Thearch.Lput(uint32(s.filesize)) 247 Thearch.Lput(s.prot1) 248 Thearch.Lput(s.prot2) 249 Thearch.Lput(s.nsect) 250 Thearch.Lput(s.flag) 251 } 252 253 for j = 0; uint32(j) < s.nsect; j++ { 254 t = &s.sect[j] 255 if macho64 { 256 strnput(t.name, 16) 257 strnput(t.segname, 16) 258 Thearch.Vput(t.addr) 259 Thearch.Vput(t.size) 260 Thearch.Lput(t.off) 261 Thearch.Lput(t.align) 262 Thearch.Lput(t.reloc) 263 Thearch.Lput(t.nreloc) 264 Thearch.Lput(t.flag) 265 Thearch.Lput(t.res1) /* reserved */ 266 Thearch.Lput(t.res2) /* reserved */ 267 Thearch.Lput(0) /* reserved */ 268 } else { 269 strnput(t.name, 16) 270 strnput(t.segname, 16) 271 Thearch.Lput(uint32(t.addr)) 272 Thearch.Lput(uint32(t.size)) 273 Thearch.Lput(t.off) 274 Thearch.Lput(t.align) 275 Thearch.Lput(t.reloc) 276 Thearch.Lput(t.nreloc) 277 Thearch.Lput(t.flag) 278 Thearch.Lput(t.res1) /* reserved */ 279 Thearch.Lput(t.res2) /* reserved */ 280 } 281 } 282 } 283 284 var l *MachoLoad 285 for i := 0; i < len(load); i++ { 286 l = &load[i] 287 Thearch.Lput(l.type_) 288 Thearch.Lput(4 * (uint32(len(l.data)) + 2)) 289 for j = 0; j < len(l.data); j++ { 290 Thearch.Lput(l.data[j]) 291 } 292 } 293 294 return int(coutbuf.Offset() - o1) 295 } 296 297 func (ctxt *Link) domacho() { 298 if *FlagD { 299 return 300 } 301 302 // empirically, string table must begin with " \x00". 303 s := ctxt.Syms.Lookup(".machosymstr", 0) 304 305 s.Type = obj.SMACHOSYMSTR 306 s.Attr |= AttrReachable 307 Adduint8(ctxt, s, ' ') 308 Adduint8(ctxt, s, '\x00') 309 310 s = ctxt.Syms.Lookup(".machosymtab", 0) 311 s.Type = obj.SMACHOSYMTAB 312 s.Attr |= AttrReachable 313 314 if Linkmode != LinkExternal { 315 s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub 316 s.Type = obj.SMACHOPLT 317 s.Attr |= AttrReachable 318 319 s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr 320 s.Type = obj.SMACHOGOT 321 s.Attr |= AttrReachable 322 s.Align = 4 323 324 s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt 325 s.Type = obj.SMACHOINDIRECTPLT 326 s.Attr |= AttrReachable 327 328 s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got 329 s.Type = obj.SMACHOINDIRECTGOT 330 s.Attr |= AttrReachable 331 } 332 } 333 334 func Machoadddynlib(lib string) { 335 // Will need to store the library name rounded up 336 // and 24 bytes of header metadata. If not enough 337 // space, grab another page of initial space at the 338 // beginning of the output file. 339 loadBudget -= (len(lib)+7)/8*8 + 24 340 341 if loadBudget < 0 { 342 HEADR += 4096 343 *FlagTextAddr += 4096 344 loadBudget += 4096 345 } 346 347 dylib = append(dylib, lib) 348 } 349 350 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *Section, segname string) { 351 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) 352 353 var msect *MachoSect 354 if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 || 355 (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin)) || 356 (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin))) { 357 // Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode 358 // complains about absolute relocs in __TEXT, so if the section is not 359 // executable, put it in __DATA segment. 360 msect = newMachoSect(mseg, buf, "__DATA") 361 } else { 362 msect = newMachoSect(mseg, buf, segname) 363 } 364 365 if sect.Rellen > 0 { 366 msect.reloc = uint32(sect.Reloff) 367 msect.nreloc = uint32(sect.Rellen / 8) 368 } 369 370 for 1<<msect.align < sect.Align { 371 msect.align++ 372 } 373 msect.addr = sect.Vaddr 374 msect.size = sect.Length 375 376 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen { 377 // data in file 378 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr { 379 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name) 380 } 381 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr) 382 } else { 383 // zero fill 384 msect.off = 0 385 386 msect.flag |= 1 387 } 388 389 if sect.Rwx&1 != 0 { 390 msect.flag |= 0x400 /* has instructions */ 391 } 392 393 if sect.Name == ".plt" { 394 msect.name = "__symbol_stub1" 395 msect.flag = 0x80000408 /* only instructions, code, symbol stubs */ 396 msect.res1 = 0 //nkind[SymKindLocal]; 397 msect.res2 = 6 398 } 399 400 if sect.Name == ".got" { 401 msect.name = "__nl_symbol_ptr" 402 msect.flag = 6 /* section with nonlazy symbol pointers */ 403 msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */ 404 } 405 406 if sect.Name == ".init_array" { 407 msect.name = "__mod_init_func" 408 msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS 409 } 410 411 if segname == "__DWARF" { 412 msect.flag |= 0x02000000 413 } 414 } 415 416 func Asmbmacho(ctxt *Link) { 417 /* apple MACH */ 418 va := *FlagTextAddr - int64(HEADR) 419 420 mh := getMachoHdr() 421 switch SysArch.Family { 422 default: 423 Exitf("unknown macho architecture: %v", SysArch.Family) 424 425 case sys.ARM: 426 mh.cpu = MACHO_CPU_ARM 427 mh.subcpu = MACHO_SUBCPU_ARMV7 428 429 case sys.AMD64: 430 mh.cpu = MACHO_CPU_AMD64 431 mh.subcpu = MACHO_SUBCPU_X86 432 433 case sys.ARM64: 434 mh.cpu = MACHO_CPU_ARM64 435 mh.subcpu = MACHO_SUBCPU_ARM64_ALL 436 437 case sys.I386: 438 mh.cpu = MACHO_CPU_386 439 mh.subcpu = MACHO_SUBCPU_X86 440 } 441 442 var ms *MachoSeg 443 if Linkmode == LinkExternal { 444 /* segment for entire file */ 445 ms = newMachoSeg("", 40) 446 447 ms.fileoffset = Segtext.Fileoff 448 if SysArch.Family == sys.ARM || Buildmode == BuildmodeCArchive { 449 ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff 450 } else { 451 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff 452 ms.vsize = ms.filesize 453 } 454 } 455 456 /* segment for zero page */ 457 if Linkmode != LinkExternal { 458 ms = newMachoSeg("__PAGEZERO", 0) 459 ms.vsize = uint64(va) 460 } 461 462 /* text */ 463 v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) 464 465 if Linkmode != LinkExternal { 466 ms = newMachoSeg("__TEXT", 20) 467 ms.vaddr = uint64(va) 468 ms.vsize = uint64(v) 469 ms.fileoffset = 0 470 ms.filesize = uint64(v) 471 ms.prot1 = 7 472 ms.prot2 = 5 473 } 474 475 for sect := Segtext.Sect; sect != nil; sect = sect.Next { 476 machoshbits(ctxt, ms, sect, "__TEXT") 477 } 478 479 /* data */ 480 if Linkmode != LinkExternal { 481 w := int64(Segdata.Length) 482 ms = newMachoSeg("__DATA", 20) 483 ms.vaddr = uint64(va) + uint64(v) 484 ms.vsize = uint64(w) 485 ms.fileoffset = uint64(v) 486 ms.filesize = Segdata.Filelen 487 ms.prot1 = 3 488 ms.prot2 = 3 489 } 490 491 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 492 machoshbits(ctxt, ms, sect, "__DATA") 493 } 494 495 /* dwarf */ 496 if !*FlagW { 497 if Linkmode != LinkExternal { 498 ms = newMachoSeg("__DWARF", 20) 499 ms.vaddr = Segdwarf.Vaddr 500 ms.vsize = 0 501 ms.fileoffset = Segdwarf.Fileoff 502 ms.filesize = Segdwarf.Filelen 503 } 504 for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { 505 machoshbits(ctxt, ms, sect, "__DWARF") 506 } 507 } 508 509 if Linkmode != LinkExternal { 510 switch SysArch.Family { 511 default: 512 Exitf("unknown macho architecture: %v", SysArch.Family) 513 514 case sys.ARM: 515 ml := newMachoLoad(5, 17+2) /* unix thread */ 516 ml.data[0] = 1 /* thread type */ 517 ml.data[1] = 17 /* word count */ 518 ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */ 519 520 case sys.AMD64: 521 ml := newMachoLoad(5, 42+2) /* unix thread */ 522 ml.data[0] = 4 /* thread type */ 523 ml.data[1] = 42 /* word count */ 524 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */ 525 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) 526 527 case sys.ARM64: 528 ml := newMachoLoad(5, 68+2) /* unix thread */ 529 ml.data[0] = 6 /* thread type */ 530 ml.data[1] = 68 /* word count */ 531 ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */ 532 ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32) 533 534 case sys.I386: 535 ml := newMachoLoad(5, 16+2) /* unix thread */ 536 ml.data[0] = 1 /* thread type */ 537 ml.data[1] = 16 /* word count */ 538 ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */ 539 } 540 } 541 542 if !*FlagD { 543 // must match domacholink below 544 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 545 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 546 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 547 s4 := ctxt.Syms.Lookup(".machosymstr", 0) 548 549 if Linkmode != LinkExternal { 550 ms := newMachoSeg("__LINKEDIT", 0) 551 ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound))) 552 ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size) 553 ms.fileoffset = uint64(linkoff) 554 ms.filesize = ms.vsize 555 ms.prot1 = 7 556 ms.prot2 = 3 557 } 558 559 ml := newMachoLoad(2, 4) /* LC_SYMTAB */ 560 ml.data[0] = uint32(linkoff) /* symoff */ 561 ml.data[1] = uint32(nsortsym) /* nsyms */ 562 ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */ 563 ml.data[3] = uint32(s4.Size) /* strsize */ 564 565 machodysymtab(ctxt) 566 567 if Linkmode != LinkExternal { 568 ml := newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */ 569 ml.data[0] = 12 /* offset to string */ 570 stringtouint32(ml.data[1:], "/usr/lib/dyld") 571 572 for i := 0; i < len(dylib); i++ { 573 ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */ 574 ml.data[0] = 24 /* offset of string from beginning of load */ 575 ml.data[1] = 0 /* time stamp */ 576 ml.data[2] = 0 /* version */ 577 ml.data[3] = 0 /* compatibility version */ 578 stringtouint32(ml.data[4:], dylib[i]) 579 } 580 } 581 } 582 583 if Linkmode == LinkInternal { 584 // For lldb, must say LC_VERSION_MIN_MACOSX or else 585 // it won't know that this Mach-O binary is from OS X 586 // (could be iOS or WatchOS instead). 587 // Go on iOS uses linkmode=external, and linkmode=external 588 // adds this itself. So we only need this code for linkmode=internal 589 // and we can assume OS X. 590 // 591 // See golang.org/issues/12941. 592 const LC_VERSION_MIN_MACOSX = 0x24 593 594 ml := newMachoLoad(LC_VERSION_MIN_MACOSX, 2) 595 ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0 596 ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0 597 } 598 599 a := machowrite() 600 if int32(a) > HEADR { 601 Exitf("HEADR too small: %d > %d", a, HEADR) 602 } 603 } 604 605 func symkind(s *Symbol) int { 606 if s.Type == obj.SDYNIMPORT { 607 return SymKindUndef 608 } 609 if s.Attr.CgoExport() { 610 return SymKindExtdef 611 } 612 return SymKindLocal 613 } 614 615 func addsym(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) { 616 if s == nil { 617 return 618 } 619 620 switch type_ { 621 default: 622 return 623 624 case DataSym, BSSSym, TextSym: 625 break 626 } 627 628 if sortsym != nil { 629 sortsym[nsortsym] = s 630 nkind[symkind(s)]++ 631 } 632 633 nsortsym++ 634 } 635 636 type machoscmp []*Symbol 637 638 func (x machoscmp) Len() int { 639 return len(x) 640 } 641 642 func (x machoscmp) Swap(i, j int) { 643 x[i], x[j] = x[j], x[i] 644 } 645 646 func (x machoscmp) Less(i, j int) bool { 647 s1 := x[i] 648 s2 := x[j] 649 650 k1 := symkind(s1) 651 k2 := symkind(s2) 652 if k1 != k2 { 653 return k1 < k2 654 } 655 656 return s1.Extname < s2.Extname 657 } 658 659 func machogenasmsym(ctxt *Link) { 660 genasmsym(ctxt, addsym) 661 for _, s := range ctxt.Syms.Allsym { 662 if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ { 663 if s.Attr.Reachable() { 664 addsym(ctxt, s, "", DataSym, 0, nil) 665 } 666 } 667 } 668 } 669 670 func machosymorder(ctxt *Link) { 671 // On Mac OS X Mountain Lion, we must sort exported symbols 672 // So we sort them here and pre-allocate dynid for them 673 // See https://golang.org/issue/4029 674 for i := 0; i < len(dynexp); i++ { 675 dynexp[i].Attr |= AttrReachable 676 } 677 machogenasmsym(ctxt) 678 sortsym = make([]*Symbol, nsortsym) 679 nsortsym = 0 680 machogenasmsym(ctxt) 681 sort.Sort(machoscmp(sortsym[:nsortsym])) 682 for i := 0; i < nsortsym; i++ { 683 sortsym[i].Dynid = int32(i) 684 } 685 } 686 687 func machosymtab(ctxt *Link) { 688 symtab := ctxt.Syms.Lookup(".machosymtab", 0) 689 symstr := ctxt.Syms.Lookup(".machosymstr", 0) 690 691 for i := 0; i < nsortsym; i++ { 692 s := sortsym[i] 693 Adduint32(ctxt, symtab, uint32(symstr.Size)) 694 695 // In normal buildmodes, only add _ to C symbols, as 696 // Go symbols have dot in the name. 697 // 698 // When dynamically linking, prefix all non-local 699 // symbols with _ as dlsym on darwin requires it to 700 // resolve any symbol. 701 if !strings.Contains(s.Extname, ".") || (ctxt.DynlinkingGo() && !s.Attr.Local()) { 702 Adduint8(ctxt, symstr, '_') 703 } 704 705 // replace "·" as ".", because DTrace cannot handle it. 706 Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1)) 707 708 if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ { 709 Adduint8(ctxt, symtab, 0x01) // type N_EXT, external symbol 710 Adduint8(ctxt, symtab, 0) // no section 711 Adduint16(ctxt, symtab, 0) // desc 712 adduintxx(ctxt, symtab, 0, SysArch.PtrSize) // no value 713 } else { 714 if s.Attr.CgoExport() || (ctxt.DynlinkingGo() && !s.Attr.Local()) { 715 Adduint8(ctxt, symtab, 0x0f) 716 } else { 717 Adduint8(ctxt, symtab, 0x0e) 718 } 719 o := s 720 for o.Outer != nil { 721 o = o.Outer 722 } 723 if o.Sect == nil { 724 Errorf(s, "missing section for symbol") 725 Adduint8(ctxt, symtab, 0) 726 } else { 727 Adduint8(ctxt, symtab, uint8(o.Sect.Extnum)) 728 } 729 Adduint16(ctxt, symtab, 0) // desc 730 adduintxx(ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize) 731 } 732 } 733 } 734 735 func machodysymtab(ctxt *Link) { 736 ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */ 737 738 n := 0 739 ml.data[0] = uint32(n) /* ilocalsym */ 740 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 741 n += nkind[SymKindLocal] 742 743 ml.data[2] = uint32(n) /* iextdefsym */ 744 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 745 n += nkind[SymKindExtdef] 746 747 ml.data[4] = uint32(n) /* iundefsym */ 748 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 749 750 ml.data[6] = 0 /* tocoffset */ 751 ml.data[7] = 0 /* ntoc */ 752 ml.data[8] = 0 /* modtaboff */ 753 ml.data[9] = 0 /* nmodtab */ 754 ml.data[10] = 0 /* extrefsymoff */ 755 ml.data[11] = 0 /* nextrefsyms */ 756 757 // must match domacholink below 758 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 759 760 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 761 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 762 ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */ 763 ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */ 764 765 ml.data[14] = 0 /* extreloff */ 766 ml.data[15] = 0 /* nextrel */ 767 ml.data[16] = 0 /* locreloff */ 768 ml.data[17] = 0 /* nlocrel */ 769 } 770 771 func Domacholink(ctxt *Link) int64 { 772 machosymtab(ctxt) 773 774 // write data that will be linkedit section 775 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 776 777 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 778 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 779 s4 := ctxt.Syms.Lookup(".machosymstr", 0) 780 781 // Force the linkedit section to end on a 16-byte 782 // boundary. This allows pure (non-cgo) Go binaries 783 // to be code signed correctly. 784 // 785 // Apple's codesign_allocate (a helper utility for 786 // the codesign utility) can do this fine itself if 787 // it is run on a dynamic Mach-O binary. However, 788 // when it is run on a pure (non-cgo) Go binary, where 789 // the linkedit section is mostly empty, it fails to 790 // account for the extra padding that it itself adds 791 // when adding the LC_CODE_SIGNATURE load command 792 // (which must be aligned on a 16-byte boundary). 793 // 794 // By forcing the linkedit section to end on a 16-byte 795 // boundary, codesign_allocate will not need to apply 796 // any alignment padding itself, working around the 797 // issue. 798 for s4.Size%16 != 0 { 799 Adduint8(ctxt, s4, 0) 800 } 801 802 size := int(s1.Size + s2.Size + s3.Size + s4.Size) 803 804 if size > 0 { 805 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound)) 806 Cseek(linkoff) 807 808 Cwrite(s1.P[:s1.Size]) 809 Cwrite(s2.P[:s2.Size]) 810 Cwrite(s3.P[:s3.Size]) 811 Cwrite(s4.P[:s4.Size]) 812 } 813 814 return Rnd(int64(size), int64(*FlagRound)) 815 } 816 817 func machorelocsect(ctxt *Link, sect *Section, syms []*Symbol) { 818 // If main section has no bits, nothing to relocate. 819 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 820 return 821 } 822 823 sect.Reloff = uint64(coutbuf.Offset()) 824 for i, s := range syms { 825 if !s.Attr.Reachable() { 826 continue 827 } 828 if uint64(s.Value) >= sect.Vaddr { 829 syms = syms[i:] 830 break 831 } 832 } 833 834 eaddr := int32(sect.Vaddr + sect.Length) 835 for _, sym := range syms { 836 if !sym.Attr.Reachable() { 837 continue 838 } 839 if sym.Value >= int64(eaddr) { 840 break 841 } 842 for ri := 0; ri < len(sym.R); ri++ { 843 r := &sym.R[ri] 844 if r.Done != 0 { 845 continue 846 } 847 if r.Xsym == nil { 848 Errorf(sym, "missing xsym in relocation") 849 continue 850 } 851 if !r.Xsym.Attr.Reachable() { 852 Errorf(sym, "unreachable reloc %v target %v", r.Type, r.Xsym.Name) 853 } 854 if Thearch.Machoreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 { 855 Errorf(sym, "unsupported obj reloc %v/%d to %s", r.Type, r.Siz, r.Sym.Name) 856 } 857 } 858 } 859 860 sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff 861 } 862 863 func Machoemitreloc(ctxt *Link) { 864 for coutbuf.Offset()&7 != 0 { 865 Cput(0) 866 } 867 868 machorelocsect(ctxt, Segtext.Sect, ctxt.Textp) 869 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { 870 machorelocsect(ctxt, sect, datap) 871 } 872 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 873 machorelocsect(ctxt, sect, datap) 874 } 875 for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { 876 machorelocsect(ctxt, sect, dwarfp) 877 } 878 }