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