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