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

     1  // Inferno utils/5l/asm.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2016 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package mips
    32  
    33  import (
    34  	"debug/elf"
    35  
    36  	"github.com/go-asm/go/cmd/link/ld"
    37  	"github.com/go-asm/go/cmd/link/loader"
    38  	"github.com/go-asm/go/cmd/link/sym"
    39  	"github.com/go-asm/go/cmd/objabi"
    40  	"github.com/go-asm/go/cmd/sys"
    41  )
    42  
    43  func gentext(ctxt *ld.Link, ldr *loader.Loader) {
    44  	return
    45  }
    46  
    47  func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
    48  	out.Write32(uint32(sectoff))
    49  
    50  	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
    51  	switch r.Type {
    52  	default:
    53  		return false
    54  	case objabi.R_ADDR, objabi.R_DWARFSECREF:
    55  		if r.Size != 4 {
    56  			return false
    57  		}
    58  		out.Write32(uint32(elf.R_MIPS_32) | uint32(elfsym)<<8)
    59  	case objabi.R_ADDRMIPS:
    60  		out.Write32(uint32(elf.R_MIPS_LO16) | uint32(elfsym)<<8)
    61  	case objabi.R_ADDRMIPSU:
    62  		out.Write32(uint32(elf.R_MIPS_HI16) | uint32(elfsym)<<8)
    63  	case objabi.R_ADDRMIPSTLS:
    64  		out.Write32(uint32(elf.R_MIPS_TLS_TPREL_LO16) | uint32(elfsym)<<8)
    65  	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
    66  		out.Write32(uint32(elf.R_MIPS_26) | uint32(elfsym)<<8)
    67  	}
    68  
    69  	return true
    70  }
    71  
    72  func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
    73  	return
    74  }
    75  
    76  func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
    77  	return false
    78  }
    79  
    80  func applyrel(arch *sys.Arch, ldr *loader.Loader, rt objabi.RelocType, off int32, s loader.Sym, val int64, t int64) int64 {
    81  	o := uint32(val)
    82  	switch rt {
    83  	case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS:
    84  		return int64(o&0xffff0000 | uint32(t)&0xffff)
    85  	case objabi.R_ADDRMIPSU:
    86  		return int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff)
    87  	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
    88  		return int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000)
    89  	default:
    90  		return val
    91  	}
    92  }
    93  
    94  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) {
    95  	rs := r.Sym()
    96  	if target.IsExternal() {
    97  		switch r.Type() {
    98  		default:
    99  			return val, 0, false
   100  
   101  		case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
   102  			// set up addend for eventual relocation via outer symbol.
   103  			_, off := ld.FoldSubSymbolOffset(ldr, rs)
   104  			xadd := r.Add() + off
   105  			return applyrel(target.Arch, ldr, r.Type(), r.Off(), s, val, xadd), 1, true
   106  
   107  		case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS:
   108  			return applyrel(target.Arch, ldr, r.Type(), r.Off(), s, val, r.Add()), 1, true
   109  		}
   110  	}
   111  
   112  	const isOk = true
   113  	const noExtReloc = 0
   114  	switch rt := r.Type(); rt {
   115  	case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
   116  		t := ldr.SymValue(rs) + r.Add()
   117  		return applyrel(target.Arch, ldr, rt, r.Off(), s, val, t), noExtReloc, isOk
   118  	case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
   119  		t := ldr.SymValue(rs) + r.Add()
   120  
   121  		if t&3 != 0 {
   122  			ldr.Errorf(s, "direct call is not aligned: %s %x", ldr.SymName(rs), t)
   123  		}
   124  
   125  		// check if target address is in the same 256 MB region as the next instruction
   126  		if (ldr.SymValue(s)+int64(r.Off())+4)&0xf0000000 != (t & 0xf0000000) {
   127  			ldr.Errorf(s, "direct call too far: %s %x", ldr.SymName(rs), t)
   128  		}
   129  
   130  		return applyrel(target.Arch, ldr, rt, r.Off(), s, val, t), noExtReloc, isOk
   131  	case objabi.R_ADDRMIPSTLS:
   132  		// thread pointer is at 0x7000 offset from the start of TLS data area
   133  		t := ldr.SymValue(rs) + r.Add() - 0x7000
   134  		if t < -32768 || t >= 32678 {
   135  			ldr.Errorf(s, "TLS offset out of range %d", t)
   136  		}
   137  		return applyrel(target.Arch, ldr, rt, r.Off(), s, val, t), noExtReloc, isOk
   138  	}
   139  
   140  	return val, 0, false
   141  }
   142  
   143  func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
   144  	return -1
   145  }
   146  
   147  func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
   148  	switch r.Type() {
   149  	case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
   150  		return ld.ExtrelocViaOuterSym(ldr, r, s), true
   151  
   152  	case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS:
   153  		return ld.ExtrelocSimple(ldr, r), true
   154  	}
   155  	return loader.ExtReloc{}, false
   156  }