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