// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package loong64

import (
	"cmd/internal/objabi"
	"cmd/internal/sys"
	"cmd/link/internal/ld"
	"cmd/link/internal/loader"
	"cmd/link/internal/sym"
	"debug/elf"
	"log"
)

func gentext(ctxt *ld.Link, ldr *loader.Loader) {}

func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
	log.Fatalf("adddynrel not implemented")
	return false
}

func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
	// loong64 ELF relocation (endian neutral)
	//		offset     uint64
	//		symreloc   uint64  // The high 32-bit is the symbol, the low 32-bit is the relocation type.
	//		addend     int64

	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
	switch r.Type {
	default:
		return false
	case objabi.R_ADDR, objabi.R_DWARFSECREF:
		switch r.Size {
		case 4:
			out.Write64(uint64(sectoff))
			out.Write64(uint64(elf.R_LARCH_32) | uint64(elfsym)<<32)
			out.Write64(uint64(r.Xadd))
		case 8:
			out.Write64(uint64(sectoff))
			out.Write64(uint64(elf.R_LARCH_64) | uint64(elfsym)<<32)
			out.Write64(uint64(r.Xadd))
		default:
			return false
		}
	case objabi.R_ADDRLOONG64TLS:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_TLS_LE_LO12) | uint64(elfsym)<<32)
		out.Write64(uint64(r.Xadd))

	case objabi.R_ADDRLOONG64TLSU:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_TLS_LE_HI20) | uint64(elfsym)<<32)
		out.Write64(uint64(r.Xadd))

	case objabi.R_CALLLOONG64:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_B26) | uint64(elfsym)<<32)
		out.Write64(uint64(r.Xadd))

	case objabi.R_LOONG64_TLS_IE_PCREL_HI:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_HI20) | uint64(elfsym)<<32)
		out.Write64(uint64(0x0))

	case objabi.R_LOONG64_TLS_IE_LO:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_TLS_IE_PC_LO12) | uint64(elfsym)<<32)
		out.Write64(uint64(0x0))

	case objabi.R_ADDRLOONG64:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_PCALA_LO12) | uint64(elfsym)<<32)
		out.Write64(uint64(r.Xadd))

	case objabi.R_ADDRLOONG64U:
		out.Write64(uint64(sectoff))
		out.Write64(uint64(elf.R_LARCH_PCALA_HI20) | uint64(elfsym)<<32)
		out.Write64(uint64(r.Xadd))
	}

	return true
}

func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
	return
}

func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
	return false
}

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) {
	rs := r.Sym()
	if target.IsExternal() {
		switch r.Type() {
		default:
			return val, 0, false
		case objabi.R_ADDRLOONG64,
			objabi.R_ADDRLOONG64U:
			// set up addend for eventual relocation via outer symbol.
			rs, _ := ld.FoldSubSymbolOffset(ldr, rs)
			rst := ldr.SymType(rs)
			if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
				ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
			}
			return val, 1, true
		case objabi.R_ADDRLOONG64TLS,
			objabi.R_ADDRLOONG64TLSU,
			objabi.R_CALLLOONG64,
			objabi.R_JMPLOONG64,
			objabi.R_LOONG64_TLS_IE_PCREL_HI,
			objabi.R_LOONG64_TLS_IE_LO:
			return val, 1, true
		}
	}

	const isOk = true
	const noExtReloc = 0

	switch r.Type() {
	case objabi.R_CONST:
		return r.Add(), noExtReloc, isOk
	case objabi.R_GOTOFF:
		return ldr.SymValue(r.Sym()) + r.Add() - ldr.SymValue(syms.GOT), noExtReloc, isOk
	case objabi.R_ADDRLOONG64,
		objabi.R_ADDRLOONG64U:
		pc := ldr.SymValue(s) + int64(r.Off())
		t := calculatePCAlignedReloc(r.Type(), ldr.SymAddr(rs)+r.Add(), pc)
		if r.Type() == objabi.R_ADDRLOONG64 {
			return int64(val&0xffc003ff | (t << 10)), noExtReloc, isOk
		}
		return int64(val&0xfe00001f | (t << 5)), noExtReloc, isOk
	case objabi.R_ADDRLOONG64TLS,
		objabi.R_ADDRLOONG64TLSU:
		t := ldr.SymAddr(rs) + r.Add()
		if r.Type() == objabi.R_ADDRLOONG64TLS {
			return int64(val&0xffc003ff | ((t & 0xfff) << 10)), noExtReloc, isOk
		}
		return int64(val&0xfe00001f | (((t) >> 12 << 5) & 0x1ffffe0)), noExtReloc, isOk
	case objabi.R_CALLLOONG64,
		objabi.R_JMPLOONG64:
		pc := ldr.SymValue(s) + int64(r.Off())
		t := ldr.SymAddr(rs) + r.Add() - pc
		return int64(val&0xfc000000 | (((t >> 2) & 0xffff) << 10) | (((t >> 2) & 0x3ff0000) >> 16)), noExtReloc, isOk
	}

	return val, 0, false
}

func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
	return -1
}

func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
	switch r.Type() {
	case objabi.R_ADDRLOONG64,
		objabi.R_ADDRLOONG64U:
		return ld.ExtrelocViaOuterSym(ldr, r, s), true

	case objabi.R_ADDRLOONG64TLS,
		objabi.R_ADDRLOONG64TLSU,
		objabi.R_CONST,
		objabi.R_GOTOFF,
		objabi.R_CALLLOONG64,
		objabi.R_JMPLOONG64,
		objabi.R_LOONG64_TLS_IE_PCREL_HI,
		objabi.R_LOONG64_TLS_IE_LO:
		return ld.ExtrelocSimple(ldr, r), true
	}
	return loader.ExtReloc{}, false
}

func isRequestingLowPageBits(t objabi.RelocType) bool {
	switch t {
	case objabi.R_ADDRLOONG64:
		return true
	}
	return false
}

// Calculates the value to put into the immediate slot, according to the
// desired relocation type, target and PC.
// The value to use varies based on the reloc type. Namely, the absolute low
// bits of the target are to be used for the low part, while the page-aligned
// offset is to be used for the higher part. A "page" here is not related to
// the system's actual page size, but rather a fixed 12-bit range (designed to
// cooperate with ADDI/LD/ST's 12-bit immediates).
func calculatePCAlignedReloc(t objabi.RelocType, tgt int64, pc int64) int64 {
	if isRequestingLowPageBits(t) {
		// corresponding immediate field is 12 bits wide
		return tgt & 0xfff
	}

	pageDelta := (tgt >> 12) - (pc >> 12)
	if tgt&0xfff >= 0x800 {
		// adjust for sign-extended addition of the low bits
		pageDelta += 1
	}
	// corresponding immediate field is 20 bits wide
	return pageDelta & 0xfffff
}
