github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/riscv64/asm.go (about)

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