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