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