github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/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 "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 // 666 // The version must be at least 10.9; see golang.org/issues/30488. 667 ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2) 668 ml.data[0] = 10<<16 | 9<<8 | 0<<0 // OS X version 10.9.0 669 ml.data[1] = 10<<16 | 9<<8 | 0<<0 // SDK 10.9.0 670 } 671 672 a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode) 673 if int32(a) > HEADR { 674 Exitf("HEADR too small: %d > %d", a, HEADR) 675 } 676 } 677 678 func symkind(s *sym.Symbol) int { 679 if s.Type == sym.SDYNIMPORT { 680 return SymKindUndef 681 } 682 if s.Attr.CgoExport() { 683 return SymKindExtdef 684 } 685 return SymKindLocal 686 } 687 688 func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) { 689 if s == nil { 690 return 691 } 692 693 switch type_ { 694 default: 695 return 696 697 case DataSym, BSSSym, TextSym: 698 break 699 } 700 701 if sortsym != nil { 702 sortsym[nsortsym] = s 703 nkind[symkind(s)]++ 704 } 705 706 nsortsym++ 707 } 708 709 type machoscmp []*sym.Symbol 710 711 func (x machoscmp) Len() int { 712 return len(x) 713 } 714 715 func (x machoscmp) Swap(i, j int) { 716 x[i], x[j] = x[j], x[i] 717 } 718 719 func (x machoscmp) Less(i, j int) bool { 720 s1 := x[i] 721 s2 := x[j] 722 723 k1 := symkind(s1) 724 k2 := symkind(s2) 725 if k1 != k2 { 726 return k1 < k2 727 } 728 729 return s1.Extname() < s2.Extname() 730 } 731 732 func machogenasmsym(ctxt *Link) { 733 genasmsym(ctxt, addsym) 734 for _, s := range ctxt.Syms.Allsym { 735 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ { 736 if s.Attr.Reachable() { 737 addsym(ctxt, s, "", DataSym, 0, nil) 738 } 739 } 740 } 741 } 742 743 func machosymorder(ctxt *Link) { 744 // On Mac OS X Mountain Lion, we must sort exported symbols 745 // So we sort them here and pre-allocate dynid for them 746 // See https://golang.org/issue/4029 747 for i := range dynexp { 748 dynexp[i].Attr |= sym.AttrReachable 749 } 750 machogenasmsym(ctxt) 751 sortsym = make([]*sym.Symbol, nsortsym) 752 nsortsym = 0 753 machogenasmsym(ctxt) 754 sort.Sort(machoscmp(sortsym[:nsortsym])) 755 for i := 0; i < nsortsym; i++ { 756 sortsym[i].Dynid = int32(i) 757 } 758 } 759 760 // machoShouldExport reports whether a symbol needs to be exported. 761 // 762 // When dynamically linking, all non-local variables and plugin-exported 763 // symbols need to be exported. 764 func machoShouldExport(ctxt *Link, s *sym.Symbol) bool { 765 if !ctxt.DynlinkingGo() || s.Attr.Local() { 766 return false 767 } 768 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) { 769 return true 770 } 771 if strings.HasPrefix(s.Name, "go.itab.") { 772 return true 773 } 774 if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") { 775 // reduce runtime typemap pressure, but do not 776 // export alg functions (type..*), as these 777 // appear in pclntable. 778 return true 779 } 780 if strings.HasPrefix(s.Name, "go.link.pkghash") { 781 return true 782 } 783 return s.Type >= sym.SELFSECT // only writable sections 784 } 785 786 func machosymtab(ctxt *Link) { 787 symtab := ctxt.Syms.Lookup(".machosymtab", 0) 788 symstr := ctxt.Syms.Lookup(".machosymstr", 0) 789 790 for i := 0; i < nsortsym; i++ { 791 s := sortsym[i] 792 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size)) 793 794 export := machoShouldExport(ctxt, s) 795 796 // In normal buildmodes, only add _ to C symbols, as 797 // Go symbols have dot in the name. 798 // 799 // Do not export C symbols in plugins, as runtime C 800 // symbols like crosscall2 are in pclntab and end up 801 // pointing at the host binary, breaking unwinding. 802 // See Issue #18190. 803 cexport := !strings.Contains(s.Extname(), ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s)) 804 if cexport || export { 805 symstr.AddUint8('_') 806 } 807 808 // replace "·" as ".", because DTrace cannot handle it. 809 Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1)) 810 811 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ { 812 symtab.AddUint8(0x01) // type N_EXT, external symbol 813 symtab.AddUint8(0) // no section 814 symtab.AddUint16(ctxt.Arch, 0) // desc 815 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value 816 } else { 817 if s.Attr.CgoExport() || export { 818 symtab.AddUint8(0x0f) 819 } else { 820 symtab.AddUint8(0x0e) 821 } 822 o := s 823 for o.Outer != nil { 824 o = o.Outer 825 } 826 if o.Sect == nil { 827 Errorf(s, "missing section for symbol") 828 symtab.AddUint8(0) 829 } else { 830 symtab.AddUint8(uint8(o.Sect.Extnum)) 831 } 832 symtab.AddUint16(ctxt.Arch, 0) // desc 833 symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize) 834 } 835 } 836 } 837 838 func machodysymtab(ctxt *Link) { 839 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18) 840 841 n := 0 842 ml.data[0] = uint32(n) /* ilocalsym */ 843 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 844 n += nkind[SymKindLocal] 845 846 ml.data[2] = uint32(n) /* iextdefsym */ 847 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 848 n += nkind[SymKindExtdef] 849 850 ml.data[4] = uint32(n) /* iundefsym */ 851 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 852 853 ml.data[6] = 0 /* tocoffset */ 854 ml.data[7] = 0 /* ntoc */ 855 ml.data[8] = 0 /* modtaboff */ 856 ml.data[9] = 0 /* nmodtab */ 857 ml.data[10] = 0 /* extrefsymoff */ 858 ml.data[11] = 0 /* nextrefsyms */ 859 860 // must match domacholink below 861 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 862 863 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 864 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 865 ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */ 866 ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */ 867 868 ml.data[14] = 0 /* extreloff */ 869 ml.data[15] = 0 /* nextrel */ 870 ml.data[16] = 0 /* locreloff */ 871 ml.data[17] = 0 /* nlocrel */ 872 } 873 874 func Domacholink(ctxt *Link) int64 { 875 machosymtab(ctxt) 876 877 // write data that will be linkedit section 878 s1 := ctxt.Syms.Lookup(".machosymtab", 0) 879 880 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0) 881 s3 := ctxt.Syms.Lookup(".linkedit.got", 0) 882 s4 := ctxt.Syms.Lookup(".machosymstr", 0) 883 884 // Force the linkedit section to end on a 16-byte 885 // boundary. This allows pure (non-cgo) Go binaries 886 // to be code signed correctly. 887 // 888 // Apple's codesign_allocate (a helper utility for 889 // the codesign utility) can do this fine itself if 890 // it is run on a dynamic Mach-O binary. However, 891 // when it is run on a pure (non-cgo) Go binary, where 892 // the linkedit section is mostly empty, it fails to 893 // account for the extra padding that it itself adds 894 // when adding the LC_CODE_SIGNATURE load command 895 // (which must be aligned on a 16-byte boundary). 896 // 897 // By forcing the linkedit section to end on a 16-byte 898 // boundary, codesign_allocate will not need to apply 899 // any alignment padding itself, working around the 900 // issue. 901 for s4.Size%16 != 0 { 902 s4.AddUint8(0) 903 } 904 905 size := int(s1.Size + s2.Size + s3.Size + s4.Size) 906 907 if size > 0 { 908 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound)) 909 ctxt.Out.SeekSet(linkoff) 910 911 ctxt.Out.Write(s1.P[:s1.Size]) 912 ctxt.Out.Write(s2.P[:s2.Size]) 913 ctxt.Out.Write(s3.P[:s3.Size]) 914 ctxt.Out.Write(s4.P[:s4.Size]) 915 } 916 917 return Rnd(int64(size), int64(*FlagRound)) 918 } 919 920 func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) { 921 // If main section has no bits, nothing to relocate. 922 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 923 return 924 } 925 926 sect.Reloff = uint64(ctxt.Out.Offset()) 927 for i, s := range syms { 928 if !s.Attr.Reachable() { 929 continue 930 } 931 if uint64(s.Value) >= sect.Vaddr { 932 syms = syms[i:] 933 break 934 } 935 } 936 937 eaddr := int32(sect.Vaddr + sect.Length) 938 for _, s := range syms { 939 if !s.Attr.Reachable() { 940 continue 941 } 942 if s.Value >= int64(eaddr) { 943 break 944 } 945 for ri := range s.R { 946 r := &s.R[ri] 947 if r.Done { 948 continue 949 } 950 if r.Xsym == nil { 951 Errorf(s, "missing xsym in relocation") 952 continue 953 } 954 if !r.Xsym.Attr.Reachable() { 955 Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name) 956 } 957 if !thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) { 958 Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name) 959 } 960 } 961 } 962 963 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 964 } 965 966 func Machoemitreloc(ctxt *Link) { 967 for ctxt.Out.Offset()&7 != 0 { 968 ctxt.Out.Write8(0) 969 } 970 971 machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp) 972 for _, sect := range Segtext.Sections[1:] { 973 machorelocsect(ctxt, sect, datap) 974 } 975 for _, sect := range Segdata.Sections { 976 machorelocsect(ctxt, sect, datap) 977 } 978 for _, sect := range Segdwarf.Sections { 979 machorelocsect(ctxt, sect, dwarfp) 980 } 981 }