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