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