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

     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  	"debug/elf"
     9  	"log"
    10  
    11  	"github.com/go-asm/go/cmd/link/ld"
    12  	"github.com/go-asm/go/cmd/link/loader"
    13  	"github.com/go-asm/go/cmd/link/sym"
    14  	"github.com/go-asm/go/cmd/objabi"
    15  	"github.com/go-asm/go/cmd/sys"
    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_ADDRLOONG64U)
    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_ADDRLOONG64)
    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  	log.Fatalf("adddynrel not implemented")
    62  	return false
    63  }
    64  
    65  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
    66  	// loong64 ELF relocation (endian neutral)
    67  	//		offset     uint64
    68  	//		symreloc   uint64  // The high 32-bit is the symbol, the low 32-bit is the relocation type.
    69  	//		addend     int64
    70  
    71  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
    72  	switch r.Type {
    73  	default:
    74  		return false
    75  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
    76  		switch r.Size {
    77  		case 4:
    78  			out.Write64(uint64(sectoff))
    79  			out.Write64(uint64(elf.R_LARCH_32) | uint64(elfsym)<<32)
    80  			out.Write64(uint64(r.Xadd))
    81  		case 8:
    82  			out.Write64(uint64(sectoff))
    83  			out.Write64(uint64(elf.R_LARCH_64) | uint64(elfsym)<<32)
    84  			out.Write64(uint64(r.Xadd))
    85  		default:
    86  			return false
    87  		}
    88  	case objabi.R_ADDRLOONG64TLS:
    89  		out.Write64(uint64(sectoff))
    90  		out.Write64(uint64(elf.R_LARCH_TLS_LE_LO12) | uint64(elfsym)<<32)
    91  		out.Write64(uint64(r.Xadd))
    92  
    93  	case objabi.R_ADDRLOONG64TLSU:
    94  		out.Write64(uint64(sectoff))
    95  		out.Write64(uint64(elf.R_LARCH_TLS_LE_HI20) | uint64(elfsym)<<32)
    96  		out.Write64(uint64(r.Xadd))
    97  
    98  	case objabi.R_CALLLOONG64:
    99  		out.Write64(uint64(sectoff))
   100  		out.Write64(uint64(elf.R_LARCH_B26) | uint64(elfsym)<<32)
   101  		out.Write64(uint64(r.Xadd))
   102  
   103  	case objabi.R_LOONG64_TLS_IE_PCREL_HI:
   104  		out.Write64(uint64(sectoff))
   105  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_HI20) | uint64(elfsym)<<32)
   106  		out.Write64(uint64(0x0))
   107  
   108  	case objabi.R_LOONG64_TLS_IE_LO:
   109  		out.Write64(uint64(sectoff))
   110  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_LO12) | uint64(elfsym)<<32)
   111  		out.Write64(uint64(0x0))
   112  
   113  	case objabi.R_ADDRLOONG64:
   114  		out.Write64(uint64(sectoff))
   115  		out.Write64(uint64(elf.R_LARCH_PCALA_LO12) | uint64(elfsym)<<32)
   116  		out.Write64(uint64(r.Xadd))
   117  
   118  	case objabi.R_ADDRLOONG64U:
   119  		out.Write64(uint64(sectoff))
   120  		out.Write64(uint64(elf.R_LARCH_PCALA_HI20) | uint64(elfsym)<<32)
   121  		out.Write64(uint64(r.Xadd))
   122  
   123  	case objabi.R_LOONG64_GOT_HI:
   124  		out.Write64(uint64(sectoff))
   125  		out.Write64(uint64(elf.R_LARCH_GOT_PC_HI20) | uint64(elfsym)<<32)
   126  		out.Write64(uint64(0x0))
   127  
   128  	case objabi.R_LOONG64_GOT_LO:
   129  		out.Write64(uint64(sectoff))
   130  		out.Write64(uint64(elf.R_LARCH_GOT_PC_LO12) | uint64(elfsym)<<32)
   131  		out.Write64(uint64(0x0))
   132  	}
   133  
   134  	return true
   135  }
   136  
   137  func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   138  	return
   139  }
   140  
   141  func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
   142  	return false
   143  }
   144  
   145  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) {
   146  	rs := r.Sym()
   147  	if target.IsExternal() {
   148  		switch r.Type() {
   149  		default:
   150  			return val, 0, false
   151  		case objabi.R_ADDRLOONG64,
   152  			objabi.R_ADDRLOONG64U:
   153  			// set up addend for eventual relocation via outer symbol.
   154  			rs, _ := ld.FoldSubSymbolOffset(ldr, rs)
   155  			rst := ldr.SymType(rs)
   156  			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
   157  				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
   158  			}
   159  			return val, 1, true
   160  		case objabi.R_ADDRLOONG64TLS,
   161  			objabi.R_ADDRLOONG64TLSU,
   162  			objabi.R_CALLLOONG64,
   163  			objabi.R_JMPLOONG64,
   164  			objabi.R_LOONG64_TLS_IE_PCREL_HI,
   165  			objabi.R_LOONG64_TLS_IE_LO,
   166  			objabi.R_LOONG64_GOT_HI,
   167  			objabi.R_LOONG64_GOT_LO:
   168  			return val, 1, true
   169  		}
   170  	}
   171  
   172  	const isOk = true
   173  	const noExtReloc = 0
   174  
   175  	switch r.Type() {
   176  	case objabi.R_CONST:
   177  		return r.Add(), noExtReloc, isOk
   178  	case objabi.R_GOTOFF:
   179  		return ldr.SymValue(r.Sym()) + r.Add() - ldr.SymValue(syms.GOT), noExtReloc, isOk
   180  	case objabi.R_ADDRLOONG64,
   181  		objabi.R_ADDRLOONG64U:
   182  		pc := ldr.SymValue(s) + int64(r.Off())
   183  		t := calculatePCAlignedReloc(r.Type(), ldr.SymAddr(rs)+r.Add(), pc)
   184  		if r.Type() == objabi.R_ADDRLOONG64 {
   185  			return int64(val&0xffc003ff | (t << 10)), noExtReloc, isOk
   186  		}
   187  		return int64(val&0xfe00001f | (t << 5)), noExtReloc, isOk
   188  	case objabi.R_ADDRLOONG64TLS,
   189  		objabi.R_ADDRLOONG64TLSU:
   190  		t := ldr.SymAddr(rs) + r.Add()
   191  		if r.Type() == objabi.R_ADDRLOONG64TLS {
   192  			return int64(val&0xffc003ff | ((t & 0xfff) << 10)), noExtReloc, isOk
   193  		}
   194  		return int64(val&0xfe00001f | (((t) >> 12 << 5) & 0x1ffffe0)), noExtReloc, isOk
   195  	case objabi.R_CALLLOONG64,
   196  		objabi.R_JMPLOONG64:
   197  		pc := ldr.SymValue(s) + int64(r.Off())
   198  		t := ldr.SymAddr(rs) + r.Add() - pc
   199  		return int64(val&0xfc000000 | (((t >> 2) & 0xffff) << 10) | (((t >> 2) & 0x3ff0000) >> 16)), noExtReloc, isOk
   200  	}
   201  
   202  	return val, 0, false
   203  }
   204  
   205  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   206  	return -1
   207  }
   208  
   209  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   210  	switch r.Type() {
   211  	case objabi.R_ADDRLOONG64,
   212  		objabi.R_ADDRLOONG64U,
   213  		objabi.R_LOONG64_GOT_HI,
   214  		objabi.R_LOONG64_GOT_LO:
   215  
   216  		return ld.ExtrelocViaOuterSym(ldr, r, s), true
   217  
   218  	case objabi.R_ADDRLOONG64TLS,
   219  		objabi.R_ADDRLOONG64TLSU,
   220  		objabi.R_CONST,
   221  		objabi.R_GOTOFF,
   222  		objabi.R_CALLLOONG64,
   223  		objabi.R_JMPLOONG64,
   224  		objabi.R_LOONG64_TLS_IE_PCREL_HI,
   225  		objabi.R_LOONG64_TLS_IE_LO:
   226  		return ld.ExtrelocSimple(ldr, r), true
   227  	}
   228  	return loader.ExtReloc{}, false
   229  }
   230  
   231  func isRequestingLowPageBits(t objabi.RelocType) bool {
   232  	switch t {
   233  	case objabi.R_ADDRLOONG64:
   234  		return true
   235  	}
   236  	return false
   237  }
   238  
   239  // Calculates the value to put into the immediate slot, according to the
   240  // desired relocation type, target and PC.
   241  // The value to use varies based on the reloc type. Namely, the absolute low
   242  // bits of the target are to be used for the low part, while the page-aligned
   243  // offset is to be used for the higher part. A "page" here is not related to
   244  // the system's actual page size, but rather a fixed 12-bit range (designed to
   245  // cooperate with ADDI/LD/ST's 12-bit immediates).
   246  func calculatePCAlignedReloc(t objabi.RelocType, tgt int64, pc int64) int64 {
   247  	if isRequestingLowPageBits(t) {
   248  		// corresponding immediate field is 12 bits wide
   249  		return tgt & 0xfff
   250  	}
   251  
   252  	pageDelta := (tgt >> 12) - (pc >> 12)
   253  	if tgt&0xfff >= 0x800 {
   254  		// adjust for sign-extended addition of the low bits
   255  		pageDelta += 1
   256  	}
   257  	// corresponding immediate field is 20 bits wide
   258  	return pageDelta & 0xfffff
   259  }