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

     1  // Copyright 2022 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 loong64
     6  
     7  import (
     8  	"cmd/internal/objabi"
     9  	"cmd/internal/sys"
    10  	"cmd/link/internal/ld"
    11  	"cmd/link/internal/loader"
    12  	"cmd/link/internal/sym"
    13  	"debug/elf"
    14  	"fmt"
    15  	"log"
    16  )
    17  
    18  func gentext(ctxt *ld.Link, ldr *loader.Loader) {
    19  	initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
    20  	if initfunc == nil {
    21  		return
    22  	}
    23  
    24  	o := func(op uint32) {
    25  		initfunc.AddUint32(ctxt.Arch, op)
    26  	}
    27  
    28  	// Emit the following function:
    29  	//
    30  	//	local.dso_init:
    31  	//		la.pcrel $a0, local.moduledata
    32  	//		b runtime.addmoduledata
    33  
    34  	//	0000000000000000 <local.dso_init>:
    35  	//	0:	1a000004	pcalau12i	$a0, 0
    36  	//				0: R_LARCH_PCALA_HI20	local.moduledata
    37  	o(0x1a000004)
    38  	rel, _ := initfunc.AddRel(objabi.R_LOONG64_ADDR_HI)
    39  	rel.SetOff(0)
    40  	rel.SetSiz(4)
    41  	rel.SetSym(ctxt.Moduledata)
    42  
    43  	//	4:	02c00084	addi.d	$a0, $a0, 0
    44  	//				4: R_LARCH_PCALA_LO12	local.moduledata
    45  	o(0x02c00084)
    46  	rel2, _ := initfunc.AddRel(objabi.R_LOONG64_ADDR_LO)
    47  	rel2.SetOff(4)
    48  	rel2.SetSiz(4)
    49  	rel2.SetSym(ctxt.Moduledata)
    50  
    51  	//	8:	50000000	b	0
    52  	//				8: R_LARCH_B26	runtime.addmoduledata
    53  	o(0x50000000)
    54  	rel3, _ := initfunc.AddRel(objabi.R_CALLLOONG64)
    55  	rel3.SetOff(8)
    56  	rel3.SetSiz(4)
    57  	rel3.SetSym(addmoduledata)
    58  }
    59  
    60  func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
    61  	targ := r.Sym()
    62  	var targType sym.SymKind
    63  	if targ != 0 {
    64  		targType = ldr.SymType(targ)
    65  	}
    66  
    67  	switch r.Type() {
    68  	default:
    69  		if r.Type() >= objabi.ElfRelocOffset {
    70  			ldr.Errorf(s, "adddynrel: unexpected reloction type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
    71  			return false
    72  		}
    73  
    74  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_64):
    75  		if targType == sym.SDYNIMPORT {
    76  			ldr.Errorf(s, "unexpected R_LARCH_64 relocation for dynamic symbol %s", ldr.SymName(targ))
    77  		}
    78  		su := ldr.MakeSymbolUpdater(s)
    79  		su.SetRelocType(rIdx, objabi.R_ADDR)
    80  		if target.IsPIE() && target.IsInternal() {
    81  			// For internal linking PIE, this R_ADDR relocation cannot
    82  			// be resolved statically. We need to generate a dynamic
    83  			// relocation. Let the code below handle it.
    84  			break
    85  		}
    86  		return true
    87  
    88  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_B26),
    89  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_CALL36):
    90  		if targType == sym.SDYNIMPORT {
    91  			addpltsym(target, ldr, syms, targ)
    92  			su := ldr.MakeSymbolUpdater(s)
    93  			su.SetRelocSym(rIdx, syms.PLT)
    94  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
    95  		}
    96  		if targType == 0 || targType == sym.SXREF {
    97  			ldr.Errorf(s, "unknown symbol %s in callloong64", ldr.SymName(targ))
    98  		}
    99  		relocType := objabi.R_CALLLOONG64
   100  		if r.Type() == objabi.ElfRelocOffset+objabi.RelocType(elf.R_LARCH_CALL36) {
   101  			relocType = objabi.R_LOONG64_CALL36
   102  		}
   103  		su := ldr.MakeSymbolUpdater(s)
   104  		su.SetRelocType(rIdx, relocType)
   105  		return true
   106  
   107  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_GOT_PC_HI20),
   108  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_GOT_PC_LO12):
   109  		if targType != sym.SDYNIMPORT {
   110  			// TODO: turn LDR of GOT entry into ADR of symbol itself
   111  		}
   112  
   113  		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_LARCH_64))
   114  		su := ldr.MakeSymbolUpdater(s)
   115  		if r.Type() == objabi.ElfRelocOffset+objabi.RelocType(elf.R_LARCH_GOT_PC_HI20) {
   116  			su.SetRelocType(rIdx, objabi.R_LOONG64_ADDR_HI)
   117  		} else {
   118  			su.SetRelocType(rIdx, objabi.R_LOONG64_ADDR_LO)
   119  		}
   120  		su.SetRelocSym(rIdx, syms.GOT)
   121  		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
   122  		return true
   123  
   124  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_PCALA_HI20),
   125  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_PCALA_LO12),
   126  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_PCREL20_S2):
   127  		if targType == sym.SDYNIMPORT {
   128  			ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   129  		}
   130  		if targType == 0 || targType == sym.SXREF {
   131  			ldr.Errorf(s, "unknown symbol %s", ldr.SymName(targ))
   132  		}
   133  
   134  		var relocType objabi.RelocType
   135  		switch r.Type() - objabi.ElfRelocOffset {
   136  		case objabi.RelocType(elf.R_LARCH_PCALA_HI20):
   137  			relocType = objabi.R_LOONG64_ADDR_HI
   138  		case objabi.RelocType(elf.R_LARCH_PCALA_LO12):
   139  			relocType = objabi.R_LOONG64_ADDR_LO
   140  		case objabi.RelocType(elf.R_LARCH_PCREL20_S2):
   141  			relocType = objabi.R_LOONG64_ADDR_PCREL20_S2
   142  		}
   143  		su := ldr.MakeSymbolUpdater(s)
   144  		su.SetRelocType(rIdx, relocType)
   145  		return true
   146  
   147  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_ADD64),
   148  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_SUB64):
   149  		su := ldr.MakeSymbolUpdater(s)
   150  		if r.Type() == objabi.ElfRelocOffset+objabi.RelocType(elf.R_LARCH_ADD64) {
   151  			su.SetRelocType(rIdx, objabi.R_LOONG64_ADD64)
   152  		} else {
   153  			su.SetRelocType(rIdx, objabi.R_LOONG64_SUB64)
   154  		}
   155  		return true
   156  
   157  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_B16),
   158  		objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_B21):
   159  		if targType == sym.SDYNIMPORT {
   160  			addpltsym(target, ldr, syms, targ)
   161  			su := ldr.MakeSymbolUpdater(s)
   162  			su.SetRelocSym(rIdx, syms.PLT)
   163  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
   164  		}
   165  		if targType == 0 || targType == sym.SXREF {
   166  			ldr.Errorf(s, "unknown symbol %s in R_JMPxxLOONG64", ldr.SymName(targ))
   167  		}
   168  		su := ldr.MakeSymbolUpdater(s)
   169  		if r.Type() == objabi.ElfRelocOffset+objabi.RelocType(elf.R_LARCH_B16) {
   170  			su.SetRelocType(rIdx, objabi.R_JMP16LOONG64)
   171  		} else {
   172  			su.SetRelocType(rIdx, objabi.R_JMP21LOONG64)
   173  		}
   174  		return true
   175  	}
   176  
   177  	relocs := ldr.Relocs(s)
   178  	r = relocs.At(rIdx)
   179  
   180  	switch r.Type() {
   181  	case objabi.R_CALLLOONG64:
   182  		if targType != sym.SDYNIMPORT {
   183  			return true
   184  		}
   185  		if target.IsExternal() {
   186  			return true
   187  		}
   188  
   189  		// Internal linking.
   190  		if r.Add() != 0 {
   191  			ldr.Errorf(s, "PLT call with no-zero addend (%v)", r.Add())
   192  		}
   193  
   194  		// Build a PLT entry and change the relocation target to that entry.
   195  		addpltsym(target, ldr, syms, targ)
   196  		su := ldr.MakeSymbolUpdater(s)
   197  		su.SetRelocSym(rIdx, syms.PLT)
   198  		su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
   199  		return true
   200  
   201  	case objabi.R_ADDR:
   202  		if ldr.SymType(s) == sym.STEXT && target.IsElf() {
   203  			// The code is asking for the address of an external
   204  			// function. We provide it with the address of the
   205  			// correspondent GOT symbol.
   206  			ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_LARCH_64))
   207  			su := ldr.MakeSymbolUpdater(s)
   208  			su.SetRelocSym(rIdx, syms.GOT)
   209  			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
   210  			return true
   211  		}
   212  
   213  		// Process dynamic relocations for the data sections.
   214  		if target.IsPIE() && target.IsInternal() {
   215  			// When internally linking, generate dynamic relocations
   216  			// for all typical R_ADDR relocations. The exception
   217  			// are those R_ADDR that are created as part of generating
   218  			// the dynamic relocations and must be resolved statically.
   219  			//
   220  			// There are three phases relevant to understanding this:
   221  			//
   222  			//	dodata()  // we are here
   223  			//	address() // symbol address assignment
   224  			//	reloc()   // resolution of static R_ADDR relocs
   225  			//
   226  			// At this point symbol addresses have not been
   227  			// assigned yet (as the final size of the .rela section
   228  			// will affect the addresses), and so we cannot write
   229  			// the Elf64_Rela.r_offset now. Instead we delay it
   230  			// until after the 'address' phase of the linker is
   231  			// complete. We do this via Addaddrplus, which creates
   232  			// a new R_ADDR relocation which will be resolved in
   233  			// the 'reloc' phase.
   234  			//
   235  			// These synthetic static R_ADDR relocs must be skipped
   236  			// now, or else we will be caught in an infinite loop
   237  			// of generating synthetic relocs for our synthetic
   238  			// relocs.
   239  			//
   240  			// Furthermore, the rela sections contain dynamic
   241  			// relocations with R_ADDR relocations on
   242  			// Elf64_Rela.r_offset. This field should contain the
   243  			// symbol offset as determined by reloc(), not the
   244  			// final dynamically linked address as a dynamic
   245  			// relocation would provide.
   246  			switch ldr.SymName(s) {
   247  			case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
   248  				return false
   249  			}
   250  		} else {
   251  			// Either internally linking a static executable,
   252  			// in which case we can resolve these relocations
   253  			// statically in the 'reloc' phase, or externally
   254  			// linking, in which case the relocation will be
   255  			// prepared in the 'reloc' phase and passed to the
   256  			// external linker in the 'asmb' phase.
   257  			if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
   258  				break
   259  			}
   260  		}
   261  
   262  		if target.IsElf() {
   263  			// Generate R_LARCH_RELATIVE relocations for best
   264  			// efficiency in the dynamic linker.
   265  			//
   266  			// As noted above, symbol addresses have not been
   267  			// assigned yet, so we can't generate the final reloc
   268  			// entry yet. We ultimately want:
   269  			//
   270  			// r_offset = s + r.Off
   271  			// r_info = R_LARCH_RELATIVE
   272  			// r_addend = targ + r.Add
   273  			//
   274  			// The dynamic linker will set *offset = base address +
   275  			// addend.
   276  			//
   277  			// AddAddrPlus is used for r_offset and r_addend to
   278  			// generate new R_ADDR relocations that will update
   279  			// these fields in the 'reloc' phase.
   280  			rela := ldr.MakeSymbolUpdater(syms.Rela)
   281  			rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
   282  			if r.Siz() == 8 {
   283  				rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_LARCH_RELATIVE)))
   284  			} else {
   285  				ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
   286  			}
   287  			rela.AddAddrPlus(target.Arch, targ, r.Add())
   288  			return true
   289  		}
   290  
   291  	case objabi.R_LOONG64_GOT_HI,
   292  		objabi.R_LOONG64_GOT_LO:
   293  		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_LARCH_64))
   294  		su := ldr.MakeSymbolUpdater(s)
   295  		if r.Type() == objabi.R_LOONG64_GOT_HI {
   296  			su.SetRelocType(rIdx, objabi.R_LOONG64_ADDR_HI)
   297  		} else {
   298  			su.SetRelocType(rIdx, objabi.R_LOONG64_ADDR_LO)
   299  		}
   300  		su.SetRelocSym(rIdx, syms.GOT)
   301  		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
   302  		return true
   303  	}
   304  	return false
   305  }
   306  
   307  func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   308  	if plt.Size() == 0 {
   309  		// pcalau12i $r14, imm
   310  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_LOONG64_ADDR_HI, 4)
   311  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x1a00000e)
   312  
   313  		// sub.d $r13, $r13, $r15
   314  		plt.AddUint32(ctxt.Arch, 0x0011bdad)
   315  
   316  		// ld.d $r15, $r14, imm
   317  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_LOONG64_ADDR_LO, 4)
   318  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x28c001cf)
   319  
   320  		// addi.d $r13, $r13, -40
   321  		plt.AddUint32(ctxt.Arch, 0x02ff61ad)
   322  
   323  		// addi.d $r12, $r14, imm
   324  		plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_LOONG64_ADDR_LO, 4)
   325  		plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x2c001cc)
   326  
   327  		// srli.d $r13, $r13, 1
   328  		plt.AddUint32(ctxt.Arch, 0x004505ad)
   329  
   330  		// ld.d $r12, $r12, 8
   331  		plt.AddUint32(ctxt.Arch, 0x28c0218c)
   332  
   333  		// jirl $r0, $r15, 0
   334  		plt.AddUint32(ctxt.Arch, 0x4c0001e0)
   335  
   336  		// check gotplt.size == 0
   337  		if gotplt.Size() != 0 {
   338  			ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
   339  		}
   340  
   341  		gotplt.AddUint64(ctxt.Arch, 0)
   342  		gotplt.AddUint64(ctxt.Arch, 0)
   343  	}
   344  }
   345  
   346  func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
   347  	if ldr.SymPlt(s) >= 0 {
   348  		return
   349  	}
   350  
   351  	ld.Adddynsym(ldr, target, syms, s)
   352  
   353  	if target.IsElf() {
   354  		plt := ldr.MakeSymbolUpdater(syms.PLT)
   355  		gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
   356  		rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
   357  		if plt.Size() == 0 {
   358  			panic("plt is not set up")
   359  		}
   360  
   361  		// pcalau12i $r15, imm
   362  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
   363  		plt.SetUint32(target.Arch, plt.Size()-4, 0x1a00000f)
   364  		relocs := plt.Relocs()
   365  		plt.SetRelocType(relocs.Count()-1, objabi.R_LOONG64_ADDR_HI)
   366  
   367  		// ld.d $r15, $r15, imm
   368  		plt.AddAddrPlus4(target.Arch, gotplt.Sym(), gotplt.Size())
   369  		plt.SetUint32(target.Arch, plt.Size()-4, 0x28c001ef)
   370  		relocs = plt.Relocs()
   371  		plt.SetRelocType(relocs.Count()-1, objabi.R_LOONG64_ADDR_LO)
   372  
   373  		// pcaddu12i $r13, 0
   374  		plt.AddUint32(target.Arch, 0x1c00000d)
   375  
   376  		// jirl r0, r15, 0
   377  		plt.AddUint32(target.Arch, 0x4c0001e0)
   378  
   379  		// add to got.plt: pointer to plt[0]
   380  		gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
   381  
   382  		// rela
   383  		rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
   384  		sDynid := ldr.SymDynid(s)
   385  		rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_LARCH_JUMP_SLOT)))
   386  		rela.AddUint64(target.Arch, 0)
   387  
   388  		ldr.SetPlt(s, int32(plt.Size()-16))
   389  	} else {
   390  		ldr.Errorf(s, "addpltsym: unsupport binary format")
   391  	}
   392  }
   393  
   394  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
   395  	// loong64 ELF relocation (endian neutral)
   396  	//		offset     uint64
   397  	//		symreloc   uint64  // The high 32-bit is the symbol, the low 32-bit is the relocation type.
   398  	//		addend     int64
   399  
   400  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
   401  	switch r.Type {
   402  	default:
   403  		return false
   404  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
   405  		switch r.Size {
   406  		case 4:
   407  			out.Write64(uint64(sectoff))
   408  			out.Write64(uint64(elf.R_LARCH_32) | uint64(elfsym)<<32)
   409  			out.Write64(uint64(r.Xadd))
   410  		case 8:
   411  			out.Write64(uint64(sectoff))
   412  			out.Write64(uint64(elf.R_LARCH_64) | uint64(elfsym)<<32)
   413  			out.Write64(uint64(r.Xadd))
   414  		default:
   415  			return false
   416  		}
   417  	case objabi.R_LOONG64_TLS_LE_LO:
   418  		out.Write64(uint64(sectoff))
   419  		out.Write64(uint64(elf.R_LARCH_TLS_LE_LO12) | uint64(elfsym)<<32)
   420  		out.Write64(uint64(r.Xadd))
   421  
   422  	case objabi.R_LOONG64_TLS_LE_HI:
   423  		out.Write64(uint64(sectoff))
   424  		out.Write64(uint64(elf.R_LARCH_TLS_LE_HI20) | uint64(elfsym)<<32)
   425  		out.Write64(uint64(r.Xadd))
   426  
   427  	case objabi.R_CALLLOONG64:
   428  		out.Write64(uint64(sectoff))
   429  		out.Write64(uint64(elf.R_LARCH_B26) | uint64(elfsym)<<32)
   430  		out.Write64(uint64(r.Xadd))
   431  
   432  	case objabi.R_LOONG64_CALL36:
   433  		out.Write64(uint64(sectoff))
   434  		out.Write64(uint64(elf.R_LARCH_CALL36) | uint64(elfsym)<<32)
   435  		out.Write64(uint64(r.Xadd))
   436  
   437  	case objabi.R_LOONG64_TLS_IE_HI:
   438  		out.Write64(uint64(sectoff))
   439  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_HI20) | uint64(elfsym)<<32)
   440  		out.Write64(uint64(0x0))
   441  
   442  	case objabi.R_LOONG64_TLS_IE_LO:
   443  		out.Write64(uint64(sectoff))
   444  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_LO12) | uint64(elfsym)<<32)
   445  		out.Write64(uint64(0x0))
   446  
   447  	case objabi.R_LOONG64_ADDR_LO:
   448  		out.Write64(uint64(sectoff))
   449  		out.Write64(uint64(elf.R_LARCH_PCALA_LO12) | uint64(elfsym)<<32)
   450  		out.Write64(uint64(r.Xadd))
   451  
   452  	case objabi.R_LOONG64_ADDR_HI:
   453  		out.Write64(uint64(sectoff))
   454  		out.Write64(uint64(elf.R_LARCH_PCALA_HI20) | uint64(elfsym)<<32)
   455  		out.Write64(uint64(r.Xadd))
   456  
   457  	case objabi.R_LOONG64_ADDR_PCREL20_S2:
   458  		out.Write64(uint64(sectoff))
   459  		out.Write64(uint64(elf.R_LARCH_PCREL20_S2) | uint64(elfsym)<<32)
   460  		out.Write64(uint64(r.Xadd))
   461  
   462  	case objabi.R_LOONG64_GOT_HI:
   463  		out.Write64(uint64(sectoff))
   464  		out.Write64(uint64(elf.R_LARCH_GOT_PC_HI20) | uint64(elfsym)<<32)
   465  		out.Write64(uint64(0x0))
   466  
   467  	case objabi.R_LOONG64_GOT_LO:
   468  		out.Write64(uint64(sectoff))
   469  		out.Write64(uint64(elf.R_LARCH_GOT_PC_LO12) | uint64(elfsym)<<32)
   470  		out.Write64(uint64(0x0))
   471  	}
   472  
   473  	return true
   474  }
   475  
   476  func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
   477  	return false
   478  }
   479  
   480  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) {
   481  	rs := r.Sym()
   482  	if target.IsExternal() {
   483  		switch r.Type() {
   484  		default:
   485  			return val, 0, false
   486  		case objabi.R_LOONG64_ADDR_HI,
   487  			objabi.R_LOONG64_ADDR_LO,
   488  			objabi.R_LOONG64_ADDR_PCREL20_S2:
   489  			// set up addend for eventual relocation via outer symbol.
   490  			rs, _ := ld.FoldSubSymbolOffset(ldr, rs)
   491  			rst := ldr.SymType(rs)
   492  			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
   493  				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
   494  			}
   495  			return val, 1, true
   496  		case objabi.R_LOONG64_TLS_LE_HI,
   497  			objabi.R_LOONG64_TLS_LE_LO,
   498  			objabi.R_CALLLOONG64,
   499  			objabi.R_LOONG64_CALL36,
   500  			objabi.R_JMPLOONG64,
   501  			objabi.R_LOONG64_TLS_IE_HI,
   502  			objabi.R_LOONG64_TLS_IE_LO,
   503  			objabi.R_LOONG64_GOT_HI,
   504  			objabi.R_LOONG64_GOT_LO:
   505  			return val, 1, true
   506  		}
   507  	}
   508  
   509  	const isOk = true
   510  	const noExtReloc = 0
   511  
   512  	switch r.Type() {
   513  	case objabi.R_CONST:
   514  		return r.Add(), noExtReloc, isOk
   515  	case objabi.R_GOTOFF:
   516  		return ldr.SymValue(r.Sym()) + r.Add() - ldr.SymValue(syms.GOT), noExtReloc, isOk
   517  	case objabi.R_LOONG64_ADDR_HI,
   518  		objabi.R_LOONG64_ADDR_LO:
   519  		pc := ldr.SymValue(s) + int64(r.Off())
   520  		t := calculatePCAlignedReloc(r.Type(), ldr.SymAddr(rs)+r.Add(), pc)
   521  		if r.Type() == objabi.R_LOONG64_ADDR_LO {
   522  			return val&0xffc003ff | (t << 10), noExtReloc, isOk
   523  		}
   524  		return val&0xfe00001f | (t << 5), noExtReloc, isOk
   525  	case objabi.R_LOONG64_ADDR_PCREL20_S2:
   526  		pc := ldr.SymValue(s) + int64(r.Off())
   527  		t := (ldr.SymAddr(rs) + r.Add() - pc) >> 2
   528  		return val&0xfe00001f | ((t & 0xfffff) << 5), noExtReloc, isOk
   529  	case objabi.R_LOONG64_TLS_LE_HI,
   530  		objabi.R_LOONG64_TLS_LE_LO:
   531  		t := ldr.SymAddr(rs) + r.Add()
   532  		if r.Type() == objabi.R_LOONG64_TLS_LE_LO {
   533  			return val&0xffc003ff | ((t & 0xfff) << 10), noExtReloc, isOk
   534  		}
   535  		return val&0xfe00001f | (((t) >> 12 << 5) & 0x1ffffe0), noExtReloc, isOk
   536  	case objabi.R_CALLLOONG64,
   537  		objabi.R_JMPLOONG64:
   538  		pc := ldr.SymValue(s) + int64(r.Off())
   539  		t := ldr.SymAddr(rs) + r.Add() - pc
   540  		return val&0xfc000000 | (((t >> 2) & 0xffff) << 10) | (((t >> 2) & 0x3ff0000) >> 16), noExtReloc, isOk
   541  
   542  	case objabi.R_LOONG64_CALL36:
   543  		pc := ldr.SymValue(s) + int64(r.Off())
   544  		t := (ldr.SymAddr(rs) + r.Add() - pc) >> 2
   545  		// val is pcaddu18i (lower half) + jirl (upper half)
   546  		pcaddu18i := (val & 0xfe00001f) | (((t + 0x8000) >> 16) << 5)
   547  		jirl := ((val >> 32) & 0xfc0003ff) | ((t & 0xffff) << 10)
   548  		return pcaddu18i | (jirl << 32), noExtReloc, isOk
   549  
   550  	case objabi.R_JMP16LOONG64,
   551  		objabi.R_JMP21LOONG64:
   552  		pc := ldr.SymValue(s) + int64(r.Off())
   553  		t := ldr.SymAddr(rs) + r.Add() - pc
   554  		if r.Type() == objabi.R_JMP16LOONG64 {
   555  			return val&0xfc0003ff | (((t >> 2) & 0xffff) << 10), noExtReloc, isOk
   556  		}
   557  		return val&0xfc0003e0 | (((t >> 2) & 0xffff) << 10) | (((t >> 2) & 0x1f0000) >> 16), noExtReloc, isOk
   558  
   559  	case objabi.R_LOONG64_TLS_IE_HI,
   560  		objabi.R_LOONG64_TLS_IE_LO:
   561  		if target.IsPIE() && target.IsElf() {
   562  			if !target.IsLinux() {
   563  				ldr.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
   564  			}
   565  			t := ldr.SymAddr(rs) + r.Add()
   566  			if r.Type() == objabi.R_LOONG64_TLS_IE_HI {
   567  				// pcalau12i -> lu12i.w
   568  				return (0x14000000 | (val & 0x1f) | ((t >> 12) << 5)), noExtReloc, isOk
   569  			}
   570  			// ld.d -> ori
   571  			return (0x03800000 | (val & 0x3ff) | ((t & 0xfff) << 10)), noExtReloc, isOk
   572  		} else {
   573  			log.Fatalf("cannot handle R_LOONG64_TLS_IE_x (sym %s) when linking internally", ldr.SymName(rs))
   574  		}
   575  
   576  	case objabi.R_LOONG64_ADD64, objabi.R_LOONG64_SUB64:
   577  		if r.Type() == objabi.R_LOONG64_ADD64 {
   578  			return val + ldr.SymAddr(rs) + r.Add(), noExtReloc, isOk
   579  		}
   580  		return val - (ldr.SymAddr(rs) + r.Add()), noExtReloc, isOk
   581  	}
   582  
   583  	return val, 0, false
   584  }
   585  
   586  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   587  	return -1
   588  }
   589  
   590  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   591  	switch r.Type() {
   592  	case objabi.R_LOONG64_ADDR_HI,
   593  		objabi.R_LOONG64_ADDR_LO,
   594  		objabi.R_LOONG64_GOT_HI,
   595  		objabi.R_LOONG64_GOT_LO:
   596  		return ld.ExtrelocViaOuterSym(ldr, r, s), true
   597  
   598  	case objabi.R_LOONG64_TLS_LE_HI,
   599  		objabi.R_LOONG64_TLS_LE_LO,
   600  		objabi.R_CONST,
   601  		objabi.R_GOTOFF,
   602  		objabi.R_CALLLOONG64,
   603  		objabi.R_JMPLOONG64,
   604  		objabi.R_LOONG64_TLS_IE_HI,
   605  		objabi.R_LOONG64_TLS_IE_LO:
   606  		return ld.ExtrelocSimple(ldr, r), true
   607  	}
   608  	return loader.ExtReloc{}, false
   609  }
   610  
   611  func isRequestingLowPageBits(t objabi.RelocType) bool {
   612  	switch t {
   613  	case objabi.R_LOONG64_ADDR_LO:
   614  		return true
   615  	}
   616  	return false
   617  }
   618  
   619  // Calculates the value to put into the immediate slot, according to the
   620  // desired relocation type, target and PC.
   621  // The value to use varies based on the reloc type. Namely, the absolute low
   622  // bits of the target are to be used for the low part, while the page-aligned
   623  // offset is to be used for the higher part. A "page" here is not related to
   624  // the system's actual page size, but rather a fixed 12-bit range (designed to
   625  // cooperate with ADDI/LD/ST's 12-bit immediates).
   626  func calculatePCAlignedReloc(t objabi.RelocType, tgt int64, pc int64) int64 {
   627  	if isRequestingLowPageBits(t) {
   628  		// corresponding immediate field is 12 bits wide
   629  		return tgt & 0xfff
   630  	}
   631  
   632  	pageDelta := (tgt >> 12) - (pc >> 12)
   633  	if tgt&0xfff >= 0x800 {
   634  		// adjust for sign-extended addition of the low bits
   635  		pageDelta += 1
   636  	}
   637  	// corresponding immediate field is 20 bits wide
   638  	return pageDelta & 0xfffff
   639  }
   640  
   641  // Convert the direct jump relocation r to refer to a trampoline if the target is too far.
   642  func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
   643  	relocs := ldr.Relocs(s)
   644  	r := relocs.At(ri)
   645  	switch r.Type() {
   646  	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_LARCH_B26), objabi.R_CALLLOONG64:
   647  		if ldr.SymType(rs) == sym.SDYNIMPORT {
   648  			// Nothing to do.
   649  			// The plt symbol has not been added. If we add tramp
   650  			// here, plt will not work.
   651  			return
   652  		}
   653  
   654  		var t int64
   655  		// ldr.SymValue(rs) == 0 indicates a cross-package jump to a function that is not yet
   656  		// laid out. Conservatively use a trampoline. This should be rare, as we lay out packages
   657  		// in dependency order.
   658  		if ldr.SymValue(rs) != 0 {
   659  			t = ldr.SymValue(rs) + r.Add() - (ldr.SymValue(s) + int64(r.Off()))
   660  		}
   661  		if t >= 1<<27 || t < -1<<27 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && (ldr.SymPkg(s) == "" || ldr.SymPkg(s) != ldr.SymPkg(rs))) {
   662  			// direct call too far need to insert trampoline.
   663  			// look up existing trampolines first. if we found one within the range
   664  			// of direct call, we can reuse it. otherwise create a new one.
   665  			var tramp loader.Sym
   666  			for i := 0; ; i++ {
   667  				oName := ldr.SymName(rs)
   668  				name := oName + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
   669  				tramp = ldr.LookupOrCreateSym(name, ldr.SymVersion(rs))
   670  				ldr.SetAttrReachable(tramp, true)
   671  				if ldr.SymType(tramp) == sym.SDYNIMPORT {
   672  					// don't reuse trampoline defined in other module
   673  					continue
   674  				}
   675  				if oName == "runtime.deferreturn" {
   676  					ldr.SetIsDeferReturnTramp(tramp, true)
   677  				}
   678  				if ldr.SymValue(tramp) == 0 {
   679  					// either the trampoline does not exist -- we need to create one,
   680  					// or found one the address which is not assigned -- this will be
   681  					// laid down immediately after the current function. use this one.
   682  					break
   683  				}
   684  
   685  				t = ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
   686  				if t >= -1<<27 && t < 1<<27 {
   687  					// found an existing trampoline that is not too far
   688  					// we can just use it.
   689  					break
   690  				}
   691  			}
   692  			if ldr.SymType(tramp) == 0 {
   693  				// trampoline does not exist, create one
   694  				trampb := ldr.MakeSymbolUpdater(tramp)
   695  				ctxt.AddTramp(trampb, ldr.SymType(s))
   696  				if ldr.SymType(rs) == sym.SDYNIMPORT {
   697  					if r.Add() != 0 {
   698  						ctxt.Errorf(s, "nonzero addend for DYNIMPORT call: %v+%d", ldr.SymName(rs), r.Add())
   699  					}
   700  					gentrampgot(ctxt, ldr, trampb, rs)
   701  				} else {
   702  					gentramp(ctxt, ldr, trampb, rs, r.Add())
   703  				}
   704  			}
   705  			// modify reloc to point to tramp, which will be resolved later
   706  			sb := ldr.MakeSymbolUpdater(s)
   707  			relocs := sb.Relocs()
   708  			r := relocs.At(ri)
   709  			r.SetSym(tramp)
   710  			r.SetAdd(0) // clear the offset embedded in the instruction
   711  		}
   712  	default:
   713  		ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
   714  	}
   715  }
   716  
   717  // generate a trampoline to target+offset.
   718  func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
   719  	tramp.SetSize(12) // 3 instructions
   720  	P := make([]byte, tramp.Size())
   721  
   722  	o1 := uint32(0x1a00001e) // pcalau12i $r30, 0
   723  	ctxt.Arch.ByteOrder.PutUint32(P, o1)
   724  	r1, _ := tramp.AddRel(objabi.R_LOONG64_ADDR_HI)
   725  	r1.SetOff(0)
   726  	r1.SetSiz(4)
   727  	r1.SetSym(target)
   728  	r1.SetAdd(offset)
   729  
   730  	o2 := uint32(0x02c003de) // addi.d $r30, $r30, 0
   731  	ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
   732  	r2, _ := tramp.AddRel(objabi.R_LOONG64_ADDR_LO)
   733  	r2.SetOff(4)
   734  	r2.SetSiz(4)
   735  	r2.SetSym(target)
   736  	r2.SetAdd(offset)
   737  
   738  	o3 := uint32(0x4c0003c0) // jirl $r0, $r30, 0
   739  	ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
   740  
   741  	tramp.SetData(P)
   742  }
   743  
   744  func gentrampgot(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym) {
   745  	tramp.SetSize(12) // 3 instructions
   746  	P := make([]byte, tramp.Size())
   747  
   748  	o1 := uint32(0x1a00001e) // pcalau12i $r30, 0
   749  	ctxt.Arch.ByteOrder.PutUint32(P, o1)
   750  	r1, _ := tramp.AddRel(objabi.R_LOONG64_GOT_HI)
   751  	r1.SetOff(0)
   752  	r1.SetSiz(4)
   753  	r1.SetSym(target)
   754  
   755  	o2 := uint32(0x28c003de) // ld.d $r30, $r30, 0
   756  	ctxt.Arch.ByteOrder.PutUint32(P[4:], o2)
   757  	r2, _ := tramp.AddRel(objabi.R_LOONG64_GOT_LO)
   758  	r2.SetOff(4)
   759  	r2.SetSiz(4)
   760  	r2.SetSym(target)
   761  
   762  	o3 := uint32(0x4c0003c0) // jirl $r0, $r30, 0
   763  	ctxt.Arch.ByteOrder.PutUint32(P[8:], o3)
   764  
   765  	tramp.SetData(P)
   766  }
   767  

View as plain text