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