Home | History | Annotate | Download | only in ld
      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