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

View as plain text