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