github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 "cmd/internal/objabi" 9 "cmd/internal/sys" 10 "cmd/link/internal/sym" 11 "sort" 12 "strings" 13 ) 14 15 type MachoHdr struct { 16 cpu uint32 17 subcpu uint32 18 } 19 20 type MachoSect struct { 21 name string 22 segname string 23 addr uint64 24 size uint64 25 off uint32 26 align uint32 27 reloc uint32 28 nreloc uint32 29 flag uint32 30 res1 uint32 31 res2 uint32 32 } 33 34 type MachoSeg struct { 35 name string 36 vsize uint64 37 vaddr uint64 38 fileoffset uint64 39 filesize uint64 40 prot1 uint32 41 prot2 uint32 42 nsect uint32 43 msect uint32 44 sect []MachoSect 45 flag uint32 46 } 47 48 type MachoLoad struct { 49 type_ uint32 50 data []uint32 51 } 52 53 /* 54 * Total amount of space to reserve at the start of the file 55 * for Header, PHeaders, and SHeaders. 56 * May waste some. 57 */ 58 const ( 59 INITIAL_MACHO_HEADR = 4 * 1024 60 ) 61 62 const ( 63 MACHO_CPU_AMD64 = 1<<24 | 7 64 MACHO_CPU_386 = 7 65 MACHO_SUBCPU_X86 = 3 66 MACHO_CPU_ARM = 12 67 MACHO_SUBCPU_ARM = 0 68 MACHO_SUBCPU_ARMV7 = 9 69 MACHO_CPU_ARM64 = 1<<24 | 12 70 MACHO_SUBCPU_ARM64_ALL = 0 71 MACHO32SYMSIZE = 12 72 MACHO64SYMSIZE = 16 73 MACHO_X86_64_RELOC_UNSIGNED = 0 74 MACHO_X86_64_RELOC_SIGNED = 1 75 MACHO_X86_64_RELOC_BRANCH = 2 76 MACHO_X86_64_RELOC_GOT_LOAD = 3 77 MACHO_X86_64_RELOC_GOT = 4 78 MACHO_X86_64_RELOC_SUBTRACTOR = 5 79 MACHO_X86_64_RELOC_SIGNED_1 = 6 80 MACHO_X86_64_RELOC_SIGNED_2 = 7 81 MACHO_X86_64_RELOC_SIGNED_4 = 8 82 MACHO_ARM_RELOC_VANILLA = 0 83 MACHO_ARM_RELOC_PAIR = 1 84 MACHO_ARM_RELOC_SECTDIFF = 2 85 MACHO_ARM_RELOC_BR24 = 5 86 MACHO_ARM64_RELOC_UNSIGNED = 0 87 MACHO_ARM64_RELOC_BRANCH26 = 2 88 MACHO_ARM64_RELOC_PAGE21 = 3 89 MACHO_ARM64_RELOC_PAGEOFF12 = 4 90 MACHO_ARM64_RELOC_ADDEND = 10 91 MACHO_GENERIC_RELOC_VANILLA = 0 92 MACHO_FAKE_GOTPCREL = 100 93 ) 94 95 const ( 96 MH_MAGIC = 0xfeedface 97 MH_MAGIC_64 = 0xfeedfacf 98 99 MH_OBJECT = 0x1 100 MH_EXECUTE = 0x2 101 102 MH_NOUNDEFS = 0x1 103 ) 104 105 const ( 106 LC_SEGMENT = 0x1 107 LC_SYMTAB = 0x2 108 LC_SYMSEG = 0x3 109 LC_THREAD = 0x4 110 LC_UNIXTHREAD = 0x5 111 LC_LOADFVMLIB = 0x6 112 LC_IDFVMLIB = 0x7 113 LC_IDENT = 0x8 114 LC_FVMFILE = 0x9 115 LC_PREPAGE = 0xa 116 LC_DYSYMTAB = 0xb 117 LC_LOAD_DYLIB = 0xc 118 LC_ID_DYLIB = 0xd 119 LC_LOAD_DYLINKER = 0xe 120 LC_ID_DYLINKER = 0xf 121 LC_PREBOUND_DYLIB = 0x10 122 LC_ROUTINES = 0x11 123 LC_SUB_FRAMEWORK = 0x12 124 LC_SUB_UMBRELLA = 0x13 125 LC_SUB_CLIENT = 0x14 126 LC_SUB_LIBRARY = 0x15 127 LC_TWOLEVEL_HINTS = 0x16 128 LC_PREBIND_CKSUM = 0x17 129 LC_LOAD_WEAK_DYLIB = 0x18 130 LC_SEGMENT_64 = 0x19 131 LC_ROUTINES_64 = 0x1a 132 LC_UUID = 0x1b 133 LC_RPATH = 0x8000001c 134 LC_CODE_SIGNATURE = 0x1d 135 LC_SEGMENT_SPLIT_INFO = 0x1e 136 LC_REEXPORT_DYLIB = 0x8000001f 137 LC_LAZY_LOAD_DYLIB = 0x20 138 LC_ENCRYPTION_INFO = 0x21 139 LC_DYLD_INFO = 0x22 140 LC_DYLD_INFO_ONLY = 0x80000022 141 LC_LOAD_UPWARD_DYLIB = 0x80000023 142 LC_VERSION_MIN_MACOSX = 0x24 143 LC_VERSION_MIN_IPHONEOS = 0x25 144 LC_FUNCTION_STARTS = 0x26 145 LC_DYLD_ENVIRONMENT = 0x27 146 LC_MAIN = 0x80000028 147 LC_DATA_IN_CODE = 0x29 148 LC_SOURCE_VERSION = 0x2A 149 LC_DYLIB_CODE_SIGN_DRS = 0x2B 150 LC_ENCRYPTION_INFO_64 = 0x2C 151 LC_LINKER_OPTION = 0x2D 152 LC_LINKER_OPTIMIZATION_HINT = 0x2E 153 LC_VERSION_MIN_TVOS = 0x2F 154 LC_VERSION_MIN_WATCHOS = 0x30 155 LC_VERSION_NOTE = 0x31 156 LC_BUILD_VERSION = 0x32 157 ) 158 159 const ( 160 S_REGULAR = 0x0 161 S_ZEROFILL = 0x1 162 S_NON_LAZY_SYMBOL_POINTERS = 0x6 163 S_SYMBOL_STUBS = 0x8 164 S_MOD_INIT_FUNC_POINTERS = 0x9 165 S_ATTR_PURE_INSTRUCTIONS = 0x80000000 166 S_ATTR_DEBUG = 0x02000000 167 S_ATTR_SOME_INSTRUCTIONS = 0x00000400 168 ) 169 170 // Mach-O file writing 171 // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html 172 173 var machohdr MachoHdr 174 175 var load []MachoLoad 176 177 var seg [16]MachoSeg 178 179 var nseg int 180 181 var ndebug int 182 183 var nsect int 184 185 const ( 186 SymKindLocal = 0 + iota 187 SymKindExtdef 188 SymKindUndef 189 NumSymKind 190 ) 191 192 var nkind [NumSymKind]int 193 194 var sortsym []*sym.Symbol 195 196 var nsortsym int 197 198 // Amount of space left for adding load commands 199 // that refer to dynamic libraries. Because these have 200 // to go in the Mach-O header, we can't just pick a 201 // "big enough" header size. The initial header is 202 // one page, the non-dynamic library stuff takes 203 // up about 1300 bytes; we overestimate that as 2k. 204 var loadBudget = INITIAL_MACHO_HEADR - 2*1024 205 206 func getMachoHdr() *MachoHdr { 207 return &machohdr 208 } 209 210 func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad { 211 if arch.PtrSize == 8 && (ndata&1 != 0) { 212 ndata++ 213 } 214 215 load = append(load, MachoLoad{}) 216 l := &load[len(load)-1] 217 l.type_ = type_ 218 l.data = make([]uint32, ndata) 219 return l 220 } 221 222 func newMachoSeg(name string, msect int) *MachoSeg { 223 if nseg >= len(seg) { 224 Exitf("too many segs") 225 } 226 227 s := &seg[nseg] 228 nseg++ 229 s.name = name 230 s.msect = uint32(msect) 231 s.sect = make([]MachoSect, msect) 232 return s 233 } 234 235 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect { 236 if seg.nsect >= seg.msect { 237 Exitf("too many sects in segment %s", seg.name) 238 } 239 240 s := &seg.sect[seg.nsect] 241 seg.nsect++ 242 s.name = name 243 s.segname = segname 244 nsect++ 245 return s 246 } 247 248 // Generic linking code. 249 250 var dylib []string 251 252 var linkoff int64 253 254 func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int { 255 o1 := out.Offset() 256 257 loadsize := 4 * 4 * ndebug 258 for i := range load { 259 loadsize += 4 * (len(load[i].data) + 2) 260 } 261 if arch.PtrSize == 8 { 262 loadsize += 18 * 4 * nseg 263 loadsize += 20 * 4 * nsect 264 } else { 265 loadsize += 14 * 4 * nseg 266 loadsize += 17 * 4 * nsect 267 } 268 269 if arch.PtrSize == 8 { 270 out.Write32(MH_MAGIC_64) 271 } else { 272 out.Write32(MH_MAGIC) 273 } 274 out.Write32(machohdr.cpu) 275 out.Write32(machohdr.subcpu) 276 if linkmode == LinkExternal { 277 out.Write32(MH_OBJECT) /* file type - mach object */ 278 } else { 279 out.Write32(MH_EXECUTE) /* file type - mach executable */ 280 } 281 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug)) 282 out.Write32(uint32(loadsize)) 283 if nkind[SymKindUndef] == 0 { 284 out.Write32(MH_NOUNDEFS) /* flags - no undefines */ 285 } else { 286 out.Write32(0) /* flags */ 287 } 288 if arch.PtrSize == 8 { 289 out.Write32(0) /* reserved */ 290 } 291 292 for i := 0; i < nseg; i++ { 293 s := &seg[i] 294 if arch.PtrSize == 8 { 295 out.Write32(LC_SEGMENT_64) 296 out.Write32(72 + 80*s.nsect) 297 out.WriteStringN(s.name, 16) 298 out.Write64(s.vaddr) 299 out.Write64(s.vsize) 300 out.Write64(s.fileoffset) 301 out.Write64(s.filesize) 302 out.Write32(s.prot1) 303 out.Write32(s.prot2) 304 out.Write32(s.nsect) 305 out.Write32(s.flag) 306 } else { 307 out.Write32(LC_SEGMENT) 308 out.Write32(56 + 68*s.nsect) 309 out.WriteStringN(s.name, 16) 310 out.Write32(uint32(s.vaddr)) 311 out.Write32(uint32(s.vsize)) 312 out.Write32(uint32(s.fileoffset)) 313 out.Write32(uint32(s.filesize)) 314 out.Write32(s.prot1) 315 out.Write32(s.prot2) 316 out.Write32(s.nsect) 317 out.Write32(s.flag) 318 } 319 320 for j := uint32(0); j < s.nsect; j++ { 321 t := &s.sect[j] 322 if arch.PtrSize == 8 { 323 out.WriteStringN(t.name, 16) 324 out.WriteStringN(t.segname, 16) 325 out.Write64(t.addr) 326 out.Write64(t.size) 327 out.Write32(t.off) 328 out.Write32(t.align) 329 out.Write32(t.reloc) 330 out.Write32(t.nreloc) 331 out.Write32(t.flag) 332 out.Write32(t.res1) /* reserved */ 333 out.Write32(t.res2) /* reserved */ 334 out.Write32(0) /* reserved */ 335 } else { 336 out.WriteStringN(t.name, 16) 337 out.WriteStringN(t.segname, 16) 338 out.Write32(uint32(t.addr)) 339 out.Write32(uint32(t.size)) 340 out.Write32(t.off) 341 out.Write32(t.align) 342 out.Write32(t.reloc) 343 out.Write32(t.nreloc) 344 out.Write32(t.flag) 345 out.Write32(t.res1) /* reserved */ 346 out.Write32(t.res2) /* reserved */ 347 } 348 } 349 } 350 351 for i := range load { 352 l := &load[i] 353 out.Write32(l.type_) 354 out.Write32(4 * (uint32(len(l.data)) + 2)) 355 for j := 0; j < len(l.data); j++ { 356 out.Write32(l.data[j]) 357 } 358 } 359 360 return int(out.Offset() - o1) 361 } 362 363 func (ctxt *Link) domacho() { 364 if *FlagD { 365 return 366 } 367 368 // empirically, string table must begin with " \x00". 369 s := ctxt.Syms.Lookup(".machosymstr", 0) 370 371 s.Type = sym.SMACHOSYMSTR 372 s.Attr |= sym.AttrReachable 373 s.AddUint8(' ') 374 s.AddUint8('\x00') 375 376 s = ctxt.Syms.Lookup(".machosymtab", 0) 377 s.Type = sym.SMACHOSYMTAB 378 s.Attr |= sym.AttrReachable 379 380 if ctxt.LinkMode != LinkExternal { 381 s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub 382 s.Type = sym.SMACHOPLT 383 s.Attr |= sym.AttrReachable 384 385 s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr 386 s.Type = sym.SMACHOGOT 387 s.Attr |= sym.AttrReachable 388 s.Align = 4 389 390 s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt 391 s.Type = sym.SMACHOINDIRECTPLT 392 s.Attr |= sym.AttrReachable 393 394 s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got 395 s.Type = sym.SMACHOINDIRECTGOT 396 s.Attr |= sym.AttrReachable 397 } 398 } 399 400 func machoadddynlib(lib string, linkmode LinkMode) { 401 if seenlib[lib] || linkmode == LinkExternal { 402 return 403 } 404 seenlib[lib] = true 405 406 // Will need to store the library name rounded up 407 // and 24 bytes of header metadata. If not enough 408 // space, grab another page of initial space at the 409 // beginning of the output file. 410 loadBudget -= (len(lib)+7)/8*8 + 24 411 412 if loadBudget < 0 { 413 HEADR += 4096 414 *FlagTextAddr += 4096 415 loadBudget += 4096 416 } 417 418 dylib = append(dylib, lib) 419 } 420 421 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) { 422 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) 423 424 var msect *MachoSect 425 if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 || 426 (ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe) || 427 (ctxt.Arch.Family == sys.ARM && ctxt.BuildMode != BuildModeExe)) { 428 // Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode 429 // complains about absolute relocs in __TEXT, so if the section is not 430 // executable, put it in __DATA segment. 431 msect = newMachoSect(mseg, buf, "__DATA") 432 } else { 433 msect = newMachoSect(mseg, buf, segname) 434 } 435 436 if sect.Rellen > 0 { 437 msect.reloc = uint32(sect.Reloff) 438 msect.nreloc = uint32(sect.Rellen / 8) 439 } 440 441 for 1<<msect.align < sect.Align { 442 msect.align++ 443 } 444 msect.addr = sect.Vaddr 445 msect.size = sect.Length 446 447 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen { 448 // data in file 449 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr { 450 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name) 451 } 452 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr) 453 } else { 454 msect.off = 0 455 msect.flag |= S_ZEROFILL 456 } 457 458 if sect.Rwx&1 != 0 { 459 msect.flag |= S_ATTR_SOME_INSTRUCTIONS 460 } 461 462 if sect.Name == ".text" { 463 msect.flag |= S_ATTR_PURE_INSTRUCTIONS 464 } 465 466 if sect.Name == ".plt" { 467 msect.name = "__symbol_stub1" 468 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS 469 msect.res1 = 0 //nkind[SymKindLocal]; 470 msect.res2 = 6 471 } 472 473 if sect.Name == ".got" { 474 msect.name = "__nl_symbol_ptr" 475 msect.flag = S_NON_LAZY_SYMBOL_POINTERS 476 msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */ 477 } 478 479 if sect.Name == ".init_array" { 480 msect.name = "__mod_init_func" 481 msect.flag = S_MOD_INIT_FUNC_POINTERS 482 } 483 484 if segname == "__DWARF" { 485 msect.flag |= S_ATTR_DEBUG 486 } 487 } 488 489 func Asmbmacho(ctxt *Link) { 490 /* apple MACH */ 491 va := *FlagTextAddr - int64(HEADR) 492 493 mh := getMachoHdr() 494 switch ctxt.Arch.Family { 495 default: 496 Exitf("unknown macho architecture: %v", ctxt.Arch.Family) 497 498 case sys.ARM: 499 mh.cpu = MACHO_CPU_ARM 500 mh.subcpu = MACHO_SUBCPU_ARMV7 501 502 case sys.AMD64: 503 mh.cpu = MACHO_CPU_AMD64 504 mh.subcpu = MACHO_SUBCPU_X86 505 506 case sys.ARM64: 507 mh.cpu = MACHO_CPU_ARM64 508 mh.subcpu = MACHO_SUBCPU_ARM64_ALL 509 510 case sys.I386: 511 mh.cpu = MACHO_CPU_386 512 mh.subcpu = MACHO_SUBCPU_X86 513 } 514 515 var ms *MachoSeg 516 if ctxt.LinkMode == LinkExternal { 517 /* segment for entire file */ 518 ms = newMachoSeg("", 40) 519 520 ms.fileoffset = Segtext.Fileoff 521 if ctxt.Arch.Family == sys.ARM || ctxt.BuildMode == BuildModeCArchive { 522 ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff 523 } else { 524 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff 525 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr 526 } 527 } 528 529 /* segment for zero page */ 530 if ctxt.LinkMode != LinkExternal { 531 ms = newMachoSeg("__PAGEZERO", 0) 532 ms.vsize = uint64(va) 533 } 534 535 /* text */ 536 v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) 537 538 if ctxt.LinkMode != LinkExternal { 539 ms = newMachoSeg("__TEXT", 20) 540 ms.vaddr = uint64(va) 541 ms.vsize = uint64(v) 542 ms.fileoffset = 0 543 ms.filesize = uint64(v) 544 ms.prot1 = 7 545 ms.prot2 = 5 546 } 547 548 for _, sect := range Segtext.Sections { 549 machoshbits(ctxt, ms, sect, "__TEXT") 550 } 551 552 /* data */ 553 if ctxt.LinkMode != LinkExternal { 554 w := int64(Segdata.Length) 555 ms = newMachoSeg("__DATA", 20) 556 ms.vaddr = uint64(va) + uint64(v) 557 ms.vsize = uint64(w) 558 ms.fileoffset = uint64(v) 559 ms.filesize = Segdata.Filelen 560 ms.prot1 = 3 561 ms.prot2 = 3 562 } 563 564 for _, sect := range Segdata.Sections { 565 machoshbits(ctxt, ms, sect, "__DATA") 566 } 567 568 /* dwarf */ 569 if !*FlagW { 570 if ctxt.LinkMode != LinkExternal { 571 ms = newMachoSeg("__DWARF", 20) 572 ms.vaddr = Segdwarf.Vaddr 573 ms.vsize = 0 574 ms.fileoffset = Segdwarf.Fileoff 575 ms.filesize = Segdwarf.Filelen 576 } 577 for _, sect := range Segdwarf.Sections { 578 machoshbits(ctxt, ms, sect, "__DWARF") 579 } 580 } 581 582 if ctxt.LinkMode != LinkExternal { 583 switch ctxt.Arch.Family { 584 default: 585 Exitf("unknown macho architecture: %v", ctxt.Arch.Family) 586 587 case sys.ARM: 588 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 17+2) 589 ml.data[0] = 1 /* thread type */ 590 ml.data[1] = 17 /* word count */ 591 ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */ 592 593 case sys.AMD64: 594 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2) 595 ml.data[0] = 4 /* thread type */ 596 ml.data[1] = 42 /* word count */ 597 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */ 598 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32) 599 600 case sys.ARM64: 601 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2) 602 ml.data[0] = 6 /* thread type */ 603 ml.data[1] = 68 /* word count */ 604 ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */ 605 ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32) 606 607 case sys.I386: 608 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 16+2) 609 ml.data[0] = 1 /* thread type */ 610 ml.data[1] = 16 /* word count */ 611 ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */ 612 } 613 } 614 615 if !*FlagD { 616 // must match domacholink below 617 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 618 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 619 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 620 s4 := ctxt.Syms.Lookup(".machosymstr", 0) 621 622 if ctxt.LinkMode != LinkExternal { 623 ms := newMachoSeg("__LINKEDIT", 0) 624 ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound))) 625 ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size) 626 ms.fileoffset = uint64(linkoff) 627 ms.filesize = ms.vsize 628 ms.prot1 = 7 629 ms.prot2 = 3 630 } 631 632 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4) 633 ml.data[0] = uint32(linkoff) /* symoff */ 634 ml.data[1] = uint32(nsortsym) /* nsyms */ 635 ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */ 636 ml.data[3] = uint32(s4.Size) /* strsize */ 637 638 machodysymtab(ctxt) 639 640 if ctxt.LinkMode != LinkExternal { 641 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6) 642 ml.data[0] = 12 /* offset to string */ 643 stringtouint32(ml.data[1:], "/usr/lib/dyld") 644 645 for _, lib := range dylib { 646 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2) 647 ml.data[0] = 24 /* offset of string from beginning of load */ 648 ml.data[1] = 0 /* time stamp */ 649 ml.data[2] = 0 /* version */ 650 ml.data[3] = 0 /* compatibility version */ 651 stringtouint32(ml.data[4:], lib) 652 } 653 } 654 } 655 656 if ctxt.LinkMode == LinkInternal { 657 // For lldb, must say LC_VERSION_MIN_MACOSX or else 658 // it won't know that this Mach-O binary is from OS X 659 // (could be iOS or WatchOS instead). 660 // Go on iOS uses linkmode=external, and linkmode=external 661 // adds this itself. So we only need this code for linkmode=internal 662 // and we can assume OS X. 663 // 664 // See golang.org/issues/12941. 665 ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2) 666 ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0 667 ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0 668 } 669 670 a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode) 671 if int32(a) > HEADR { 672 Exitf("HEADR too small: %d > %d", a, HEADR) 673 } 674 } 675 676 func symkind(s *sym.Symbol) int { 677 if s.Type == sym.SDYNIMPORT { 678 return SymKindUndef 679 } 680 if s.Attr.CgoExport() { 681 return SymKindExtdef 682 } 683 return SymKindLocal 684 } 685 686 func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) { 687 if s == nil { 688 return 689 } 690 691 switch type_ { 692 default: 693 return 694 695 case DataSym, BSSSym, TextSym: 696 break 697 } 698 699 if sortsym != nil { 700 sortsym[nsortsym] = s 701 nkind[symkind(s)]++ 702 } 703 704 nsortsym++ 705 } 706 707 type machoscmp []*sym.Symbol 708 709 func (x machoscmp) Len() int { 710 return len(x) 711 } 712 713 func (x machoscmp) Swap(i, j int) { 714 x[i], x[j] = x[j], x[i] 715 } 716 717 func (x machoscmp) Less(i, j int) bool { 718 s1 := x[i] 719 s2 := x[j] 720 721 k1 := symkind(s1) 722 k2 := symkind(s2) 723 if k1 != k2 { 724 return k1 < k2 725 } 726 727 return s1.Extname() < s2.Extname() 728 } 729 730 func machogenasmsym(ctxt *Link) { 731 genasmsym(ctxt, addsym) 732 for _, s := range ctxt.Syms.Allsym { 733 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ { 734 if s.Attr.Reachable() { 735 addsym(ctxt, s, "", DataSym, 0, nil) 736 } 737 } 738 } 739 } 740 741 func machosymorder(ctxt *Link) { 742 // On Mac OS X Mountain Lion, we must sort exported symbols 743 // So we sort them here and pre-allocate dynid for them 744 // See https://golang.org/issue/4029 745 for i := range dynexp { 746 dynexp[i].Attr |= sym.AttrReachable 747 } 748 machogenasmsym(ctxt) 749 sortsym = make([]*sym.Symbol, nsortsym) 750 nsortsym = 0 751 machogenasmsym(ctxt) 752 sort.Sort(machoscmp(sortsym[:nsortsym])) 753 for i := 0; i < nsortsym; i++ { 754 sortsym[i].Dynid = int32(i) 755 } 756 } 757 758 // machoShouldExport reports whether a symbol needs to be exported. 759 // 760 // When dynamically linking, all non-local variables and plugin-exported 761 // symbols need to be exported. 762 func machoShouldExport(ctxt *Link, s *sym.Symbol) bool { 763 if !ctxt.DynlinkingGo() || s.Attr.Local() { 764 return false 765 } 766 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) { 767 return true 768 } 769 if strings.HasPrefix(s.Name, "go.itab.") { 770 return true 771 } 772 if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") { 773 // reduce runtime typemap pressure, but do not 774 // export alg functions (type..*), as these 775 // appear in pclntable. 776 return true 777 } 778 if strings.HasPrefix(s.Name, "go.link.pkghash") { 779 return true 780 } 781 return s.Type >= sym.SELFSECT // only writable sections 782 } 783 784 func machosymtab(ctxt *Link) { 785 symtab := ctxt.Syms.Lookup(".machosymtab", 0) 786 symstr := ctxt.Syms.Lookup(".machosymstr", 0) 787 788 for i := 0; i < nsortsym; i++ { 789 s := sortsym[i] 790 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size)) 791 792 export := machoShouldExport(ctxt, s) 793 794 // In normal buildmodes, only add _ to C symbols, as 795 // Go symbols have dot in the name. 796 // 797 // Do not export C symbols in plugins, as runtime C 798 // symbols like crosscall2 are in pclntab and end up 799 // pointing at the host binary, breaking unwinding. 800 // See Issue #18190. 801 cexport := !strings.Contains(s.Extname(), ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s)) 802 if cexport || export { 803 symstr.AddUint8('_') 804 } 805 806 // replace "·" as ".", because DTrace cannot handle it. 807 Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1)) 808 809 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ { 810 symtab.AddUint8(0x01) // type N_EXT, external symbol 811 symtab.AddUint8(0) // no section 812 symtab.AddUint16(ctxt.Arch, 0) // desc 813 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value 814 } else { 815 if s.Attr.CgoExport() || export { 816 symtab.AddUint8(0x0f) 817 } else { 818 symtab.AddUint8(0x0e) 819 } 820 o := s 821 for o.Outer != nil { 822 o = o.Outer 823 } 824 if o.Sect == nil { 825 Errorf(s, "missing section for symbol") 826 symtab.AddUint8(0) 827 } else { 828 symtab.AddUint8(uint8(o.Sect.Extnum)) 829 } 830 symtab.AddUint16(ctxt.Arch, 0) // desc 831 symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize) 832 } 833 } 834 } 835 836 func machodysymtab(ctxt *Link) { 837 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18) 838 839 n := 0 840 ml.data[0] = uint32(n) /* ilocalsym */ 841 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 842 n += nkind[SymKindLocal] 843 844 ml.data[2] = uint32(n) /* iextdefsym */ 845 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 846 n += nkind[SymKindExtdef] 847 848 ml.data[4] = uint32(n) /* iundefsym */ 849 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 850 851 ml.data[6] = 0 /* tocoffset */ 852 ml.data[7] = 0 /* ntoc */ 853 ml.data[8] = 0 /* modtaboff */ 854 ml.data[9] = 0 /* nmodtab */ 855 ml.data[10] = 0 /* extrefsymoff */ 856 ml.data[11] = 0 /* nextrefsyms */ 857 858 // must match domacholink below 859 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 860 861 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 862 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 863 ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */ 864 ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */ 865 866 ml.data[14] = 0 /* extreloff */ 867 ml.data[15] = 0 /* nextrel */ 868 ml.data[16] = 0 /* locreloff */ 869 ml.data[17] = 0 /* nlocrel */ 870 } 871 872 func Domacholink(ctxt *Link) int64 { 873 machosymtab(ctxt) 874 875 // write data that will be linkedit section 876 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 877 878 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 879 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 880 s4 := ctxt.Syms.Lookup(".machosymstr", 0) 881 882 // Force the linkedit section to end on a 16-byte 883 // boundary. This allows pure (non-cgo) Go binaries 884 // to be code signed correctly. 885 // 886 // Apple's codesign_allocate (a helper utility for 887 // the codesign utility) can do this fine itself if 888 // it is run on a dynamic Mach-O binary. However, 889 // when it is run on a pure (non-cgo) Go binary, where 890 // the linkedit section is mostly empty, it fails to 891 // account for the extra padding that it itself adds 892 // when adding the LC_CODE_SIGNATURE load command 893 // (which must be aligned on a 16-byte boundary). 894 // 895 // By forcing the linkedit section to end on a 16-byte 896 // boundary, codesign_allocate will not need to apply 897 // any alignment padding itself, working around the 898 // issue. 899 for s4.Size%16 != 0 { 900 s4.AddUint8(0) 901 } 902 903 size := int(s1.Size + s2.Size + s3.Size + s4.Size) 904 905 if size > 0 { 906 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound)) 907 ctxt.Out.SeekSet(linkoff) 908 909 ctxt.Out.Write(s1.P[:s1.Size]) 910 ctxt.Out.Write(s2.P[:s2.Size]) 911 ctxt.Out.Write(s3.P[:s3.Size]) 912 ctxt.Out.Write(s4.P[:s4.Size]) 913 } 914 915 return Rnd(int64(size), int64(*FlagRound)) 916 } 917 918 func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) { 919 // If main section has no bits, nothing to relocate. 920 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 921 return 922 } 923 924 sect.Reloff = uint64(ctxt.Out.Offset()) 925 for i, s := range syms { 926 if !s.Attr.Reachable() { 927 continue 928 } 929 if uint64(s.Value) >= sect.Vaddr { 930 syms = syms[i:] 931 break 932 } 933 } 934 935 eaddr := int32(sect.Vaddr + sect.Length) 936 for _, s := range syms { 937 if !s.Attr.Reachable() { 938 continue 939 } 940 if s.Value >= int64(eaddr) { 941 break 942 } 943 for ri := range s.R { 944 r := &s.R[ri] 945 if r.Done { 946 continue 947 } 948 if r.Xsym == nil { 949 Errorf(s, "missing xsym in relocation") 950 continue 951 } 952 if !r.Xsym.Attr.Reachable() { 953 Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name) 954 } 955 if !thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) { 956 Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name) 957 } 958 } 959 } 960 961 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 962 } 963 964 func Machoemitreloc(ctxt *Link) { 965 for ctxt.Out.Offset()&7 != 0 { 966 ctxt.Out.Write8(0) 967 } 968 969 machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp) 970 for _, sect := range Segtext.Sections[1:] { 971 machorelocsect(ctxt, sect, datap) 972 } 973 for _, sect := range Segdata.Sections { 974 machorelocsect(ctxt, sect, datap) 975 } 976 for _, sect := range Segdwarf.Sections { 977 machorelocsect(ctxt, sect, dwarfp) 978 } 979 }