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 5package ld 6 7import ( 8 "bytes" 9 "cmd/internal/codesign" 10 "cmd/internal/objabi" 11 "cmd/internal/sys" 12 "cmd/link/internal/loader" 13 "cmd/link/internal/sym" 14 "debug/macho" 15 "encoding/binary" 16 "fmt" 17 "internal/buildcfg" 18 "io" 19 "os" 20 "sort" 21 "strings" 22 "unsafe" 23) 24 25type MachoHdr struct { 26 cpu uint32 27 subcpu uint32 28} 29 30type MachoSect struct { 31 name string 32 segname string 33 addr uint64 34 size uint64 35 off uint32 36 align uint32 37 reloc uint32 38 nreloc uint32 39 flag uint32 40 res1 uint32 41 res2 uint32 42} 43 44type MachoSeg struct { 45 name string 46 vsize uint64 47 vaddr uint64 48 fileoffset uint64 49 filesize uint64 50 prot1 uint32 51 prot2 uint32 52 nsect uint32 53 msect uint32 54 sect []MachoSect 55 flag uint32 56} 57 58// MachoPlatformLoad represents a LC_VERSION_MIN_* or 59// LC_BUILD_VERSION load command. 60type MachoPlatformLoad struct { 61 platform MachoPlatform // One of PLATFORM_* constants. 62 cmd MachoLoad 63} 64 65type MachoLoad struct { 66 type_ uint32 67 data []uint32 68} 69 70type MachoPlatform int 71 72/* 73 * Total amount of space to reserve at the start of the file 74 * for Header, PHeaders, and SHeaders. 75 * May waste some. 76 */ 77const ( 78 INITIAL_MACHO_HEADR = 4 * 1024 79) 80 81const ( 82 MACHO_CPU_AMD64 = 1<<24 | 7 83 MACHO_CPU_386 = 7 84 MACHO_SUBCPU_X86 = 3 85 MACHO_CPU_ARM = 12 86 MACHO_SUBCPU_ARM = 0 87 MACHO_SUBCPU_ARMV7 = 9 88 MACHO_CPU_ARM64 = 1<<24 | 12 89 MACHO_SUBCPU_ARM64_ALL = 0 90 MACHO_SUBCPU_ARM64_V8 = 1 91 MACHO_SUBCPU_ARM64E = 2 92 MACHO32SYMSIZE = 12 93 MACHO64SYMSIZE = 16 94 MACHO_X86_64_RELOC_UNSIGNED = 0 95 MACHO_X86_64_RELOC_SIGNED = 1 96 MACHO_X86_64_RELOC_BRANCH = 2 97 MACHO_X86_64_RELOC_GOT_LOAD = 3 98 MACHO_X86_64_RELOC_GOT = 4 99 MACHO_X86_64_RELOC_SUBTRACTOR = 5 100 MACHO_X86_64_RELOC_SIGNED_1 = 6 101 MACHO_X86_64_RELOC_SIGNED_2 = 7 102 MACHO_X86_64_RELOC_SIGNED_4 = 8 103 MACHO_ARM_RELOC_VANILLA = 0 104 MACHO_ARM_RELOC_PAIR = 1 105 MACHO_ARM_RELOC_SECTDIFF = 2 106 MACHO_ARM_RELOC_BR24 = 5 107 MACHO_ARM64_RELOC_UNSIGNED = 0 108 MACHO_ARM64_RELOC_BRANCH26 = 2 109 MACHO_ARM64_RELOC_PAGE21 = 3 110 MACHO_ARM64_RELOC_PAGEOFF12 = 4 111 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5 112 MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6 113 MACHO_ARM64_RELOC_ADDEND = 10 114 MACHO_GENERIC_RELOC_VANILLA = 0 115 MACHO_FAKE_GOTPCREL = 100 116) 117 118const ( 119 MH_MAGIC = 0xfeedface 120 MH_MAGIC_64 = 0xfeedfacf 121 122 MH_OBJECT = 0x1 123 MH_EXECUTE = 0x2 124 125 MH_NOUNDEFS = 0x1 126 MH_DYLDLINK = 0x4 127 MH_PIE = 0x200000 128) 129 130const ( 131 LC_SEGMENT = 0x1 132 LC_SYMTAB = 0x2 133 LC_SYMSEG = 0x3 134 LC_THREAD = 0x4 135 LC_UNIXTHREAD = 0x5 136 LC_LOADFVMLIB = 0x6 137 LC_IDFVMLIB = 0x7 138 LC_IDENT = 0x8 139 LC_FVMFILE = 0x9 140 LC_PREPAGE = 0xa 141 LC_DYSYMTAB = 0xb 142 LC_LOAD_DYLIB = 0xc 143 LC_ID_DYLIB = 0xd 144 LC_LOAD_DYLINKER = 0xe 145 LC_ID_DYLINKER = 0xf 146 LC_PREBOUND_DYLIB = 0x10 147 LC_ROUTINES = 0x11 148 LC_SUB_FRAMEWORK = 0x12 149 LC_SUB_UMBRELLA = 0x13 150 LC_SUB_CLIENT = 0x14 151 LC_SUB_LIBRARY = 0x15 152 LC_TWOLEVEL_HINTS = 0x16 153 LC_PREBIND_CKSUM = 0x17 154 LC_LOAD_WEAK_DYLIB = 0x80000018 155 LC_SEGMENT_64 = 0x19 156 LC_ROUTINES_64 = 0x1a 157 LC_UUID = 0x1b 158 LC_RPATH = 0x8000001c 159 LC_CODE_SIGNATURE = 0x1d 160 LC_SEGMENT_SPLIT_INFO = 0x1e 161 LC_REEXPORT_DYLIB = 0x8000001f 162 LC_LAZY_LOAD_DYLIB = 0x20 163 LC_ENCRYPTION_INFO = 0x21 164 LC_DYLD_INFO = 0x22 165 LC_DYLD_INFO_ONLY = 0x80000022 166 LC_LOAD_UPWARD_DYLIB = 0x80000023 167 LC_VERSION_MIN_MACOSX = 0x24 168 LC_VERSION_MIN_IPHONEOS = 0x25 169 LC_FUNCTION_STARTS = 0x26 170 LC_DYLD_ENVIRONMENT = 0x27 171 LC_MAIN = 0x80000028 172 LC_DATA_IN_CODE = 0x29 173 LC_SOURCE_VERSION = 0x2A 174 LC_DYLIB_CODE_SIGN_DRS = 0x2B 175 LC_ENCRYPTION_INFO_64 = 0x2C 176 LC_LINKER_OPTION = 0x2D 177 LC_LINKER_OPTIMIZATION_HINT = 0x2E 178 LC_VERSION_MIN_TVOS = 0x2F 179 LC_VERSION_MIN_WATCHOS = 0x30 180 LC_VERSION_NOTE = 0x31 181 LC_BUILD_VERSION = 0x32 182 LC_DYLD_EXPORTS_TRIE = 0x80000033 183 LC_DYLD_CHAINED_FIXUPS = 0x80000034 184) 185 186const ( 187 S_REGULAR = 0x0 188 S_ZEROFILL = 0x1 189 S_NON_LAZY_SYMBOL_POINTERS = 0x6 190 S_SYMBOL_STUBS = 0x8 191 S_MOD_INIT_FUNC_POINTERS = 0x9 192 S_ATTR_PURE_INSTRUCTIONS = 0x80000000 193 S_ATTR_DEBUG = 0x02000000 194 S_ATTR_SOME_INSTRUCTIONS = 0x00000400 195) 196 197const ( 198 PLATFORM_MACOS MachoPlatform = 1 199 PLATFORM_IOS MachoPlatform = 2 200 PLATFORM_TVOS MachoPlatform = 3 201 PLATFORM_WATCHOS MachoPlatform = 4 202 PLATFORM_BRIDGEOS MachoPlatform = 5 203 PLATFORM_MACCATALYST MachoPlatform = 6 204) 205 206// rebase table opcode 207const ( 208 REBASE_TYPE_POINTER = 1 209 REBASE_TYPE_TEXT_ABSOLUTE32 = 2 210 REBASE_TYPE_TEXT_PCREL32 = 3 211 212 REBASE_OPCODE_MASK = 0xF0 213 REBASE_IMMEDIATE_MASK = 0x0F 214 REBASE_OPCODE_DONE = 0x00 215 REBASE_OPCODE_SET_TYPE_IMM = 0x10 216 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20 217 REBASE_OPCODE_ADD_ADDR_ULEB = 0x30 218 REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40 219 REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50 220 REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60 221 REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70 222 REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80 223) 224 225// bind table opcode 226const ( 227 BIND_TYPE_POINTER = 1 228 BIND_TYPE_TEXT_ABSOLUTE32 = 2 229 BIND_TYPE_TEXT_PCREL32 = 3 230 231 BIND_SPECIAL_DYLIB_SELF = 0 232 BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1 233 BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2 234 BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3 235 236 BIND_OPCODE_MASK = 0xF0 237 BIND_IMMEDIATE_MASK = 0x0F 238 BIND_OPCODE_DONE = 0x00 239 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10 240 BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20 241 BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30 242 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40 243 BIND_OPCODE_SET_TYPE_IMM = 0x50 244 BIND_OPCODE_SET_ADDEND_SLEB = 0x60 245 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70 246 BIND_OPCODE_ADD_ADDR_ULEB = 0x80 247 BIND_OPCODE_DO_BIND = 0x90 248 BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0 249 BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0 250 BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0 251 BIND_OPCODE_THREADED = 0xD0 252 BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00 253 BIND_SUBOPCODE_THREADED_APPLY = 0x01 254) 255 256const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header 257 258// Mach-O file writing 259// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html 260 261var machohdr MachoHdr 262 263var load []MachoLoad 264 265var machoPlatform MachoPlatform 266 267var seg [16]MachoSeg 268 269var nseg int 270 271var ndebug int 272 273var nsect int 274 275const ( 276 SymKindLocal = 0 + iota 277 SymKindExtdef 278 SymKindUndef 279 NumSymKind 280) 281 282var nkind [NumSymKind]int 283 284var sortsym []loader.Sym 285 286var nsortsym int 287 288// Amount of space left for adding load commands 289// that refer to dynamic libraries. Because these have 290// to go in the Mach-O header, we can't just pick a 291// "big enough" header size. The initial header is 292// one page, the non-dynamic library stuff takes 293// up about 1300 bytes; we overestimate that as 2k. 294var loadBudget = INITIAL_MACHO_HEADR - 2*1024 295 296func getMachoHdr() *MachoHdr { 297 return &machohdr 298} 299 300func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad { 301 if arch.PtrSize == 8 && (ndata&1 != 0) { 302 ndata++ 303 } 304 305 load = append(load, MachoLoad{}) 306 l := &load[len(load)-1] 307 l.type_ = type_ 308 l.data = make([]uint32, ndata) 309 return l 310} 311 312func newMachoSeg(name string, msect int) *MachoSeg { 313 if nseg >= len(seg) { 314 Exitf("too many segs") 315 } 316 317 s := &seg[nseg] 318 nseg++ 319 s.name = name 320 s.msect = uint32(msect) 321 s.sect = make([]MachoSect, msect) 322 return s 323} 324 325func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect { 326 if seg.nsect >= seg.msect { 327 Exitf("too many sects in segment %s", seg.name) 328 } 329 330 s := &seg.sect[seg.nsect] 331 seg.nsect++ 332 s.name = name 333 s.segname = segname 334 nsect++ 335 return s 336} 337 338// Generic linking code. 339 340var dylib []string 341 342var linkoff int64 343 344func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int { 345 o1 := out.Offset() 346 347 loadsize := 4 * 4 * ndebug 348 for i := range load { 349 loadsize += 4 * (len(load[i].data) + 2) 350 } 351 if arch.PtrSize == 8 { 352 loadsize += 18 * 4 * nseg 353 loadsize += 20 * 4 * nsect 354 } else { 355 loadsize += 14 * 4 * nseg 356 loadsize += 17 * 4 * nsect 357 } 358 359 if arch.PtrSize == 8 { 360 out.Write32(MH_MAGIC_64) 361 } else { 362 out.Write32(MH_MAGIC) 363 } 364 out.Write32(machohdr.cpu) 365 out.Write32(machohdr.subcpu) 366 if linkmode == LinkExternal { 367 out.Write32(MH_OBJECT) /* file type - mach object */ 368 } else { 369 out.Write32(MH_EXECUTE) /* file type - mach executable */ 370 } 371 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug)) 372 out.Write32(uint32(loadsize)) 373 flags := uint32(0) 374 if nkind[SymKindUndef] == 0 { 375 flags |= MH_NOUNDEFS 376 } 377 if ctxt.IsPIE() && linkmode == LinkInternal { 378 flags |= MH_PIE | MH_DYLDLINK 379 } 380 out.Write32(flags) /* flags */ 381 if arch.PtrSize == 8 { 382 out.Write32(0) /* reserved */ 383 } 384 385 for i := 0; i < nseg; i++ { 386 s := &seg[i] 387 if arch.PtrSize == 8 { 388 out.Write32(LC_SEGMENT_64) 389 out.Write32(72 + 80*s.nsect) 390 out.WriteStringN(s.name, 16) 391 out.Write64(s.vaddr) 392 out.Write64(s.vsize) 393 out.Write64(s.fileoffset) 394 out.Write64(s.filesize) 395 out.Write32(s.prot1) 396 out.Write32(s.prot2) 397 out.Write32(s.nsect) 398 out.Write32(s.flag) 399 } else { 400 out.Write32(LC_SEGMENT) 401 out.Write32(56 + 68*s.nsect) 402 out.WriteStringN(s.name, 16) 403 out.Write32(uint32(s.vaddr)) 404 out.Write32(uint32(s.vsize)) 405 out.Write32(uint32(s.fileoffset)) 406 out.Write32(uint32(s.filesize)) 407 out.Write32(s.prot1) 408 out.Write32(s.prot2) 409 out.Write32(s.nsect) 410 out.Write32(s.flag) 411 } 412 413 for j := uint32(0); j < s.nsect; j++ { 414 t := &s.sect[j] 415 if arch.PtrSize == 8 { 416 out.WriteStringN(t.name, 16) 417 out.WriteStringN(t.segname, 16) 418 out.Write64(t.addr) 419 out.Write64(t.size) 420 out.Write32(t.off) 421 out.Write32(t.align) 422 out.Write32(t.reloc) 423 out.Write32(t.nreloc) 424 out.Write32(t.flag) 425 out.Write32(t.res1) /* reserved */ 426 out.Write32(t.res2) /* reserved */ 427 out.Write32(0) /* reserved */ 428 } else { 429 out.WriteStringN(t.name, 16) 430 out.WriteStringN(t.segname, 16) 431 out.Write32(uint32(t.addr)) 432 out.Write32(uint32(t.size)) 433 out.Write32(t.off) 434 out.Write32(t.align) 435 out.Write32(t.reloc) 436 out.Write32(t.nreloc) 437 out.Write32(t.flag) 438 out.Write32(t.res1) /* reserved */ 439 out.Write32(t.res2) /* reserved */ 440 } 441 } 442 } 443 444 for i := range load { 445 l := &load[i] 446 out.Write32(l.type_) 447 out.Write32(4 * (uint32(len(l.data)) + 2)) 448 for j := 0; j < len(l.data); j++ { 449 out.Write32(l.data[j]) 450 } 451 } 452 453 return int(out.Offset() - o1) 454} 455 456func (ctxt *Link) domacho() { 457 if *FlagD { 458 return 459 } 460 461 // Copy platform load command. 462 for _, h := range hostobj { 463 load, err := hostobjMachoPlatform(&h) 464 if err != nil { 465 Exitf("%v", err) 466 } 467 if load != nil { 468 machoPlatform = load.platform 469 ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data))) 470 copy(ml.data, load.cmd.data) 471 break 472 } 473 } 474 if machoPlatform == 0 { 475 machoPlatform = PLATFORM_MACOS 476 if buildcfg.GOOS == "ios" { 477 machoPlatform = PLATFORM_IOS 478 } 479 if ctxt.LinkMode == LinkInternal && machoPlatform == PLATFORM_MACOS { 480 var version uint32 481 switch ctxt.Arch.Family { 482 case sys.ARM64, sys.AMD64: 483 // This must be fairly recent for Apple signing (go.dev/issue/30488). 484 // Having too old a version here was also implicated in some problems 485 // calling into macOS libraries (go.dev/issue/56784). 486 // In general this can be the most recent supported macOS version. 487 version = 11<<16 | 0<<8 | 0<<0 // 11.0.0 488 } 489 ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4) 490 ml.data[0] = uint32(machoPlatform) 491 ml.data[1] = version // OS version 492 ml.data[2] = version // SDK version 493 ml.data[3] = 0 // ntools 494 } 495 } 496 497 // empirically, string table must begin with " \x00". 498 s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0) 499 sb := ctxt.loader.MakeSymbolUpdater(s) 500 501 sb.SetType(sym.SMACHOSYMSTR) 502 sb.SetReachable(true) 503 sb.AddUint8(' ') 504 sb.AddUint8('\x00') 505 506 s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0) 507 sb = ctxt.loader.MakeSymbolUpdater(s) 508 sb.SetType(sym.SMACHOSYMTAB) 509 sb.SetReachable(true) 510 511 if ctxt.IsInternal() { 512 s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub 513 sb = ctxt.loader.MakeSymbolUpdater(s) 514 sb.SetType(sym.SMACHOPLT) 515 sb.SetReachable(true) 516 517 s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr 518 sb = ctxt.loader.MakeSymbolUpdater(s) 519 sb.SetType(sym.SMACHOGOT) 520 sb.SetReachable(true) 521 sb.SetAlign(4) 522 523 s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt 524 sb = ctxt.loader.MakeSymbolUpdater(s) 525 sb.SetType(sym.SMACHOINDIRECTPLT) 526 sb.SetReachable(true) 527 528 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got 529 sb = ctxt.loader.MakeSymbolUpdater(s) 530 sb.SetType(sym.SMACHOINDIRECTGOT) 531 sb.SetReachable(true) 532 } 533 534 // Add a dummy symbol that will become the __asm marker section. 535 if ctxt.IsExternal() { 536 s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0) 537 sb = ctxt.loader.MakeSymbolUpdater(s) 538 sb.SetType(sym.SMACHO) 539 sb.SetReachable(true) 540 sb.AddUint8(0) 541 } 542 543 // Un-export runtime symbols from plugins. Since the runtime 544 // is included in both the main binary and each plugin, these 545 // symbols appear in both images. If we leave them exported in 546 // the plugin, then the dynamic linker will resolve 547 // relocations to these functions in the plugin's functab to 548 // point to the main image, causing the runtime to think the 549 // plugin's functab is corrupted. By unexporting them, these 550 // become static references, which are resolved to the 551 // plugin's text. 552 // 553 // It would be better to omit the runtime from plugins. (Using 554 // relative PCs in the functab instead of relocations would 555 // also address this.) 556 // 557 // See issue #18190. 558 if ctxt.BuildMode == BuildModePlugin { 559 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} { 560 // Most of these are data symbols or C 561 // symbols, so they have symbol version 0. 562 ver := 0 563 // _cgo_panic is a Go function, so it uses ABIInternal. 564 if name == "_cgo_panic" { 565 ver = abiInternalVer 566 } 567 s := ctxt.loader.Lookup(name, ver) 568 if s != 0 { 569 ctxt.loader.SetAttrCgoExportDynamic(s, false) 570 } 571 } 572 } 573} 574 575func machoadddynlib(lib string, linkmode LinkMode) { 576 if seenlib[lib] || linkmode == LinkExternal { 577 return 578 } 579 seenlib[lib] = true 580 581 // Will need to store the library name rounded up 582 // and 24 bytes of header metadata. If not enough 583 // space, grab another page of initial space at the 584 // beginning of the output file. 585 loadBudget -= (len(lib)+7)/8*8 + 24 586 587 if loadBudget < 0 { 588 HEADR += 4096 589 *FlagTextAddr += 4096 590 loadBudget += 4096 591 } 592 593 dylib = append(dylib, lib) 594} 595 596func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) { 597 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) 598 599 msect := newMachoSect(mseg, buf, segname) 600 601 if sect.Rellen > 0 { 602 msect.reloc = uint32(sect.Reloff) 603 msect.nreloc = uint32(sect.Rellen / 8) 604 } 605 606 for 1<<msect.align < sect.Align { 607 msect.align++ 608 } 609 msect.addr = sect.Vaddr 610 msect.size = sect.Length 611 612 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen { 613 // data in file 614 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr { 615 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name) 616 } 617 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr) 618 } else { 619 msect.off = 0 620 msect.flag |= S_ZEROFILL 621 } 622 623 if sect.Rwx&1 != 0 { 624 msect.flag |= S_ATTR_SOME_INSTRUCTIONS 625 } 626 627 if sect.Name == ".text" { 628 msect.flag |= S_ATTR_PURE_INSTRUCTIONS 629 } 630 631 if sect.Name == ".plt" { 632 msect.name = "__symbol_stub1" 633 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS 634 msect.res1 = 0 //nkind[SymKindLocal]; 635 msect.res2 = 6 636 } 637 638 if sect.Name == ".got" { 639 msect.name = "__nl_symbol_ptr" 640 msect.flag = S_NON_LAZY_SYMBOL_POINTERS 641 msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */ 642 } 643 644 if sect.Name == ".init_array" { 645 msect.name = "__mod_init_func" 646 msect.flag = S_MOD_INIT_FUNC_POINTERS 647 } 648 649 // Some platforms such as watchOS and tvOS require binaries with 650 // bitcode enabled. The Go toolchain can't output bitcode, so use 651 // a marker section in the __LLVM segment, "__asm", to tell the Apple 652 // toolchain that the Go text came from assembler and thus has no 653 // bitcode. This is not true, but Kotlin/Native, Rust and Flutter 654 // are also using this trick. 655 if sect.Name == ".llvmasm" { 656 msect.name = "__asm" 657 msect.segname = "__LLVM" 658 } 659 660 if segname == "__DWARF" { 661 msect.flag |= S_ATTR_DEBUG 662 } 663} 664 665func asmbMacho(ctxt *Link) { 666 machlink := doMachoLink(ctxt) 667 if ctxt.IsExternal() { 668 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *FlagRound)) + uint64(machlink)) 669 ctxt.Out.SeekSet(symo) 670 machoEmitReloc(ctxt) 671 } 672 ctxt.Out.SeekSet(0) 673 674 ldr := ctxt.loader 675 676 /* apple MACH */ 677 va := *FlagTextAddr - int64(HEADR) 678 679 mh := getMachoHdr() 680 switch ctxt.Arch.Family { 681 default: 682 Exitf("unknown macho architecture: %v", ctxt.Arch.Family) 683 684 case sys.AMD64: 685 mh.cpu = MACHO_CPU_AMD64 686 mh.subcpu = MACHO_SUBCPU_X86 687 688 case sys.ARM64: 689 mh.cpu = MACHO_CPU_ARM64 690 mh.subcpu = MACHO_SUBCPU_ARM64_ALL 691 } 692 693 var ms *MachoSeg 694 if ctxt.LinkMode == LinkExternal { 695 /* segment for entire file */ 696 ms = newMachoSeg("", 40) 697 698 ms.fileoffset = Segtext.Fileoff 699 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff 700 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr 701 } 702 703 /* segment for zero page */ 704 if ctxt.LinkMode != LinkExternal { 705 ms = newMachoSeg("__PAGEZERO", 0) 706 ms.vsize = uint64(va) 707 } 708 709 /* text */ 710 v := Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) 711 712 var mstext *MachoSeg 713 if ctxt.LinkMode != LinkExternal { 714 ms = newMachoSeg("__TEXT", 20) 715 ms.vaddr = uint64(va) 716 ms.vsize = uint64(v) 717 ms.fileoffset = 0 718 ms.filesize = uint64(v) 719 ms.prot1 = 7 720 ms.prot2 = 5 721 mstext = ms 722 } 723 724 for _, sect := range Segtext.Sections { 725 machoshbits(ctxt, ms, sect, "__TEXT") 726 } 727 728 /* rodata */ 729 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 { 730 ms = newMachoSeg("__DATA_CONST", 20) 731 ms.vaddr = Segrelrodata.Vaddr 732 ms.vsize = Segrelrodata.Length 733 ms.fileoffset = Segrelrodata.Fileoff 734 ms.filesize = Segrelrodata.Filelen 735 ms.prot1 = 3 736 ms.prot2 = 3 737 ms.flag = 0x10 // SG_READ_ONLY 738 } 739 740 for _, sect := range Segrelrodata.Sections { 741 machoshbits(ctxt, ms, sect, "__DATA_CONST") 742 } 743 744 /* data */ 745 if ctxt.LinkMode != LinkExternal { 746 ms = newMachoSeg("__DATA", 20) 747 ms.vaddr = Segdata.Vaddr 748 ms.vsize = Segdata.Length 749 ms.fileoffset = Segdata.Fileoff 750 ms.filesize = Segdata.Filelen 751 ms.prot1 = 3 752 ms.prot2 = 3 753 } 754 755 for _, sect := range Segdata.Sections { 756 machoshbits(ctxt, ms, sect, "__DATA") 757 } 758 759 /* dwarf */ 760 if !*FlagW { 761 if ctxt.LinkMode != LinkExternal { 762 ms = newMachoSeg("__DWARF", 20) 763 ms.vaddr = Segdwarf.Vaddr 764 ms.vsize = 0 765 ms.fileoffset = Segdwarf.Fileoff 766 ms.filesize = Segdwarf.Filelen 767 } 768 for _, sect := range Segdwarf.Sections { 769 machoshbits(ctxt, ms, sect, "__DWARF") 770 } 771 } 772 773 if ctxt.LinkMode != LinkExternal { 774 switch ctxt.Arch.Family { 775 default: 776 Exitf("unknown macho architecture: %v", ctxt.Arch.Family) 777 778 case sys.AMD64: 779 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2) 780 ml.data[0] = 4 /* thread type */ 781 ml.data[1] = 42 /* word count */ 782 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */ 783 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) 784 785 case sys.ARM64: 786 ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4) 787 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) 788 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32) 789 } 790 } 791 792 var codesigOff int64 793 if !*FlagD { 794 // must match doMachoLink below 795 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0)) 796 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0)) 797 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0)) 798 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) 799 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) 800 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0)) 801 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0)) 802 803 if ctxt.LinkMode != LinkExternal { 804 ms := newMachoSeg("__LINKEDIT", 0) 805 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound)) 806 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7) 807 ms.fileoffset = uint64(linkoff) 808 ms.filesize = ms.vsize 809 ms.prot1 = 1 810 ms.prot2 = 1 811 812 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6 813 } 814 815 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() { 816 ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10) 817 ml.data[0] = uint32(linkoff) // rebase off 818 ml.data[1] = uint32(s1) // rebase size 819 ml.data[2] = uint32(linkoff + s1) // bind off 820 ml.data[3] = uint32(s2) // bind size 821 ml.data[4] = 0 // weak bind off 822 ml.data[5] = 0 // weak bind size 823 ml.data[6] = 0 // lazy bind off 824 ml.data[7] = 0 // lazy bind size 825 ml.data[8] = 0 // export 826 ml.data[9] = 0 // export size 827 } 828 829 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4) 830 ml.data[0] = uint32(linkoff + s1 + s2) /* symoff */ 831 ml.data[1] = uint32(nsortsym) /* nsyms */ 832 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */ 833 ml.data[3] = uint32(s6) /* strsize */ 834 835 if ctxt.LinkMode != LinkExternal { 836 machodysymtab(ctxt, linkoff+s1+s2) 837 838 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6) 839 ml.data[0] = 12 /* offset to string */ 840 stringtouint32(ml.data[1:], "/usr/lib/dyld") 841 842 for _, lib := range dylib { 843 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2) 844 ml.data[0] = 24 /* offset of string from beginning of load */ 845 ml.data[1] = 0 /* time stamp */ 846 ml.data[2] = 0 /* version */ 847 ml.data[3] = 0 /* compatibility version */ 848 stringtouint32(ml.data[4:], lib) 849 } 850 } 851 852 if ctxt.IsInternal() && ctxt.NeedCodeSign() { 853 ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2) 854 ml.data[0] = uint32(codesigOff) 855 ml.data[1] = uint32(s7) 856 } 857 } 858 859 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode) 860 if int32(a) > HEADR { 861 Exitf("HEADR too small: %d > %d", a, HEADR) 862 } 863 864 // Now we have written everything. Compute the code signature (which 865 // is a hash of the file content, so it must be done at last.) 866 if ctxt.IsInternal() && ctxt.NeedCodeSign() { 867 cs := ldr.Lookup(".machocodesig", 0) 868 data := ctxt.Out.Data() 869 if int64(len(data)) != codesigOff { 870 panic("wrong size") 871 } 872 codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE()) 873 ctxt.Out.SeekSet(codesigOff) 874 ctxt.Out.Write(ldr.Data(cs)) 875 } 876} 877 878func symkind(ldr *loader.Loader, s loader.Sym) int { 879 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT { 880 return SymKindUndef 881 } 882 if ldr.AttrCgoExport(s) { 883 return SymKindExtdef 884 } 885 return SymKindLocal 886} 887 888func collectmachosyms(ctxt *Link) { 889 ldr := ctxt.loader 890 891 addsym := func(s loader.Sym) { 892 sortsym = append(sortsym, s) 893 nkind[symkind(ldr, s)]++ 894 } 895 896 // On Mach-O, even with -s, we still need to keep dynamically exported and 897 // referenced symbols. We can strip defined local text and data symbols. 898 // So *FlagS is applied based on symbol type. 899 900 // Add special runtime.text and runtime.etext symbols (which are local). 901 // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo(). 902 // See data.go:/textaddress 903 // NOTE: runtime.text.N symbols (if we split text sections) are not added, though, 904 // so we handle them here. 905 if !*FlagS { 906 if !ctxt.DynlinkingGo() { 907 s := ldr.Lookup("runtime.text", 0) 908 if ldr.SymType(s) == sym.STEXT { 909 addsym(s) 910 } 911 } 912 for n := range Segtext.Sections[1:] { 913 s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0) 914 if s != 0 { 915 addsym(s) 916 } else { 917 break 918 } 919 } 920 if !ctxt.DynlinkingGo() { 921 s := ldr.Lookup("runtime.etext", 0) 922 if ldr.SymType(s) == sym.STEXT { 923 addsym(s) 924 } 925 } 926 } 927 928 // Add text symbols. 929 for _, s := range ctxt.Textp { 930 if *FlagS && !ldr.AttrCgoExportDynamic(s) { 931 continue 932 } 933 addsym(s) 934 } 935 936 shouldBeInSymbolTable := func(s loader.Sym) bool { 937 if ldr.AttrNotInSymbolTable(s) { 938 return false 939 } 940 name := ldr.SymName(s) // TODO: try not to read the name 941 if name == "" || name[0] == '.' { 942 return false 943 } 944 return true 945 } 946 947 // Add data symbols and external references. 948 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 949 if !ldr.AttrReachable(s) { 950 continue 951 } 952 t := ldr.SymType(s) 953 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata 954 if t == sym.STLSBSS { 955 // TLSBSS is not used on darwin. See data.go:allocateDataSections 956 continue 957 } 958 if !shouldBeInSymbolTable(s) { 959 continue 960 } 961 if *FlagS && !ldr.AttrCgoExportDynamic(s) { 962 continue 963 } 964 addsym(s) 965 continue 966 } 967 968 switch t { 969 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT: 970 // Keep dynamic symbol references even if *FlagS. 971 addsym(s) 972 } 973 974 // Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix. 975 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" { 976 // But only on macOS. 977 if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST { 978 switch n := ldr.SymExtname(s); n { 979 case "fdopendir": 980 switch buildcfg.GOARCH { 981 case "amd64": 982 ldr.SetSymExtname(s, n+"$INODE64") 983 } 984 case "readdir_r", "getfsstat": 985 switch buildcfg.GOARCH { 986 case "amd64": 987 ldr.SetSymExtname(s, n+"$INODE64") 988 } 989 } 990 } 991 } 992 } 993 994 nsortsym = len(sortsym) 995} 996 997func machosymorder(ctxt *Link) { 998 ldr := ctxt.loader 999 1000 // On Mac OS X Mountain Lion, we must sort exported symbols 1001 // So we sort them here and pre-allocate dynid for them 1002 // See https://golang.org/issue/4029 1003 for _, s := range ctxt.dynexp { 1004 if !ldr.AttrReachable(s) { 1005 panic("dynexp symbol is not reachable") 1006 } 1007 } 1008 collectmachosyms(ctxt) 1009 sort.Slice(sortsym[:nsortsym], func(i, j int) bool { 1010 s1 := sortsym[i] 1011 s2 := sortsym[j] 1012 k1 := symkind(ldr, s1) 1013 k2 := symkind(ldr, s2) 1014 if k1 != k2 { 1015 return k1 < k2 1016 } 1017 return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms 1018 }) 1019 for i, s := range sortsym { 1020 ldr.SetSymDynid(s, int32(i)) 1021 } 1022} 1023 1024// AddMachoSym adds s to Mach-O symbol table, used in GenSymLate. 1025// Currently only used on ARM64 when external linking. 1026func AddMachoSym(ldr *loader.Loader, s loader.Sym) { 1027 ldr.SetSymDynid(s, int32(nsortsym)) 1028 sortsym = append(sortsym, s) 1029 nsortsym++ 1030 nkind[symkind(ldr, s)]++ 1031} 1032 1033// machoShouldExport reports whether a symbol needs to be exported. 1034// 1035// When dynamically linking, all non-local variables and plugin-exported 1036// symbols need to be exported. 1037func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool { 1038 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) { 1039 return false 1040 } 1041 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) { 1042 return true 1043 } 1044 name := ldr.SymName(s) 1045 if strings.HasPrefix(name, "go:itab.") { 1046 return true 1047 } 1048 if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") { 1049 // reduce runtime typemap pressure, but do not 1050 // export alg functions (type:.*), as these 1051 // appear in pclntable. 1052 return true 1053 } 1054 if strings.HasPrefix(name, "go:link.pkghash") { 1055 return true 1056 } 1057 return ldr.SymType(s) >= sym.SFirstWritable // only writable sections 1058} 1059 1060func machosymtab(ctxt *Link) { 1061 ldr := ctxt.loader 1062 symtab := ldr.CreateSymForUpdate(".machosymtab", 0) 1063 symstr := ldr.CreateSymForUpdate(".machosymstr", 0) 1064 1065 for _, s := range sortsym[:nsortsym] { 1066 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size())) 1067 1068 export := machoShouldExport(ctxt, ldr, s) 1069 1070 // Prefix symbol names with "_" to match the system toolchain. 1071 // (We used to only prefix C symbols, which is all required for the build. 1072 // But some tools don't recognize Go symbols as symbols, so we prefix them 1073 // as well.) 1074 symstr.AddUint8('_') 1075 1076 // replace "·" as ".", because DTrace cannot handle it. 1077 name := strings.Replace(ldr.SymExtname(s), "·", ".", -1) 1078 1079 name = mangleABIName(ctxt, ldr, s, name) 1080 symstr.Addstring(name) 1081 1082 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT { 1083 symtab.AddUint8(0x01) // type N_EXT, external symbol 1084 symtab.AddUint8(0) // no section 1085 symtab.AddUint16(ctxt.Arch, 0) // desc 1086 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value 1087 } else { 1088 if export || ldr.AttrCgoExportDynamic(s) { 1089 symtab.AddUint8(0x0f) // N_SECT | N_EXT 1090 } else if ldr.AttrCgoExportStatic(s) { 1091 // Only export statically, not dynamically. (N_PEXT is like hidden visibility) 1092 symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT 1093 } else { 1094 symtab.AddUint8(0x0e) // N_SECT 1095 } 1096 o := s 1097 if outer := ldr.OuterSym(o); outer != 0 { 1098 o = outer 1099 } 1100 if ldr.SymSect(o) == nil { 1101 ldr.Errorf(s, "missing section for symbol") 1102 symtab.AddUint8(0) 1103 } else { 1104 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum)) 1105 } 1106 symtab.AddUint16(ctxt.Arch, 0) // desc 1107 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize) 1108 } 1109 } 1110} 1111 1112func machodysymtab(ctxt *Link, base int64) { 1113 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18) 1114 1115 n := 0 1116 ml.data[0] = uint32(n) /* ilocalsym */ 1117 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 1118 n += nkind[SymKindLocal] 1119 1120 ml.data[2] = uint32(n) /* iextdefsym */ 1121 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 1122 n += nkind[SymKindExtdef] 1123 1124 ml.data[4] = uint32(n) /* iundefsym */ 1125 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 1126 1127 ml.data[6] = 0 /* tocoffset */ 1128 ml.data[7] = 0 /* ntoc */ 1129 ml.data[8] = 0 /* modtaboff */ 1130 ml.data[9] = 0 /* nmodtab */ 1131 ml.data[10] = 0 /* extrefsymoff */ 1132 ml.data[11] = 0 /* nextrefsyms */ 1133 1134 ldr := ctxt.loader 1135 1136 // must match domacholink below 1137 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0)) 1138 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) 1139 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) 1140 ml.data[12] = uint32(base + s1) /* indirectsymoff */ 1141 ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */ 1142 1143 ml.data[14] = 0 /* extreloff */ 1144 ml.data[15] = 0 /* nextrel */ 1145 ml.data[16] = 0 /* locreloff */ 1146 ml.data[17] = 0 /* nlocrel */ 1147} 1148 1149func doMachoLink(ctxt *Link) int64 { 1150 machosymtab(ctxt) 1151 machoDyldInfo(ctxt) 1152 1153 ldr := ctxt.loader 1154 1155 // write data that will be linkedit section 1156 s1 := ldr.Lookup(".machorebase", 0) 1157 s2 := ldr.Lookup(".machobind", 0) 1158 s3 := ldr.Lookup(".machosymtab", 0) 1159 s4 := ctxt.ArchSyms.LinkEditPLT 1160 s5 := ctxt.ArchSyms.LinkEditGOT 1161 s6 := ldr.Lookup(".machosymstr", 0) 1162 1163 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6) 1164 1165 // Force the linkedit section to end on a 16-byte 1166 // boundary. This allows pure (non-cgo) Go binaries 1167 // to be code signed correctly. 1168 // 1169 // Apple's codesign_allocate (a helper utility for 1170 // the codesign utility) can do this fine itself if 1171 // it is run on a dynamic Mach-O binary. However, 1172 // when it is run on a pure (non-cgo) Go binary, where 1173 // the linkedit section is mostly empty, it fails to 1174 // account for the extra padding that it itself adds 1175 // when adding the LC_CODE_SIGNATURE load command 1176 // (which must be aligned on a 16-byte boundary). 1177 // 1178 // By forcing the linkedit section to end on a 16-byte 1179 // boundary, codesign_allocate will not need to apply 1180 // any alignment padding itself, working around the 1181 // issue. 1182 if size%16 != 0 { 1183 n := 16 - size%16 1184 s6b := ldr.MakeSymbolUpdater(s6) 1185 s6b.Grow(s6b.Size() + n) 1186 s6b.SetSize(s6b.Size() + n) 1187 size += n 1188 } 1189 1190 if size > 0 { 1191 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound) + Rnd(int64(Segdwarf.Filelen), *FlagRound) 1192 ctxt.Out.SeekSet(linkoff) 1193 1194 ctxt.Out.Write(ldr.Data(s1)) 1195 ctxt.Out.Write(ldr.Data(s2)) 1196 ctxt.Out.Write(ldr.Data(s3)) 1197 ctxt.Out.Write(ldr.Data(s4)) 1198 ctxt.Out.Write(ldr.Data(s5)) 1199 ctxt.Out.Write(ldr.Data(s6)) 1200 1201 // Add code signature if necessary. This must be the last. 1202 s7 := machoCodeSigSym(ctxt, linkoff+size) 1203 size += ldr.SymSize(s7) 1204 } 1205 1206 return Rnd(size, *FlagRound) 1207} 1208 1209func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) { 1210 // If main section has no bits, nothing to relocate. 1211 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 1212 return 1213 } 1214 ldr := ctxt.loader 1215 1216 for i, s := range syms { 1217 if !ldr.AttrReachable(s) { 1218 continue 1219 } 1220 if uint64(ldr.SymValue(s)) >= sect.Vaddr { 1221 syms = syms[i:] 1222 break 1223 } 1224 } 1225 1226 eaddr := sect.Vaddr + sect.Length 1227 for _, s := range syms { 1228 if !ldr.AttrReachable(s) { 1229 continue 1230 } 1231 if ldr.SymValue(s) >= int64(eaddr) { 1232 break 1233 } 1234 1235 // Compute external relocations on the go, and pass to Machoreloc1 1236 // to stream out. 1237 relocs := ldr.Relocs(s) 1238 for ri := 0; ri < relocs.Count(); ri++ { 1239 r := relocs.At(ri) 1240 rr, ok := extreloc(ctxt, ldr, s, r) 1241 if !ok { 1242 continue 1243 } 1244 if rr.Xsym == 0 { 1245 ldr.Errorf(s, "missing xsym in relocation") 1246 continue 1247 } 1248 if !ldr.AttrReachable(rr.Xsym) { 1249 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym)) 1250 } 1251 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) { 1252 ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym())) 1253 } 1254 } 1255 } 1256 1257 // sanity check 1258 if uint64(out.Offset()) != sect.Reloff+sect.Rellen { 1259 panic("machorelocsect: size mismatch") 1260 } 1261} 1262 1263func machoEmitReloc(ctxt *Link) { 1264 for ctxt.Out.Offset()&7 != 0 { 1265 ctxt.Out.Write8(0) 1266 } 1267 1268 sizeExtRelocs(ctxt, thearch.MachorelocSize) 1269 relocSect, wg := relocSectFn(ctxt, machorelocsect) 1270 1271 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp) 1272 for _, sect := range Segtext.Sections[1:] { 1273 if sect.Name == ".text" { 1274 relocSect(ctxt, sect, ctxt.Textp) 1275 } else { 1276 relocSect(ctxt, sect, ctxt.datap) 1277 } 1278 } 1279 for _, sect := range Segrelrodata.Sections { 1280 relocSect(ctxt, sect, ctxt.datap) 1281 } 1282 for _, sect := range Segdata.Sections { 1283 relocSect(ctxt, sect, ctxt.datap) 1284 } 1285 for i := 0; i < len(Segdwarf.Sections); i++ { 1286 sect := Segdwarf.Sections[i] 1287 si := dwarfp[i] 1288 if si.secSym() != loader.Sym(sect.Sym) || 1289 ctxt.loader.SymSect(si.secSym()) != sect { 1290 panic("inconsistency between dwarfp and Segdwarf") 1291 } 1292 relocSect(ctxt, sect, si.syms) 1293 } 1294 wg.Wait() 1295} 1296 1297// hostobjMachoPlatform returns the first platform load command found 1298// in the host object, if any. 1299func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) { 1300 f, err := os.Open(h.file) 1301 if err != nil { 1302 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err) 1303 } 1304 defer f.Close() 1305 sr := io.NewSectionReader(f, h.off, h.length) 1306 m, err := macho.NewFile(sr) 1307 if err != nil { 1308 // Not a valid Mach-O file. 1309 return nil, nil 1310 } 1311 return peekMachoPlatform(m) 1312} 1313 1314// peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION 1315// load command found in the Mach-O file, if any. 1316func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) { 1317 for _, cmd := range m.Loads { 1318 raw := cmd.Raw() 1319 ml := MachoLoad{ 1320 type_: m.ByteOrder.Uint32(raw), 1321 } 1322 // Skip the type and command length. 1323 data := raw[8:] 1324 var p MachoPlatform 1325 switch ml.type_ { 1326 case LC_VERSION_MIN_IPHONEOS: 1327 p = PLATFORM_IOS 1328 case LC_VERSION_MIN_MACOSX: 1329 p = PLATFORM_MACOS 1330 case LC_VERSION_MIN_WATCHOS: 1331 p = PLATFORM_WATCHOS 1332 case LC_VERSION_MIN_TVOS: 1333 p = PLATFORM_TVOS 1334 case LC_BUILD_VERSION: 1335 p = MachoPlatform(m.ByteOrder.Uint32(data)) 1336 default: 1337 continue 1338 } 1339 ml.data = make([]uint32, len(data)/4) 1340 r := bytes.NewReader(data) 1341 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil { 1342 return nil, err 1343 } 1344 return &MachoPlatformLoad{ 1345 platform: p, 1346 cmd: ml, 1347 }, nil 1348 } 1349 return nil, nil 1350} 1351 1352// A rebase entry tells the dynamic linker the data at sym+off needs to be 1353// relocated when the in-memory image moves. (This is somewhat like, say, 1354// ELF R_X86_64_RELATIVE). 1355// For now, the only kind of entry we support is that the data is an absolute 1356// address. That seems all we need. 1357// In the binary it uses a compact stateful bytecode encoding. So we record 1358// entries as we go and build the table at the end. 1359type machoRebaseRecord struct { 1360 sym loader.Sym 1361 off int64 1362} 1363 1364var machorebase []machoRebaseRecord 1365 1366func MachoAddRebase(s loader.Sym, off int64) { 1367 machorebase = append(machorebase, machoRebaseRecord{s, off}) 1368} 1369 1370// A bind entry tells the dynamic linker the data at GOT+off should be bound 1371// to the address of the target symbol, which is a dynamic import. 1372// For now, the only kind of entry we support is that the data is an absolute 1373// address, and the source symbol is always the GOT. That seems all we need. 1374// In the binary it uses a compact stateful bytecode encoding. So we record 1375// entries as we go and build the table at the end. 1376type machoBindRecord struct { 1377 off int64 1378 targ loader.Sym 1379} 1380 1381var machobind []machoBindRecord 1382 1383func MachoAddBind(off int64, targ loader.Sym) { 1384 machobind = append(machobind, machoBindRecord{off, targ}) 1385} 1386 1387// Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command. 1388// See mach-o/loader.h, struct dyld_info_command, for the encoding. 1389// e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h 1390func machoDyldInfo(ctxt *Link) { 1391 ldr := ctxt.loader 1392 rebase := ldr.CreateSymForUpdate(".machorebase", 0) 1393 bind := ldr.CreateSymForUpdate(".machobind", 0) 1394 1395 if !(ctxt.IsPIE() && ctxt.IsInternal()) { 1396 return 1397 } 1398 1399 segId := func(seg *sym.Segment) uint8 { 1400 switch seg { 1401 case &Segtext: 1402 return 1 1403 case &Segrelrodata: 1404 return 2 1405 case &Segdata: 1406 if Segrelrodata.Length > 0 { 1407 return 3 1408 } 1409 return 2 1410 } 1411 panic("unknown segment") 1412 } 1413 1414 dylibId := func(s loader.Sym) int { 1415 slib := ldr.SymDynimplib(s) 1416 for i, lib := range dylib { 1417 if lib == slib { 1418 return i + 1 1419 } 1420 } 1421 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from 1422 } 1423 1424 // Rebase table. 1425 // TODO: use more compact encoding. The encoding is stateful, and 1426 // we can use delta encoding. 1427 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER) 1428 for _, r := range machorebase { 1429 seg := ldr.SymSect(r.sym).Seg 1430 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr 1431 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) 1432 rebase.AddUleb(off) 1433 1434 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1) 1435 } 1436 rebase.AddUint8(REBASE_OPCODE_DONE) 1437 sz := Rnd(rebase.Size(), 8) 1438 rebase.Grow(sz) 1439 rebase.SetSize(sz) 1440 1441 // Bind table. 1442 // TODO: compact encoding, as above. 1443 // TODO: lazy binding? 1444 got := ctxt.GOT 1445 seg := ldr.SymSect(got).Seg 1446 gotAddr := ldr.SymValue(got) 1447 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER) 1448 for _, r := range machobind { 1449 off := uint64(gotAddr+r.off) - seg.Vaddr 1450 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) 1451 bind.AddUleb(off) 1452 1453 d := dylibId(r.targ) 1454 if d > 0 && d < 128 { 1455 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf) 1456 } else if d >= 128 { 1457 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) 1458 bind.AddUleb(uint64(d)) 1459 } else { // d <= 0 1460 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf) 1461 } 1462 1463 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) 1464 // target symbol name as a C string, with _ prefix 1465 bind.AddUint8('_') 1466 bind.Addstring(ldr.SymExtname(r.targ)) 1467 1468 bind.AddUint8(BIND_OPCODE_DO_BIND) 1469 } 1470 bind.AddUint8(BIND_OPCODE_DONE) 1471 sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink 1472 bind.Grow(sz) 1473 bind.SetSize(sz) 1474 1475 // TODO: export table. 1476 // The symbols names are encoded as a trie. I'm really too lazy to do that 1477 // for now. 1478 // Without it, the symbols are not dynamically exported, so they cannot be 1479 // e.g. dlsym'd. But internal linking is not the default in that case, so 1480 // it is fine. 1481} 1482 1483// machoCodeSigSym creates and returns a symbol for code signature. 1484// The symbol context is left as zeros, which will be generated at the end 1485// (as it depends on the rest of the file). 1486func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym { 1487 ldr := ctxt.loader 1488 cs := ldr.CreateSymForUpdate(".machocodesig", 0) 1489 if !ctxt.NeedCodeSign() || ctxt.IsExternal() { 1490 return cs.Sym() 1491 } 1492 sz := codesign.Size(codeSize, "a.out") 1493 cs.Grow(sz) 1494 cs.SetSize(sz) 1495 return cs.Sym() 1496} 1497 1498// machoCodeSign code-signs Mach-O file fname with an ad-hoc signature. 1499// This is used for updating an external linker generated binary. 1500func machoCodeSign(ctxt *Link, fname string) error { 1501 f, err := os.OpenFile(fname, os.O_RDWR, 0) 1502 if err != nil { 1503 return err 1504 } 1505 defer f.Close() 1506 1507 mf, err := macho.NewFile(f) 1508 if err != nil { 1509 return err 1510 } 1511 if mf.Magic != macho.Magic64 { 1512 Exitf("not 64-bit Mach-O file: %s", fname) 1513 } 1514 1515 // Find existing LC_CODE_SIGNATURE and __LINKEDIT segment 1516 var sigOff, sigSz, csCmdOff, linkeditOff int64 1517 var linkeditSeg, textSeg *macho.Segment 1518 loadOff := int64(machoHeaderSize64) 1519 get32 := mf.ByteOrder.Uint32 1520 for _, l := range mf.Loads { 1521 data := l.Raw() 1522 cmd, sz := get32(data), get32(data[4:]) 1523 if cmd == LC_CODE_SIGNATURE { 1524 sigOff = int64(get32(data[8:])) 1525 sigSz = int64(get32(data[12:])) 1526 csCmdOff = loadOff 1527 } 1528 if seg, ok := l.(*macho.Segment); ok { 1529 switch seg.Name { 1530 case "__LINKEDIT": 1531 linkeditSeg = seg 1532 linkeditOff = loadOff 1533 case "__TEXT": 1534 textSeg = seg 1535 } 1536 } 1537 loadOff += int64(sz) 1538 } 1539 1540 if sigOff == 0 { 1541 // The C linker doesn't generate a signed binary, for some reason. 1542 // Skip. 1543 return nil 1544 } 1545 1546 fi, err := f.Stat() 1547 if err != nil { 1548 return err 1549 } 1550 if sigOff+sigSz != fi.Size() { 1551 // We don't expect anything after the signature (this will invalidate 1552 // the signature anyway.) 1553 return fmt.Errorf("unexpected content after code signature") 1554 } 1555 1556 sz := codesign.Size(sigOff, "a.out") 1557 if sz != sigSz { 1558 // Update the load command, 1559 var tmp [8]byte 1560 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz)) 1561 _, err = f.WriteAt(tmp[:4], csCmdOff+12) 1562 if err != nil { 1563 return err 1564 } 1565 1566 // Uodate the __LINKEDIT segment. 1567 segSz := sigOff + sz - int64(linkeditSeg.Offset) 1568 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz)) 1569 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz))) 1570 if err != nil { 1571 return err 1572 } 1573 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz))) 1574 if err != nil { 1575 return err 1576 } 1577 } 1578 1579 cs := make([]byte, sz) 1580 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE()) 1581 _, err = f.WriteAt(cs, sigOff) 1582 if err != nil { 1583 return err 1584 } 1585 err = f.Truncate(sigOff + sz) 1586 return err 1587} 1588