github.com/bir3/gocompiler@v0.9.2202/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 ctxt.IsExternal() { 669 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *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), *FlagRound) 712 713 var mstext *MachoSeg 714 if ctxt.LinkMode != LinkExternal { 715 ms = newMachoSeg("__TEXT", 20) 716 ms.vaddr = uint64(va) 717 ms.vsize = uint64(v) 718 ms.fileoffset = 0 719 ms.filesize = uint64(v) 720 ms.prot1 = 7 721 ms.prot2 = 5 722 mstext = ms 723 } 724 725 for _, sect := range Segtext.Sections { 726 machoshbits(ctxt, ms, sect, "__TEXT") 727 } 728 729 /* rodata */ 730 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 { 731 ms = newMachoSeg("__DATA_CONST", 20) 732 ms.vaddr = Segrelrodata.Vaddr 733 ms.vsize = Segrelrodata.Length 734 ms.fileoffset = Segrelrodata.Fileoff 735 ms.filesize = Segrelrodata.Filelen 736 ms.prot1 = 3 737 ms.prot2 = 3 738 ms.flag = 0x10 // SG_READ_ONLY 739 } 740 741 for _, sect := range Segrelrodata.Sections { 742 machoshbits(ctxt, ms, sect, "__DATA_CONST") 743 } 744 745 /* data */ 746 if ctxt.LinkMode != LinkExternal { 747 ms = newMachoSeg("__DATA", 20) 748 ms.vaddr = Segdata.Vaddr 749 ms.vsize = Segdata.Length 750 ms.fileoffset = Segdata.Fileoff 751 ms.filesize = Segdata.Filelen 752 ms.prot1 = 3 753 ms.prot2 = 3 754 } 755 756 for _, sect := range Segdata.Sections { 757 machoshbits(ctxt, ms, sect, "__DATA") 758 } 759 760 /* dwarf */ 761 if !*FlagW { 762 if ctxt.LinkMode != LinkExternal { 763 ms = newMachoSeg("__DWARF", 20) 764 ms.vaddr = Segdwarf.Vaddr 765 ms.vsize = 0 766 ms.fileoffset = Segdwarf.Fileoff 767 ms.filesize = Segdwarf.Filelen 768 } 769 for _, sect := range Segdwarf.Sections { 770 machoshbits(ctxt, ms, sect, "__DWARF") 771 } 772 } 773 774 if ctxt.LinkMode != LinkExternal { 775 switch ctxt.Arch.Family { 776 default: 777 Exitf("unknown macho architecture: %v", ctxt.Arch.Family) 778 779 case sys.AMD64: 780 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2) 781 ml.data[0] = 4 /* thread type */ 782 ml.data[1] = 42 /* word count */ 783 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */ 784 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) 785 786 case sys.ARM64: 787 ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4) 788 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) 789 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32) 790 } 791 } 792 793 var codesigOff int64 794 if !*FlagD { 795 // must match doMachoLink below 796 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0)) 797 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0)) 798 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0)) 799 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) 800 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) 801 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0)) 802 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0)) 803 804 if ctxt.LinkMode != LinkExternal { 805 ms := newMachoSeg("__LINKEDIT", 0) 806 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound)) 807 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7) 808 ms.fileoffset = uint64(linkoff) 809 ms.filesize = ms.vsize 810 ms.prot1 = 1 811 ms.prot2 = 1 812 813 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6 814 } 815 816 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() { 817 ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10) 818 ml.data[0] = uint32(linkoff) // rebase off 819 ml.data[1] = uint32(s1) // rebase size 820 ml.data[2] = uint32(linkoff + s1) // bind off 821 ml.data[3] = uint32(s2) // bind size 822 ml.data[4] = 0 // weak bind off 823 ml.data[5] = 0 // weak bind size 824 ml.data[6] = 0 // lazy bind off 825 ml.data[7] = 0 // lazy bind size 826 ml.data[8] = 0 // export 827 ml.data[9] = 0 // export size 828 } 829 830 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4) 831 ml.data[0] = uint32(linkoff + s1 + s2) /* symoff */ 832 ml.data[1] = uint32(nsortsym) /* nsyms */ 833 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */ 834 ml.data[3] = uint32(s6) /* strsize */ 835 836 if ctxt.LinkMode != LinkExternal { 837 machodysymtab(ctxt, linkoff+s1+s2) 838 839 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6) 840 ml.data[0] = 12 /* offset to string */ 841 stringtouint32(ml.data[1:], "/usr/lib/dyld") 842 843 for _, lib := range dylib { 844 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2) 845 ml.data[0] = 24 /* offset of string from beginning of load */ 846 ml.data[1] = 0 /* time stamp */ 847 ml.data[2] = 0 /* version */ 848 ml.data[3] = 0 /* compatibility version */ 849 stringtouint32(ml.data[4:], lib) 850 } 851 } 852 853 if ctxt.IsInternal() && ctxt.NeedCodeSign() { 854 ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2) 855 ml.data[0] = uint32(codesigOff) 856 ml.data[1] = uint32(s7) 857 } 858 } 859 860 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode) 861 if int32(a) > HEADR { 862 Exitf("HEADR too small: %d > %d", a, HEADR) 863 } 864 865 // Now we have written everything. Compute the code signature (which 866 // is a hash of the file content, so it must be done at last.) 867 if ctxt.IsInternal() && ctxt.NeedCodeSign() { 868 cs := ldr.Lookup(".machocodesig", 0) 869 data := ctxt.Out.Data() 870 if int64(len(data)) != codesigOff { 871 panic("wrong size") 872 } 873 codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE()) 874 ctxt.Out.SeekSet(codesigOff) 875 ctxt.Out.Write(ldr.Data(cs)) 876 } 877 } 878 879 func symkind(ldr *loader.Loader, s loader.Sym) int { 880 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT { 881 return SymKindUndef 882 } 883 if ldr.AttrCgoExport(s) { 884 return SymKindExtdef 885 } 886 return SymKindLocal 887 } 888 889 func collectmachosyms(ctxt *Link) { 890 ldr := ctxt.loader 891 892 addsym := func(s loader.Sym) { 893 sortsym = append(sortsym, s) 894 nkind[symkind(ldr, s)]++ 895 } 896 897 // On Mach-O, even with -s, we still need to keep dynamically exported and 898 // referenced symbols. We can strip defined local text and data symbols. 899 // So *FlagS is applied based on symbol type. 900 901 // Add special runtime.text and runtime.etext symbols (which are local). 902 // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo(). 903 // See data.go:/textaddress 904 if !*FlagS { 905 if !ctxt.DynlinkingGo() { 906 s := ldr.Lookup("runtime.text", 0) 907 if ldr.SymType(s) == sym.STEXT { 908 addsym(s) 909 } 910 for n := range Segtext.Sections[1:] { 911 s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0) 912 if s != 0 { 913 addsym(s) 914 } else { 915 break 916 } 917 } 918 s = ldr.Lookup("runtime.etext", 0) 919 if ldr.SymType(s) == sym.STEXT { 920 addsym(s) 921 } 922 } 923 } 924 925 // Add text symbols. 926 for _, s := range ctxt.Textp { 927 if *FlagS && !ldr.AttrCgoExportDynamic(s) { 928 continue 929 } 930 addsym(s) 931 } 932 933 shouldBeInSymbolTable := func(s loader.Sym) bool { 934 if ldr.AttrNotInSymbolTable(s) { 935 return false 936 } 937 name := ldr.SymName(s) // TODO: try not to read the name 938 if name == "" || name[0] == '.' { 939 return false 940 } 941 return true 942 } 943 944 // Add data symbols and external references. 945 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 946 if !ldr.AttrReachable(s) { 947 continue 948 } 949 t := ldr.SymType(s) 950 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata 951 if t == sym.STLSBSS { 952 // TLSBSS is not used on darwin. See data.go:allocateDataSections 953 continue 954 } 955 if !shouldBeInSymbolTable(s) { 956 continue 957 } 958 if *FlagS && !ldr.AttrCgoExportDynamic(s) { 959 continue 960 } 961 addsym(s) 962 continue 963 } 964 965 switch t { 966 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT: 967 // Keep dynamic symbol references even if *FlagS. 968 addsym(s) 969 } 970 971 // Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix. 972 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" { 973 // But only on macOS. 974 if machoPlatform == PLATFORM_MACOS { 975 switch n := ldr.SymExtname(s); n { 976 case "fdopendir": 977 switch buildcfg.GOARCH { 978 case "amd64": 979 ldr.SetSymExtname(s, n+"$INODE64") 980 } 981 case "readdir_r", "getfsstat": 982 switch buildcfg.GOARCH { 983 case "amd64": 984 ldr.SetSymExtname(s, n+"$INODE64") 985 } 986 } 987 } 988 } 989 } 990 991 nsortsym = len(sortsym) 992 } 993 994 func machosymorder(ctxt *Link) { 995 ldr := ctxt.loader 996 997 // On Mac OS X Mountain Lion, we must sort exported symbols 998 // So we sort them here and pre-allocate dynid for them 999 // See https://golang.org/issue/4029 1000 for _, s := range ctxt.dynexp { 1001 if !ldr.AttrReachable(s) { 1002 panic("dynexp symbol is not reachable") 1003 } 1004 } 1005 collectmachosyms(ctxt) 1006 sort.Slice(sortsym[:nsortsym], func(i, j int) bool { 1007 s1 := sortsym[i] 1008 s2 := sortsym[j] 1009 k1 := symkind(ldr, s1) 1010 k2 := symkind(ldr, s2) 1011 if k1 != k2 { 1012 return k1 < k2 1013 } 1014 return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms 1015 }) 1016 for i, s := range sortsym { 1017 ldr.SetSymDynid(s, int32(i)) 1018 } 1019 } 1020 1021 // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate. 1022 // Currently only used on ARM64 when external linking. 1023 func AddMachoSym(ldr *loader.Loader, s loader.Sym) { 1024 ldr.SetSymDynid(s, int32(nsortsym)) 1025 sortsym = append(sortsym, s) 1026 nsortsym++ 1027 nkind[symkind(ldr, s)]++ 1028 } 1029 1030 // machoShouldExport reports whether a symbol needs to be exported. 1031 // 1032 // When dynamically linking, all non-local variables and plugin-exported 1033 // symbols need to be exported. 1034 func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool { 1035 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) { 1036 return false 1037 } 1038 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) { 1039 return true 1040 } 1041 name := ldr.SymName(s) 1042 if strings.HasPrefix(name, "go:itab.") { 1043 return true 1044 } 1045 if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") { 1046 // reduce runtime typemap pressure, but do not 1047 // export alg functions (type:.*), as these 1048 // appear in pclntable. 1049 return true 1050 } 1051 if strings.HasPrefix(name, "go:link.pkghash") { 1052 return true 1053 } 1054 return ldr.SymType(s) >= sym.SFirstWritable // only writable sections 1055 } 1056 1057 func machosymtab(ctxt *Link) { 1058 ldr := ctxt.loader 1059 symtab := ldr.CreateSymForUpdate(".machosymtab", 0) 1060 symstr := ldr.CreateSymForUpdate(".machosymstr", 0) 1061 1062 for _, s := range sortsym[:nsortsym] { 1063 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size())) 1064 1065 export := machoShouldExport(ctxt, ldr, s) 1066 1067 // Prefix symbol names with "_" to match the system toolchain. 1068 // (We used to only prefix C symbols, which is all required for the build. 1069 // But some tools don't recognize Go symbols as symbols, so we prefix them 1070 // as well.) 1071 symstr.AddUint8('_') 1072 1073 // replace "·" as ".", because DTrace cannot handle it. 1074 name := strings.Replace(ldr.SymExtname(s), "·", ".", -1) 1075 1076 name = mangleABIName(ctxt, ldr, s, name) 1077 symstr.Addstring(name) 1078 1079 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT { 1080 symtab.AddUint8(0x01) // type N_EXT, external symbol 1081 symtab.AddUint8(0) // no section 1082 symtab.AddUint16(ctxt.Arch, 0) // desc 1083 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value 1084 } else { 1085 if export || ldr.AttrCgoExportDynamic(s) { 1086 symtab.AddUint8(0x0f) // N_SECT | N_EXT 1087 } else if ldr.AttrCgoExportStatic(s) { 1088 // Only export statically, not dynamically. (N_PEXT is like hidden visibility) 1089 symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT 1090 } else { 1091 symtab.AddUint8(0x0e) // N_SECT 1092 } 1093 o := s 1094 if outer := ldr.OuterSym(o); outer != 0 { 1095 o = outer 1096 } 1097 if ldr.SymSect(o) == nil { 1098 ldr.Errorf(s, "missing section for symbol") 1099 symtab.AddUint8(0) 1100 } else { 1101 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum)) 1102 } 1103 symtab.AddUint16(ctxt.Arch, 0) // desc 1104 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize) 1105 } 1106 } 1107 } 1108 1109 func machodysymtab(ctxt *Link, base int64) { 1110 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18) 1111 1112 n := 0 1113 ml.data[0] = uint32(n) /* ilocalsym */ 1114 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 1115 n += nkind[SymKindLocal] 1116 1117 ml.data[2] = uint32(n) /* iextdefsym */ 1118 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 1119 n += nkind[SymKindExtdef] 1120 1121 ml.data[4] = uint32(n) /* iundefsym */ 1122 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 1123 1124 ml.data[6] = 0 /* tocoffset */ 1125 ml.data[7] = 0 /* ntoc */ 1126 ml.data[8] = 0 /* modtaboff */ 1127 ml.data[9] = 0 /* nmodtab */ 1128 ml.data[10] = 0 /* extrefsymoff */ 1129 ml.data[11] = 0 /* nextrefsyms */ 1130 1131 ldr := ctxt.loader 1132 1133 // must match domacholink below 1134 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0)) 1135 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT) 1136 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT) 1137 ml.data[12] = uint32(base + s1) /* indirectsymoff */ 1138 ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */ 1139 1140 ml.data[14] = 0 /* extreloff */ 1141 ml.data[15] = 0 /* nextrel */ 1142 ml.data[16] = 0 /* locreloff */ 1143 ml.data[17] = 0 /* nlocrel */ 1144 } 1145 1146 func doMachoLink(ctxt *Link) int64 { 1147 machosymtab(ctxt) 1148 machoDyldInfo(ctxt) 1149 1150 ldr := ctxt.loader 1151 1152 // write data that will be linkedit section 1153 s1 := ldr.Lookup(".machorebase", 0) 1154 s2 := ldr.Lookup(".machobind", 0) 1155 s3 := ldr.Lookup(".machosymtab", 0) 1156 s4 := ctxt.ArchSyms.LinkEditPLT 1157 s5 := ctxt.ArchSyms.LinkEditGOT 1158 s6 := ldr.Lookup(".machosymstr", 0) 1159 1160 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6) 1161 1162 // Force the linkedit section to end on a 16-byte 1163 // boundary. This allows pure (non-cgo) Go binaries 1164 // to be code signed correctly. 1165 // 1166 // Apple's codesign_allocate (a helper utility for 1167 // the codesign utility) can do this fine itself if 1168 // it is run on a dynamic Mach-O binary. However, 1169 // when it is run on a pure (non-cgo) Go binary, where 1170 // the linkedit section is mostly empty, it fails to 1171 // account for the extra padding that it itself adds 1172 // when adding the LC_CODE_SIGNATURE load command 1173 // (which must be aligned on a 16-byte boundary). 1174 // 1175 // By forcing the linkedit section to end on a 16-byte 1176 // boundary, codesign_allocate will not need to apply 1177 // any alignment padding itself, working around the 1178 // issue. 1179 if size%16 != 0 { 1180 n := 16 - size%16 1181 s6b := ldr.MakeSymbolUpdater(s6) 1182 s6b.Grow(s6b.Size() + n) 1183 s6b.SetSize(s6b.Size() + n) 1184 size += n 1185 } 1186 1187 if size > 0 { 1188 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound) + Rnd(int64(Segdwarf.Filelen), *FlagRound) 1189 ctxt.Out.SeekSet(linkoff) 1190 1191 ctxt.Out.Write(ldr.Data(s1)) 1192 ctxt.Out.Write(ldr.Data(s2)) 1193 ctxt.Out.Write(ldr.Data(s3)) 1194 ctxt.Out.Write(ldr.Data(s4)) 1195 ctxt.Out.Write(ldr.Data(s5)) 1196 ctxt.Out.Write(ldr.Data(s6)) 1197 1198 // Add code signature if necessary. This must be the last. 1199 s7 := machoCodeSigSym(ctxt, linkoff+size) 1200 size += ldr.SymSize(s7) 1201 } 1202 1203 return Rnd(size, *FlagRound) 1204 } 1205 1206 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) { 1207 // If main section has no bits, nothing to relocate. 1208 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 1209 return 1210 } 1211 ldr := ctxt.loader 1212 1213 for i, s := range syms { 1214 if !ldr.AttrReachable(s) { 1215 continue 1216 } 1217 if uint64(ldr.SymValue(s)) >= sect.Vaddr { 1218 syms = syms[i:] 1219 break 1220 } 1221 } 1222 1223 eaddr := sect.Vaddr + sect.Length 1224 for _, s := range syms { 1225 if !ldr.AttrReachable(s) { 1226 continue 1227 } 1228 if ldr.SymValue(s) >= int64(eaddr) { 1229 break 1230 } 1231 1232 // Compute external relocations on the go, and pass to Machoreloc1 1233 // to stream out. 1234 relocs := ldr.Relocs(s) 1235 for ri := 0; ri < relocs.Count(); ri++ { 1236 r := relocs.At(ri) 1237 rr, ok := extreloc(ctxt, ldr, s, r) 1238 if !ok { 1239 continue 1240 } 1241 if rr.Xsym == 0 { 1242 ldr.Errorf(s, "missing xsym in relocation") 1243 continue 1244 } 1245 if !ldr.AttrReachable(rr.Xsym) { 1246 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym)) 1247 } 1248 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) { 1249 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())) 1250 } 1251 } 1252 } 1253 1254 // sanity check 1255 if uint64(out.Offset()) != sect.Reloff+sect.Rellen { 1256 panic("machorelocsect: size mismatch") 1257 } 1258 } 1259 1260 func machoEmitReloc(ctxt *Link) { 1261 for ctxt.Out.Offset()&7 != 0 { 1262 ctxt.Out.Write8(0) 1263 } 1264 1265 sizeExtRelocs(ctxt, thearch.MachorelocSize) 1266 relocSect, wg := relocSectFn(ctxt, machorelocsect) 1267 1268 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp) 1269 for _, sect := range Segtext.Sections[1:] { 1270 if sect.Name == ".text" { 1271 relocSect(ctxt, sect, ctxt.Textp) 1272 } else { 1273 relocSect(ctxt, sect, ctxt.datap) 1274 } 1275 } 1276 for _, sect := range Segrelrodata.Sections { 1277 relocSect(ctxt, sect, ctxt.datap) 1278 } 1279 for _, sect := range Segdata.Sections { 1280 relocSect(ctxt, sect, ctxt.datap) 1281 } 1282 for i := 0; i < len(Segdwarf.Sections); i++ { 1283 sect := Segdwarf.Sections[i] 1284 si := dwarfp[i] 1285 if si.secSym() != loader.Sym(sect.Sym) || 1286 ctxt.loader.SymSect(si.secSym()) != sect { 1287 panic("inconsistency between dwarfp and Segdwarf") 1288 } 1289 relocSect(ctxt, sect, si.syms) 1290 } 1291 wg.Wait() 1292 } 1293 1294 // hostobjMachoPlatform returns the first platform load command found 1295 // in the host object, if any. 1296 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) { 1297 f, err := os.Open(h.file) 1298 if err != nil { 1299 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err) 1300 } 1301 defer f.Close() 1302 sr := io.NewSectionReader(f, h.off, h.length) 1303 m, err := macho.NewFile(sr) 1304 if err != nil { 1305 // Not a valid Mach-O file. 1306 return nil, nil 1307 } 1308 return peekMachoPlatform(m) 1309 } 1310 1311 // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION 1312 // load command found in the Mach-O file, if any. 1313 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) { 1314 for _, cmd := range m.Loads { 1315 raw := cmd.Raw() 1316 ml := MachoLoad{ 1317 type_: m.ByteOrder.Uint32(raw), 1318 } 1319 // Skip the type and command length. 1320 data := raw[8:] 1321 var p MachoPlatform 1322 switch ml.type_ { 1323 case LC_VERSION_MIN_IPHONEOS: 1324 p = PLATFORM_IOS 1325 case LC_VERSION_MIN_MACOSX: 1326 p = PLATFORM_MACOS 1327 case LC_VERSION_MIN_WATCHOS: 1328 p = PLATFORM_WATCHOS 1329 case LC_VERSION_MIN_TVOS: 1330 p = PLATFORM_TVOS 1331 case LC_BUILD_VERSION: 1332 p = MachoPlatform(m.ByteOrder.Uint32(data)) 1333 default: 1334 continue 1335 } 1336 ml.data = make([]uint32, len(data)/4) 1337 r := bytes.NewReader(data) 1338 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil { 1339 return nil, err 1340 } 1341 return &MachoPlatformLoad{ 1342 platform: p, 1343 cmd: ml, 1344 }, nil 1345 } 1346 return nil, nil 1347 } 1348 1349 // A rebase entry tells the dynamic linker the data at sym+off needs to be 1350 // relocated when the in-memory image moves. (This is somewhat like, say, 1351 // ELF R_X86_64_RELATIVE). 1352 // For now, the only kind of entry we support is that the data is an absolute 1353 // address. That seems all we need. 1354 // In the binary it uses a compact stateful bytecode encoding. So we record 1355 // entries as we go and build the table at the end. 1356 type machoRebaseRecord struct { 1357 sym loader.Sym 1358 off int64 1359 } 1360 1361 var machorebase []machoRebaseRecord 1362 1363 func MachoAddRebase(s loader.Sym, off int64) { 1364 machorebase = append(machorebase, machoRebaseRecord{s, off}) 1365 } 1366 1367 // A bind entry tells the dynamic linker the data at GOT+off should be bound 1368 // to the address of the target symbol, which is a dynamic import. 1369 // For now, the only kind of entry we support is that the data is an absolute 1370 // address, and the source symbol is always the GOT. That seems all we need. 1371 // In the binary it uses a compact stateful bytecode encoding. So we record 1372 // entries as we go and build the table at the end. 1373 type machoBindRecord struct { 1374 off int64 1375 targ loader.Sym 1376 } 1377 1378 var machobind []machoBindRecord 1379 1380 func MachoAddBind(off int64, targ loader.Sym) { 1381 machobind = append(machobind, machoBindRecord{off, targ}) 1382 } 1383 1384 // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command. 1385 // See mach-o/loader.h, struct dyld_info_command, for the encoding. 1386 // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h 1387 func machoDyldInfo(ctxt *Link) { 1388 ldr := ctxt.loader 1389 rebase := ldr.CreateSymForUpdate(".machorebase", 0) 1390 bind := ldr.CreateSymForUpdate(".machobind", 0) 1391 1392 if !(ctxt.IsPIE() && ctxt.IsInternal()) { 1393 return 1394 } 1395 1396 segId := func(seg *sym.Segment) uint8 { 1397 switch seg { 1398 case &Segtext: 1399 return 1 1400 case &Segrelrodata: 1401 return 2 1402 case &Segdata: 1403 if Segrelrodata.Length > 0 { 1404 return 3 1405 } 1406 return 2 1407 } 1408 panic("unknown segment") 1409 } 1410 1411 dylibId := func(s loader.Sym) int { 1412 slib := ldr.SymDynimplib(s) 1413 for i, lib := range dylib { 1414 if lib == slib { 1415 return i + 1 1416 } 1417 } 1418 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from 1419 } 1420 1421 // Rebase table. 1422 // TODO: use more compact encoding. The encoding is stateful, and 1423 // we can use delta encoding. 1424 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER) 1425 for _, r := range machorebase { 1426 seg := ldr.SymSect(r.sym).Seg 1427 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr 1428 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) 1429 rebase.AddUleb(off) 1430 1431 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1) 1432 } 1433 rebase.AddUint8(REBASE_OPCODE_DONE) 1434 sz := Rnd(rebase.Size(), 8) 1435 rebase.Grow(sz) 1436 rebase.SetSize(sz) 1437 1438 // Bind table. 1439 // TODO: compact encoding, as above. 1440 // TODO: lazy binding? 1441 got := ctxt.GOT 1442 seg := ldr.SymSect(got).Seg 1443 gotAddr := ldr.SymValue(got) 1444 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER) 1445 for _, r := range machobind { 1446 off := uint64(gotAddr+r.off) - seg.Vaddr 1447 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg)) 1448 bind.AddUleb(off) 1449 1450 d := dylibId(r.targ) 1451 if d > 0 && d < 128 { 1452 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf) 1453 } else if d >= 128 { 1454 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) 1455 bind.AddUleb(uint64(d)) 1456 } else { // d <= 0 1457 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf) 1458 } 1459 1460 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) 1461 // target symbol name as a C string, with _ prefix 1462 bind.AddUint8('_') 1463 bind.Addstring(ldr.SymExtname(r.targ)) 1464 1465 bind.AddUint8(BIND_OPCODE_DO_BIND) 1466 } 1467 bind.AddUint8(BIND_OPCODE_DONE) 1468 sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink 1469 bind.Grow(sz) 1470 bind.SetSize(sz) 1471 1472 // TODO: export table. 1473 // The symbols names are encoded as a trie. I'm really too lazy to do that 1474 // for now. 1475 // Without it, the symbols are not dynamically exported, so they cannot be 1476 // e.g. dlsym'd. But internal linking is not the default in that case, so 1477 // it is fine. 1478 } 1479 1480 // machoCodeSigSym creates and returns a symbol for code signature. 1481 // The symbol context is left as zeros, which will be generated at the end 1482 // (as it depends on the rest of the file). 1483 func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym { 1484 ldr := ctxt.loader 1485 cs := ldr.CreateSymForUpdate(".machocodesig", 0) 1486 if !ctxt.NeedCodeSign() || ctxt.IsExternal() { 1487 return cs.Sym() 1488 } 1489 sz := codesign.Size(codeSize, "a.out") 1490 cs.Grow(sz) 1491 cs.SetSize(sz) 1492 return cs.Sym() 1493 } 1494 1495 // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature. 1496 // This is used for updating an external linker generated binary. 1497 func machoCodeSign(ctxt *Link, fname string) error { 1498 f, err := os.OpenFile(fname, os.O_RDWR, 0) 1499 if err != nil { 1500 return err 1501 } 1502 defer f.Close() 1503 1504 mf, err := macho.NewFile(f) 1505 if err != nil { 1506 return err 1507 } 1508 if mf.Magic != macho.Magic64 { 1509 Exitf("not 64-bit Mach-O file: %s", fname) 1510 } 1511 1512 // Find existing LC_CODE_SIGNATURE and __LINKEDIT segment 1513 var sigOff, sigSz, csCmdOff, linkeditOff int64 1514 var linkeditSeg, textSeg *macho.Segment 1515 loadOff := int64(machoHeaderSize64) 1516 get32 := mf.ByteOrder.Uint32 1517 for _, l := range mf.Loads { 1518 data := l.Raw() 1519 cmd, sz := get32(data), get32(data[4:]) 1520 if cmd == LC_CODE_SIGNATURE { 1521 sigOff = int64(get32(data[8:])) 1522 sigSz = int64(get32(data[12:])) 1523 csCmdOff = loadOff 1524 } 1525 if seg, ok := l.(*macho.Segment); ok { 1526 switch seg.Name { 1527 case "__LINKEDIT": 1528 linkeditSeg = seg 1529 linkeditOff = loadOff 1530 case "__TEXT": 1531 textSeg = seg 1532 } 1533 } 1534 loadOff += int64(sz) 1535 } 1536 1537 if sigOff == 0 { 1538 // The C linker doesn't generate a signed binary, for some reason. 1539 // Skip. 1540 return nil 1541 } 1542 1543 fi, err := f.Stat() 1544 if err != nil { 1545 return err 1546 } 1547 if sigOff+sigSz != fi.Size() { 1548 // We don't expect anything after the signature (this will invalidate 1549 // the signature anyway.) 1550 return fmt.Errorf("unexpected content after code signature") 1551 } 1552 1553 sz := codesign.Size(sigOff, "a.out") 1554 if sz != sigSz { 1555 // Update the load command, 1556 var tmp [8]byte 1557 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz)) 1558 _, err = f.WriteAt(tmp[:4], csCmdOff+12) 1559 if err != nil { 1560 return err 1561 } 1562 1563 // Uodate the __LINKEDIT segment. 1564 segSz := sigOff + sz - int64(linkeditSeg.Offset) 1565 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz)) 1566 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz))) 1567 if err != nil { 1568 return err 1569 } 1570 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz))) 1571 if err != nil { 1572 return err 1573 } 1574 } 1575 1576 cs := make([]byte, sz) 1577 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE()) 1578 _, err = f.WriteAt(cs, sigOff) 1579 if err != nil { 1580 return err 1581 } 1582 err = f.Truncate(sigOff + sz) 1583 return err 1584 }