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