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  	case objabi.R_ARM64_GOTPCREL:
   418  		if target.IsExternal() {
   419  			// External linker will do this relocation.
   420  			return true
   421  		}
   422  		if targType != sym.SDYNIMPORT {
   423  			ldr.Errorf(s, "R_ARM64_GOTPCREL target is not SDYNIMPORT symbol: %v", ldr.SymName(targ))
   424  		}
   425  		if r.Add() != 0 {
   426  			ldr.Errorf(s, "R_ARM64_GOTPCREL with non-zero addend (%v)", r.Add())
   427  		}
   428  		if target.IsElf() {
   429  			ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_AARCH64_GLOB_DAT))
   430  		} else {
   431  			ld.AddGotSym(target, ldr, syms, targ, 0)
   432  		}
   433  		// turn into two relocations, one for each instruction.
   434  		su := ldr.MakeSymbolUpdater(s)
   435  		r.SetType(objabi.R_ARM64_GOT)
   436  		r.SetSiz(4)
   437  		r.SetSym(syms.GOT)
   438  		r.SetAdd(int64(ldr.SymGot(targ)))
   439  		r2, _ := su.AddRel(objabi.R_ARM64_GOT)
   440  		r2.SetSiz(4)
   441  		r2.SetOff(r.Off() + 4)
   442  		r2.SetSym(syms.GOT)
   443  		r2.SetAdd(int64(ldr.SymGot(targ)))
   444  		return true
   445  	}
   446  	return false
   447  }
   448  
   449  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
   450  	out.Write64(uint64(sectoff))
   451  
   452  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
   453  	siz := r.Size
   454  	switch r.Type {
   455  	default:
   456  		return false
   457  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
   458  		switch siz {
   459  		case 4:
   460  			out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)
   461  		case 8:
   462  			out.Write64(uint64(elf.R_AARCH64_ABS64) | uint64(elfsym)<<32)
   463  		default:
   464  			return false
   465  		}
   466  	case objabi.R_ADDRARM64:
   467  		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
   468  		out.Write64(uint64(elf.R_AARCH64_ADR_PREL_PG_HI21) | uint64(elfsym)<<32)
   469  		out.Write64(uint64(r.Xadd))
   470  		out.Write64(uint64(sectoff + 4))
   471  		out.Write64(uint64(elf.R_AARCH64_ADD_ABS_LO12_NC) | uint64(elfsym)<<32)
   472  	case objabi.R_ARM64_TLS_LE:
   473  		out.Write64(uint64(elf.R_AARCH64_TLSLE_MOVW_TPREL_G0) | uint64(elfsym)<<32)
   474  	case objabi.R_ARM64_TLS_IE:
   475  		out.Write64(uint64(elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) | uint64(elfsym)<<32)
   476  		out.Write64(uint64(r.Xadd))
   477  		out.Write64(uint64(sectoff + 4))
   478  		out.Write64(uint64(elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) | uint64(elfsym)<<32)
   479  	case objabi.R_ARM64_GOTPCREL:
   480  		out.Write64(uint64(elf.R_AARCH64_ADR_GOT_PAGE) | uint64(elfsym)<<32)
   481  		out.Write64(uint64(r.Xadd))
   482  		out.Write64(uint64(sectoff + 4))
   483  		out.Write64(uint64(elf.R_AARCH64_LD64_GOT_LO12_NC) | uint64(elfsym)<<32)
   484  	case objabi.R_CALLARM64:
   485  		if siz != 4 {
   486  			return false
   487  		}
   488  		out.Write64(uint64(elf.R_AARCH64_CALL26) | uint64(elfsym)<<32)
   489  
   490  	}
   491  	out.Write64(uint64(r.Xadd))
   492  
   493  	return true
   494  }
   495  
   496  // sign-extends from 21, 24-bit.
   497  func signext21(x int64) int64 { return x << (64 - 21) >> (64 - 21) }
   498  func signext24(x int64) int64 { return x << (64 - 24) >> (64 - 24) }
   499  
   500  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
   501  	var v uint32
   502  
   503  	rs := r.Xsym
   504  	rt := r.Type
   505  	siz := r.Size
   506  	xadd := r.Xadd
   507  
   508  	if xadd != signext24(xadd) {
   509  		// If the relocation target would overflow the addend, then target
   510  		// a linker-manufactured label symbol with a smaller addend instead.
   511  		label := ldr.Lookup(offsetLabelName(ldr, rs, xadd/machoRelocLimit*machoRelocLimit), ldr.SymVersion(rs))
   512  		if label != 0 {
   513  			xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label)
   514  			rs = label
   515  		}
   516  		if xadd != signext24(xadd) {
   517  			ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
   518  		}
   519  	}
   520  
   521  	if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL {
   522  		if ldr.SymDynid(rs) < 0 {
   523  			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))
   524  			return false
   525  		}
   526  
   527  		v = uint32(ldr.SymDynid(rs))
   528  		v |= 1 << 27 // external relocation
   529  	} else {
   530  		v = uint32(ldr.SymSect(rs).Extnum)
   531  		if v == 0 {
   532  			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))
   533  			return false
   534  		}
   535  	}
   536  
   537  	switch rt {
   538  	default:
   539  		return false
   540  	case objabi.R_ADDR:
   541  		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
   542  	case objabi.R_CALLARM64:
   543  		if xadd != 0 {
   544  			ldr.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", ldr.SymName(rs), xadd)
   545  		}
   546  
   547  		v |= 1 << 24 // pc-relative bit
   548  		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
   549  	case objabi.R_ADDRARM64:
   550  		siz = 4
   551  		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
   552  		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
   553  		if r.Xadd != 0 {
   554  			out.Write32(uint32(sectoff + 4))
   555  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   556  		}
   557  		out.Write32(uint32(sectoff + 4))
   558  		out.Write32(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
   559  		if r.Xadd != 0 {
   560  			out.Write32(uint32(sectoff))
   561  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   562  		}
   563  		v |= 1 << 24 // pc-relative bit
   564  		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
   565  	case objabi.R_ARM64_GOTPCREL:
   566  		siz = 4
   567  		// Two relocation entries: MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21
   568  		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
   569  		if r.Xadd != 0 {
   570  			out.Write32(uint32(sectoff + 4))
   571  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   572  		}
   573  		out.Write32(uint32(sectoff + 4))
   574  		out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
   575  		if r.Xadd != 0 {
   576  			out.Write32(uint32(sectoff))
   577  			out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
   578  		}
   579  		v |= 1 << 24 // pc-relative bit
   580  		v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
   581  	}
   582  
   583  	switch siz {
   584  	default:
   585  		return false
   586  	case 1:
   587  		v |= 0 << 25
   588  	case 2:
   589  		v |= 1 << 25
   590  	case 4:
   591  		v |= 2 << 25
   592  	case 8:
   593  		v |= 3 << 25
   594  	}
   595  
   596  	out.Write32(uint32(sectoff))
   597  	out.Write32(v)
   598  	return true
   599  }
   600  
   601  func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
   602  	rs := r.Xsym
   603  	rt := r.Type
   604  
   605  	if r.Xadd != signext21(r.Xadd) {
   606  		// If the relocation target would overflow the addend, then target
   607  		// a linker-manufactured label symbol with a smaller addend instead.
   608  		label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
   609  		if label == 0 {
   610  			ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
   611  			return false
   612  		}
   613  		rs = label
   614  	}
   615  	if rt == objabi.R_CALLARM64 && r.Xadd != 0 {
   616  		label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd), ldr.SymVersion(rs))
   617  		if label == 0 {
   618  			ldr.Errorf(s, "invalid relocation: %v %s+0x%x", rt, ldr.SymName(rs), r.Xadd)
   619  			return false
   620  		}
   621  		rs = label
   622  	}
   623  	symdynid := ldr.SymDynid(rs)
   624  	if symdynid < 0 {
   625  		ldr.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
   626  		return false
   627  	}
   628  
   629  	switch rt {
   630  	default:
   631  		return false
   632  
   633  	case objabi.R_DWARFSECREF:
   634  		out.Write32(uint32(sectoff))
   635  		out.Write32(uint32(symdynid))
   636  		out.Write16(ld.IMAGE_REL_ARM64_SECREL)
   637  
   638  	case objabi.R_ADDR:
   639  		out.Write32(uint32(sectoff))
   640  		out.Write32(uint32(symdynid))
   641  		if r.Size == 8 {
   642  			out.Write16(ld.IMAGE_REL_ARM64_ADDR64)
   643  		} else {
   644  			out.Write16(ld.IMAGE_REL_ARM64_ADDR32)
   645  		}
   646  
   647  	case objabi.R_ADDRARM64:
   648  		// Note: r.Xadd has been taken care of below, in archreloc.
   649  		out.Write32(uint32(sectoff))
   650  		out.Write32(uint32(symdynid))
   651  		out.Write16(ld.IMAGE_REL_ARM64_PAGEBASE_REL21)
   652  
   653  		out.Write32(uint32(sectoff + 4))
   654  		out.Write32(uint32(symdynid))
   655  		out.Write16(ld.IMAGE_REL_ARM64_PAGEOFFSET_12A)
   656  
   657  	case objabi.R_CALLARM64:
   658  		// Note: r.Xadd has been taken care of above, by using a label pointing into the middle of the function.
   659  		out.Write32(uint32(sectoff))
   660  		out.Write32(uint32(symdynid))
   661  		out.Write16(ld.IMAGE_REL_ARM64_BRANCH26)
   662  	}
   663  
   664  	return true
   665  }
   666  
   667  func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (int64, int, bool) {
   668  	const noExtReloc = 0
   669  	const isOk = true
   670  
   671  	rs := ldr.ResolveABIAlias(r.Sym())
   672  
   673  	if target.IsExternal() {
   674  		nExtReloc := 0
   675  		switch rt := r.Type(); rt {
   676  		default:
   677  		case objabi.R_ARM64_GOTPCREL,
   678  			objabi.R_ADDRARM64:
   679  
   680  			// set up addend for eventual relocation via outer symbol.
   681  			rs, off := ld.FoldSubSymbolOffset(ldr, rs)
   682  			xadd := r.Add() + off
   683  			rst := ldr.SymType(rs)
   684  			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
   685  				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
   686  			}
   687  
   688  			nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
   689  			if target.IsDarwin() && xadd != 0 {
   690  				nExtReloc = 4 // need another two relocations for non-zero addend
   691  			}
   692  
   693  			if target.IsWindows() {
   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  				// The first instruction (ADRP) has a 21-bit immediate field,
   704  				// and the second (ADD) has a 12-bit immediate field.
   705  				// The first instruction is only for high bits, but to get the carry bits right we have
   706  				// to put the full addend, including the bottom 12 bits again.
   707  				// That limits the distance of any addend to only 21 bits.
   708  				// But we assume that LDRP's top bit will be interpreted as a sign bit,
   709  				// so we only use 20 bits.
   710  				// pereloc takes care of introducing new symbol labels
   711  				// every megabyte for longer relocations.
   712  				xadd := uint32(xadd)
   713  				o0 |= (xadd&3)<<29 | (xadd&0xffffc)<<3
   714  				o1 |= (xadd & 0xfff) << 10
   715  
   716  				if target.IsBigEndian() {
   717  					val = int64(o0)<<32 | int64(o1)
   718  				} else {
   719  					val = int64(o1)<<32 | int64(o0)
   720  				}
   721  			}
   722  
   723  			return val, nExtReloc, isOk
   724  		case objabi.R_CALLARM64,
   725  			objabi.R_ARM64_TLS_LE,
   726  			objabi.R_ARM64_TLS_IE:
   727  			nExtReloc = 1
   728  			if rt == objabi.R_ARM64_TLS_IE {
   729  				nExtReloc = 2 // need two ELF relocations. see elfreloc1
   730  			}
   731  			return val, nExtReloc, isOk
   732  
   733  		case objabi.R_ADDR:
   734  			if target.IsWindows() && r.Add() != 0 {
   735  				if r.Siz() == 8 {
   736  					val = r.Add()
   737  				} else if target.IsBigEndian() {
   738  					val = int64(uint32(val)) | int64(r.Add())<<32
   739  				} else {
   740  					val = val>>32<<32 | int64(uint32(r.Add()))
   741  				}
   742  				return val, 1, true
   743  			}
   744  		}
   745  	}
   746  
   747  	switch r.Type() {
   748  	case objabi.R_ADDRARM64:
   749  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   750  		if t >= 1<<32 || t < -1<<32 {
   751  			ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   752  		}
   753  
   754  		var o0, o1 uint32
   755  
   756  		if target.IsBigEndian() {
   757  			o0 = uint32(val >> 32)
   758  			o1 = uint32(val)
   759  		} else {
   760  			o0 = uint32(val)
   761  			o1 = uint32(val >> 32)
   762  		}
   763  
   764  		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   765  		o1 |= uint32(t&0xfff) << 10
   766  
   767  		// when laid out, the instruction order must always be o1, o2.
   768  		if target.IsBigEndian() {
   769  			return int64(o0)<<32 | int64(o1), noExtReloc, true
   770  		}
   771  		return int64(o1)<<32 | int64(o0), noExtReloc, true
   772  
   773  	case objabi.R_ARM64_TLS_LE:
   774  		if target.IsDarwin() {
   775  			ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
   776  		}
   777  		// The TCB is two pointers. This is not documented anywhere, but is
   778  		// de facto part of the ABI.
   779  		v := ldr.SymValue(rs) + int64(2*target.Arch.PtrSize)
   780  		if v < 0 || v >= 32678 {
   781  			ldr.Errorf(s, "TLS offset out of range %d", v)
   782  		}
   783  		return val | (v << 5), noExtReloc, true
   784  
   785  	case objabi.R_ARM64_TLS_IE:
   786  		if target.IsPIE() && target.IsElf() {
   787  			// We are linking the final executable, so we
   788  			// can optimize any TLS IE relocation to LE.
   789  
   790  			if !target.IsLinux() {
   791  				ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
   792  			}
   793  
   794  			// The TCB is two pointers. This is not documented anywhere, but is
   795  			// de facto part of the ABI.
   796  			v := ldr.SymAddr(rs) + int64(2*target.Arch.PtrSize) + r.Add()
   797  			if v < 0 || v >= 32678 {
   798  				ldr.Errorf(s, "TLS offset out of range %d", v)
   799  			}
   800  
   801  			var o0, o1 uint32
   802  			if target.IsBigEndian() {
   803  				o0 = uint32(val >> 32)
   804  				o1 = uint32(val)
   805  			} else {
   806  				o0 = uint32(val)
   807  				o1 = uint32(val >> 32)
   808  			}
   809  
   810  			// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21
   811  			// turn ADRP to MOVZ
   812  			o0 = 0xd2a00000 | uint32(o0&0x1f) | (uint32((v>>16)&0xffff) << 5)
   813  			// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC
   814  			// turn LD64 to MOVK
   815  			if v&3 != 0 {
   816  				ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", v)
   817  			}
   818  			o1 = 0xf2800000 | uint32(o1&0x1f) | (uint32(v&0xffff) << 5)
   819  
   820  			// when laid out, the instruction order must always be o0, o1.
   821  			if target.IsBigEndian() {
   822  				return int64(o0)<<32 | int64(o1), noExtReloc, isOk
   823  			}
   824  			return int64(o1)<<32 | int64(o0), noExtReloc, isOk
   825  		} else {
   826  			log.Fatalf("cannot handle R_ARM64_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
   827  		}
   828  
   829  	case objabi.R_CALLARM64:
   830  		var t int64
   831  		if ldr.SymType(rs) == sym.SDYNIMPORT {
   832  			t = (ldr.SymAddr(syms.PLT) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
   833  		} else {
   834  			t = (ldr.SymAddr(rs) + r.Add()) - (ldr.SymValue(s) + int64(r.Off()))
   835  		}
   836  		if t >= 1<<27 || t < -1<<27 {
   837  			ldr.Errorf(s, "program too large, call relocation distance = %d", t)
   838  		}
   839  		return val | ((t >> 2) & 0x03ffffff), noExtReloc, true
   840  
   841  	case objabi.R_ARM64_GOT:
   842  		if (val>>24)&0x9f == 0x90 {
   843  			// R_AARCH64_ADR_GOT_PAGE
   844  			// patch instruction: adrp
   845  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   846  			if t >= 1<<32 || t < -1<<32 {
   847  				ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   848  			}
   849  			var o0 uint32
   850  			o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   851  			return val | int64(o0), noExtReloc, isOk
   852  		} else if val>>24 == 0xf9 {
   853  			// R_AARCH64_LD64_GOT_LO12_NC
   854  			// patch instruction: ldr
   855  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   856  			if t&7 != 0 {
   857  				ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LD64_GOT_LO12_NC", t)
   858  			}
   859  			var o1 uint32
   860  			o1 |= uint32(t&0xfff) << (10 - 3)
   861  			return val | int64(uint64(o1)), noExtReloc, isOk
   862  		} else {
   863  			ldr.Errorf(s, "unsupported instruction for %x R_GOTARM64", val)
   864  		}
   865  
   866  	case objabi.R_ARM64_PCREL:
   867  		if (val>>24)&0x9f == 0x90 {
   868  			// R_AARCH64_ADR_PREL_PG_HI21
   869  			// patch instruction: adrp
   870  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   871  			if t >= 1<<32 || t < -1<<32 {
   872  				ldr.Errorf(s, "program too large, address relocation distance = %d", t)
   873  			}
   874  			o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   875  			return val | int64(o0), noExtReloc, isOk
   876  		} else if (val>>24)&0x9f == 0x91 {
   877  			// ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
   878  			// patch instruction: add
   879  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   880  			o1 := uint32(t&0xfff) << 10
   881  			return val | int64(o1), noExtReloc, isOk
   882  		} else if (val>>24)&0x3b == 0x39 {
   883  			// Mach-O ARM64_RELOC_PAGEOFF12
   884  			// patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
   885  			// Mach-O uses same relocation type for them.
   886  			shift := uint32(val) >> 30
   887  			if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
   888  				shift = 4
   889  			}
   890  			t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   891  			if t&(1<<shift-1) != 0 {
   892  				ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
   893  			}
   894  			o1 := (uint32(t&0xfff) >> shift) << 10
   895  			return val | int64(o1), noExtReloc, isOk
   896  		} else {
   897  			ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
   898  		}
   899  
   900  	case objabi.R_ARM64_LDST8:
   901  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   902  		o0 := uint32(t&0xfff) << 10
   903  		return val | int64(o0), noExtReloc, true
   904  
   905  	case objabi.R_ARM64_LDST16:
   906  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   907  		if t&1 != 0 {
   908  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST16_ABS_LO12_NC", t)
   909  		}
   910  		o0 := (uint32(t&0xfff) >> 1) << 10
   911  		return val | int64(o0), noExtReloc, true
   912  
   913  	case objabi.R_ARM64_LDST32:
   914  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   915  		if t&3 != 0 {
   916  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST32_ABS_LO12_NC", t)
   917  		}
   918  		o0 := (uint32(t&0xfff) >> 2) << 10
   919  		return val | int64(o0), noExtReloc, true
   920  
   921  	case objabi.R_ARM64_LDST64:
   922  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   923  		if t&7 != 0 {
   924  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST64_ABS_LO12_NC", t)
   925  		}
   926  		o0 := (uint32(t&0xfff) >> 3) << 10
   927  		return val | int64(o0), noExtReloc, true
   928  
   929  	case objabi.R_ARM64_LDST128:
   930  		t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
   931  		if t&15 != 0 {
   932  			ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST128_ABS_LO12_NC", t)
   933  		}
   934  		o0 := (uint32(t&0xfff) >> 4) << 10
   935  		return val | int64(o0), noExtReloc, true
   936  	}
   937  
   938  	return val, 0, false
   939  }
   940  
   941  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   942  	log.Fatalf("unexpected relocation variant")
   943  	return -1
   944  }
   945  
   946  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   947  	switch rt := r.Type(); rt {
   948  	case objabi.R_ARM64_GOTPCREL,
   949  		objabi.R_ADDRARM64:
   950  		rr := ld.ExtrelocViaOuterSym(ldr, r, s)
   951  
   952  		// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
   953  		// will make the linking fail because it thinks the code is not PIC even though
   954  		// the BR26 relocation should be fully resolved at link time.
   955  		// That is the reason why the next if block is disabled. When the bug in ld64
   956  		// is fixed, we can enable this block and also enable duff's device in cmd/7g.
   957  		if false && target.IsDarwin() {
   958  			// Mach-O wants the addend to be encoded in the instruction
   959  			// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
   960  			// can only encode 24-bit of signed addend, but the instructions
   961  			// supports 33-bit of signed addend, so we always encode the
   962  			// addend in place.
   963  			rr.Xadd = 0
   964  		}
   965  		return rr, true
   966  	case objabi.R_CALLARM64,
   967  		objabi.R_ARM64_TLS_LE,
   968  		objabi.R_ARM64_TLS_IE:
   969  		return ld.ExtrelocSimple(ldr, r), true
   970  	}
   971  	return loader.ExtReloc{}, false
   972  }
   973  
   974  func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   975  	if plt.Size() == 0 {
   976  		// stp     x16, x30, [sp, #-16]!
   977  		// identifying information
   978  		plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
   979  
   980  		// the following two instructions (adrp + ldr) load *got[2] into x17
   981  		// adrp    x16, &got[0]
   982  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
   983  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
   984  
   985  		// <imm> is the offset value of &got[2] to &got[0], the same below
   986  		// ldr     x17, [x16, <imm>]
   987  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
   988  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
   989  
   990  		// add     x16, x16, <imm>
   991  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
   992  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
   993  
   994  		// br      x17
   995  		plt.AddUint32(ctxt.Arch, 0xd61f0220)
   996  
   997  		// 3 nop for place holder
   998  		plt.AddUint32(ctxt.Arch, 0xd503201f)
   999  		plt.AddUint32(ctxt.Arch, 0xd503201f)
  1000  		plt.AddUint32(ctxt.Arch, 0xd503201f)
  1001  
  1002  		// check gotplt.size == 0
  1003  		if gotplt.Size() != 0 {
  1004  			ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
  1005  		}
  1006  		gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
  1007  
  1008  		gotplt.AddUint64(ctxt.Arch, 0)
  1009  		gotplt.AddUint64(ctxt.Arch, 0)
  1010  	}
  1011  }
  1012  
  1013  func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
  1014  	if ldr.SymPlt(s) >= 0 {
  1015  		return
  1016  	}
  1017  
  1018  	ld.Adddynsym(ldr, target, syms, s)
  1019  
  1020  	if target.IsElf() {
  1021  		plt := ldr.MakeSymbolUpdater(syms.PLT)
  1022  		gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
  1023  		rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
  1024  		if plt.Size() == 0 {
  1025  			panic("plt is not set up")
  1026  		}
  1027  
  1028  		// adrp    x16, &got.plt[0]
  1029  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
  1030  		plt.SetUint32(target.Arch, plt.Size()-4, 0x90000010)
  1031  		relocs := plt.Relocs()
  1032  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
  1033  
  1034  		// <offset> is the offset value of &got.plt[n] to &got.plt[0]
  1035  		// ldr     x17, [x16, <offset>]
  1036  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
  1037  		plt.SetUint32(target.Arch, plt.Size()-4, 0xf9400211)
  1038  		relocs = plt.Relocs()
  1039  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_GOT)
  1040  
  1041  		// add     x16, x16, <offset>
  1042  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
  1043  		plt.SetUint32(target.Arch, plt.Size()-4, 0x91000210)
  1044  		relocs = plt.Relocs()
  1045  		plt.SetRelocType(relocs.Count()-1, objabi.R_ARM64_PCREL)
  1046  
  1047  		// br      x17
  1048  		plt.AddUint32(target.Arch, 0xd61f0220)
  1049  
  1050  		// add to got.plt: pointer to plt[0]
  1051  		gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
  1052  
  1053  		// rela
  1054  		rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
  1055  		sDynid := ldr.SymDynid(s)
  1056  
  1057  		rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
  1058  		rela.AddUint64(target.Arch, 0)
  1059  
  1060  		ldr.SetPlt(s, int32(plt.Size()-16))
  1061  	} else if target.IsDarwin() {
  1062  		ld.AddGotSym(target, ldr, syms, s, 0)
  1063  
  1064  		sDynid := ldr.SymDynid(s)
  1065  		lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
  1066  		lep.AddUint32(target.Arch, uint32(sDynid))
  1067  
  1068  		plt := ldr.MakeSymbolUpdater(syms.PLT)
  1069  		ldr.SetPlt(s, int32(plt.Size()))
  1070  
  1071  		// adrp x16, GOT
  1072  		plt.AddUint32(target.Arch, 0x90000010)
  1073  		r, _ := plt.AddRel(objabi.R_ARM64_GOT)
  1074  		r.SetOff(int32(plt.Size() - 4))
  1075  		r.SetSiz(4)
  1076  		r.SetSym(syms.GOT)
  1077  		r.SetAdd(int64(ldr.SymGot(s)))
  1078  
  1079  		// ldr x17, [x16, <offset>]
  1080  		plt.AddUint32(target.Arch, 0xf9400211)
  1081  		r, _ = plt.AddRel(objabi.R_ARM64_GOT)
  1082  		r.SetOff(int32(plt.Size() - 4))
  1083  		r.SetSiz(4)
  1084  		r.SetSym(syms.GOT)
  1085  		r.SetAdd(int64(ldr.SymGot(s)))
  1086  
  1087  		// br x17
  1088  		plt.AddUint32(target.Arch, 0xd61f0220)
  1089  	} else {
  1090  		ldr.Errorf(s, "addpltsym: unsupported binary format")
  1091  	}
  1092  }
  1093  
  1094  const (
  1095  	machoRelocLimit = 1 << 23
  1096  	peRelocLimit    = 1 << 20
  1097  )
  1098  
  1099  func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
  1100  	// When external linking on darwin, Mach-O relocation has only signed 24-bit
  1101  	// addend. For large symbols, we generate "label" symbols in the middle, so
  1102  	// that relocations can target them with smaller addends.
  1103  	// On Windows, we only get 21 bits, again (presumably) signed.
  1104  	if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
  1105  		return
  1106  	}
  1107  
  1108  	limit := int64(machoRelocLimit)
  1109  	if ctxt.IsWindows() {
  1110  		limit = peRelocLimit
  1111  	}
  1112  
  1113  	if ctxt.IsDarwin() {
  1114  		big := false
  1115  		for _, seg := range ld.Segments {
  1116  			if seg.Length >= machoRelocLimit {
  1117  				big = true
  1118  				break
  1119  			}
  1120  		}
  1121  		if !big {
  1122  			return // skip work if nothing big
  1123  		}
  1124  	}
  1125  
  1126  	// addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc.
  1127  	addLabelSyms := func(s loader.Sym, limit, sz int64) {
  1128  		v := ldr.SymValue(s)
  1129  		for off := limit; off < sz; off += limit {
  1130  			p := ldr.LookupOrCreateSym(offsetLabelName(ldr, s, off), ldr.SymVersion(s))
  1131  			ldr.SetAttrReachable(p, true)
  1132  			ldr.SetSymValue(p, v+off)
  1133  			ldr.SetSymSect(p, ldr.SymSect(s))
  1134  			if ctxt.IsDarwin() {
  1135  				ld.AddMachoSym(ldr, p)
  1136  			} else if ctxt.IsWindows() {
  1137  				ld.AddPELabelSym(ldr, p)
  1138  			} else {
  1139  				panic("missing case in gensymlate")
  1140  			}
  1141  			// fmt.Printf("gensymlate %s %x\n", ldr.SymName(p), ldr.SymValue(p))
  1142  		}
  1143  	}
  1144  
  1145  	for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
  1146  		if !ldr.AttrReachable(s) {
  1147  			continue
  1148  		}
  1149  		if ldr.SymType(s) == sym.STEXT {
  1150  			if ctxt.IsDarwin() || ctxt.IsWindows() {
  1151  				// Cannot relocate into middle of function.
  1152  				// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
  1153  				switch ldr.SymName(s) {
  1154  				case "runtime.duffcopy":
  1155  					addLabelSyms(s, 8, 8*64)
  1156  				case "runtime.duffzero":
  1157  					addLabelSyms(s, 4, 4*64)
  1158  				}
  1159  			}
  1160  			continue // we don't target the middle of other functions
  1161  		}
  1162  		sz := ldr.SymSize(s)
  1163  		if sz <= limit {
  1164  			continue
  1165  		}
  1166  		addLabelSyms(s, limit, sz)
  1167  	}
  1168  
  1169  	// Also for carrier symbols (for which SymSize is 0)
  1170  	for _, ss := range ld.CarrierSymByType {
  1171  		if ss.Sym != 0 && ss.Size > limit {
  1172  			addLabelSyms(ss.Sym, limit, ss.Size)
  1173  		}
  1174  	}
  1175  }
  1176  
  1177  // offsetLabelName returns the name of the "label" symbol used for a
  1178  // relocation targeting s+off. The label symbols is used on Darwin/Windows
  1179  // when external linking, so that the addend fits in a Mach-O/PE relocation.
  1180  func offsetLabelName(ldr *loader.Loader, s loader.Sym, off int64) string {
  1181  	if off>>20<<20 == off {
  1182  		return fmt.Sprintf("%s+%dMB", ldr.SymExtname(s), off>>20)
  1183  	}
  1184  	return fmt.Sprintf("%s+%d", ldr.SymExtname(s), off)
  1185  }
  1186  
  1187  // Convert the direct jump relocation r to refer to a trampoline if the target is too far
  1188  func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
  1189  	relocs := ldr.Relocs(s)
  1190  	r := relocs.At(ri)
  1191  	const pcrel = 1
  1192  	switch r.Type() {
  1193  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
  1194  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26),
  1195  		objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
  1196  		// Host object relocations that will be turned into a PLT call.
  1197  		// The PLT may be too far. Insert a trampoline for them.
  1198  		fallthrough
  1199  	case objabi.R_CALLARM64:
  1200  		var t int64
  1201  		// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
  1202  		// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
  1203  		// in dependency order.
  1204  		if ldr.SymValue(rs) != 0 {
  1205  			t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
  1206  		}
  1207  		if t >= 1<<27 || t < -1<<27 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && (ldr.SymPkg(s) == "" || ldr.SymPkg(s) != ldr.SymPkg(rs))) {
  1208  			// direct call too far, need to insert trampoline.
  1209  			// look up existing trampolines first. if we found one within the range
  1210  			// of direct call, we can reuse it. otherwise create a new one.
  1211  			var tramp loader.Sym
  1212  			for i := 0; ; i++ {
  1213  				oName := ldr.SymName(rs)
  1214  				name := oName + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
  1215  				tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
  1216  				ldr.SetAttrReachable(tramp, true)
  1217  				if ldr.SymType(tramp) == sym.SDYNIMPORT {
  1218  					// don't reuse trampoline defined in other module
  1219  					continue
  1220  				}
  1221  				if oName == "runtime.deferreturn" {
  1222  					ldr.SetIsDeferReturnTramp(tramp, true)
  1223  				}
  1224  				if ldr.SymValue(tramp) == 0 {
  1225  					// either the trampoline does not exist -- we need to create one,
  1226  					// or found one the address which is not assigned -- this will be
  1227  					// laid down immediately after the current function. use this one.
  1228  					break
  1229  				}
  1230  
  1231  				t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
  1232  				if t >= -1<<27 && t < 1<<27 {
  1233  					// found an existing trampoline that is not too far
  1234  					// we can just use it
  1235  					break
  1236  				}
  1237  			}
  1238  			if ldr.SymType(tramp) == 0 {
  1239  				// trampoline does not exist, create one
  1240  				trampb := ldr.MakeSymbolUpdater(tramp)
  1241  				ctxt.AddTramp(trampb)
  1242  				if ldr.SymType(rs) == sym.SDYNIMPORT {
  1243  					if r.Add() != 0 {
  1244  						ctxt.Errorf(s, "nonzero addend for DYNIMPORT call: %v+%d", ldr.SymName(rs), r.Add())
  1245  					}
  1246  					gentrampgot(ctxt, ldr, trampb, rs)
  1247  				} else {
  1248  					gentramp(ctxt, ldr, trampb, rs, r.Add())
  1249  				}
  1250  			}
  1251  			// modify reloc to point to tramp, which will be resolved later
  1252  			sb := ldr.MakeSymbolUpdater(s)
  1253  			relocs := sb.Relocs()
  1254  			r := relocs.At(ri)
  1255  			r.SetSym(tramp)
  1256  			r.SetAdd(0) // clear the offset embedded in the instruction
  1257  		}
  1258  	default:
  1259  		ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
  1260  	}
  1261  }
  1262  
  1263  // generate a trampoline to target+offset.
  1264  func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
  1265  	tramp.SetSize(12) // 3 instructions
  1266  	P := make([]byte, tramp.Size())
  1267  	o1 := uint32(0x90000010) // adrp x16, target
  1268  	o2 := uint32(0x91000210) // add x16, pc-relative-offset
  1269  	o3 := uint32(0xd61f0200) // br x16
  1270  	ctxt.Arch.ByteOrder.PutUint32(P, o1)
  1271  	ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
  1272  	ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
  1273  	tramp.SetData(P)
  1274  
  1275  	r, _ := tramp.AddRel(objabi.R_ADDRARM64)
  1276  	r.SetSiz(8)
  1277  	r.SetSym(target)
  1278  	r.SetAdd(offset)
  1279  }
  1280  
  1281  // generate a trampoline to target+offset for a DYNIMPORT symbol via GOT.
  1282  func gentrampgot(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym) {
  1283  	tramp.SetSize(12) // 3 instructions
  1284  	P := make([]byte, tramp.Size())
  1285  	o1 := uint32(0x90000010) // adrp x16, target@GOT
  1286  	o2 := uint32(0xf9400210) // ldr x16, [x16, offset]
  1287  	o3 := uint32(0xd61f0200) // br x16
  1288  	ctxt.Arch.ByteOrder.PutUint32(P, o1)
  1289  	ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
  1290  	ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
  1291  	tramp.SetData(P)
  1292  
  1293  	r, _ := tramp.AddRel(objabi.R_ARM64_GOTPCREL)
  1294  	r.SetSiz(8)
  1295  	r.SetSym(target)
  1296  }
  1297  

View as plain text