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

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package riscv64
     6  
     7  import (
     8  	"cmd/internal/obj/riscv"
     9  	"cmd/internal/objabi"
    10  	"cmd/internal/sys"
    11  	"cmd/link/internal/ld"
    12  	"cmd/link/internal/loader"
    13  	"cmd/link/internal/sym"
    14  	"debug/elf"
    15  	"fmt"
    16  	"log"
    17  	"sort"
    18  )
    19  
    20  // fakeLabelName matches the RISCV_FAKE_LABEL_NAME from binutils.
    21  const fakeLabelName = ".L0 "
    22  
    23  func gentext(ctxt *ld.Link, ldr *loader.Loader) {
    24  	initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
    25  	if initfunc == nil {
    26  		return
    27  	}
    28  
    29  	// Emit the following function:
    30  	//
    31  	// go.link.addmoduledatainit:
    32  	//      auipc a0, %pcrel_hi(local.moduledata)
    33  	//      addi  a0, %pcrel_lo(local.moduledata)
    34  	//      j     runtime.addmoduledata
    35  
    36  	sz := initfunc.AddSymRef(ctxt.Arch, ctxt.Moduledata, 0, objabi.R_RISCV_PCREL_ITYPE, 8)
    37  	initfunc.SetUint32(ctxt.Arch, sz-8, 0x00000517) // auipc a0, %pcrel_hi(local.moduledata)
    38  	initfunc.SetUint32(ctxt.Arch, sz-4, 0x00050513) // addi  a0, %pcrel_lo(local.moduledata)
    39  
    40  	sz = initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_RISCV_JAL, 4)
    41  	initfunc.SetUint32(ctxt.Arch, sz-4, 0x0000006f) // j runtime.addmoduledata
    42  }
    43  
    44  func findHI20Reloc(ldr *loader.Loader, s loader.Sym, val int64) *loader.Reloc {
    45  	outer := ldr.OuterSym(s)
    46  	if outer == 0 {
    47  		return nil
    48  	}
    49  	relocs := ldr.Relocs(outer)
    50  	start := sort.Search(relocs.Count(), func(i int) bool { return ldr.SymValue(outer)+int64(relocs.At(i).Off()) >= val })
    51  	for idx := start; idx < relocs.Count(); idx++ {
    52  		r := relocs.At(idx)
    53  		if ldr.SymValue(outer)+int64(r.Off()) != val {
    54  			break
    55  		}
    56  		if r.Type() == objabi.R_RISCV_GOT_HI20 || r.Type() == objabi.R_RISCV_PCREL_HI20 {
    57  			return &r
    58  		}
    59  	}
    60  	return nil
    61  }
    62  
    63  func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
    64  	targ := r.Sym()
    65  
    66  	var targType sym.SymKind
    67  	if targ != 0 {
    68  		targType = ldr.SymType(targ)
    69  	}
    70  
    71  	switch r.Type() {
    72  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL),
    73  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL_PLT):
    74  
    75  		if targType == sym.SDYNIMPORT {
    76  			addpltsym(target, ldr, syms, targ)
    77  			su := ldr.MakeSymbolUpdater(s)
    78  			su.SetRelocSym(rIdx, syms.PLT)
    79  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
    80  		}
    81  		if targType == 0 || targType == sym.SXREF {
    82  			ldr.Errorf(s, "unknown symbol %s in RISCV call", ldr.SymName(targ))
    83  		}
    84  		su := ldr.MakeSymbolUpdater(s)
    85  		su.SetRelocType(rIdx, objabi.R_RISCV_CALL)
    86  		return true
    87  
    88  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_GOT_HI20):
    89  		if targType != sym.SDYNIMPORT {
    90  			// TODO(jsing): Could convert to non-GOT reference.
    91  		}
    92  
    93  		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_RISCV_64))
    94  		su := ldr.MakeSymbolUpdater(s)
    95  		su.SetRelocType(rIdx, objabi.R_RISCV_GOT_HI20)
    96  		su.SetRelocSym(rIdx, syms.GOT)
    97  		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
    98  		return true
    99  
   100  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_HI20):
   101  		su := ldr.MakeSymbolUpdater(s)
   102  		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_HI20)
   103  		return true
   104  
   105  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_I):
   106  		if r.Add() != 0 {
   107  			ldr.Errorf(s, "R_RISCV_PCREL_LO12_I with non-zero addend")
   108  		}
   109  		su := ldr.MakeSymbolUpdater(s)
   110  		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_I)
   111  		return true
   112  
   113  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_S):
   114  		if r.Add() != 0 {
   115  			ldr.Errorf(s, "R_RISCV_PCREL_LO12_S with non-zero addend")
   116  		}
   117  		su := ldr.MakeSymbolUpdater(s)
   118  		su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S)
   119  		return true
   120  
   121  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_32_PCREL):
   122  		su := ldr.MakeSymbolUpdater(s)
   123  		su.SetRelocType(rIdx, objabi.R_PCREL)
   124  		return true
   125  
   126  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_64):
   127  		su := ldr.MakeSymbolUpdater(s)
   128  		su.SetRelocType(rIdx, objabi.R_ADDR)
   129  		return true
   130  
   131  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_ADD32):
   132  		su := ldr.MakeSymbolUpdater(s)
   133  		su.SetRelocType(rIdx, objabi.R_RISCV_ADD32)
   134  		return true
   135  
   136  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_SUB32):
   137  		su := ldr.MakeSymbolUpdater(s)
   138  		su.SetRelocType(rIdx, objabi.R_RISCV_SUB32)
   139  		return true
   140  
   141  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH):
   142  		su := ldr.MakeSymbolUpdater(s)
   143  		su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH)
   144  		return true
   145  
   146  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_JUMP):
   147  		su := ldr.MakeSymbolUpdater(s)
   148  		su.SetRelocType(rIdx, objabi.R_RISCV_RVC_JUMP)
   149  		return true
   150  
   151  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_BRANCH):
   152  		su := ldr.MakeSymbolUpdater(s)
   153  		su.SetRelocType(rIdx, objabi.R_RISCV_BRANCH)
   154  		return true
   155  
   156  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RELAX):
   157  		// Ignore relaxations, at least for now.
   158  		return true
   159  
   160  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_JAL):
   161  		su := ldr.MakeSymbolUpdater(s)
   162  		su.SetRelocType(rIdx, objabi.R_RISCV_JAL)
   163  		return true
   164  
   165  	default:
   166  		if r.Type() >= objabi.ElfRelocOffset {
   167  			ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
   168  			return false
   169  		}
   170  	}
   171  
   172  	// Reread the reloc to incorporate any changes in type above.
   173  	relocs := ldr.Relocs(s)
   174  	r = relocs.At(rIdx)
   175  
   176  	switch r.Type() {
   177  	case objabi.R_RISCV_CALL:
   178  		if targType != sym.SDYNIMPORT {
   179  			// nothing to do, the relocation will be laid out in reloc
   180  			return true
   181  		}
   182  		if target.IsExternal() {
   183  			// External linker will do this relocation.
   184  			return true
   185  		}
   186  		// Internal linking.
   187  		if r.Add() != 0 {
   188  			ldr.Errorf(s, "PLT reference with non-zero addend (%v)", r.Add())
   189  		}
   190  		// Build a PLT entry and change the relocation target to that entry.
   191  		addpltsym(target, ldr, syms, targ)
   192  		su := ldr.MakeSymbolUpdater(s)
   193  		su.SetRelocSym(rIdx, syms.PLT)
   194  		su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
   195  
   196  		return true
   197  	}
   198  
   199  	return false
   200  }
   201  
   202  func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
   203  	if ctxt.LinkMode != ld.LinkExternal {
   204  		return
   205  	}
   206  
   207  	// Generate a local text symbol for each relocation target, as the
   208  	// R_RISCV_PCREL_LO12_* relocations generated by elfreloc1 need it.
   209  	if ctxt.Textp == nil {
   210  		log.Fatal("genSymsLate called before Textp has been assigned")
   211  	}
   212  	var hi20Syms []loader.Sym
   213  	for _, s := range ctxt.Textp {
   214  		relocs := ldr.Relocs(s)
   215  		for ri := 0; ri < relocs.Count(); ri++ {
   216  			r := relocs.At(ri)
   217  			if r.Type() != objabi.R_RISCV_CALL &&
   218  				r.Type() != objabi.R_RISCV_PCREL_ITYPE &&
   219  				r.Type() != objabi.R_RISCV_PCREL_STYPE &&
   220  				r.Type() != objabi.R_RISCV_TLS_IE &&
   221  				r.Type() != objabi.R_RISCV_GOT_PCREL_ITYPE {
   222  				continue
   223  			}
   224  			if r.Off() == 0 && ldr.SymType(s).IsText() {
   225  				// Use the symbol for the function instead of creating
   226  				// an overlapping symbol.
   227  				continue
   228  			}
   229  
   230  			// TODO(jsing): Consider generating ELF symbols without needing
   231  			// loader symbols, in order to reduce memory consumption. This
   232  			// would require changes to genelfsym so that it called
   233  			// putelfsym and putelfsyment as appropriate.
   234  			sb := ldr.MakeSymbolBuilder(fakeLabelName)
   235  			sb.SetType(sym.STEXT)
   236  			sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
   237  			sb.SetLocal(true)
   238  			sb.SetReachable(true)
   239  			sb.SetVisibilityHidden(true)
   240  			sb.SetSect(ldr.SymSect(s))
   241  			if outer := ldr.OuterSym(s); outer != 0 {
   242  				ldr.AddInteriorSym(outer, sb.Sym())
   243  			}
   244  			hi20Syms = append(hi20Syms, sb.Sym())
   245  		}
   246  	}
   247  	ctxt.Textp = append(ctxt.Textp, hi20Syms...)
   248  	ldr.SortSyms(ctxt.Textp)
   249  }
   250  
   251  func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
   252  	idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
   253  	if idx >= len(ctxt.Textp) {
   254  		return 0
   255  	}
   256  	if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s).IsText() {
   257  		return s
   258  	}
   259  	return 0
   260  }
   261  
   262  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
   263  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
   264  	switch r.Type {
   265  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
   266  		out.Write64(uint64(sectoff))
   267  		switch r.Size {
   268  		case 4:
   269  			out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
   270  		case 8:
   271  			out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
   272  		default:
   273  			ld.Errorf("unknown size %d for %v relocation", r.Size, r.Type)
   274  			return false
   275  		}
   276  		out.Write64(uint64(r.Xadd))
   277  
   278  	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
   279  		out.Write64(uint64(sectoff))
   280  		out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32)
   281  		out.Write64(uint64(r.Xadd))
   282  
   283  	case objabi.R_RISCV_CALL,
   284  		objabi.R_RISCV_PCREL_ITYPE,
   285  		objabi.R_RISCV_PCREL_STYPE,
   286  		objabi.R_RISCV_TLS_IE,
   287  		objabi.R_RISCV_GOT_PCREL_ITYPE:
   288  		// Find the text symbol for the AUIPC instruction targeted
   289  		// by this relocation.
   290  		relocs := ldr.Relocs(s)
   291  		offset := int64(relocs.At(ri).Off())
   292  		hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
   293  		if hi20Sym == 0 {
   294  			ld.Errorf("failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
   295  			return false
   296  		}
   297  		hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
   298  
   299  		// Emit two relocations - a R_RISCV_PCREL_HI20 relocation and a
   300  		// corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation.
   301  		// Note that the LO12 relocation must point to a target that has a valid
   302  		// HI20 PC-relative relocation text symbol, which in turn points to the
   303  		// given symbol. For further details see section 8.4.9 of the RISC-V ABIs
   304  		// Specification:
   305  		//
   306  		//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
   307  		//
   308  		var hiRel, loRel elf.R_RISCV
   309  		switch r.Type {
   310  		case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
   311  			hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
   312  		case objabi.R_RISCV_PCREL_STYPE:
   313  			hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
   314  		case objabi.R_RISCV_TLS_IE:
   315  			hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
   316  		case objabi.R_RISCV_GOT_PCREL_ITYPE:
   317  			hiRel, loRel = elf.R_RISCV_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
   318  		}
   319  		out.Write64(uint64(sectoff))
   320  		out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
   321  		out.Write64(uint64(r.Xadd))
   322  		out.Write64(uint64(sectoff + 4))
   323  		out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
   324  		out.Write64(uint64(0))
   325  
   326  	case objabi.R_RISCV_TLS_LE:
   327  		out.Write64(uint64(sectoff))
   328  		out.Write64(uint64(elf.R_RISCV_TPREL_HI20) | uint64(elfsym)<<32)
   329  		out.Write64(uint64(r.Xadd))
   330  		out.Write64(uint64(sectoff + 4))
   331  		out.Write64(uint64(elf.R_RISCV_TPREL_LO12_I) | uint64(elfsym)<<32)
   332  		out.Write64(uint64(r.Xadd))
   333  
   334  	default:
   335  		return false
   336  	}
   337  
   338  	return true
   339  }
   340  
   341  func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   342  	if plt.Size() != 0 {
   343  		return
   344  	}
   345  	if gotplt.Size() != 0 {
   346  		ctxt.Errorf(gotplt.Sym(), "got.plt is not empty")
   347  	}
   348  
   349  	// See section 8.4.6 of the RISC-V ABIs Specification:
   350  	//
   351  	//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
   352  	//
   353  	// 1:   auipc  t2, %pcrel_hi(.got.plt)
   354  	//      sub    t1, t1, t3               # shifted .got.plt offset + hdr size + 12
   355  	//      l[w|d] t3, %pcrel_lo(1b)(t2)    # _dl_runtime_resolve
   356  	//      addi   t1, t1, -(hdr size + 12) # shifted .got.plt offset
   357  	//      addi   t0, t2, %pcrel_lo(1b)    # &.got.plt
   358  	//      srli   t1, t1, log2(16/PTRSIZE) # .got.plt offset
   359  	//      l[w|d] t0, PTRSIZE(t0)          # link map
   360  	//      jr     t3
   361  
   362  	plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_RISCV_PCREL_HI20, 4)
   363  	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00000397) // auipc   t2,0x0
   364  
   365  	sb := ldr.MakeSymbolBuilder(fakeLabelName)
   366  	sb.SetType(sym.STEXT)
   367  	sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
   368  	sb.SetLocal(true)
   369  	sb.SetReachable(true)
   370  	sb.SetVisibilityHidden(true)
   371  	plt.AddInteriorSym(sb.Sym())
   372  
   373  	plt.AddUint32(ctxt.Arch, 0x41c30333) // sub     t1,t1,t3
   374  
   375  	plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
   376  	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x0003be03) // ld      t3,0(t2)
   377  
   378  	plt.AddUint32(ctxt.Arch, 0xfd430313) // addi    t1,t1,-44
   379  
   380  	plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
   381  	plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00038293) // addi    t0,t2,0
   382  
   383  	plt.AddUint32(ctxt.Arch, 0x00135313) // srli    t1,t1,0x1
   384  	plt.AddUint32(ctxt.Arch, 0x0082b283) // ld      t0,8(t0)
   385  	plt.AddUint32(ctxt.Arch, 0x00008e02) // jr      t3
   386  
   387  	gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0) // got.plt[0] = _dl_runtime_resolve
   388  	gotplt.AddUint64(ctxt.Arch, 0)            // got.plt[1] = link map
   389  }
   390  
   391  func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
   392  	if ldr.SymPlt(s) >= 0 {
   393  		return
   394  	}
   395  
   396  	ld.Adddynsym(ldr, target, syms, s)
   397  
   398  	plt := ldr.MakeSymbolUpdater(syms.PLT)
   399  	gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
   400  	rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
   401  	if plt.Size() == 0 {
   402  		panic("plt is not set up")
   403  	}
   404  
   405  	// See section 8.4.6 of the RISC-V ABIs Specification:
   406  	//
   407  	//  https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
   408  	//
   409  	// 1:  auipc   t3, %pcrel_hi(function@.got.plt)
   410  	//     l[w|d]  t3, %pcrel_lo(1b)(t3)
   411  	//     jalr    t1, t3
   412  	//     nop
   413  
   414  	plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_RISCV_PCREL_HI20, 4)
   415  	plt.SetUint32(target.Arch, plt.Size()-4, 0x00000e17) // auipc   t3,0x0
   416  
   417  	sb := ldr.MakeSymbolBuilder(fakeLabelName)
   418  	sb.SetType(sym.STEXT)
   419  	sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
   420  	sb.SetLocal(true)
   421  	sb.SetReachable(true)
   422  	sb.SetVisibilityHidden(true)
   423  	plt.AddInteriorSym(sb.Sym())
   424  
   425  	plt.AddSymRef(target.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
   426  	plt.SetUint32(target.Arch, plt.Size()-4, 0x000e3e03) // ld      t3,0(t3)
   427  	plt.AddUint32(target.Arch, 0x000e0367)               // jalr    t1,t3
   428  	plt.AddUint32(target.Arch, 0x00000001)               // nop
   429  
   430  	ldr.SetPlt(s, int32(plt.Size()-16))
   431  
   432  	// add to got.plt: pointer to plt[0]
   433  	gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
   434  
   435  	// rela
   436  	rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
   437  	sDynid := ldr.SymDynid(s)
   438  
   439  	rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_RISCV_JUMP_SLOT)))
   440  	rela.AddUint64(target.Arch, 0)
   441  }
   442  
   443  func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
   444  	log.Fatalf("machoreloc1 not implemented")
   445  	return false
   446  }
   447  
   448  func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
   449  	rs := r.Sym()
   450  	pc := ldr.SymValue(s) + int64(r.Off())
   451  
   452  	// If the call points to a trampoline, see if we can reach the symbol
   453  	// directly. This situation can occur when the relocation symbol is
   454  	// not assigned an address until after the trampolines are generated.
   455  	if r.Type() == objabi.R_RISCV_JAL_TRAMP {
   456  		relocs := ldr.Relocs(rs)
   457  		if relocs.Count() != 1 {
   458  			ldr.Errorf(s, "trampoline %v has %d relocations", ldr.SymName(rs), relocs.Count())
   459  		}
   460  		tr := relocs.At(0)
   461  		if tr.Type() != objabi.R_RISCV_CALL {
   462  			ldr.Errorf(s, "trampoline %v has unexpected relocation %v", ldr.SymName(rs), tr.Type())
   463  		}
   464  		trs := tr.Sym()
   465  		if ldr.SymValue(trs) != 0 && ldr.SymType(trs) != sym.SDYNIMPORT && ldr.SymType(trs) != sym.SUNDEFEXT {
   466  			trsOff := ldr.SymValue(trs) + tr.Add() - pc
   467  			if trsOff >= -(1<<20) && trsOff < (1<<20) {
   468  				r.SetType(objabi.R_RISCV_JAL)
   469  				r.SetSym(trs)
   470  				r.SetAdd(tr.Add())
   471  				rs = trs
   472  			}
   473  		}
   474  
   475  	}
   476  
   477  	if target.IsExternal() {
   478  		switch r.Type() {
   479  		case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
   480  			return val, 1, true
   481  
   482  		case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE:
   483  			return val, 2, true
   484  		}
   485  
   486  		return val, 0, false
   487  	}
   488  
   489  	off := ldr.SymValue(rs) + r.Add() - pc
   490  
   491  	switch r.Type() {
   492  	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
   493  		// Generate instruction immediates.
   494  		imm, err := riscv.EncodeJImmediate(off)
   495  		if err != nil {
   496  			ldr.Errorf(s, "cannot encode J-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   497  		}
   498  		immMask := int64(riscv.JTypeImmMask)
   499  
   500  		val = (val &^ immMask) | imm
   501  
   502  		return val, 0, true
   503  
   504  	case objabi.R_RISCV_TLS_IE:
   505  		log.Fatalf("cannot handle R_RISCV_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
   506  		return val, 0, false
   507  
   508  	case objabi.R_RISCV_TLS_LE:
   509  		// Generate LUI and ADDIW instruction immediates.
   510  		off := r.Add()
   511  
   512  		low, high, err := riscv.Split32BitImmediate(off)
   513  		if err != nil {
   514  			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
   515  		}
   516  
   517  		luiImm, err := riscv.EncodeUImmediate(high)
   518  		if err != nil {
   519  			ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE LUI relocation offset for %s: %v", ldr.SymName(rs), err)
   520  		}
   521  
   522  		addiwImm, err := riscv.EncodeIImmediate(low)
   523  		if err != nil {
   524  			ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   525  		}
   526  
   527  		lui := int64(uint32(val))
   528  		addiw := int64(uint32(val >> 32))
   529  
   530  		lui = (lui &^ riscv.UTypeImmMask) | int64(uint32(luiImm))
   531  		addiw = (addiw &^ riscv.ITypeImmMask) | int64(uint32(addiwImm))
   532  
   533  		return addiw<<32 | lui, 0, true
   534  
   535  	case objabi.R_RISCV_BRANCH:
   536  		pc := ldr.SymValue(s) + int64(r.Off())
   537  		off := ldr.SymValue(rs) + r.Add() - pc
   538  
   539  		imm, err := riscv.EncodeBImmediate(off)
   540  		if err != nil {
   541  			ldr.Errorf(s, "cannot encode B-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   542  		}
   543  		ins := (int64(uint32(val)) &^ riscv.BTypeImmMask) | int64(uint32(imm))
   544  
   545  		return ins, 0, true
   546  
   547  	case objabi.R_RISCV_RVC_BRANCH, objabi.R_RISCV_RVC_JUMP:
   548  		pc := ldr.SymValue(s) + int64(r.Off())
   549  		off := ldr.SymValue(rs) + r.Add() - pc
   550  
   551  		var err error
   552  		var imm, immMask int64
   553  		switch r.Type() {
   554  		case objabi.R_RISCV_RVC_BRANCH:
   555  			immMask = riscv.CBTypeImmMask
   556  			imm, err = riscv.EncodeCBImmediate(off)
   557  			if err != nil {
   558  				ldr.Errorf(s, "cannot encode CB-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   559  			}
   560  		case objabi.R_RISCV_RVC_JUMP:
   561  			immMask = riscv.CJTypeImmMask
   562  			imm, err = riscv.EncodeCJImmediate(off)
   563  			if err != nil {
   564  				ldr.Errorf(s, "cannot encode CJ-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   565  			}
   566  		default:
   567  			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
   568  		}
   569  
   570  		ins := (int64(uint16(val)) &^ immMask) | int64(uint16(imm))
   571  
   572  		return ins, 0, true
   573  
   574  	case objabi.R_RISCV_GOT_HI20, objabi.R_RISCV_PCREL_HI20:
   575  		pc := ldr.SymValue(s) + int64(r.Off())
   576  		off := ldr.SymValue(rs) + r.Add() - pc
   577  
   578  		// Generate AUIPC immediates.
   579  		_, high, err := riscv.Split32BitImmediate(off)
   580  		if err != nil {
   581  			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
   582  		}
   583  
   584  		auipcImm, err := riscv.EncodeUImmediate(high)
   585  		if err != nil {
   586  			ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
   587  		}
   588  
   589  		auipc := int64(uint32(val))
   590  		auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
   591  
   592  		return auipc, 0, true
   593  
   594  	case objabi.R_RISCV_PCREL_LO12_I, objabi.R_RISCV_PCREL_LO12_S:
   595  		hi20Reloc := findHI20Reloc(ldr, rs, ldr.SymValue(rs))
   596  		if hi20Reloc == nil {
   597  			ldr.Errorf(s, "missing HI20 relocation for LO12 relocation with %s (%d)", ldr.SymName(rs), rs)
   598  		}
   599  
   600  		pc := ldr.SymValue(s) + int64(hi20Reloc.Off())
   601  		off := ldr.SymValue(hi20Reloc.Sym()) + hi20Reloc.Add() - pc
   602  
   603  		low, _, err := riscv.Split32BitImmediate(off)
   604  		if err != nil {
   605  			ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
   606  		}
   607  
   608  		var imm, immMask int64
   609  		switch r.Type() {
   610  		case objabi.R_RISCV_PCREL_LO12_I:
   611  			immMask = riscv.ITypeImmMask
   612  			imm, err = riscv.EncodeIImmediate(low)
   613  			if err != nil {
   614  				ldr.Errorf(s, "cannot encode objabi.R_RISCV_PCREL_LO12_I I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   615  			}
   616  		case objabi.R_RISCV_PCREL_LO12_S:
   617  			immMask = riscv.STypeImmMask
   618  			imm, err = riscv.EncodeSImmediate(low)
   619  			if err != nil {
   620  				ldr.Errorf(s, "cannot encode R_RISCV_PCREL_LO12_S S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   621  			}
   622  		default:
   623  			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
   624  		}
   625  
   626  		ins := int64(uint32(val))
   627  		ins = (ins &^ immMask) | int64(uint32(imm))
   628  		return ins, 0, true
   629  
   630  	case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
   631  		// Generate AUIPC and second instruction immediates.
   632  		low, high, err := riscv.Split32BitImmediate(off)
   633  		if err != nil {
   634  			ldr.Errorf(s, "pc-relative relocation does not fit in 32 bits: %d", off)
   635  		}
   636  
   637  		auipcImm, err := riscv.EncodeUImmediate(high)
   638  		if err != nil {
   639  			ldr.Errorf(s, "cannot encode AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
   640  		}
   641  
   642  		var secondImm, secondImmMask int64
   643  		switch r.Type() {
   644  		case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE:
   645  			secondImmMask = riscv.ITypeImmMask
   646  			secondImm, err = riscv.EncodeIImmediate(low)
   647  			if err != nil {
   648  				ldr.Errorf(s, "cannot encode I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   649  			}
   650  		case objabi.R_RISCV_PCREL_STYPE:
   651  			secondImmMask = riscv.STypeImmMask
   652  			secondImm, err = riscv.EncodeSImmediate(low)
   653  			if err != nil {
   654  				ldr.Errorf(s, "cannot encode S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
   655  			}
   656  		default:
   657  			panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
   658  		}
   659  
   660  		auipc := int64(uint32(val))
   661  		second := int64(uint32(val >> 32))
   662  
   663  		auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
   664  		second = (second &^ secondImmMask) | int64(uint32(secondImm))
   665  
   666  		return second<<32 | auipc, 0, true
   667  
   668  	case objabi.R_RISCV_ADD32:
   669  		addr := val + ldr.SymValue(rs) + r.Add()
   670  		return int64(uint32(addr)), 0, true
   671  
   672  	case objabi.R_RISCV_SUB32:
   673  		addr := val - ldr.SymValue(rs) - r.Add()
   674  		return int64(uint32(addr)), 0, true
   675  	}
   676  
   677  	return val, 0, false
   678  }
   679  
   680  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   681  	log.Fatalf("archrelocvariant")
   682  	return -1
   683  }
   684  
   685  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   686  	switch r.Type() {
   687  	case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP:
   688  		return ld.ExtrelocSimple(ldr, r), true
   689  
   690  	case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE:
   691  		return ld.ExtrelocViaOuterSym(ldr, r, s), true
   692  	}
   693  	return loader.ExtReloc{}, false
   694  }
   695  
   696  func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
   697  	relocs := ldr.Relocs(s)
   698  	r := relocs.At(ri)
   699  
   700  	switch r.Type() {
   701  	case objabi.R_RISCV_JAL:
   702  		pc := ldr.SymValue(s) + int64(r.Off())
   703  		off := ldr.SymValue(rs) + r.Add() - pc
   704  
   705  		// Relocation symbol has an address and is directly reachable,
   706  		// therefore there is no need for a trampoline.
   707  		if ldr.SymValue(rs) != 0 && off >= -(1<<20) && off < (1<<20) && (*ld.FlagDebugTramp <= 1 || ldr.SymPkg(s) == ldr.SymPkg(rs)) {
   708  			break
   709  		}
   710  
   711  		// Relocation symbol is too far for a direct call or has not
   712  		// yet been given an address. See if an existing trampoline is
   713  		// reachable and if so, reuse it. Otherwise we need to create
   714  		// a new trampoline.
   715  		var tramp loader.Sym
   716  		for i := 0; ; i++ {
   717  			oName := ldr.SymName(rs)
   718  			name := fmt.Sprintf("%s-tramp%d", oName, i)
   719  			if r.Add() != 0 {
   720  				name = fmt.Sprintf("%s%+x-tramp%d", oName, r.Add(), i)
   721  			}
   722  			tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
   723  			ldr.SetAttrReachable(tramp, true)
   724  			if ldr.SymType(tramp) == sym.SDYNIMPORT {
   725  				// Do not reuse trampoline defined in other module.
   726  				continue
   727  			}
   728  			if oName == "runtime.deferreturn" {
   729  				ldr.SetIsDeferReturnTramp(tramp, true)
   730  			}
   731  			if ldr.SymValue(tramp) == 0 {
   732  				// Either trampoline does not exist or we found one
   733  				// that does not have an address assigned and will be
   734  				// laid down immediately after the current function.
   735  				break
   736  			}
   737  
   738  			trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
   739  			if trampOff >= -(1<<20) && trampOff < (1<<20) {
   740  				// An existing trampoline that is reachable.
   741  				break
   742  			}
   743  		}
   744  		if ldr.SymType(tramp) == 0 {
   745  			trampb := ldr.MakeSymbolUpdater(tramp)
   746  			ctxt.AddTramp(trampb, ldr.SymType(s))
   747  			genCallTramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, r.Add())
   748  		}
   749  		sb := ldr.MakeSymbolUpdater(s)
   750  		if ldr.SymValue(rs) == 0 {
   751  			// In this case the target symbol has not yet been assigned an
   752  			// address, so we have to assume a trampoline is required. Mark
   753  			// this as a call via a trampoline so that we can potentially
   754  			// switch to a direct call during relocation.
   755  			sb.SetRelocType(ri, objabi.R_RISCV_JAL_TRAMP)
   756  		}
   757  		relocs := sb.Relocs()
   758  		r := relocs.At(ri)
   759  		r.SetSym(tramp)
   760  		r.SetAdd(0)
   761  
   762  	case objabi.R_RISCV_CALL:
   763  		// Nothing to do, already using AUIPC+JALR.
   764  
   765  	default:
   766  		ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
   767  	}
   768  }
   769  
   770  func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
   771  	tramp.AddUint32(arch, 0x00000f97) // AUIPC	$0, X31
   772  	tramp.AddUint32(arch, 0x000f8067) // JALR	X0, (X31)
   773  
   774  	r, _ := tramp.AddRel(objabi.R_RISCV_CALL)
   775  	r.SetSiz(8)
   776  	r.SetSym(target)
   777  	r.SetAdd(offset)
   778  }
   779  

View as plain text