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' || (Thearch.Thechar == '6' && Buildmode == BuildmodeCShared)) { 360 // Darwin external linker on arm64 and on amd64 in c-shared buildmode 361 // complains about absolute relocs in __TEXT, so if the section is not 362 // executable, put it in __DATA segment. 363 msect = newMachoSect(mseg, buf, "__DATA") 364 } else { 365 msect = newMachoSect(mseg, buf, segname) 366 } 367 368 if sect.Rellen > 0 { 369 msect.reloc = uint32(sect.Reloff) 370 msect.nreloc = uint32(sect.Rellen / 8) 371 } 372 373 for 1<<msect.align < sect.Align { 374 msect.align++ 375 } 376 msect.addr = sect.Vaddr 377 msect.size = sect.Length 378 379 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen { 380 // data in file 381 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr { 382 Diag("macho cannot represent section %s crossing data and bss", sect.Name) 383 } 384 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr) 385 } else { 386 // zero fill 387 msect.off = 0 388 389 msect.flag |= 1 390 } 391 392 if sect.Rwx&1 != 0 { 393 msect.flag |= 0x400 /* has instructions */ 394 } 395 396 if sect.Name == ".plt" { 397 msect.name = "__symbol_stub1" 398 msect.flag = 0x80000408 /* only instructions, code, symbol stubs */ 399 msect.res1 = 0 //nkind[SymKindLocal]; 400 msect.res2 = 6 401 } 402 403 if sect.Name == ".got" { 404 msect.name = "__nl_symbol_ptr" 405 msect.flag = 6 /* section with nonlazy symbol pointers */ 406 msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */ 407 } 408 409 if sect.Name == ".init_array" { 410 msect.name = "__mod_init_func" 411 msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS 412 } 413 } 414 415 func Asmbmacho() { 416 /* apple MACH */ 417 va := INITTEXT - int64(HEADR) 418 419 mh := getMachoHdr() 420 switch Thearch.Thechar { 421 default: 422 Exitf("unknown macho architecture: %v", Thearch.Thechar) 423 424 case '5': 425 mh.cpu = MACHO_CPU_ARM 426 mh.subcpu = MACHO_SUBCPU_ARMV7 427 428 case '6': 429 mh.cpu = MACHO_CPU_AMD64 430 mh.subcpu = MACHO_SUBCPU_X86 431 432 case '7': 433 mh.cpu = MACHO_CPU_ARM64 434 mh.subcpu = MACHO_SUBCPU_ARM64_ALL 435 436 case '8': 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 Thearch.Thechar == '5' { 448 ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff 449 } else { 450 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff 451 ms.vsize = ms.filesize 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(INITRND)) 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 := Segtext.Sect; sect != nil; sect = sect.Next { 475 machoshbits(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 := Segdata.Sect; sect != nil; sect = sect.Next { 491 machoshbits(ms, sect, "__DATA") 492 } 493 494 if Linkmode != LinkExternal { 495 switch Thearch.Thechar { 496 default: 497 Exitf("unknown macho architecture: %v", Thearch.Thechar) 498 499 case '5': 500 ml := newMachoLoad(5, 17+2) /* unix thread */ 501 ml.data[0] = 1 /* thread type */ 502 ml.data[1] = 17 /* word count */ 503 ml.data[2+15] = uint32(Entryvalue()) /* start pc */ 504 505 case '6': 506 ml := newMachoLoad(5, 42+2) /* unix thread */ 507 ml.data[0] = 4 /* thread type */ 508 ml.data[1] = 42 /* word count */ 509 ml.data[2+32] = uint32(Entryvalue()) /* start pc */ 510 ml.data[2+32+1] = uint32(Entryvalue() >> 32) 511 512 case '7': 513 ml := newMachoLoad(5, 68+2) /* unix thread */ 514 ml.data[0] = 6 /* thread type */ 515 ml.data[1] = 68 /* word count */ 516 ml.data[2+64] = uint32(Entryvalue()) /* start pc */ 517 ml.data[2+64+1] = uint32(Entryvalue() >> 32) 518 519 case '8': 520 ml := newMachoLoad(5, 16+2) /* unix thread */ 521 ml.data[0] = 1 /* thread type */ 522 ml.data[1] = 16 /* word count */ 523 ml.data[2+10] = uint32(Entryvalue()) /* start pc */ 524 } 525 } 526 527 if Debug['d'] == 0 { 528 // must match domacholink below 529 s1 := Linklookup(Ctxt, ".machosymtab", 0) 530 531 s2 := Linklookup(Ctxt, ".linkedit.plt", 0) 532 s3 := Linklookup(Ctxt, ".linkedit.got", 0) 533 s4 := Linklookup(Ctxt, ".machosymstr", 0) 534 535 if Linkmode != LinkExternal { 536 ms := newMachoSeg("__LINKEDIT", 0) 537 ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND))) 538 ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size) 539 ms.fileoffset = uint64(linkoff) 540 ms.filesize = ms.vsize 541 ms.prot1 = 7 542 ms.prot2 = 3 543 } 544 545 ml := newMachoLoad(2, 4) /* LC_SYMTAB */ 546 ml.data[0] = uint32(linkoff) /* symoff */ 547 ml.data[1] = uint32(nsortsym) /* nsyms */ 548 ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */ 549 ml.data[3] = uint32(s4.Size) /* strsize */ 550 551 machodysymtab() 552 553 if Linkmode != LinkExternal { 554 ml := newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */ 555 ml.data[0] = 12 /* offset to string */ 556 stringtouint32(ml.data[1:], "/usr/lib/dyld") 557 558 for i := 0; i < len(dylib); i++ { 559 ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */ 560 ml.data[0] = 24 /* offset of string from beginning of load */ 561 ml.data[1] = 0 /* time stamp */ 562 ml.data[2] = 0 /* version */ 563 ml.data[3] = 0 /* compatibility version */ 564 stringtouint32(ml.data[4:], dylib[i]) 565 } 566 } 567 } 568 569 // TODO: dwarf headers go in ms too 570 if Debug['s'] == 0 { 571 dwarfaddmachoheaders(ms) 572 } 573 574 a := machowrite() 575 if int32(a) > HEADR { 576 Exitf("HEADR too small: %d > %d", a, HEADR) 577 } 578 } 579 580 func symkind(s *LSym) int { 581 if s.Type == obj.SDYNIMPORT { 582 return SymKindUndef 583 } 584 if s.Cgoexport != 0 { 585 return SymKindExtdef 586 } 587 return SymKindLocal 588 } 589 590 func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) { 591 if s == nil { 592 return 593 } 594 595 switch type_ { 596 default: 597 return 598 599 case 'D', 'B', 'T': 600 break 601 } 602 603 if sortsym != nil { 604 sortsym[nsortsym] = s 605 nkind[symkind(s)]++ 606 } 607 608 nsortsym++ 609 } 610 611 type machoscmp []*LSym 612 613 func (x machoscmp) Len() int { 614 return len(x) 615 } 616 617 func (x machoscmp) Swap(i, j int) { 618 x[i], x[j] = x[j], x[i] 619 } 620 621 func (x machoscmp) Less(i, j int) bool { 622 s1 := x[i] 623 s2 := x[j] 624 625 k1 := symkind(s1) 626 k2 := symkind(s2) 627 if k1 != k2 { 628 return k1-k2 < 0 629 } 630 631 return stringsCompare(s1.Extname, s2.Extname) < 0 632 } 633 634 func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { 635 genasmsym(put) 636 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 637 if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ { 638 if s.Reachable { 639 put(s, "", 'D', 0, 0, 0, nil) 640 } 641 } 642 } 643 } 644 645 func machosymorder() { 646 // On Mac OS X Mountain Lion, we must sort exported symbols 647 // So we sort them here and pre-allocate dynid for them 648 // See https://golang.org/issue/4029 649 for i := 0; i < len(dynexp); i++ { 650 dynexp[i].Reachable = true 651 } 652 machogenasmsym(addsym) 653 sortsym = make([]*LSym, nsortsym) 654 nsortsym = 0 655 machogenasmsym(addsym) 656 sort.Sort(machoscmp(sortsym[:nsortsym])) 657 for i := 0; i < nsortsym; i++ { 658 sortsym[i].Dynid = int32(i) 659 } 660 } 661 662 func machosymtab() { 663 var s *LSym 664 var o *LSym 665 var p string 666 667 symtab := Linklookup(Ctxt, ".machosymtab", 0) 668 symstr := Linklookup(Ctxt, ".machosymstr", 0) 669 670 for i := 0; i < nsortsym; i++ { 671 s = sortsym[i] 672 Adduint32(Ctxt, symtab, uint32(symstr.Size)) 673 674 // Only add _ to C symbols. Go symbols have dot in the name. 675 if !strings.Contains(s.Extname, ".") { 676 Adduint8(Ctxt, symstr, '_') 677 } 678 679 // replace "" as ".", because DTrace cannot handle it. 680 if !strings.Contains(s.Extname, "") { 681 Addstring(symstr, s.Extname) 682 } else { 683 for p = s.Extname; p != ""; p = p[1:] { 684 if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 { 685 Adduint8(Ctxt, symstr, '.') 686 p = p[1:] 687 } else { 688 Adduint8(Ctxt, symstr, uint8(p[0])) 689 } 690 } 691 692 Adduint8(Ctxt, symstr, '\x00') 693 } 694 695 if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ { 696 Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol 697 Adduint8(Ctxt, symtab, 0) // no section 698 Adduint16(Ctxt, symtab, 0) // desc 699 adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value 700 } else { 701 if s.Cgoexport != 0 { 702 Adduint8(Ctxt, symtab, 0x0f) 703 } else { 704 Adduint8(Ctxt, symtab, 0x0e) 705 } 706 o = s 707 for o.Outer != nil { 708 o = o.Outer 709 } 710 if o.Sect == nil { 711 Diag("missing section for %s", s.Name) 712 Adduint8(Ctxt, symtab, 0) 713 } else { 714 Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum)) 715 } 716 Adduint16(Ctxt, symtab, 0) // desc 717 adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize) 718 } 719 } 720 } 721 722 func machodysymtab() { 723 ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */ 724 725 n := 0 726 ml.data[0] = uint32(n) /* ilocalsym */ 727 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */ 728 n += nkind[SymKindLocal] 729 730 ml.data[2] = uint32(n) /* iextdefsym */ 731 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */ 732 n += nkind[SymKindExtdef] 733 734 ml.data[4] = uint32(n) /* iundefsym */ 735 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */ 736 737 ml.data[6] = 0 /* tocoffset */ 738 ml.data[7] = 0 /* ntoc */ 739 ml.data[8] = 0 /* modtaboff */ 740 ml.data[9] = 0 /* nmodtab */ 741 ml.data[10] = 0 /* extrefsymoff */ 742 ml.data[11] = 0 /* nextrefsyms */ 743 744 // must match domacholink below 745 s1 := Linklookup(Ctxt, ".machosymtab", 0) 746 747 s2 := Linklookup(Ctxt, ".linkedit.plt", 0) 748 s3 := Linklookup(Ctxt, ".linkedit.got", 0) 749 ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */ 750 ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */ 751 752 ml.data[14] = 0 /* extreloff */ 753 ml.data[15] = 0 /* nextrel */ 754 ml.data[16] = 0 /* locreloff */ 755 ml.data[17] = 0 /* nlocrel */ 756 } 757 758 func Domacholink() int64 { 759 machosymtab() 760 761 // write data that will be linkedit section 762 s1 := Linklookup(Ctxt, ".machosymtab", 0) 763 764 s2 := Linklookup(Ctxt, ".linkedit.plt", 0) 765 s3 := Linklookup(Ctxt, ".linkedit.got", 0) 766 s4 := Linklookup(Ctxt, ".machosymstr", 0) 767 768 // Force the linkedit section to end on a 16-byte 769 // boundary. This allows pure (non-cgo) Go binaries 770 // to be code signed correctly. 771 // 772 // Apple's codesign_allocate (a helper utility for 773 // the codesign utility) can do this fine itself if 774 // it is run on a dynamic Mach-O binary. However, 775 // when it is run on a pure (non-cgo) Go binary, where 776 // the linkedit section is mostly empty, it fails to 777 // account for the extra padding that it itself adds 778 // when adding the LC_CODE_SIGNATURE load command 779 // (which must be aligned on a 16-byte boundary). 780 // 781 // By forcing the linkedit section to end on a 16-byte 782 // boundary, codesign_allocate will not need to apply 783 // any alignment padding itself, working around the 784 // issue. 785 for s4.Size%16 != 0 { 786 Adduint8(Ctxt, s4, 0) 787 } 788 789 size := int(s1.Size + s2.Size + s3.Size + s4.Size) 790 791 if size > 0 { 792 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND)) 793 Cseek(linkoff) 794 795 Cwrite(s1.P[:s1.Size]) 796 Cwrite(s2.P[:s2.Size]) 797 Cwrite(s3.P[:s3.Size]) 798 Cwrite(s4.P[:s4.Size]) 799 } 800 801 return Rnd(int64(size), int64(INITRND)) 802 } 803 804 func machorelocsect(sect *Section, first *LSym) { 805 // If main section has no bits, nothing to relocate. 806 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 807 return 808 } 809 810 sect.Reloff = uint64(Cpos()) 811 var sym *LSym 812 for sym = first; sym != nil; sym = sym.Next { 813 if !sym.Reachable { 814 continue 815 } 816 if uint64(sym.Value) >= sect.Vaddr { 817 break 818 } 819 } 820 821 eaddr := int32(sect.Vaddr + sect.Length) 822 var r *Reloc 823 var ri int 824 for ; sym != nil; sym = sym.Next { 825 if !sym.Reachable { 826 continue 827 } 828 if sym.Value >= int64(eaddr) { 829 break 830 } 831 Ctxt.Cursym = sym 832 833 for ri = 0; ri < len(sym.R); ri++ { 834 r = &sym.R[ri] 835 if r.Done != 0 { 836 continue 837 } 838 if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 { 839 Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 840 } 841 } 842 } 843 844 sect.Rellen = uint64(Cpos()) - sect.Reloff 845 } 846 847 func Machoemitreloc() { 848 for Cpos()&7 != 0 { 849 Cput(0) 850 } 851 852 machorelocsect(Segtext.Sect, Ctxt.Textp) 853 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { 854 machorelocsect(sect, datap) 855 } 856 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 857 machorelocsect(sect, datap) 858 } 859 dwarfemitreloc() 860 } 861