github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/s390x/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 s390x 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 // gentext generates assembly to append the local moduledata to the global 44 // moduledata linked list at initialization time. This is only done if the runtime 45 // is in a different module. 46 // 47 // <go.link.addmoduledata>: 48 // larl %r2, <local.moduledata> 49 // jg <runtime.addmoduledata@plt> 50 // undef 51 // 52 // The job of appending the moduledata is delegated to runtime.addmoduledata. 53 func gentext(ctxt *ld.Link, ldr *loader.Loader) { 54 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt) 55 if initfunc == nil { 56 return 57 } 58 59 // larl %r2, <local.moduledata> 60 initfunc.AddUint8(0xc0) 61 initfunc.AddUint8(0x20) 62 initfunc.AddSymRef(ctxt.Arch, ctxt.Moduledata, 6, objabi.R_PCREL, 4) 63 r1 := initfunc.Relocs() 64 ldr.SetRelocVariant(initfunc.Sym(), r1.Count()-1, sym.RV_390_DBL) 65 66 // jg <runtime.addmoduledata[@plt]> 67 initfunc.AddUint8(0xc0) 68 initfunc.AddUint8(0xf4) 69 initfunc.AddSymRef(ctxt.Arch, addmoduledata, 6, objabi.R_CALL, 4) 70 r2 := initfunc.Relocs() 71 ldr.SetRelocVariant(initfunc.Sym(), r2.Count()-1, sym.RV_390_DBL) 72 73 // undef (for debugging) 74 initfunc.AddUint32(ctxt.Arch, 0) 75 } 76 77 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool { 78 targ := r.Sym() 79 var targType sym.SymKind 80 if targ != 0 { 81 targType = ldr.SymType(targ) 82 } 83 84 switch r.Type() { 85 default: 86 if r.Type() >= objabi.ElfRelocOffset { 87 ldr.Errorf(s, "unexpected relocation type %d", r.Type()) 88 return false 89 } 90 91 // Handle relocations found in ELF object files. 92 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12), 93 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12): 94 ldr.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type()-objabi.ElfRelocOffset) 95 return false 96 97 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8), 98 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16), 99 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32), 100 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64): 101 if targType == sym.SDYNIMPORT { 102 ldr.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", ldr.SymName(targ)) 103 } 104 105 su := ldr.MakeSymbolUpdater(s) 106 su.SetRelocType(rIdx, objabi.R_ADDR) 107 return true 108 109 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16), 110 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32), 111 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64): 112 if targType == sym.SDYNIMPORT { 113 ldr.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", ldr.SymName(targ)) 114 } 115 if targType == 0 || targType == sym.SXREF { 116 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ)) 117 } 118 su := ldr.MakeSymbolUpdater(s) 119 su.SetRelocType(rIdx, objabi.R_PCREL) 120 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 121 return true 122 123 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16), 124 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32), 125 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64): 126 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset) 127 return true 128 129 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL), 130 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL): 131 su := ldr.MakeSymbolUpdater(s) 132 su.SetRelocType(rIdx, objabi.R_PCREL) 133 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL) 134 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 135 if targType == sym.SDYNIMPORT { 136 addpltsym(target, ldr, syms, targ) 137 r.SetSym(syms.PLT) 138 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ))) 139 } 140 return true 141 142 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32), 143 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64): 144 su := ldr.MakeSymbolUpdater(s) 145 su.SetRelocType(rIdx, objabi.R_PCREL) 146 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 147 if targType == sym.SDYNIMPORT { 148 addpltsym(target, ldr, syms, targ) 149 r.SetSym(syms.PLT) 150 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ))) 151 } 152 return true 153 154 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY): 155 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset) 156 return false 157 158 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT): 159 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset) 160 return false 161 162 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT): 163 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset) 164 return false 165 166 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE): 167 ldr.Errorf(s, "unimplemented S390x relocation: %v", r.Type()-objabi.ElfRelocOffset) 168 return false 169 170 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF): 171 if targType == sym.SDYNIMPORT { 172 ldr.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", ldr.SymName(targ)) 173 } 174 su := ldr.MakeSymbolUpdater(s) 175 su.SetRelocType(rIdx, objabi.R_GOTOFF) 176 return true 177 178 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC): 179 su := ldr.MakeSymbolUpdater(s) 180 su.SetRelocType(rIdx, objabi.R_PCREL) 181 r.SetSym(syms.GOT) 182 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 183 return true 184 185 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL), 186 objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL): 187 su := ldr.MakeSymbolUpdater(s) 188 su.SetRelocType(rIdx, objabi.R_PCREL) 189 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL) 190 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 191 if targType == sym.SDYNIMPORT { 192 ldr.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", ldr.SymName(targ)) 193 } 194 return true 195 196 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL): 197 su := ldr.MakeSymbolUpdater(s) 198 su.SetRelocType(rIdx, objabi.R_PCREL) 199 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL) 200 r.SetSym(syms.GOT) 201 su.SetRelocAdd(rIdx, r.Add()+int64(r.Siz())) 202 return true 203 204 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT): 205 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_390_GLOB_DAT)) 206 su := ldr.MakeSymbolUpdater(s) 207 su.SetRelocType(rIdx, objabi.R_PCREL) 208 ldr.SetRelocVariant(s, rIdx, sym.RV_390_DBL) 209 r.SetSym(syms.GOT) 210 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))+int64(r.Siz())) 211 return true 212 } 213 // Handle references to ELF symbols from our own object files. 214 return targType != sym.SDYNIMPORT 215 } 216 217 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool { 218 out.Write64(uint64(sectoff)) 219 220 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym) 221 siz := r.Size 222 switch r.Type { 223 default: 224 return false 225 case objabi.R_TLS_LE: 226 switch siz { 227 default: 228 return false 229 case 4: 230 // WARNING - silently ignored by linker in ELF64 231 out.Write64(uint64(elf.R_390_TLS_LE32) | uint64(elfsym)<<32) 232 case 8: 233 // WARNING - silently ignored by linker in ELF32 234 out.Write64(uint64(elf.R_390_TLS_LE64) | uint64(elfsym)<<32) 235 } 236 case objabi.R_TLS_IE: 237 switch siz { 238 default: 239 return false 240 case 4: 241 out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32) 242 } 243 case objabi.R_ADDR, objabi.R_DWARFSECREF: 244 switch siz { 245 default: 246 return false 247 case 4: 248 out.Write64(uint64(elf.R_390_32) | uint64(elfsym)<<32) 249 case 8: 250 out.Write64(uint64(elf.R_390_64) | uint64(elfsym)<<32) 251 } 252 case objabi.R_GOTPCREL: 253 if siz == 4 { 254 out.Write64(uint64(elf.R_390_GOTENT) | uint64(elfsym)<<32) 255 } else { 256 return false 257 } 258 case objabi.R_PCREL, objabi.R_PCRELDBL, objabi.R_CALL: 259 elfrel := elf.R_390_NONE 260 rVariant := ldr.RelocVariant(s, ri) 261 isdbl := rVariant&sym.RV_TYPE_MASK == sym.RV_390_DBL 262 // TODO(mundaym): all DBL style relocations should be 263 // signalled using the variant - see issue 14218. 264 switch r.Type { 265 case objabi.R_PCRELDBL, objabi.R_CALL: 266 isdbl = true 267 } 268 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT && (ldr.SymElfType(r.Xsym) == elf.STT_FUNC || r.Type == objabi.R_CALL) { 269 if isdbl { 270 switch siz { 271 case 2: 272 elfrel = elf.R_390_PLT16DBL 273 case 4: 274 elfrel = elf.R_390_PLT32DBL 275 } 276 } else { 277 switch siz { 278 case 4: 279 elfrel = elf.R_390_PLT32 280 case 8: 281 elfrel = elf.R_390_PLT64 282 } 283 } 284 } else { 285 if isdbl { 286 switch siz { 287 case 2: 288 elfrel = elf.R_390_PC16DBL 289 case 4: 290 elfrel = elf.R_390_PC32DBL 291 } 292 } else { 293 switch siz { 294 case 2: 295 elfrel = elf.R_390_PC16 296 case 4: 297 elfrel = elf.R_390_PC32 298 case 8: 299 elfrel = elf.R_390_PC64 300 } 301 } 302 } 303 if elfrel == elf.R_390_NONE { 304 return false // unsupported size/dbl combination 305 } 306 out.Write64(uint64(elfrel) | uint64(elfsym)<<32) 307 } 308 309 out.Write64(uint64(r.Xadd)) 310 return true 311 } 312 313 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) { 314 if plt.Size() == 0 { 315 // stg %r1,56(%r15) 316 plt.AddUint8(0xe3) 317 plt.AddUint8(0x10) 318 plt.AddUint8(0xf0) 319 plt.AddUint8(0x38) 320 plt.AddUint8(0x00) 321 plt.AddUint8(0x24) 322 // larl %r1,_GLOBAL_OFFSET_TABLE_ 323 plt.AddUint8(0xc0) 324 plt.AddUint8(0x10) 325 plt.AddSymRef(ctxt.Arch, got.Sym(), 6, objabi.R_PCRELDBL, 4) 326 // mvc 48(8,%r15),8(%r1) 327 plt.AddUint8(0xd2) 328 plt.AddUint8(0x07) 329 plt.AddUint8(0xf0) 330 plt.AddUint8(0x30) 331 plt.AddUint8(0x10) 332 plt.AddUint8(0x08) 333 // lg %r1,16(%r1) 334 plt.AddUint8(0xe3) 335 plt.AddUint8(0x10) 336 plt.AddUint8(0x10) 337 plt.AddUint8(0x10) 338 plt.AddUint8(0x00) 339 plt.AddUint8(0x04) 340 // br %r1 341 plt.AddUint8(0x07) 342 plt.AddUint8(0xf1) 343 // nopr %r0 344 plt.AddUint8(0x07) 345 plt.AddUint8(0x00) 346 // nopr %r0 347 plt.AddUint8(0x07) 348 plt.AddUint8(0x00) 349 // nopr %r0 350 plt.AddUint8(0x07) 351 plt.AddUint8(0x00) 352 353 // assume got->size == 0 too 354 got.AddAddrPlus(ctxt.Arch, dynamic, 0) 355 356 got.AddUint64(ctxt.Arch, 0) 357 got.AddUint64(ctxt.Arch, 0) 358 } 359 } 360 361 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool { 362 return false 363 } 364 365 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) { 366 return val, 0, false 367 } 368 369 func archrelocvariant(target *ld.Target, ldr *loader.Loader, r loader.Reloc, rv sym.RelocVariant, s loader.Sym, t int64, p []byte) int64 { 370 switch rv & sym.RV_TYPE_MASK { 371 default: 372 ldr.Errorf(s, "unexpected relocation variant %d", rv) 373 return t 374 375 case sym.RV_NONE: 376 return t 377 378 case sym.RV_390_DBL: 379 if t&1 != 0 { 380 ldr.Errorf(s, "%s+%v is not 2-byte aligned", ldr.SymName(r.Sym()), ldr.SymValue(r.Sym())) 381 } 382 return t >> 1 383 } 384 } 385 386 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) { 387 if ldr.SymPlt(s) >= 0 { 388 return 389 } 390 391 ld.Adddynsym(ldr, target, syms, s) 392 393 if target.IsElf() { 394 plt := ldr.MakeSymbolUpdater(syms.PLT) 395 got := ldr.MakeSymbolUpdater(syms.GOT) 396 rela := ldr.MakeSymbolUpdater(syms.RelaPLT) 397 if plt.Size() == 0 { 398 panic("plt is not set up") 399 } 400 // larl %r1,_GLOBAL_OFFSET_TABLE_+index 401 402 plt.AddUint8(0xc0) 403 plt.AddUint8(0x10) 404 plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size()+6) 405 pltrelocs := plt.Relocs() 406 ldr.SetRelocVariant(plt.Sym(), pltrelocs.Count()-1, sym.RV_390_DBL) 407 408 // add to got: pointer to current pos in plt 409 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size()+8) // weird but correct 410 // lg %r1,0(%r1) 411 plt.AddUint8(0xe3) 412 plt.AddUint8(0x10) 413 plt.AddUint8(0x10) 414 plt.AddUint8(0x00) 415 plt.AddUint8(0x00) 416 plt.AddUint8(0x04) 417 // br %r1 418 plt.AddUint8(0x07) 419 plt.AddUint8(0xf1) 420 // basr %r1,%r0 421 plt.AddUint8(0x0d) 422 plt.AddUint8(0x10) 423 // lgf %r1,12(%r1) 424 plt.AddUint8(0xe3) 425 plt.AddUint8(0x10) 426 plt.AddUint8(0x10) 427 plt.AddUint8(0x0c) 428 plt.AddUint8(0x00) 429 plt.AddUint8(0x14) 430 // jg .plt 431 plt.AddUint8(0xc0) 432 plt.AddUint8(0xf4) 433 434 plt.AddUint32(target.Arch, uint32(-((plt.Size() - 2) >> 1))) // roll-your-own relocation 435 //.plt index 436 plt.AddUint32(target.Arch, uint32(rela.Size())) // rela size before current entry 437 438 // rela 439 rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8) 440 441 sDynid := ldr.SymDynid(s) 442 rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT))) 443 rela.AddUint64(target.Arch, 0) 444 445 ldr.SetPlt(s, int32(plt.Size()-32)) 446 447 } else { 448 ldr.Errorf(s, "addpltsym: unsupported binary format") 449 } 450 }