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  	"log"
    15  )
    16  
    17  func gentext(ctxt *ld.Link, ldr *loader.Loader) {
    18  	initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
    19  	if initfunc == nil {
    20  		return
    21  	}
    22  
    23  	o := func(op uint32) {
    24  		initfunc.AddUint32(ctxt.Arch, op)
    25  	}
    26  
    27  	// Emit the following function:
    28  	//
    29  	//	local.dso_init:
    30  	//		la.pcrel $a0, local.moduledata
    31  	//		b runtime.addmoduledata
    32  
    33  	//	0000000000000000 <local.dso_init>:
    34  	//	0:	1a000004	pcalau12i	$a0, 0
    35  	//				0: R_LARCH_PCALA_HI20	local.moduledata
    36  	o(0x1a000004)
    37  	rel, _ := initfunc.AddRel(objabi.R_LOONG64_ADDR_HI)
    38  	rel.SetOff(0)
    39  	rel.SetSiz(4)
    40  	rel.SetSym(ctxt.Moduledata)
    41  
    42  	//	4:	02c00084	addi.d	$a0, $a0, 0
    43  	//				4: R_LARCH_PCALA_LO12	local.moduledata
    44  	o(0x02c00084)
    45  	rel2, _ := initfunc.AddRel(objabi.R_LOONG64_ADDR_LO)
    46  	rel2.SetOff(4)
    47  	rel2.SetSiz(4)
    48  	rel2.SetSym(ctxt.Moduledata)
    49  
    50  	//	8:	50000000	b	0
    51  	//				8: R_LARCH_B26	runtime.addmoduledata
    52  	o(0x50000000)
    53  	rel3, _ := initfunc.AddRel(objabi.R_CALLLOONG64)
    54  	rel3.SetOff(8)
    55  	rel3.SetSiz(4)
    56  	rel3.SetSym(addmoduledata)
    57  }
    58  
    59  func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
    60  	log.Fatalf("adddynrel not implemented")
    61  	return false
    62  }
    63  
    64  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
    65  	// loong64 ELF relocation (endian neutral)
    66  	//		offset     uint64
    67  	//		symreloc   uint64  // The high 32-bit is the symbol, the low 32-bit is the relocation type.
    68  	//		addend     int64
    69  
    70  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
    71  	switch r.Type {
    72  	default:
    73  		return false
    74  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
    75  		switch r.Size {
    76  		case 4:
    77  			out.Write64(uint64(sectoff))
    78  			out.Write64(uint64(elf.R_LARCH_32) | uint64(elfsym)<<32)
    79  			out.Write64(uint64(r.Xadd))
    80  		case 8:
    81  			out.Write64(uint64(sectoff))
    82  			out.Write64(uint64(elf.R_LARCH_64) | uint64(elfsym)<<32)
    83  			out.Write64(uint64(r.Xadd))
    84  		default:
    85  			return false
    86  		}
    87  	case objabi.R_LOONG64_TLS_LE_LO:
    88  		out.Write64(uint64(sectoff))
    89  		out.Write64(uint64(elf.R_LARCH_TLS_LE_LO12) | uint64(elfsym)<<32)
    90  		out.Write64(uint64(r.Xadd))
    91  
    92  	case objabi.R_LOONG64_TLS_LE_HI:
    93  		out.Write64(uint64(sectoff))
    94  		out.Write64(uint64(elf.R_LARCH_TLS_LE_HI20) | uint64(elfsym)<<32)
    95  		out.Write64(uint64(r.Xadd))
    96  
    97  	case objabi.R_CALLLOONG64:
    98  		out.Write64(uint64(sectoff))
    99  		out.Write64(uint64(elf.R_LARCH_B26) | uint64(elfsym)<<32)
   100  		out.Write64(uint64(r.Xadd))
   101  
   102  	case objabi.R_LOONG64_TLS_IE_HI:
   103  		out.Write64(uint64(sectoff))
   104  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_HI20) | uint64(elfsym)<<32)
   105  		out.Write64(uint64(0x0))
   106  
   107  	case objabi.R_LOONG64_TLS_IE_LO:
   108  		out.Write64(uint64(sectoff))
   109  		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_LO12) | uint64(elfsym)<<32)
   110  		out.Write64(uint64(0x0))
   111  
   112  	case objabi.R_LOONG64_ADDR_LO:
   113  		out.Write64(uint64(sectoff))
   114  		out.Write64(uint64(elf.R_LARCH_PCALA_LO12) | uint64(elfsym)<<32)
   115  		out.Write64(uint64(r.Xadd))
   116  
   117  	case objabi.R_LOONG64_ADDR_HI:
   118  		out.Write64(uint64(sectoff))
   119  		out.Write64(uint64(elf.R_LARCH_PCALA_HI20) | uint64(elfsym)<<32)
   120  		out.Write64(uint64(r.Xadd))
   121  
   122  	case objabi.R_LOONG64_GOT_HI:
   123  		out.Write64(uint64(sectoff))
   124  		out.Write64(uint64(elf.R_LARCH_GOT_PC_HI20) | uint64(elfsym)<<32)
   125  		out.Write64(uint64(0x0))
   126  
   127  	case objabi.R_LOONG64_GOT_LO:
   128  		out.Write64(uint64(sectoff))
   129  		out.Write64(uint64(elf.R_LARCH_GOT_PC_LO12) | uint64(elfsym)<<32)
   130  		out.Write64(uint64(0x0))
   131  	}
   132  
   133  	return true
   134  }
   135  
   136  func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
   137  	return
   138  }
   139  
   140  func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
   141  	return false
   142  }
   143  
   144  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) {
   145  	rs := r.Sym()
   146  	if target.IsExternal() {
   147  		switch r.Type() {
   148  		default:
   149  			return val, 0, false
   150  		case objabi.R_LOONG64_ADDR_HI,
   151  			objabi.R_LOONG64_ADDR_LO:
   152  			// set up addend for eventual relocation via outer symbol.
   153  			rs, _ := ld.FoldSubSymbolOffset(ldr, rs)
   154  			rst := ldr.SymType(rs)
   155  			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
   156  				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
   157  			}
   158  			return val, 1, true
   159  		case objabi.R_LOONG64_TLS_LE_HI,
   160  			objabi.R_LOONG64_TLS_LE_LO,
   161  			objabi.R_CALLLOONG64,
   162  			objabi.R_JMPLOONG64,
   163  			objabi.R_LOONG64_TLS_IE_HI,
   164  			objabi.R_LOONG64_TLS_IE_LO,
   165  			objabi.R_LOONG64_GOT_HI,
   166  			objabi.R_LOONG64_GOT_LO:
   167  			return val, 1, true
   168  		}
   169  	}
   170  
   171  	const isOk = true
   172  	const noExtReloc = 0
   173  
   174  	switch r.Type() {
   175  	case objabi.R_CONST:
   176  		return r.Add(), noExtReloc, isOk
   177  	case objabi.R_GOTOFF:
   178  		return ldr.SymValue(r.Sym()) + r.Add() - ldr.SymValue(syms.GOT), noExtReloc, isOk
   179  	case objabi.R_LOONG64_ADDR_HI,
   180  		objabi.R_LOONG64_ADDR_LO:
   181  		pc := ldr.SymValue(s) + int64(r.Off())
   182  		t := calculatePCAlignedReloc(r.Type(), ldr.SymAddr(rs)+r.Add(), pc)
   183  		if r.Type() == objabi.R_LOONG64_ADDR_LO {
   184  			return int64(val&0xffc003ff | (t << 10)), noExtReloc, isOk
   185  		}
   186  		return int64(val&0xfe00001f | (t << 5)), noExtReloc, isOk
   187  	case objabi.R_LOONG64_TLS_LE_HI,
   188  		objabi.R_LOONG64_TLS_LE_LO:
   189  		t := ldr.SymAddr(rs) + r.Add()
   190  		if r.Type() == objabi.R_LOONG64_TLS_LE_LO {
   191  			return int64(val&0xffc003ff | ((t & 0xfff) << 10)), noExtReloc, isOk
   192  		}
   193  		return int64(val&0xfe00001f | (((t) >> 12 << 5) & 0x1ffffe0)), noExtReloc, isOk
   194  	case objabi.R_CALLLOONG64,
   195  		objabi.R_JMPLOONG64:
   196  		pc := ldr.SymValue(s) + int64(r.Off())
   197  		t := ldr.SymAddr(rs) + r.Add() - pc
   198  		return int64(val&0xfc000000 | (((t >> 2) & 0xffff) << 10) | (((t >> 2) & 0x3ff0000) >> 16)), noExtReloc, isOk
   199  	}
   200  
   201  	return val, 0, false
   202  }
   203  
   204  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   205  	return -1
   206  }
   207  
   208  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   209  	switch r.Type() {
   210  	case objabi.R_LOONG64_ADDR_HI,
   211  		objabi.R_LOONG64_ADDR_LO,
   212  		objabi.R_LOONG64_GOT_HI,
   213  		objabi.R_LOONG64_GOT_LO:
   214  		return ld.ExtrelocViaOuterSym(ldr, r, s), true
   215  
   216  	case objabi.R_LOONG64_TLS_LE_HI,
   217  		objabi.R_LOONG64_TLS_LE_LO,
   218  		objabi.R_CONST,
   219  		objabi.R_GOTOFF,
   220  		objabi.R_CALLLOONG64,
   221  		objabi.R_JMPLOONG64,
   222  		objabi.R_LOONG64_TLS_IE_HI,
   223  		objabi.R_LOONG64_TLS_IE_LO:
   224  		return ld.ExtrelocSimple(ldr, r), true
   225  	}
   226  	return loader.ExtReloc{}, false
   227  }
   228  
   229  func isRequestingLowPageBits(t objabi.RelocType) bool {
   230  	switch t {
   231  	case objabi.R_LOONG64_ADDR_LO:
   232  		return true
   233  	}
   234  	return false
   235  }
   236  
   237  // Calculates the value to put into the immediate slot, according to the
   238  // desired relocation type, target and PC.
   239  // The value to use varies based on the reloc type. Namely, the absolute low
   240  // bits of the target are to be used for the low part, while the page-aligned
   241  // offset is to be used for the higher part. A "page" here is not related to
   242  // the system's actual page size, but rather a fixed 12-bit range (designed to
   243  // cooperate with ADDI/LD/ST's 12-bit immediates).
   244  func calculatePCAlignedReloc(t objabi.RelocType, tgt int64, pc int64) int64 {
   245  	if isRequestingLowPageBits(t) {
   246  		// corresponding immediate field is 12 bits wide
   247  		return tgt & 0xfff
   248  	}
   249  
   250  	pageDelta := (tgt >> 12) - (pc >> 12)
   251  	if tgt&0xfff >= 0x800 {
   252  		// adjust for sign-extended addition of the low bits
   253  		pageDelta += 1
   254  	}
   255  	// corresponding immediate field is 20 bits wide
   256  	return pageDelta & 0xfffff
   257  }
   258  

View as plain text