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

View as plain text