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 }