Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/arm64/asm.go

Documentation: cmd/link/internal/arm64

     1  // Inferno utils/5l/asm.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package arm64
    32  
    33  import (
    34  	"cmd/internal/objabi"
    35  	"cmd/internal/sys"
    36  	"cmd/link/internal/ld"
    37  	"cmd/link/internal/loader"
    38  	"cmd/link/internal/sym"
    39  	"debug/elf"
    40  	"fmt"
    41  	"log"
    42  )
    43  
    44  func gentext(ctxt *ld.Link, ldr *loader.Loader) {
    45  	initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
    46  	if initfunc == nil {
    47  		return
    48  	}
    49  
    50  	o := func(op uint32) {
    51  		initfunc.AddUint32(ctxt.Arch, op)
    52  	}
    53  	// 0000000000000000 <local.dso_init>:
    54  	// 0:	90000000 	adrp	x0, 0 <runtime.firstmoduledata>
    55  	// 	0: R_AARCH64_ADR_PREL_PG_HI21	local.moduledata
    56  	// 4:	91000000 	add	x0, x0, #0x0
    57  	// 	4: R_AARCH64_ADD_ABS_LO12_NC	local.moduledata
    58  	o(0x90000000)
    59  	o(0x91000000)
    60  	rel, _ := initfunc.AddRel(objabi.R_ADDRARM64)
    61  	rel.SetOff(0)
    62  	rel.SetSiz(8)
    63  	rel.SetSym(ctxt.Moduledata)
    64  
    65  	// 8:	14000000 	b	0 <runtime.addmoduledata>
    66  	// 	8: R_AARCH64_CALL26	runtime.addmoduledata
    67  	o(0x14000000)
    68  	rel2, _ := initfunc.AddRel(objabi.R_CALLARM64)
    69  	rel2.SetOff(8)
    70  	rel2.SetSiz(4)
    71  	rel2.SetSym(addmoduledata)
    72  }
    73  
    74  func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
    75  	targ := r.Sym()
    76  	var targType sym.SymKind
    77  	if targ != 0 {
    78  		targType = ldr.SymType(targ)
    79  	}
    80  
    81  	const pcrel = 1
    82  	switch r.Type() {
    83  	default:
    84  		if r.Type() >= objabi.ElfRelocOffset {
    85  			ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
    86  			return false
    87  		}
    88  
    89  	// Handle relocations found in ELF object files.
    90  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
    91  		if targType == sym.SDYNIMPORT {
    92  			ldr.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", ldr.SymName(targ))
    93  		}
    94  		// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
    95  		// sense and should be removed when someone has thought about it properly.
    96  		if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
    97  			ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
    98  		}
    99  		su := ldr.MakeSymbolUpdater(s)
   100  		su.SetRelocType(rIdx, objabi.R_PCREL)
   101  		su.SetRelocAdd(rIdx, r.Add()+4)
   102  		return true
   103  
   104  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
   105  		if targType == sym.SDYNIMPORT {
   106  			ldr.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", ldr.SymName(targ))
   107  		}
   108  		if targType == 0 || targType == sym.SXREF {
   109  			ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
   110  		}
   111  		su := ldr.MakeSymbolUpdater(s)
   112  		su.SetRelocType(rIdx, objabi.R_PCREL)
   113  		su.SetRelocAdd(rIdx, r.Add()+8)
   114  		return true
   115  
   116  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
   117  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
   118  		if targType == sym.SDYNIMPORT {
   119  			addpltsym(target, ldr, syms, targ)
   120  			su := ldr.MakeSymbolUpdater(s)
   121  			su.SetRelocSym(rIdx, syms.PLT)
   122  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
   123  		}
   124  		if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
   125  			ldr.Errorf(s, "unknown symbol %s in callarm64", ldr.SymName(targ))
   126  		}
   127  		su := ldr.MakeSymbolUpdater(s)
   128  		su.SetRelocType(rIdx, objabi.R_CALLARM64)
   129  		return true
   130  
   131  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
   132  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
   133  		if targType != sym.SDYNIMPORT {
   134  			// have symbol
   135  			// TODO: turn LDR of GOT entry into ADR of symbol itself
   136  		}
   137  
   138  		// fall back to using GOT
   139  		// TODO: just needs relocation, no need to put in .dynsym
   140  		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
   141  		su := ldr.MakeSymbolUpdater(s)
   142  		su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
   143  		su.SetRelocSym(rIdx, syms.GOT)
   144  		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
   145  		return true
   146  
   147  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
   148  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
   149  		if targType == sym.SDYNIMPORT {
   150  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   151  		}
   152  		if targType == 0 || targType == sym.SXREF {
   153  			ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ))
   154  		}
   155  		su := ldr.MakeSymbolUpdater(s)
   156  		su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
   157  		return true
   158  
   159  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
   160  		if targType == sym.SDYNIMPORT {
   161  			ldr.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", ldr.SymName(targ))
   162  		}
   163  		su := ldr.MakeSymbolUpdater(s)
   164  		su.SetRelocType(rIdx, objabi.R_ADDR)
   165  		if target.IsPIE() && target.IsInternal() {
   166  			// For internal linking PIE, this R_ADDR relocation cannot
   167  			// be resolved statically. We need to generate a dynamic
   168  			// relocation. Let the code below handle it.
   169  			break
   170  		}
   171  		return true
   172  
   173  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
   174  		if targType == sym.SDYNIMPORT {
   175  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   176  		}
   177  		su := ldr.MakeSymbolUpdater(s)
   178  		su.SetRelocType(rIdx, objabi.R_ARM64_LDST8)
   179  		return true
   180  
   181  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST16_ABS_LO12_NC):
   182  		if targType == sym.SDYNIMPORT {
   183  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   184  		}
   185  		su := ldr.MakeSymbolUpdater(s)
   186  		su.SetRelocType(rIdx, objabi.R_ARM64_LDST16)
   187  		return true
   188  
   189  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
   190  		if targType == sym.SDYNIMPORT {
   191  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   192  		}
   193  		su := ldr.MakeSymbolUpdater(s)
   194  		su.SetRelocType(rIdx, objabi.R_ARM64_LDST32)
   195  		return true
   196  
   197  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
   198  		if targType == sym.SDYNIMPORT {
   199  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   200  		}
   201  		su := ldr.MakeSymbolUpdater(s)
   202  		su.SetRelocType(rIdx, objabi.R_ARM64_LDST64)
   203  
   204  		return true
   205  
   206  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
   207  		if targType == sym.SDYNIMPORT {
   208  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   209  		}
   210  		su := ldr.MakeSymbolUpdater(s)
   211  		su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
   212  		return true
   213  
   214  	// Handle relocations found in Mach-O object files.
   215  	case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_UNSIGNED*2:
   216  		if targType == sym.SDYNIMPORT {
   217  			ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
   218  		}
   219  		su := ldr.MakeSymbolUpdater(s)
   220  		su.SetRelocType(rIdx, objabi.R_ADDR)
   221  		if target.IsPIE() && target.IsInternal() {
   222  			// For internal linking PIE, this R_ADDR relocation cannot
   223  			// be resolved statically. We need to generate a dynamic
   224  			// relocation. Let the code below handle it.
   225  			break
   226  		}
   227  		return true
   228  
   229  	case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
   230  		su := ldr.MakeSymbolUpdater(s)
   231  		su.SetRelocType(rIdx, objabi.R_CALLARM64)
   232  		if targType == sym.SDYNIMPORT {
   233  			addpltsym(target, ldr, syms, targ)
   234  			su.SetRelocSym(rIdx, syms.PLT)
   235  			su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
   236  		}
   237  		return true
   238  
   239  	case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGE21*2 + pcrel,
   240  		objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGEOFF12*2:
   241  		if targType == sym.SDYNIMPORT {
   242  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   243  		}
   244  		su := ldr.MakeSymbolUpdater(s)
   245  		su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
   246  		return true
   247  
   248  	case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21*2 + pcrel,
   249  		objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12*2:
   250  		if targType != sym.SDYNIMPORT {
   251  			// have symbol
   252  			// turn MOVD sym@GOT (adrp+ldr) into MOVD $sym (adrp+add)
   253  			data := ldr.Data(s)
   254  			off := r.Off()
   255  			if int(off+3) >= len(data) {
   256  				ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
   257  				return false
   258  			}
   259  			o := target.Arch.ByteOrder.Uint32(data[off:])
   260  			su := ldr.MakeSymbolUpdater(s)
   261  			switch {
   262  			case (o>>24)&0x9f == 0x90: // adrp
   263  				// keep instruction unchanged, change relocation type below
   264  			case o>>24 == 0xf9: // ldr
   265  				// rewrite to add
   266  				o = (0x91 << 24) | (o & (1<<22 - 1))
   267  				su.MakeWritable()
   268  				su.SetUint32(target.Arch, int64(off), o)
   269  			default:
   270  				ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
   271  				return false
   272  			}
   273  			su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
   274  			return true
   275  		}
   276  		ld.AddGotSym(target, ldr, syms, targ, 0)
   277  		su := ldr.MakeSymbolUpdater(s)
   278  		su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
   279  		su.SetRelocSym(rIdx, syms.GOT)
   280  		su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
   281  		return true
   282  	}
   283  
   284  	// Reread the reloc to incorporate any changes in type above.
   285  	relocs := ldr.Relocs(s)
   286  	r = relocs.At(rIdx)
   287  
   288  	switch r.Type() {
   289  	case objabi.R_CALL,
   290  		objabi.R_PCREL,
   291  		objabi.R_CALLARM64:
   292  		if targType != sym.SDYNIMPORT {
   293  			// nothing to do, the relocation will be laid out in reloc
   294  			return true
   295  		}
   296  		if target.IsExternal() {
   297  			// External linker will do this relocation.
   298  			return true
   299  		}
   300  		// Internal linking.
   301  		if r.Add() != 0 {
   302  			ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add())
   303  		}
   304  		// Build a PLT entry and change the relocation target to that entry.
   305  		addpltsym(target, ldr, syms, targ)
   306  		su := ldr.MakeSymbolUpdater(s)
   307  		su.SetRelocSym(rIdx, syms.PLT)
   308  		su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
   309  		return true
   310  
   311  	case objabi.R_ADDR:
   312  		if ldr.SymType(s) == sym.STEXT && target.IsElf() {
   313  			// The code is asking for the address of an external
   314  			// function. We provide it with the address of the
   315  			// correspondent GOT symbol.
   316  			ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
   317  			su := ldr.MakeSymbolUpdater(s)
   318  			su.SetRelocSym(rIdx, syms.GOT)
   319  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
   320  			return true
   321  		}
   322  
   323  		// Process dynamic relocations for the data sections.
   324  		if target.IsPIE() && target.IsInternal() {
   325  			// When internally linking, generate dynamic relocations
   326  			// for all typical R_ADDR relocations. The exception
   327  			// are those R_ADDR that are created as part of generating
   328  			// the dynamic relocations and must be resolved statically.
   329  			//
   330  			// There are three phases relevant to understanding this:
   331  			//
   332  			//	dodata()  // we are here
   333  			//	address() // symbol address assignment
   334  			//	reloc()   // resolution of static R_ADDR relocs
   335  			//
   336  			// At this point symbol addresses have not been
   337  			// assigned yet (as the final size of the .rela section
   338  			// will affect the addresses), and so we cannot write
   339  			// the Elf64_Rela.r_offset now. Instead we delay it
   340  			// until after the 'address' phase of the linker is
   341  			// complete. We do this via Addaddrplus, which creates
   342  			// a new R_ADDR relocation which will be resolved in
   343  			// the 'reloc' phase.
   344  			//
   345  			// These synthetic static R_ADDR relocs must be skipped
   346  			// now, or else we will be caught in an infinite loop
   347  			// of generating synthetic relocs for our synthetic
   348  			// relocs.
   349  			//
   350  			// Furthermore, the rela sections contain dynamic
   351  			// relocations with R_ADDR relocations on
   352  			// Elf64_Rela.r_offset. This field should contain the
   353  			// symbol offset as determined by reloc(), not the
   354  			// final dynamically linked address as a dynamic
   355  			// relocation would provide.
   356  			switch ldr.SymName(s) {
   357  			case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
   358  				return false
   359  			}
   360  		} else {
   361  			// Either internally linking a static executable,
   362  			// in which case we can resolve these relocations
   363  			// statically in the 'reloc' phase, or externally
   364  			// linking, in which case the relocation will be
   365  			// prepared in the 'reloc' phase and passed to the
   366  			// external linker in the 'asmb' phase.
   367  			if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
   368  				break
   369  			}
   370  		}
   371  
   372  		if target.IsElf() {
   373  			// Generate R_AARCH64_RELATIVE relocations for best
   374  			// efficiency in the dynamic linker.
   375  			//
   376  			// As noted above, symbol addresses have not been
   377  			// assigned yet, so we can't generate the final reloc
   378  			// entry yet. We ultimately want:
   379  			//
   380  			// r_offset = s + r.Off
   381  			// r_info = R_AARCH64_RELATIVE
   382  			// r_addend = targ + r.Add
   383  			//
   384  			// The dynamic linker will set *offset = base address +
   385  			// addend.
   386  			//
   387  			// AddAddrPlus is used for r_offset and r_addend to
   388  			// generate new R_ADDR relocations that will update
   389  			// these fields in the 'reloc' phase.
   390  			rela := ldr.MakeSymbolUpdater(syms.Rela)
   391  			rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
   392  			if r.Siz() == 8 {
   393  				rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
   394  			} else {
   395  				ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   396  			}
   397  			rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
   398  			// Not mark r done here. So we still apply it statically,
   399  			// so in the file content we'll also have the right offset
   400  			// to the relocation target. So it can be examined statically
   401  			// (e.g. go version).
   402  			return true
   403  		}
   404  
   405  		if target.IsDarwin() {
   406  			// Mach-O relocations are a royal pain to lay out.
   407  			// They use a compact stateful bytecode representation.
   408  			// Here we record what are needed and encode them later.
   409  			ld.MachoAddRebase(s, int64(r.Off()))
   410  			// Not mark r done here. So we still apply it statically,
   411  			// so in the file content we'll also have the right offset
   412  			// to the relocation target. So it can be examined statically
   413  			// (e.g. go version).
   414  			return true
   415  		}
   416  	}
   417  	return false
   418  }
   419  
   420  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
   421  	out.Write64(uint64(sectoff))
   422  
   423  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
   424  	siz := r.Size
   425  	switch r.Type {
   426  	default:
   427  		return false
   428  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
   429  		switch siz {
   430  		case 4:
   431  			out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)
   432  		case 8:
   433  			out.Write64(uint64(elf.R_AARCH64_ABS64) | uint64(elfsym)<<32)
   434  		default:
   435  			return false
   436  		}
   437  	case objabi.R_ADDRARM64:
   438  		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
   439  		out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
   440  		out.Write64(uint64(r.Xadd))
   441  		out.Write64(uint64(sectoff + 4))
   442  		out.Write64(uint64(elf.R_AARCH64_ADD_ABS_LO12_NC) | uint64(elfsym)<<32)
   443  	case objabi.R_ARM64_TLS_LE:
   444  		out.Write64(uint64(elf.R_AARCH64_TLSLE_MOVW_TPREL_G0) | uint64(elfsym)<<32)
   445  	case objabi.R_ARM64_TLS_IE:
   446  		out.Write64(uint64(elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) | uint64(elfsym)<<32)
   447  		out.Write64(uint64(r.Xadd))
   448  		out.Write64(uint64(sectoff + 4))
   449  		out.Write64(uint64(elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) | uint64(elfsym)<<32)
   450  	case objabi.R_ARM64_GOTPCREL:
   451  		out.Write64(uint64(elf.R_AARCH64_ADR_GOT_PAGE) | uint64(elfsym)<<32)
   452  		out.Write64(uint64(r.Xadd))
   453  		out.Write64(uint64(sectoff + 4))
   454  		out.Write64(uint64(elf.R_AARCH64_LD64_GOT_LO12_NC) | uint64(elfsym)<<32)
   455  	case objabi.R_CALLARM64:
   456  		if siz != 4 {
   457  			return false
   458  		}
   459  		out.Write64(uint64(elf.R_AARCH64_CALL26) | uint64(elfsym)<<32)
   460  
   461  	}
   462  	out.Write64(uint64(r.Xadd))
   463  
   464  	return true
   465  }
   466  
   467  // sign-extends from 24-bit.
   468  func signext24(x int64) int64 { return x << 40 >> 40 }
   469  
   470  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
   471  	var v uint32
   472  
   473  	rs := r.Xsym
   474  	rt := r.Type
   475  	siz := r.Size
   476  	xadd := r.Xadd
   477  
   478  	if xadd != signext24(xadd) {
   479  		// If the relocation target would overflow the addend, then target
   480  		// a linker-manufactured label symbol with a smaller addend instead.
   481  		label := ldr.Lookup(machoLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
   482  		if label != 0 {
   483  			xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
   484  			rs = label
   485  		}
   486  		if xadd != signext24(xadd) {
   487  			ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
   488  		}
   489  	}
   490  
   491  	if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL {
   492  		if ldr.SymDynid(rs) < 0 {
   493  			ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
   494  			return false
   495  		}
   496  
   497  		v = uint32(ldr.SymDynid(rs))
   498  		v |= 1 << 27 // external relocation
   499  	} else {
   500  		v = uint32(ldr.SymSect(rs).Extnum)
   501  		if v == 0 {
   502  			ldr.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymSect(rs).Name, ldr.SymType(rs), ldr.SymType(rs))
   503  			return false
   504  		}
   505  	}
   506  
   507  	switch rt {
   508  	default:
   509  		return false
   510  	case objabi.R_ADDR:
   511  		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
   512  	case objabi.R_CALLARM64:
   513  		if xadd != 0 {
   514  			ldr.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", ldr.SymName(rs), xadd)
   515  		}
   516  
   517  		v |= 1 << 24 // pc-relative bit
   518  		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
   519  	case objabi.R_ADDRARM64:
   520  		siz = 4
   521  		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
   522  		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
   523  		if r.Xadd != 0 {
   524  			out.Write32(uint32(sectoff + 4))
   525  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   526  		}
   527  		out.Write32(uint32(sectoff + 4))
   528  		out.Write32(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
   529  		if r.Xadd != 0 {
   530  			out.Write32(uint32(sectoff))
   531  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   532  		}
   533  		v |= 1 << 24 // pc-relative bit
   534  		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
   535  	case objabi.R_ARM64_GOTPCREL:
   536  		siz = 4
   537  		// Two relocation entries: MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21
   538  		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
   539  		if r.Xadd != 0 {
   540  			out.Write32(uint32(sectoff + 4))
   541  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   542  		}
   543  		out.Write32(uint32(sectoff + 4))
   544  		out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
   545  		if r.Xadd != 0 {
   546  			out.Write32(uint32(sectoff))
   547  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   548  		}
   549  		v |= 1 << 24 // pc-relative bit
   550  		v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
   551  	}
   552  
   553  	switch siz {
   554  	default:
   555  		return false
   556  	case 1:
   557  		v |= 0 << 25
   558  	case 2:
   559  		v |= 1 << 25
   560  	case 4:
   561  		v |= 2 << 25
   562  	case 8:
   563  		v |= 3 << 25
   564  	}
   565  
   566  	out.Write32(uint32(sectoff))
   567  	out.Write32(v)
   568  	return true
   569  }
   570  
   571  func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (int64, int, bool) {
   572  	const noExtReloc = 0
   573  	const isOk = true
   574  
   575  	rs := ldr.ResolveABIAlias(r.Sym())
   576  
   577  	if target.IsExternal() {
   578  		nExtReloc := 0
   579  		switch rt := r.Type(); rt {
   580  		default:
   581  		case objabi.R_ARM64_GOTPCREL,
   582  			objabi.R_ADDRARM64:
   583  
   584  			// set up addend for eventual relocation via outer symbol.
   585  			rs, off := ld.FoldSubSymbolOffset(ldr, rs)
   586  			xadd := r.Add() + off
   587  			rst := ldr.SymType(rs)
   588  			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
   589  				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
   590  			}
   591  
   592  			nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
   593  			if target.IsDarwin() && xadd != 0 {
   594  				nExtReloc = 4 // need another two relocations for non-zero addend
   595  			}
   596  
   597  			// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
   598  			// will make the linking fail because it thinks the code is not PIC even though
   599  			// the BR26 relocation should be fully resolved at link time.
   600  			// That is the reason why the next if block is disabled. When the bug in ld64
   601  			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
   602  			if false && target.IsDarwin() {
   603  				var o0, o1 uint32
   604  
   605  				if target.IsBigEndian() {
   606  					o0 = uint32(val >> 32)
   607  					o1 = uint32(val)
   608  				} else {
   609  					o0 = uint32(val)
   610  					o1 = uint32(val >> 32)
   611  				}
   612  				// Mach-O wants the addend to be encoded in the instruction
   613  				// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
   614  				// can only encode 24-bit of signed addend, but the instructions
   615  				// supports 33-bit of signed addend, so we always encode the
   616  				// addend in place.
   617  				o0 |= (uint32((xadd>>12)&3) << 29) | (uint32((xadd>>12>>2)&0x7ffff) << 5)
   618  				o1 |= uint32(xadd&0xfff) << 10
   619  
   620  				// when laid out, the instruction order must always be o1, o2.
   621  				if target.IsBigEndian() {
   622  					val = int64(o0)<<32 | int64(o1)
   623  				} else {
   624  					val = int64(o1)<<32 | int64(o0)
   625  				}
   626  			}
   627  
   628  			return val, nExtReloc, isOk
   629  		case objabi.R_CALLARM64,
   630  			objabi.R_ARM64_TLS_LE,
   631  			objabi.R_ARM64_TLS_IE:
   632  			nExtReloc = 1
   633  			if rt == objabi.R_ARM64_TLS_IE {
   634  				nExtReloc = 2 // need two ELF relocations. see elfreloc1
   635  			}
   636  			return val, nExtReloc, isOk
   637  		}
   638  	}
   639  
   640  	switch r.Type() {
   641  	case objabi.R_ADDRARM64:
   642  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   643  		if t >= 1<<32 || t < -1<<32 {
   644  			ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   645  		}
   646  
   647  		var o0, o1 uint32
   648  
   649  		if target.IsBigEndian() {
   650  			o0 = uint32(val >> 32)
   651  			o1 = uint32(val)
   652  		} else {
   653  			o0 = uint32(val)
   654  			o1 = uint32(val >> 32)
   655  		}
   656  
   657  		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   658  		o1 |= uint32(t&0xfff) << 10
   659  
   660  		// when laid out, the instruction order must always be o1, o2.
   661  		if target.IsBigEndian() {
   662  			return int64(o0)<<32 | int64(o1), noExtReloc, true
   663  		}
   664  		return int64(o1)<<32 | int64(o0), noExtReloc, true
   665  
   666  	case objabi.R_ARM64_TLS_LE:
   667  		if target.IsDarwin() {
   668  			ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
   669  		}
   670  		// The TCB is two pointers. This is not documented anywhere, but is
   671  		// de facto part of the ABI.
   672  		v := ldr.SymValue(rs) + int64(2*target.Arch.PtrSize)
   673  		if v < 0 || v >= 32678 {
   674  			ldr.Errorf(s, "TLS offset out of range %d", v)
   675  		}
   676  		return val | (v << 5), noExtReloc, true
   677  
   678  	case objabi.R_ARM64_TLS_IE:
   679  		if target.IsPIE() && target.IsElf() {
   680  			// We are linking the final executable, so we
   681  			// can optimize any TLS IE relocation to LE.
   682  
   683  			if !target.IsLinux() {
   684  				ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
   685  			}
   686  
   687  			// The TCB is two pointers. This is not documented anywhere, but is
   688  			// de facto part of the ABI.
   689  			v := ldr.SymAddr(rs) + int64(2*target.Arch.PtrSize) + r.Add()
   690  			if v < 0 || v >= 32678 {
   691  				ldr.Errorf(s, "TLS offset out of range %d", v)
   692  			}
   693  
   694  			var o0, o1 uint32
   695  			if target.IsBigEndian() {
   696  				o0 = uint32(val >> 32)
   697  				o1 = uint32(val)
   698  			} else {
   699  				o0 = uint32(val)
   700  				o1 = uint32(val >> 32)
   701  			}
   702  
   703  			// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21
   704  			// turn ADRP to MOVZ
   705  			o0 = 0xd2a00000 | uint32(o0&0x1f) | (uint32((v>>16)&0xffff) << 5)
   706  			// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC
   707  			// turn LD64 to MOVK
   708  			if v&3 != 0 {
   709  				ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", v)
   710  			}
   711  			o1 = 0xf2800000 | uint32(o1&0x1f) | (uint32(v&0xffff) << 5)
   712  
   713  			// when laid out, the instruction order must always be o0, o1.
   714  			if target.IsBigEndian() {
   715  				return int64(o0)<<32 | int64(o1), noExtReloc, isOk
   716  			}
   717  			return int64(o1)<<32 | int64(o0), noExtReloc, isOk
   718  		} else {
   719  			log.Fatalf("cannot handle R_ARM64_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
   720  		}
   721  
   722  	case objabi.R_CALLARM64:
   723  		var t int64
   724  		if ldr.SymType(rs) == sym.SDYNIMPORT {
   725  			t = (ldr.SymAddr(syms.PLT) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
   726  		} else {
   727  			t = (ldr.SymAddr(rs) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
   728  		}
   729  		if t >= 1<<27 || t < -1<<27 {
   730  			ldr.Errorf(s, "program too large, call relocation distance = %d", t)
   731  		}
   732  		return val | ((t >> 2) & 0x03ffffff), noExtReloc, true
   733  
   734  	case objabi.R_ARM64_GOT:
   735  		if (val>>24)&0x9f == 0x90 {
   736  			// R_AARCH64_ADR_GOT_PAGE
   737  			// patch instruction: adrp
   738  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   739  			if t >= 1<<32 || t < -1<<32 {
   740  				ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   741  			}
   742  			var o0 uint32
   743  			o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   744  			return val | int64(o0), noExtReloc, isOk
   745  		} else if val>>24 == 0xf9 {
   746  			// R_AARCH64_LD64_GOT_LO12_NC
   747  			// patch instruction: ldr
   748  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   749  			if t&7 != 0 {
   750  				ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LD64_GOT_LO12_NC", t)
   751  			}
   752  			var o1 uint32
   753  			o1 |= uint32(t&0xfff) << (10 - 3)
   754  			return val | int64(uint64(o1)), noExtReloc, isOk
   755  		} else {
   756  			ldr.Errorf(s, "unsupported instruction for %x R_GOTARM64", val)
   757  		}
   758  
   759  	case objabi.R_ARM64_PCREL:
   760  		if (val>>24)&0x9f == 0x90 {
   761  			// R_AARCH64_ADR_PREL_PG_HI21
   762  			// patch instruction: adrp
   763  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   764  			if t >= 1<<32 || t < -1<<32 {
   765  				ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   766  			}
   767  			o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   768  			return val | int64(o0), noExtReloc, isOk
   769  		} else if (val>>24)&0x9f == 0x91 {
   770  			// ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
   771  			// patch instruction: add
   772  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   773  			o1 := uint32(t&0xfff) << 10
   774  			return val | int64(o1), noExtReloc, isOk
   775  		} else if (val>>24)&0x3b == 0x39 {
   776  			// Mach-O ARM64_RELOC_PAGEOFF12
   777  			// patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
   778  			// Mach-O uses same relocation type for them.
   779  			shift := uint32(val) >> 30
   780  			if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
   781  				shift = 4
   782  			}
   783  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   784  			if t&(1<<shift-1) != 0 {
   785  				ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
   786  			}
   787  			o1 := (uint32(t&0xfff) >> shift) << 10
   788  			return val | int64(o1), noExtReloc, isOk
   789  		} else {
   790  			ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
   791  		}
   792  
   793  	case objabi.R_ARM64_LDST8:
   794  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   795  		o0 := uint32(t&0xfff) << 10
   796  		return val | int64(o0), noExtReloc, true
   797  
   798  	case objabi.R_ARM64_LDST16:
   799  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   800  		if t&1 != 0 {
   801  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST16_ABS_LO12_NC", t)
   802  		}
   803  		o0 := (uint32(t&0xfff) >> 1) << 10
   804  		return val | int64(o0), noExtReloc, true
   805  
   806  	case objabi.R_ARM64_LDST32:
   807  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   808  		if t&3 != 0 {
   809  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST32_ABS_LO12_NC", t)
   810  		}
   811  		o0 := (uint32(t&0xfff) >> 2) << 10
   812  		return val | int64(o0), noExtReloc, true
   813  
   814  	case objabi.R_ARM64_LDST64:
   815  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   816  		if t&7 != 0 {
   817  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST64_ABS_LO12_NC", t)
   818  		}
   819  		o0 := (uint32(t&0xfff) >> 3) << 10
   820  		return val | int64(o0), noExtReloc, true
   821  
   822  	case objabi.R_ARM64_LDST128:
   823  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   824  		if t&15 != 0 {
   825  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST128_ABS_LO12_NC", t)
   826  		}
   827  		o0 := (uint32(t&0xfff) >> 4) << 10
   828  		return val | int64(o0), noExtReloc, true
   829  	}
   830  
   831  	return val, 0, false
   832  }
   833  
   834  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64) int64 {
   835  	log.Fatalf("unexpected relocation variant")
   836  	return -1
   837  }
   838  
   839  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   840  	switch rt := r.Type(); rt {
   841  	case objabi.R_ARM64_GOTPCREL,
   842  		objabi.R_ADDRARM64:
   843  		rr := ld.ExtrelocViaOuterSym(ldr, r, s)
   844  
   845  		// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
   846  		// will make the linking fail because it thinks the code is not PIC even though
   847  		// the BR26 relocation should be fully resolved at link time.
   848  		// That is the reason why the next if block is disabled. When the bug in ld64
   849  		// is fixed, we can enable this block and also enable duff's device in cmd/7g.
   850  		if false && target.IsDarwin() {
   851  			// Mach-O wants the addend to be encoded in the instruction
   852  			// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
   853  			// can only encode 24-bit of signed addend, but the instructions
   854  			// supports 33-bit of signed addend, so we always encode the
   855  			// addend in place.
   856  			rr.Xadd = 0
   857  		}
   858  		return rr, true
   859  	case objabi.R_CALLARM64,
   860  		objabi.R_ARM64_TLS_LE,
   861  		objabi.R_ARM64_TLS_IE:
   862  		return ld.ExtrelocSimple(ldr, r), true
   863  	}
   864  	return loader.ExtReloc{}, false
   865  }
   866  
   867  func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   868  	if plt.Size() == 0 {
   869  		// stp     x16, x30, [sp, #-16]!
   870  		// identifying information
   871  		plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
   872  
   873  		// the following two instructions (adrp + ldr) load *got[2] into x17
   874  		// adrp    x16, &got[0]
   875  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
   876  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
   877  
   878  		// <imm> is the offset value of &got[2] to &got[0], the same below
   879  		// ldr     x17, [x16, <imm>]
   880  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
   881  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
   882  
   883  		// add     x16, x16, <imm>
   884  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
   885  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
   886  
   887  		// br      x17
   888  		plt.AddUint32(ctxt.Arch, 0xd61f0220)
   889  
   890  		// 3 nop for place holder
   891  		plt.AddUint32(ctxt.Arch, 0xd503201f)
   892  		plt.AddUint32(ctxt.Arch, 0xd503201f)
   893  		plt.AddUint32(ctxt.Arch, 0xd503201f)
   894  
   895  		// check gotplt.size == 0
   896  		if gotplt.Size() != 0 {
   897  			ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
   898  		}
   899  		gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
   900  
   901  		gotplt.AddUint64(ctxt.Arch, 0)
   902  		gotplt.AddUint64(ctxt.Arch, 0)
   903  	}
   904  }
   905  
   906  func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
   907  	if ldr.SymPlt(s) >= 0 {
   908  		return
   909  	}
   910  
   911  	ld.Adddynsym(ldr, target, syms, s)
   912  
   913  	if target.IsElf() {
   914  		plt := ldr.MakeSymbolUpdater(syms.PLT)
   915  		gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
   916  		rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
   917  		if plt.Size() == 0 {
   918  			panic("plt is not set up")
   919  		}
   920  
   921  		// adrp    x16, &got.plt[0]
   922  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
   923  		plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
   924  		relocs := plt.Relocs()
   925  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
   926  
   927  		// <offset> is the offset value of &got.plt[n] to &got.plt[0]
   928  		// ldr     x17, [x16, <offset>]
   929  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
   930  		plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
   931  		relocs = plt.Relocs()
   932  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
   933  
   934  		// add     x16, x16, <offset>
   935  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
   936  		plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
   937  		relocs = plt.Relocs()
   938  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
   939  
   940  		// br      x17
   941  		plt.AddUint32(target.Arch, 0xd61f0220)
   942  
   943  		// add to got.plt: pointer to plt[0]
   944  		gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
   945  
   946  		// rela
   947  		rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
   948  		sDynid := ldr.SymDynid(s)
   949  
   950  		rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
   951  		rela.AddUint64(target.Arch, 0)
   952  
   953  		ldr.SetPlt(s, int32(plt.Size()-16))
   954  	} else if target.IsDarwin() {
   955  		ld.AddGotSym(target, ldr, syms, s, 0)
   956  
   957  		sDynid := ldr.SymDynid(s)
   958  		lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
   959  		lep.AddUint32(target.Arch, uint32(sDynid))
   960  
   961  		plt := ldr.MakeSymbolUpdater(syms.PLT)
   962  		ldr.SetPlt(s, int32(plt.Size()))
   963  
   964  		// adrp x16, GOT
   965  		plt.AddUint32(target.Arch, 0x90000010)
   966  		r, _ := plt.AddRel(objabi.R_ARM64_GOT)
   967  		r.SetOff(int32(plt.Size() - 4))
   968  		r.SetSiz(4)
   969  		r.SetSym(syms.GOT)
   970  		r.SetAdd(int64(ldr.SymGot(s)))
   971  
   972  		// ldr x17, [x16, <offset>]
   973  		plt.AddUint32(target.Arch, 0xf9400211)
   974  		r, _ = plt.AddRel(objabi.R_ARM64_GOT)
   975  		r.SetOff(int32(plt.Size() - 4))
   976  		r.SetSiz(4)
   977  		r.SetSym(syms.GOT)
   978  		r.SetAdd(int64(ldr.SymGot(s)))
   979  
   980  		// br x17
   981  		plt.AddUint32(target.Arch, 0xd61f0220)
   982  	} else {
   983  		ldr.Errorf(s, "addpltsym: unsupported binary format")
   984  	}
   985  }
   986  
   987  const machoRelocLimit = 1 << 23
   988  
   989  func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
   990  	// When external linking on darwin, Mach-O relocation has only signed 24-bit
   991  	// addend. For large symbols, we generate "label" symbols in the middle, so
   992  	// that relocations can target them with smaller addends.
   993  	if !ctxt.IsDarwin() || !ctxt.IsExternal() {
   994  		return
   995  	}
   996  
   997  	big := false
   998  	for _, seg := range ld.Segments {
   999  		if seg.Length >= machoRelocLimit {
  1000  			big = true
  1001  			break
  1002  		}
  1003  	}
  1004  	if !big {
  1005  		return // skip work if nothing big
  1006  	}
  1007  
  1008  	// addLabelSyms adds "label" symbols at s+machoRelocLimit, s+2*machoRelocLimit, etc.
  1009  	addLabelSyms := func(s loader.Sym, sz int64) {
  1010  		v := ldr.SymValue(s)
  1011  		for off := int64(machoRelocLimit); off < sz; off += machoRelocLimit {
  1012  			p := ldr.LookupOrCreateSym(machoLabelName(ldr, s, off), ldr.SymVersion(s))
  1013  			ldr.SetAttrReachable(p, true)
  1014  			ldr.SetSymValue(p, v+off)
  1015  			ldr.SetSymSect(p, ldr.SymSect(s))
  1016  			ld.AddMachoSym(ldr, p)
  1017  			//fmt.Printf("gensymlate %s %x\n", ldr.SymName(p), ldr.SymValue(p))
  1018  		}
  1019  	}
  1020  
  1021  	for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
  1022  		if !ldr.AttrReachable(s) {
  1023  			continue
  1024  		}
  1025  		if ldr.SymType(s) == sym.STEXT {
  1026  			continue // we don't target the middle of a function
  1027  		}
  1028  		sz := ldr.SymSize(s)
  1029  		if sz <= machoRelocLimit {
  1030  			continue
  1031  		}
  1032  		addLabelSyms(s, sz)
  1033  	}
  1034  
  1035  	// Also for carrier symbols (for which SymSize is 0)
  1036  	for _, ss := range ld.CarrierSymByType {
  1037  		if ss.Sym != 0 && ss.Size > machoRelocLimit {
  1038  			addLabelSyms(ss.Sym, ss.Size)
  1039  		}
  1040  	}
  1041  }
  1042  
  1043  // machoLabelName returns the name of the "label" symbol used for a
  1044  // relocation targeting s+off. The label symbols is used on darwin
  1045  // when external linking, so that the addend fits in a Mach-O relocation.
  1046  func machoLabelName(ldr *loader.Loader, s loader.Sym, off int64) string {
  1047  	return fmt.Sprintf("%s.%d", ldr.SymExtname(s), off/machoRelocLimit)
  1048  }
  1049  

View as plain text