...

Source file src/pkg/cmd/link/internal/ld/macho.go

     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		"bytes"
     9		"cmd/internal/objabi"
    10		"cmd/internal/sys"
    11		"cmd/link/internal/sym"
    12		"debug/macho"
    13		"encoding/binary"
    14		"fmt"
    15		"io"
    16		"os"
    17		"sort"
    18		"strings"
    19	)
    20	
    21	type MachoHdr struct {
    22		cpu    uint32
    23		subcpu uint32
    24	}
    25	
    26	type MachoSect struct {
    27		name    string
    28		segname string
    29		addr    uint64
    30		size    uint64
    31		off     uint32
    32		align   uint32
    33		reloc   uint32
    34		nreloc  uint32
    35		flag    uint32
    36		res1    uint32
    37		res2    uint32
    38	}
    39	
    40	type MachoSeg struct {
    41		name       string
    42		vsize      uint64
    43		vaddr      uint64
    44		fileoffset uint64
    45		filesize   uint64
    46		prot1      uint32
    47		prot2      uint32
    48		nsect      uint32
    49		msect      uint32
    50		sect       []MachoSect
    51		flag       uint32
    52	}
    53	
    54	// MachoPlatformLoad represents a LC_VERSION_MIN_* or
    55	// LC_BUILD_VERSION load command.
    56	type MachoPlatformLoad struct {
    57		platform MachoPlatform // One of PLATFORM_* constants.
    58		cmd      MachoLoad
    59	}
    60	
    61	type MachoLoad struct {
    62		type_ uint32
    63		data  []uint32
    64	}
    65	
    66	type MachoPlatform int
    67	
    68	/*
    69	 * Total amount of space to reserve at the start of the file
    70	 * for Header, PHeaders, and SHeaders.
    71	 * May waste some.
    72	 */
    73	const (
    74		INITIAL_MACHO_HEADR = 4 * 1024
    75	)
    76	
    77	const (
    78		MACHO_CPU_AMD64               = 1<<24 | 7
    79		MACHO_CPU_386                 = 7
    80		MACHO_SUBCPU_X86              = 3
    81		MACHO_CPU_ARM                 = 12
    82		MACHO_SUBCPU_ARM              = 0
    83		MACHO_SUBCPU_ARMV7            = 9
    84		MACHO_CPU_ARM64               = 1<<24 | 12
    85		MACHO_SUBCPU_ARM64_ALL        = 0
    86		MACHO32SYMSIZE                = 12
    87		MACHO64SYMSIZE                = 16
    88		MACHO_X86_64_RELOC_UNSIGNED   = 0
    89		MACHO_X86_64_RELOC_SIGNED     = 1
    90		MACHO_X86_64_RELOC_BRANCH     = 2
    91		MACHO_X86_64_RELOC_GOT_LOAD   = 3
    92		MACHO_X86_64_RELOC_GOT        = 4
    93		MACHO_X86_64_RELOC_SUBTRACTOR = 5
    94		MACHO_X86_64_RELOC_SIGNED_1   = 6
    95		MACHO_X86_64_RELOC_SIGNED_2   = 7
    96		MACHO_X86_64_RELOC_SIGNED_4   = 8
    97		MACHO_ARM_RELOC_VANILLA       = 0
    98		MACHO_ARM_RELOC_PAIR          = 1
    99		MACHO_ARM_RELOC_SECTDIFF      = 2
   100		MACHO_ARM_RELOC_BR24          = 5
   101		MACHO_ARM64_RELOC_UNSIGNED    = 0
   102		MACHO_ARM64_RELOC_BRANCH26    = 2
   103		MACHO_ARM64_RELOC_PAGE21      = 3
   104		MACHO_ARM64_RELOC_PAGEOFF12   = 4
   105		MACHO_ARM64_RELOC_ADDEND      = 10
   106		MACHO_GENERIC_RELOC_VANILLA   = 0
   107		MACHO_FAKE_GOTPCREL           = 100
   108	)
   109	
   110	const (
   111		MH_MAGIC    = 0xfeedface
   112		MH_MAGIC_64 = 0xfeedfacf
   113	
   114		MH_OBJECT  = 0x1
   115		MH_EXECUTE = 0x2
   116	
   117		MH_NOUNDEFS = 0x1
   118	)
   119	
   120	const (
   121		LC_SEGMENT                  = 0x1
   122		LC_SYMTAB                   = 0x2
   123		LC_SYMSEG                   = 0x3
   124		LC_THREAD                   = 0x4
   125		LC_UNIXTHREAD               = 0x5
   126		LC_LOADFVMLIB               = 0x6
   127		LC_IDFVMLIB                 = 0x7
   128		LC_IDENT                    = 0x8
   129		LC_FVMFILE                  = 0x9
   130		LC_PREPAGE                  = 0xa
   131		LC_DYSYMTAB                 = 0xb
   132		LC_LOAD_DYLIB               = 0xc
   133		LC_ID_DYLIB                 = 0xd
   134		LC_LOAD_DYLINKER            = 0xe
   135		LC_ID_DYLINKER              = 0xf
   136		LC_PREBOUND_DYLIB           = 0x10
   137		LC_ROUTINES                 = 0x11
   138		LC_SUB_FRAMEWORK            = 0x12
   139		LC_SUB_UMBRELLA             = 0x13
   140		LC_SUB_CLIENT               = 0x14
   141		LC_SUB_LIBRARY              = 0x15
   142		LC_TWOLEVEL_HINTS           = 0x16
   143		LC_PREBIND_CKSUM            = 0x17
   144		LC_LOAD_WEAK_DYLIB          = 0x80000018
   145		LC_SEGMENT_64               = 0x19
   146		LC_ROUTINES_64              = 0x1a
   147		LC_UUID                     = 0x1b
   148		LC_RPATH                    = 0x8000001c
   149		LC_CODE_SIGNATURE           = 0x1d
   150		LC_SEGMENT_SPLIT_INFO       = 0x1e
   151		LC_REEXPORT_DYLIB           = 0x8000001f
   152		LC_LAZY_LOAD_DYLIB          = 0x20
   153		LC_ENCRYPTION_INFO          = 0x21
   154		LC_DYLD_INFO                = 0x22
   155		LC_DYLD_INFO_ONLY           = 0x80000022
   156		LC_LOAD_UPWARD_DYLIB        = 0x80000023
   157		LC_VERSION_MIN_MACOSX       = 0x24
   158		LC_VERSION_MIN_IPHONEOS     = 0x25
   159		LC_FUNCTION_STARTS          = 0x26
   160		LC_DYLD_ENVIRONMENT         = 0x27
   161		LC_MAIN                     = 0x80000028
   162		LC_DATA_IN_CODE             = 0x29
   163		LC_SOURCE_VERSION           = 0x2A
   164		LC_DYLIB_CODE_SIGN_DRS      = 0x2B
   165		LC_ENCRYPTION_INFO_64       = 0x2C
   166		LC_LINKER_OPTION            = 0x2D
   167		LC_LINKER_OPTIMIZATION_HINT = 0x2E
   168		LC_VERSION_MIN_TVOS         = 0x2F
   169		LC_VERSION_MIN_WATCHOS      = 0x30
   170		LC_VERSION_NOTE             = 0x31
   171		LC_BUILD_VERSION            = 0x32
   172	)
   173	
   174	const (
   175		S_REGULAR                  = 0x0
   176		S_ZEROFILL                 = 0x1
   177		S_NON_LAZY_SYMBOL_POINTERS = 0x6
   178		S_SYMBOL_STUBS             = 0x8
   179		S_MOD_INIT_FUNC_POINTERS   = 0x9
   180		S_ATTR_PURE_INSTRUCTIONS   = 0x80000000
   181		S_ATTR_DEBUG               = 0x02000000
   182		S_ATTR_SOME_INSTRUCTIONS   = 0x00000400
   183	)
   184	
   185	const (
   186		PLATFORM_MACOS    MachoPlatform = 1
   187		PLATFORM_IOS      MachoPlatform = 2
   188		PLATFORM_TVOS     MachoPlatform = 3
   189		PLATFORM_WATCHOS  MachoPlatform = 4
   190		PLATFORM_BRIDGEOS MachoPlatform = 5
   191	)
   192	
   193	// Mach-O file writing
   194	// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
   195	
   196	var machohdr MachoHdr
   197	
   198	var load []MachoLoad
   199	
   200	var machoPlatform MachoPlatform
   201	
   202	var seg [16]MachoSeg
   203	
   204	var nseg int
   205	
   206	var ndebug int
   207	
   208	var nsect int
   209	
   210	const (
   211		SymKindLocal = 0 + iota
   212		SymKindExtdef
   213		SymKindUndef
   214		NumSymKind
   215	)
   216	
   217	var nkind [NumSymKind]int
   218	
   219	var sortsym []*sym.Symbol
   220	
   221	var nsortsym int
   222	
   223	// Amount of space left for adding load commands
   224	// that refer to dynamic libraries. Because these have
   225	// to go in the Mach-O header, we can't just pick a
   226	// "big enough" header size. The initial header is
   227	// one page, the non-dynamic library stuff takes
   228	// up about 1300 bytes; we overestimate that as 2k.
   229	var loadBudget = INITIAL_MACHO_HEADR - 2*1024
   230	
   231	func getMachoHdr() *MachoHdr {
   232		return &machohdr
   233	}
   234	
   235	func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
   236		if arch.PtrSize == 8 && (ndata&1 != 0) {
   237			ndata++
   238		}
   239	
   240		load = append(load, MachoLoad{})
   241		l := &load[len(load)-1]
   242		l.type_ = type_
   243		l.data = make([]uint32, ndata)
   244		return l
   245	}
   246	
   247	func newMachoSeg(name string, msect int) *MachoSeg {
   248		if nseg >= len(seg) {
   249			Exitf("too many segs")
   250		}
   251	
   252		s := &seg[nseg]
   253		nseg++
   254		s.name = name
   255		s.msect = uint32(msect)
   256		s.sect = make([]MachoSect, msect)
   257		return s
   258	}
   259	
   260	func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
   261		if seg.nsect >= seg.msect {
   262			Exitf("too many sects in segment %s", seg.name)
   263		}
   264	
   265		s := &seg.sect[seg.nsect]
   266		seg.nsect++
   267		s.name = name
   268		s.segname = segname
   269		nsect++
   270		return s
   271	}
   272	
   273	// Generic linking code.
   274	
   275	var dylib []string
   276	
   277	var linkoff int64
   278	
   279	func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
   280		o1 := out.Offset()
   281	
   282		loadsize := 4 * 4 * ndebug
   283		for i := range load {
   284			loadsize += 4 * (len(load[i].data) + 2)
   285		}
   286		if arch.PtrSize == 8 {
   287			loadsize += 18 * 4 * nseg
   288			loadsize += 20 * 4 * nsect
   289		} else {
   290			loadsize += 14 * 4 * nseg
   291			loadsize += 17 * 4 * nsect
   292		}
   293	
   294		if arch.PtrSize == 8 {
   295			out.Write32(MH_MAGIC_64)
   296		} else {
   297			out.Write32(MH_MAGIC)
   298		}
   299		out.Write32(machohdr.cpu)
   300		out.Write32(machohdr.subcpu)
   301		if linkmode == LinkExternal {
   302			out.Write32(MH_OBJECT) /* file type - mach object */
   303		} else {
   304			out.Write32(MH_EXECUTE) /* file type - mach executable */
   305		}
   306		out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
   307		out.Write32(uint32(loadsize))
   308		if nkind[SymKindUndef] == 0 {
   309			out.Write32(MH_NOUNDEFS) /* flags - no undefines */
   310		} else {
   311			out.Write32(0) /* flags */
   312		}
   313		if arch.PtrSize == 8 {
   314			out.Write32(0) /* reserved */
   315		}
   316	
   317		for i := 0; i < nseg; i++ {
   318			s := &seg[i]
   319			if arch.PtrSize == 8 {
   320				out.Write32(LC_SEGMENT_64)
   321				out.Write32(72 + 80*s.nsect)
   322				out.WriteStringN(s.name, 16)
   323				out.Write64(s.vaddr)
   324				out.Write64(s.vsize)
   325				out.Write64(s.fileoffset)
   326				out.Write64(s.filesize)
   327				out.Write32(s.prot1)
   328				out.Write32(s.prot2)
   329				out.Write32(s.nsect)
   330				out.Write32(s.flag)
   331			} else {
   332				out.Write32(LC_SEGMENT)
   333				out.Write32(56 + 68*s.nsect)
   334				out.WriteStringN(s.name, 16)
   335				out.Write32(uint32(s.vaddr))
   336				out.Write32(uint32(s.vsize))
   337				out.Write32(uint32(s.fileoffset))
   338				out.Write32(uint32(s.filesize))
   339				out.Write32(s.prot1)
   340				out.Write32(s.prot2)
   341				out.Write32(s.nsect)
   342				out.Write32(s.flag)
   343			}
   344	
   345			for j := uint32(0); j < s.nsect; j++ {
   346				t := &s.sect[j]
   347				if arch.PtrSize == 8 {
   348					out.WriteStringN(t.name, 16)
   349					out.WriteStringN(t.segname, 16)
   350					out.Write64(t.addr)
   351					out.Write64(t.size)
   352					out.Write32(t.off)
   353					out.Write32(t.align)
   354					out.Write32(t.reloc)
   355					out.Write32(t.nreloc)
   356					out.Write32(t.flag)
   357					out.Write32(t.res1) /* reserved */
   358					out.Write32(t.res2) /* reserved */
   359					out.Write32(0)      /* reserved */
   360				} else {
   361					out.WriteStringN(t.name, 16)
   362					out.WriteStringN(t.segname, 16)
   363					out.Write32(uint32(t.addr))
   364					out.Write32(uint32(t.size))
   365					out.Write32(t.off)
   366					out.Write32(t.align)
   367					out.Write32(t.reloc)
   368					out.Write32(t.nreloc)
   369					out.Write32(t.flag)
   370					out.Write32(t.res1) /* reserved */
   371					out.Write32(t.res2) /* reserved */
   372				}
   373			}
   374		}
   375	
   376		for i := range load {
   377			l := &load[i]
   378			out.Write32(l.type_)
   379			out.Write32(4 * (uint32(len(l.data)) + 2))
   380			for j := 0; j < len(l.data); j++ {
   381				out.Write32(l.data[j])
   382			}
   383		}
   384	
   385		return int(out.Offset() - o1)
   386	}
   387	
   388	func (ctxt *Link) domacho() {
   389		if *FlagD {
   390			return
   391		}
   392	
   393		// Copy platform load command.
   394		for _, h := range hostobj {
   395			load, err := hostobjMachoPlatform(&h)
   396			if err != nil {
   397				Exitf("%v", err)
   398			}
   399			if load != nil {
   400				machoPlatform = load.platform
   401				ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
   402				copy(ml.data, load.cmd.data)
   403				break
   404			}
   405		}
   406		if machoPlatform == 0 {
   407			machoPlatform = PLATFORM_MACOS
   408			if ctxt.LinkMode == LinkInternal {
   409				// For lldb, must say LC_VERSION_MIN_MACOSX or else
   410				// it won't know that this Mach-O binary is from OS X
   411				// (could be iOS or WatchOS instead).
   412				// Go on iOS uses linkmode=external, and linkmode=external
   413				// adds this itself. So we only need this code for linkmode=internal
   414				// and we can assume OS X.
   415				//
   416				// See golang.org/issues/12941.
   417				//
   418				// The version must be at least 10.9; see golang.org/issues/30488.
   419				ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2)
   420				ml.data[0] = 10<<16 | 9<<8 | 0<<0 // OS X version 10.9.0
   421				ml.data[1] = 10<<16 | 9<<8 | 0<<0 // SDK 10.9.0
   422			}
   423		}
   424	
   425		// empirically, string table must begin with " \x00".
   426		s := ctxt.Syms.Lookup(".machosymstr", 0)
   427	
   428		s.Type = sym.SMACHOSYMSTR
   429		s.Attr |= sym.AttrReachable
   430		s.AddUint8(' ')
   431		s.AddUint8('\x00')
   432	
   433		s = ctxt.Syms.Lookup(".machosymtab", 0)
   434		s.Type = sym.SMACHOSYMTAB
   435		s.Attr |= sym.AttrReachable
   436	
   437		if ctxt.LinkMode != LinkExternal {
   438			s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
   439			s.Type = sym.SMACHOPLT
   440			s.Attr |= sym.AttrReachable
   441	
   442			s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
   443			s.Type = sym.SMACHOGOT
   444			s.Attr |= sym.AttrReachable
   445			s.Align = 4
   446	
   447			s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
   448			s.Type = sym.SMACHOINDIRECTPLT
   449			s.Attr |= sym.AttrReachable
   450	
   451			s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
   452			s.Type = sym.SMACHOINDIRECTGOT
   453			s.Attr |= sym.AttrReachable
   454		}
   455	
   456		// Add a dummy symbol that will become the __asm marker section.
   457		if ctxt.LinkMode == LinkExternal {
   458			s := ctxt.Syms.Lookup(".llvmasm", 0)
   459			s.Type = sym.SMACHO
   460			s.Attr |= sym.AttrReachable
   461			s.AddUint8(0)
   462		}
   463	}
   464	
   465	func machoadddynlib(lib string, linkmode LinkMode) {
   466		if seenlib[lib] || linkmode == LinkExternal {
   467			return
   468		}
   469		seenlib[lib] = true
   470	
   471		// Will need to store the library name rounded up
   472		// and 24 bytes of header metadata. If not enough
   473		// space, grab another page of initial space at the
   474		// beginning of the output file.
   475		loadBudget -= (len(lib)+7)/8*8 + 24
   476	
   477		if loadBudget < 0 {
   478			HEADR += 4096
   479			*FlagTextAddr += 4096
   480			loadBudget += 4096
   481		}
   482	
   483		dylib = append(dylib, lib)
   484	}
   485	
   486	func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
   487		buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
   488	
   489		var msect *MachoSect
   490		if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 ||
   491			(ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe) ||
   492			(ctxt.Arch.Family == sys.ARM && ctxt.BuildMode != BuildModeExe)) {
   493			// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
   494			// complains about absolute relocs in __TEXT, so if the section is not
   495			// executable, put it in __DATA segment.
   496			msect = newMachoSect(mseg, buf, "__DATA")
   497		} else {
   498			msect = newMachoSect(mseg, buf, segname)
   499		}
   500	
   501		if sect.Rellen > 0 {
   502			msect.reloc = uint32(sect.Reloff)
   503			msect.nreloc = uint32(sect.Rellen / 8)
   504		}
   505	
   506		for 1<<msect.align < sect.Align {
   507			msect.align++
   508		}
   509		msect.addr = sect.Vaddr
   510		msect.size = sect.Length
   511	
   512		if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
   513			// data in file
   514			if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
   515				Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
   516			}
   517			msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
   518		} else {
   519			msect.off = 0
   520			msect.flag |= S_ZEROFILL
   521		}
   522	
   523		if sect.Rwx&1 != 0 {
   524			msect.flag |= S_ATTR_SOME_INSTRUCTIONS
   525		}
   526	
   527		if sect.Name == ".text" {
   528			msect.flag |= S_ATTR_PURE_INSTRUCTIONS
   529		}
   530	
   531		if sect.Name == ".plt" {
   532			msect.name = "__symbol_stub1"
   533			msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
   534			msect.res1 = 0 //nkind[SymKindLocal];
   535			msect.res2 = 6
   536		}
   537	
   538		if sect.Name == ".got" {
   539			msect.name = "__nl_symbol_ptr"
   540			msect.flag = S_NON_LAZY_SYMBOL_POINTERS
   541			msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
   542		}
   543	
   544		if sect.Name == ".init_array" {
   545			msect.name = "__mod_init_func"
   546			msect.flag = S_MOD_INIT_FUNC_POINTERS
   547		}
   548	
   549		// Some platforms such as watchOS and tvOS require binaries with
   550		// bitcode enabled. The Go toolchain can't output bitcode, so use
   551		// a marker section in the __LLVM segment, "__asm", to tell the Apple
   552		// toolchain that the Go text came from assembler and thus has no
   553		// bitcode. This is not true, but Kotlin/Native, Rust and Flutter
   554		// are also using this trick.
   555		if sect.Name == ".llvmasm" {
   556			msect.name = "__asm"
   557			msect.segname = "__LLVM"
   558		}
   559	
   560		if segname == "__DWARF" {
   561			msect.flag |= S_ATTR_DEBUG
   562		}
   563	}
   564	
   565	func Asmbmacho(ctxt *Link) {
   566		/* apple MACH */
   567		va := *FlagTextAddr - int64(HEADR)
   568	
   569		mh := getMachoHdr()
   570		switch ctxt.Arch.Family {
   571		default:
   572			Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   573	
   574		case sys.ARM:
   575			mh.cpu = MACHO_CPU_ARM
   576			mh.subcpu = MACHO_SUBCPU_ARMV7
   577	
   578		case sys.AMD64:
   579			mh.cpu = MACHO_CPU_AMD64
   580			mh.subcpu = MACHO_SUBCPU_X86
   581	
   582		case sys.ARM64:
   583			mh.cpu = MACHO_CPU_ARM64
   584			mh.subcpu = MACHO_SUBCPU_ARM64_ALL
   585	
   586		case sys.I386:
   587			mh.cpu = MACHO_CPU_386
   588			mh.subcpu = MACHO_SUBCPU_X86
   589		}
   590	
   591		var ms *MachoSeg
   592		if ctxt.LinkMode == LinkExternal {
   593			/* segment for entire file */
   594			ms = newMachoSeg("", 40)
   595	
   596			ms.fileoffset = Segtext.Fileoff
   597			ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
   598			ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
   599		}
   600	
   601		/* segment for zero page */
   602		if ctxt.LinkMode != LinkExternal {
   603			ms = newMachoSeg("__PAGEZERO", 0)
   604			ms.vsize = uint64(va)
   605		}
   606	
   607		/* text */
   608		v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
   609	
   610		if ctxt.LinkMode != LinkExternal {
   611			ms = newMachoSeg("__TEXT", 20)
   612			ms.vaddr = uint64(va)
   613			ms.vsize = uint64(v)
   614			ms.fileoffset = 0
   615			ms.filesize = uint64(v)
   616			ms.prot1 = 7
   617			ms.prot2 = 5
   618		}
   619	
   620		for _, sect := range Segtext.Sections {
   621			machoshbits(ctxt, ms, sect, "__TEXT")
   622		}
   623	
   624		/* data */
   625		if ctxt.LinkMode != LinkExternal {
   626			w := int64(Segdata.Length)
   627			ms = newMachoSeg("__DATA", 20)
   628			ms.vaddr = uint64(va) + uint64(v)
   629			ms.vsize = uint64(w)
   630			ms.fileoffset = uint64(v)
   631			ms.filesize = Segdata.Filelen
   632			ms.prot1 = 3
   633			ms.prot2 = 3
   634		}
   635	
   636		for _, sect := range Segdata.Sections {
   637			machoshbits(ctxt, ms, sect, "__DATA")
   638		}
   639	
   640		/* dwarf */
   641		if !*FlagW {
   642			if ctxt.LinkMode != LinkExternal {
   643				ms = newMachoSeg("__DWARF", 20)
   644				ms.vaddr = Segdwarf.Vaddr
   645				ms.vsize = 0
   646				ms.fileoffset = Segdwarf.Fileoff
   647				ms.filesize = Segdwarf.Filelen
   648			}
   649			for _, sect := range Segdwarf.Sections {
   650				machoshbits(ctxt, ms, sect, "__DWARF")
   651			}
   652		}
   653	
   654		if ctxt.LinkMode != LinkExternal {
   655			switch ctxt.Arch.Family {
   656			default:
   657				Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   658	
   659			case sys.ARM:
   660				ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 17+2)
   661				ml.data[0] = 1                           /* thread type */
   662				ml.data[1] = 17                          /* word count */
   663				ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */
   664	
   665			case sys.AMD64:
   666				ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
   667				ml.data[0] = 4                           /* thread type */
   668				ml.data[1] = 42                          /* word count */
   669				ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
   670				ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
   671	
   672			case sys.ARM64:
   673				ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
   674				ml.data[0] = 6                           /* thread type */
   675				ml.data[1] = 68                          /* word count */
   676				ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
   677				ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
   678	
   679			case sys.I386:
   680				ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 16+2)
   681				ml.data[0] = 1                           /* thread type */
   682				ml.data[1] = 16                          /* word count */
   683				ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */
   684			}
   685		}
   686	
   687		if !*FlagD {
   688			// must match domacholink below
   689			s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   690			s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   691			s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   692			s4 := ctxt.Syms.Lookup(".machosymstr", 0)
   693	
   694			if ctxt.LinkMode != LinkExternal {
   695				ms := newMachoSeg("__LINKEDIT", 0)
   696				ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
   697				ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
   698				ms.fileoffset = uint64(linkoff)
   699				ms.filesize = ms.vsize
   700				ms.prot1 = 7
   701				ms.prot2 = 3
   702			}
   703	
   704			ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
   705			ml.data[0] = uint32(linkoff)                               /* symoff */
   706			ml.data[1] = uint32(nsortsym)                              /* nsyms */
   707			ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
   708			ml.data[3] = uint32(s4.Size)                               /* strsize */
   709	
   710			machodysymtab(ctxt)
   711	
   712			if ctxt.LinkMode != LinkExternal {
   713				ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
   714				ml.data[0] = 12 /* offset to string */
   715				stringtouint32(ml.data[1:], "/usr/lib/dyld")
   716	
   717				for _, lib := range dylib {
   718					ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
   719					ml.data[0] = 24 /* offset of string from beginning of load */
   720					ml.data[1] = 0  /* time stamp */
   721					ml.data[2] = 0  /* version */
   722					ml.data[3] = 0  /* compatibility version */
   723					stringtouint32(ml.data[4:], lib)
   724				}
   725			}
   726		}
   727	
   728		a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   729		if int32(a) > HEADR {
   730			Exitf("HEADR too small: %d > %d", a, HEADR)
   731		}
   732	}
   733	
   734	func symkind(s *sym.Symbol) int {
   735		if s.Type == sym.SDYNIMPORT {
   736			return SymKindUndef
   737		}
   738		if s.Attr.CgoExport() {
   739			return SymKindExtdef
   740		}
   741		return SymKindLocal
   742	}
   743	
   744	func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
   745		if s == nil {
   746			return
   747		}
   748	
   749		switch type_ {
   750		default:
   751			return
   752	
   753		case DataSym, BSSSym, TextSym:
   754			break
   755		}
   756	
   757		if sortsym != nil {
   758			sortsym[nsortsym] = s
   759			nkind[symkind(s)]++
   760		}
   761	
   762		nsortsym++
   763	}
   764	
   765	type machoscmp []*sym.Symbol
   766	
   767	func (x machoscmp) Len() int {
   768		return len(x)
   769	}
   770	
   771	func (x machoscmp) Swap(i, j int) {
   772		x[i], x[j] = x[j], x[i]
   773	}
   774	
   775	func (x machoscmp) Less(i, j int) bool {
   776		s1 := x[i]
   777		s2 := x[j]
   778	
   779		k1 := symkind(s1)
   780		k2 := symkind(s2)
   781		if k1 != k2 {
   782			return k1 < k2
   783		}
   784	
   785		return s1.Extname() < s2.Extname()
   786	}
   787	
   788	func machogenasmsym(ctxt *Link) {
   789		genasmsym(ctxt, addsym)
   790		for _, s := range ctxt.Syms.Allsym {
   791			// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
   792			if s.Type == sym.SDYNIMPORT && s.Dynimplib() == "/usr/lib/libSystem.B.dylib" {
   793				// But only on macOS.
   794				if machoPlatform == PLATFORM_MACOS {
   795					switch n := s.Extname(); n {
   796					case "fdopendir":
   797						switch objabi.GOARCH {
   798						case "amd64":
   799							s.SetExtname(n + "$INODE64")
   800						case "386":
   801							s.SetExtname(n + "$INODE64$UNIX2003")
   802						}
   803					case "readdir_r", "getfsstat":
   804						switch objabi.GOARCH {
   805						case "amd64", "386":
   806							s.SetExtname(n + "$INODE64")
   807						}
   808					}
   809				}
   810			}
   811	
   812			if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
   813				if s.Attr.Reachable() {
   814					addsym(ctxt, s, "", DataSym, 0, nil)
   815				}
   816			}
   817		}
   818	}
   819	
   820	func machosymorder(ctxt *Link) {
   821		// On Mac OS X Mountain Lion, we must sort exported symbols
   822		// So we sort them here and pre-allocate dynid for them
   823		// See https://golang.org/issue/4029
   824		for i := range dynexp {
   825			dynexp[i].Attr |= sym.AttrReachable
   826		}
   827		machogenasmsym(ctxt)
   828		sortsym = make([]*sym.Symbol, nsortsym)
   829		nsortsym = 0
   830		machogenasmsym(ctxt)
   831		sort.Sort(machoscmp(sortsym[:nsortsym]))
   832		for i := 0; i < nsortsym; i++ {
   833			sortsym[i].Dynid = int32(i)
   834		}
   835	}
   836	
   837	// machoShouldExport reports whether a symbol needs to be exported.
   838	//
   839	// When dynamically linking, all non-local variables and plugin-exported
   840	// symbols need to be exported.
   841	func machoShouldExport(ctxt *Link, s *sym.Symbol) bool {
   842		if !ctxt.DynlinkingGo() || s.Attr.Local() {
   843			return false
   844		}
   845		if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) {
   846			return true
   847		}
   848		if strings.HasPrefix(s.Name, "go.itab.") {
   849			return true
   850		}
   851		if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
   852			// reduce runtime typemap pressure, but do not
   853			// export alg functions (type..*), as these
   854			// appear in pclntable.
   855			return true
   856		}
   857		if strings.HasPrefix(s.Name, "go.link.pkghash") {
   858			return true
   859		}
   860		return s.Type >= sym.SFirstWritable // only writable sections
   861	}
   862	
   863	func machosymtab(ctxt *Link) {
   864		symtab := ctxt.Syms.Lookup(".machosymtab", 0)
   865		symstr := ctxt.Syms.Lookup(".machosymstr", 0)
   866	
   867		for i := 0; i < nsortsym; i++ {
   868			s := sortsym[i]
   869			symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
   870	
   871			export := machoShouldExport(ctxt, s)
   872	
   873			// In normal buildmodes, only add _ to C symbols, as
   874			// Go symbols have dot in the name.
   875			//
   876			// Do not export C symbols in plugins, as runtime C
   877			// symbols like crosscall2 are in pclntab and end up
   878			// pointing at the host binary, breaking unwinding.
   879			// See Issue #18190.
   880			cexport := !strings.Contains(s.Extname(), ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s))
   881			if cexport || export {
   882				symstr.AddUint8('_')
   883			}
   884	
   885			// replace "·" as ".", because DTrace cannot handle it.
   886			Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1))
   887	
   888			if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
   889				symtab.AddUint8(0x01)                             // type N_EXT, external symbol
   890				symtab.AddUint8(0)                                // no section
   891				symtab.AddUint16(ctxt.Arch, 0)                    // desc
   892				symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
   893			} else {
   894				if s.Attr.CgoExport() || export {
   895					symtab.AddUint8(0x0f)
   896				} else {
   897					symtab.AddUint8(0x0e)
   898				}
   899				o := s
   900				for o.Outer != nil {
   901					o = o.Outer
   902				}
   903				if o.Sect == nil {
   904					Errorf(s, "missing section for symbol")
   905					symtab.AddUint8(0)
   906				} else {
   907					symtab.AddUint8(uint8(o.Sect.Extnum))
   908				}
   909				symtab.AddUint16(ctxt.Arch, 0) // desc
   910				symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize)
   911			}
   912		}
   913	}
   914	
   915	func machodysymtab(ctxt *Link) {
   916		ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
   917	
   918		n := 0
   919		ml.data[0] = uint32(n)                   /* ilocalsym */
   920		ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
   921		n += nkind[SymKindLocal]
   922	
   923		ml.data[2] = uint32(n)                    /* iextdefsym */
   924		ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
   925		n += nkind[SymKindExtdef]
   926	
   927		ml.data[4] = uint32(n)                   /* iundefsym */
   928		ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
   929	
   930		ml.data[6] = 0  /* tocoffset */
   931		ml.data[7] = 0  /* ntoc */
   932		ml.data[8] = 0  /* modtaboff */
   933		ml.data[9] = 0  /* nmodtab */
   934		ml.data[10] = 0 /* extrefsymoff */
   935		ml.data[11] = 0 /* nextrefsyms */
   936	
   937		// must match domacholink below
   938		s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   939	
   940		s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   941		s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   942		ml.data[12] = uint32(linkoff + s1.Size)       /* indirectsymoff */
   943		ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
   944	
   945		ml.data[14] = 0 /* extreloff */
   946		ml.data[15] = 0 /* nextrel */
   947		ml.data[16] = 0 /* locreloff */
   948		ml.data[17] = 0 /* nlocrel */
   949	}
   950	
   951	func Domacholink(ctxt *Link) int64 {
   952		machosymtab(ctxt)
   953	
   954		// write data that will be linkedit section
   955		s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   956	
   957		s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   958		s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   959		s4 := ctxt.Syms.Lookup(".machosymstr", 0)
   960	
   961		// Force the linkedit section to end on a 16-byte
   962		// boundary. This allows pure (non-cgo) Go binaries
   963		// to be code signed correctly.
   964		//
   965		// Apple's codesign_allocate (a helper utility for
   966		// the codesign utility) can do this fine itself if
   967		// it is run on a dynamic Mach-O binary. However,
   968		// when it is run on a pure (non-cgo) Go binary, where
   969		// the linkedit section is mostly empty, it fails to
   970		// account for the extra padding that it itself adds
   971		// when adding the LC_CODE_SIGNATURE load command
   972		// (which must be aligned on a 16-byte boundary).
   973		//
   974		// By forcing the linkedit section to end on a 16-byte
   975		// boundary, codesign_allocate will not need to apply
   976		// any alignment padding itself, working around the
   977		// issue.
   978		for s4.Size%16 != 0 {
   979			s4.AddUint8(0)
   980		}
   981	
   982		size := int(s1.Size + s2.Size + s3.Size + s4.Size)
   983	
   984		if size > 0 {
   985			linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
   986			ctxt.Out.SeekSet(linkoff)
   987	
   988			ctxt.Out.Write(s1.P[:s1.Size])
   989			ctxt.Out.Write(s2.P[:s2.Size])
   990			ctxt.Out.Write(s3.P[:s3.Size])
   991			ctxt.Out.Write(s4.P[:s4.Size])
   992		}
   993	
   994		return Rnd(int64(size), int64(*FlagRound))
   995	}
   996	
   997	func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
   998		// If main section has no bits, nothing to relocate.
   999		if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
  1000			return
  1001		}
  1002	
  1003		sect.Reloff = uint64(ctxt.Out.Offset())
  1004		for i, s := range syms {
  1005			if !s.Attr.Reachable() {
  1006				continue
  1007			}
  1008			if uint64(s.Value) >= sect.Vaddr {
  1009				syms = syms[i:]
  1010				break
  1011			}
  1012		}
  1013	
  1014		eaddr := int32(sect.Vaddr + sect.Length)
  1015		for _, s := range syms {
  1016			if !s.Attr.Reachable() {
  1017				continue
  1018			}
  1019			if s.Value >= int64(eaddr) {
  1020				break
  1021			}
  1022			for ri := range s.R {
  1023				r := &s.R[ri]
  1024				if r.Done {
  1025					continue
  1026				}
  1027				if r.Xsym == nil {
  1028					Errorf(s, "missing xsym in relocation")
  1029					continue
  1030				}
  1031				if !r.Xsym.Attr.Reachable() {
  1032					Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
  1033				}
  1034				if !thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
  1035					Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
  1036				}
  1037			}
  1038		}
  1039	
  1040		sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
  1041	}
  1042	
  1043	func Machoemitreloc(ctxt *Link) {
  1044		for ctxt.Out.Offset()&7 != 0 {
  1045			ctxt.Out.Write8(0)
  1046		}
  1047	
  1048		machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp)
  1049		for _, sect := range Segtext.Sections[1:] {
  1050			machorelocsect(ctxt, sect, datap)
  1051		}
  1052		for _, sect := range Segdata.Sections {
  1053			machorelocsect(ctxt, sect, datap)
  1054		}
  1055		for _, sect := range Segdwarf.Sections {
  1056			machorelocsect(ctxt, sect, dwarfp)
  1057		}
  1058	}
  1059	
  1060	// hostobjMachoPlatform returns the first platform load command found
  1061	// in the host object, if any.
  1062	func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
  1063		f, err := os.Open(h.file)
  1064		if err != nil {
  1065			return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
  1066		}
  1067		defer f.Close()
  1068		sr := io.NewSectionReader(f, h.off, h.length)
  1069		m, err := macho.NewFile(sr)
  1070		if err != nil {
  1071			// Not a valid Mach-O file.
  1072			return nil, nil
  1073		}
  1074		return peekMachoPlatform(m)
  1075	}
  1076	
  1077	// peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
  1078	// load command found in the Mach-O file, if any.
  1079	func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
  1080		for _, cmd := range m.Loads {
  1081			raw := cmd.Raw()
  1082			ml := MachoLoad{
  1083				type_: m.ByteOrder.Uint32(raw),
  1084			}
  1085			// Skip the type and command length.
  1086			data := raw[8:]
  1087			var p MachoPlatform
  1088			switch ml.type_ {
  1089			case LC_VERSION_MIN_IPHONEOS:
  1090				p = PLATFORM_IOS
  1091			case LC_VERSION_MIN_MACOSX:
  1092				p = PLATFORM_MACOS
  1093			case LC_VERSION_MIN_WATCHOS:
  1094				p = PLATFORM_WATCHOS
  1095			case LC_VERSION_MIN_TVOS:
  1096				p = PLATFORM_TVOS
  1097			case LC_BUILD_VERSION:
  1098				p = MachoPlatform(m.ByteOrder.Uint32(data))
  1099			default:
  1100				continue
  1101			}
  1102			ml.data = make([]uint32, len(data)/4)
  1103			r := bytes.NewReader(data)
  1104			if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
  1105				return nil, err
  1106			}
  1107			return &MachoPlatformLoad{
  1108				platform: p,
  1109				cmd:      ml,
  1110			}, nil
  1111		}
  1112		return nil, nil
  1113	}
  1114	

View as plain text