github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/mips64/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 © 2009 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 mips64 32 33 import ( 34 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 35 "github.com/bir3/gocompiler/src/cmd/internal/sys" 36 "github.com/bir3/gocompiler/src/cmd/link/internal/ld" 37 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 38 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 39 "debug/elf" 40 ) 41 42 var ( 43 // dtOffsets contains offsets for entries within the .dynamic section. 44 // These are used to fix up symbol values once they are known. 45 dtOffsets map[elf.DynTag]int64 46 47 // dynSymCount contains the number of entries in the .dynsym section. 48 // This is used to populate the DT_MIPS_SYMTABNO entry in the .dynamic 49 // section. 50 dynSymCount uint64 51 52 // gotLocalCount contains the number of local global offset table 53 // entries. This is used to populate the DT_MIPS_LOCAL_GOTNO entry in 54 // the .dynamic section. 55 gotLocalCount uint64 56 57 // gotSymIndex contains the index of the first dynamic symbol table 58 // entry that corresponds to an entry in the global offset table. 59 // This is used to populate the DT_MIPS_GOTSYM entry in the .dynamic 60 // section. 61 gotSymIndex uint64 62 ) 63 64 func gentext(ctxt *ld.Link, ldr *loader.Loader) { 65 if *ld.FlagD || ctxt.Target.IsExternal() { 66 return 67 } 68 69 dynamic := ldr.MakeSymbolUpdater(ctxt.ArchSyms.Dynamic) 70 71 ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_RLD_VERSION, 1) 72 ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_BASE_ADDRESS, 0) 73 74 // elfsetupplt should have been called and gotLocalCount should now 75 // have its correct value. 76 if gotLocalCount == 0 { 77 ctxt.Errorf(0, "internal error: elfsetupplt has not been called") 78 } 79 ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_LOCAL_GOTNO, gotLocalCount) 80 81 // DT_* entries have to exist prior to elfdynhash(), which finalises the 82 // table by adding DT_NULL. However, the values for the following entries 83 // are not know until after dynreloc() has completed. Add the symbols now, 84 // then update their values prior to code generation. 85 dts := []elf.DynTag{ 86 elf.DT_MIPS_SYMTABNO, 87 elf.DT_MIPS_GOTSYM, 88 } 89 dtOffsets = make(map[elf.DynTag]int64) 90 for _, dt := range dts { 91 ld.Elfwritedynent(ctxt.Arch, dynamic, dt, 0) 92 dtOffsets[dt] = dynamic.Size() - 8 93 } 94 } 95 96 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool { 97 targ := r.Sym() 98 var targType sym.SymKind 99 if targ != 0 { 100 targType = ldr.SymType(targ) 101 } 102 103 if r.Type() >= objabi.ElfRelocOffset { 104 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type())) 105 return false 106 } 107 108 switch r.Type() { 109 case objabi.R_CALLMIPS, objabi.R_JMPMIPS: 110 if targType != sym.SDYNIMPORT { 111 // Nothing to do, the relocation will be laid out in reloc 112 return true 113 } 114 if target.IsExternal() { 115 // External linker will do this relocation. 116 return true 117 } 118 119 // Internal linking, build a PLT entry and change the relocation 120 // target to that entry. 121 if r.Add() != 0 { 122 ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add()) 123 } 124 addpltsym(target, ldr, syms, targ) 125 su := ldr.MakeSymbolUpdater(s) 126 su.SetRelocSym(rIdx, syms.PLT) 127 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ))) 128 return true 129 } 130 131 return false 132 } 133 134 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool { 135 136 // mips64 ELF relocation (endian neutral) 137 // offset uint64 138 // sym uint32 139 // ssym uint8 140 // type3 uint8 141 // type2 uint8 142 // type uint8 143 // addend int64 144 145 addend := r.Xadd 146 147 out.Write64(uint64(sectoff)) 148 149 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym) 150 out.Write32(uint32(elfsym)) 151 out.Write8(0) 152 out.Write8(0) 153 out.Write8(0) 154 switch r.Type { 155 default: 156 return false 157 case objabi.R_ADDR, objabi.R_DWARFSECREF: 158 switch r.Size { 159 case 4: 160 out.Write8(uint8(elf.R_MIPS_32)) 161 case 8: 162 out.Write8(uint8(elf.R_MIPS_64)) 163 default: 164 return false 165 } 166 case objabi.R_ADDRMIPS: 167 out.Write8(uint8(elf.R_MIPS_LO16)) 168 case objabi.R_ADDRMIPSU: 169 out.Write8(uint8(elf.R_MIPS_HI16)) 170 case objabi.R_ADDRMIPSTLS: 171 out.Write8(uint8(elf.R_MIPS_TLS_TPREL_LO16)) 172 if ctxt.Target.IsOpenbsd() { 173 // OpenBSD mips64 does not currently offset TLS by 0x7000, 174 // as such we need to add this back to get the correct offset 175 // via the external linker. 176 addend += 0x7000 177 } 178 case objabi.R_CALLMIPS, 179 objabi.R_JMPMIPS: 180 out.Write8(uint8(elf.R_MIPS_26)) 181 } 182 out.Write64(uint64(addend)) 183 184 return true 185 } 186 187 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) { 188 if plt.Size() != 0 { 189 return 190 } 191 192 // Load resolver address from got[0] into r25. 193 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPSU, 4) 194 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x3c0e0000) // lui $14, %hi(&GOTPLT[0]) 195 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPS, 4) 196 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xddd90000) // ld $25, %lo(&GOTPLT[0])($14) 197 198 // Load return address into r15, the index of the got.plt entry into r24, then 199 // JALR to the resolver. The address of the got.plt entry is currently in r24, 200 // which we have to turn into an index. 201 plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPS, 4) 202 plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x25ce0000) // addiu $14, $14, %lo(&GOTPLT[0]) 203 plt.AddUint32(ctxt.Arch, 0x030ec023) // subu $24, $24, $14 204 plt.AddUint32(ctxt.Arch, 0x03e07825) // move $15, $31 205 plt.AddUint32(ctxt.Arch, 0x0018c0c2) // srl $24, $24, 3 206 plt.AddUint32(ctxt.Arch, 0x0320f809) // jalr $25 207 plt.AddUint32(ctxt.Arch, 0x2718fffe) // subu $24, $24, 2 208 209 if gotplt.Size() != 0 { 210 ctxt.Errorf(gotplt.Sym(), "got.plt is not empty") 211 } 212 213 // Reserve got[0] for resolver address (populated by dynamic loader). 214 gotplt.AddUint32(ctxt.Arch, 0) 215 gotplt.AddUint32(ctxt.Arch, 0) 216 gotLocalCount++ 217 218 // Reserve got[1] for ELF object pointer (populated by dynamic loader). 219 gotplt.AddUint32(ctxt.Arch, 0) 220 gotplt.AddUint32(ctxt.Arch, 0) 221 gotLocalCount++ 222 } 223 224 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) { 225 if ldr.SymPlt(s) >= 0 { 226 return 227 } 228 229 dynamic := ldr.MakeSymbolUpdater(syms.Dynamic) 230 231 const dynSymEntrySize = 20 232 if gotSymIndex == 0 { 233 // Compute and update GOT symbol index. 234 gotSymIndex = uint64(ldr.SymSize(syms.DynSym) / dynSymEntrySize) 235 dynamic.SetUint(target.Arch, dtOffsets[elf.DT_MIPS_GOTSYM], gotSymIndex) 236 } 237 if dynSymCount == 0 { 238 dynSymCount = uint64(ldr.SymSize(syms.DynSym) / dynSymEntrySize) 239 } 240 241 ld.Adddynsym(ldr, target, syms, s) 242 dynSymCount++ 243 244 if !target.IsElf() { 245 ldr.Errorf(s, "addpltsym: unsupported binary format") 246 } 247 248 plt := ldr.MakeSymbolUpdater(syms.PLT) 249 gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT) 250 if plt.Size() == 0 { 251 panic("plt is not set up") 252 } 253 254 // Load got.plt entry into r25. 255 plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPSU, 4) 256 plt.SetUint32(target.Arch, plt.Size()-4, 0x3c0f0000) // lui $15, %hi(.got.plt entry) 257 plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPS, 4) 258 plt.SetUint32(target.Arch, plt.Size()-4, 0xddf90000) // ld $25, %lo(.got.plt entry)($15) 259 260 // Load address of got.plt entry into r24 and JALR to address in r25. 261 plt.AddUint32(target.Arch, 0x03200008) // jr $25 262 plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPS, 4) 263 plt.SetUint32(target.Arch, plt.Size()-4, 0x65f80000) // daddiu $24, $15, %lo(.got.plt entry) 264 265 // Add pointer to plt[0] to got.plt 266 gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0) 267 268 ldr.SetPlt(s, int32(plt.Size()-16)) 269 270 // Update dynamic symbol count. 271 dynamic.SetUint(target.Arch, dtOffsets[elf.DT_MIPS_SYMTABNO], dynSymCount) 272 } 273 274 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool { 275 return false 276 } 277 278 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) { 279 if target.IsExternal() { 280 switch r.Type() { 281 default: 282 return val, 0, false 283 284 case objabi.R_ADDRMIPS, 285 objabi.R_ADDRMIPSU, 286 objabi.R_ADDRMIPSTLS, 287 objabi.R_CALLMIPS, 288 objabi.R_JMPMIPS: 289 return val, 1, true 290 } 291 } 292 293 const isOk = true 294 const noExtReloc = 0 295 rs := r.Sym() 296 switch r.Type() { 297 case objabi.R_ADDRMIPS, 298 objabi.R_ADDRMIPSU: 299 t := ldr.SymValue(rs) + r.Add() 300 if r.Type() == objabi.R_ADDRMIPS { 301 return int64(val&0xffff0000 | t&0xffff), noExtReloc, isOk 302 } 303 return int64(val&0xffff0000 | ((t+1<<15)>>16)&0xffff), noExtReloc, isOk 304 case objabi.R_ADDRMIPSTLS: 305 // thread pointer is at 0x7000 offset from the start of TLS data area 306 t := ldr.SymValue(rs) + r.Add() - 0x7000 307 if target.IsOpenbsd() { 308 // OpenBSD mips64 does not currently offset TLS by 0x7000, 309 // as such we need to add this back to get the correct offset. 310 t += 0x7000 311 } 312 if t < -32768 || t >= 32678 { 313 ldr.Errorf(s, "TLS offset out of range %d", t) 314 } 315 return int64(val&0xffff0000 | t&0xffff), noExtReloc, isOk 316 case objabi.R_CALLMIPS, 317 objabi.R_JMPMIPS: 318 // Low 26 bits = (S + A) >> 2 319 t := ldr.SymValue(rs) + r.Add() 320 return int64(val&0xfc000000 | (t>>2)&^0xfc000000), noExtReloc, isOk 321 } 322 323 return val, 0, false 324 } 325 326 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 { 327 return -1 328 } 329 330 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) { 331 switch r.Type() { 332 case objabi.R_ADDRMIPS, 333 objabi.R_ADDRMIPSU: 334 return ld.ExtrelocViaOuterSym(ldr, r, s), true 335 336 case objabi.R_ADDRMIPSTLS, 337 objabi.R_CALLMIPS, 338 objabi.R_JMPMIPS: 339 return ld.ExtrelocSimple(ldr, r), true 340 } 341 return loader.ExtReloc{}, false 342 }