github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/x86/asm.go (about) 1 // Inferno utils/8l/asm.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/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 x86 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 "log" 41 ) 42 43 func gentext(ctxt *ld.Link, ldr *loader.Loader) { 44 if ctxt.DynlinkingGo() { 45 // We need get_pc_thunk. 46 } else { 47 switch ctxt.BuildMode { 48 case ld.BuildModeCArchive: 49 if !ctxt.IsELF { 50 return 51 } 52 case ld.BuildModePIE, ld.BuildModeCShared, ld.BuildModePlugin: 53 // We need get_pc_thunk. 54 default: 55 return 56 } 57 } 58 59 // Generate little thunks that load the PC of the next instruction into a register. 60 thunks := make([]loader.Sym, 0, 7+len(ctxt.Textp)) 61 for _, r := range [...]struct { 62 name string 63 num uint8 64 }{ 65 {"ax", 0}, 66 {"cx", 1}, 67 {"dx", 2}, 68 {"bx", 3}, 69 // sp 70 {"bp", 5}, 71 {"si", 6}, 72 {"di", 7}, 73 } { 74 thunkfunc := ldr.CreateSymForUpdate("__x86.get_pc_thunk."+r.name, 0) 75 thunkfunc.SetType(sym.STEXT) 76 ldr.SetAttrLocal(thunkfunc.Sym(), true) 77 o := func(op ...uint8) { 78 for _, op1 := range op { 79 thunkfunc.AddUint8(op1) 80 } 81 } 82 // 8b 04 24 mov (%esp),%eax 83 // Destination register is in bits 3-5 of the middle byte, so add that in. 84 o(0x8b, 0x04+r.num<<3, 0x24) 85 // c3 ret 86 o(0xc3) 87 88 thunks = append(thunks, thunkfunc.Sym()) 89 } 90 ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order 91 92 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt) 93 if initfunc == nil { 94 return 95 } 96 97 o := func(op ...uint8) { 98 for _, op1 := range op { 99 initfunc.AddUint8(op1) 100 } 101 } 102 103 // go.link.addmoduledata: 104 // 53 push %ebx 105 // e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx 106 // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata 107 // 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_ 108 // e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata 109 // 5b pop %ebx 110 // c3 ret 111 112 o(0x53) 113 114 o(0xe8) 115 initfunc.AddSymRef(ctxt.Arch, ldr.Lookup("__x86.get_pc_thunk.cx", 0), 0, objabi.R_CALL, 4) 116 117 o(0x8d, 0x81) 118 initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6) 119 120 o(0x8d, 0x99) 121 gotsym := ldr.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0) 122 initfunc.AddSymRef(ctxt.Arch, gotsym, 12, objabi.R_PCREL, 4) 123 o(0xe8) 124 initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4) 125 126 o(0x5b) 127 128 o(0xc3) 129 } 130 131 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool { 132 targ := r.Sym() 133 var targType sym.SymKind 134 if targ != 0 { 135 targType = ldr.SymType(targ) 136 } 137 138 switch r.Type() { 139 default: 140 if r.Type() >= objabi.ElfRelocOffset { 141 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type())) 142 return false 143 } 144 145 // Handle relocations found in ELF object files. 146 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32): 147 if targType == sym.SDYNIMPORT { 148 ldr.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", ldr.SymName(targ)) 149 } 150 if targType == 0 || targType == sym.SXREF { 151 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ)) 152 } 153 su := ldr.MakeSymbolUpdater(s) 154 su.SetRelocType(rIdx, objabi.R_PCREL) 155 su.SetRelocAdd(rIdx, r.Add()+4) 156 return true 157 158 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32): 159 su := ldr.MakeSymbolUpdater(s) 160 su.SetRelocType(rIdx, objabi.R_PCREL) 161 su.SetRelocAdd(rIdx, r.Add()+4) 162 if targType == sym.SDYNIMPORT { 163 addpltsym(target, ldr, syms, targ) 164 su.SetRelocSym(rIdx, syms.PLT) 165 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ))) 166 } 167 168 return true 169 170 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32), 171 objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X): 172 su := ldr.MakeSymbolUpdater(s) 173 if targType != sym.SDYNIMPORT { 174 // have symbol 175 sData := ldr.Data(s) 176 177 if r.Off() >= 2 && sData[r.Off()-2] == 0x8b { 178 su.MakeWritable() 179 180 // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. 181 writeableData := su.Data() 182 writeableData[r.Off()-2] = 0x8d 183 su.SetRelocType(rIdx, objabi.R_GOTOFF) 184 return true 185 } 186 187 if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 { 188 su.MakeWritable() 189 // turn PUSHL of GOT entry into PUSHL of symbol itself. 190 // use unnecessary SS prefix to keep instruction same length. 191 writeableData := su.Data() 192 writeableData[r.Off()-2] = 0x36 193 writeableData[r.Off()-1] = 0x68 194 su.SetRelocType(rIdx, objabi.R_ADDR) 195 return true 196 } 197 198 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ)) 199 return false 200 } 201 202 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT)) 203 su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym 204 su.SetRelocSym(rIdx, 0) 205 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))) 206 return true 207 208 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF): 209 su := ldr.MakeSymbolUpdater(s) 210 su.SetRelocType(rIdx, objabi.R_GOTOFF) 211 return true 212 213 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC): 214 su := ldr.MakeSymbolUpdater(s) 215 su.SetRelocType(rIdx, objabi.R_PCREL) 216 su.SetRelocSym(rIdx, syms.GOT) 217 su.SetRelocAdd(rIdx, r.Add()+4) 218 return true 219 220 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32): 221 if targType == sym.SDYNIMPORT { 222 ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ)) 223 } 224 su := ldr.MakeSymbolUpdater(s) 225 su.SetRelocType(rIdx, objabi.R_ADDR) 226 return true 227 228 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0: 229 su := ldr.MakeSymbolUpdater(s) 230 su.SetRelocType(rIdx, objabi.R_ADDR) 231 if targType == sym.SDYNIMPORT { 232 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ)) 233 } 234 return true 235 236 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1: 237 su := ldr.MakeSymbolUpdater(s) 238 if targType == sym.SDYNIMPORT { 239 addpltsym(target, ldr, syms, targ) 240 su.SetRelocSym(rIdx, syms.PLT) 241 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ))) 242 su.SetRelocType(rIdx, objabi.R_PCREL) 243 return true 244 } 245 246 su.SetRelocType(rIdx, objabi.R_PCREL) 247 return true 248 249 case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL: 250 su := ldr.MakeSymbolUpdater(s) 251 if targType != sym.SDYNIMPORT { 252 // have symbol 253 // turn MOVL of GOT entry into LEAL of symbol itself 254 sData := ldr.Data(s) 255 if r.Off() < 2 || sData[r.Off()-2] != 0x8b { 256 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ)) 257 return false 258 } 259 260 su.MakeWritable() 261 writeableData := su.Data() 262 writeableData[r.Off()-2] = 0x8d 263 su.SetRelocType(rIdx, objabi.R_PCREL) 264 return true 265 } 266 267 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT)) 268 su.SetRelocSym(rIdx, syms.GOT) 269 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ))) 270 su.SetRelocType(rIdx, objabi.R_PCREL) 271 return true 272 } 273 274 // Handle references to ELF symbols from our own object files. 275 if targType != sym.SDYNIMPORT { 276 return true 277 } 278 279 // Reread the reloc to incorporate any changes in type above. 280 relocs := ldr.Relocs(s) 281 r = relocs.At(rIdx) 282 283 switch r.Type() { 284 case objabi.R_CALL, 285 objabi.R_PCREL: 286 if target.IsExternal() { 287 // External linker will do this relocation. 288 return true 289 } 290 addpltsym(target, ldr, syms, targ) 291 su := ldr.MakeSymbolUpdater(s) 292 su.SetRelocSym(rIdx, syms.PLT) 293 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ))) 294 return true 295 296 case objabi.R_ADDR: 297 if ldr.SymType(s) != sym.SDATA { 298 break 299 } 300 if target.IsElf() { 301 ld.Adddynsym(ldr, target, syms, targ) 302 rel := ldr.MakeSymbolUpdater(syms.Rel) 303 rel.AddAddrPlus(target.Arch, s, int64(r.Off())) 304 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32))) 305 su := ldr.MakeSymbolUpdater(s) 306 su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym 307 su.SetRelocSym(rIdx, 0) 308 return true 309 } 310 } 311 312 return false 313 } 314 315 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool { 316 out.Write32(uint32(sectoff)) 317 318 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym) 319 siz := r.Size 320 switch r.Type { 321 default: 322 return false 323 case objabi.R_ADDR, objabi.R_DWARFSECREF: 324 if siz == 4 { 325 out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8) 326 } else { 327 return false 328 } 329 case objabi.R_GOTPCREL: 330 if siz == 4 { 331 out.Write32(uint32(elf.R_386_GOTPC)) 332 if ldr.SymName(r.Xsym) != "_GLOBAL_OFFSET_TABLE_" { 333 out.Write32(uint32(sectoff)) 334 out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8) 335 } 336 } else { 337 return false 338 } 339 case objabi.R_CALL: 340 if siz == 4 { 341 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT { 342 out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8) 343 } else { 344 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8) 345 } 346 } else { 347 return false 348 } 349 case objabi.R_PCREL: 350 if siz == 4 { 351 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8) 352 } else { 353 return false 354 } 355 case objabi.R_TLS_LE: 356 if siz == 4 { 357 out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8) 358 } else { 359 return false 360 } 361 case objabi.R_TLS_IE: 362 if siz == 4 { 363 out.Write32(uint32(elf.R_386_GOTPC)) 364 out.Write32(uint32(sectoff)) 365 out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8) 366 } else { 367 return false 368 } 369 } 370 371 return true 372 } 373 374 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool { 375 return false 376 } 377 378 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool { 379 var v uint32 380 381 rs := r.Xsym 382 rt := r.Type 383 384 if ldr.SymDynid(rs) < 0 { 385 ldr.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs)) 386 return false 387 } 388 389 out.Write32(uint32(sectoff)) 390 out.Write32(uint32(ldr.SymDynid(rs))) 391 392 switch rt { 393 default: 394 return false 395 396 case objabi.R_DWARFSECREF: 397 v = ld.IMAGE_REL_I386_SECREL 398 399 case objabi.R_ADDR: 400 v = ld.IMAGE_REL_I386_DIR32 401 402 case objabi.R_PEIMAGEOFF: 403 v = ld.IMAGE_REL_I386_DIR32NB 404 405 case objabi.R_CALL, 406 objabi.R_PCREL: 407 v = ld.IMAGE_REL_I386_REL32 408 } 409 410 out.Write16(uint16(v)) 411 412 return true 413 } 414 415 func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) { 416 return -1, 0, false 417 } 418 419 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 { 420 log.Fatalf("unexpected relocation variant") 421 return -1 422 } 423 424 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) { 425 if plt.Size() == 0 { 426 // pushl got+4 427 plt.AddUint8(0xff) 428 429 plt.AddUint8(0x35) 430 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 4) 431 432 // jmp *got+8 433 plt.AddUint8(0xff) 434 435 plt.AddUint8(0x25) 436 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 8) 437 438 // zero pad 439 plt.AddUint32(ctxt.Arch, 0) 440 441 // assume got->size == 0 too 442 got.AddAddrPlus(ctxt.Arch, dynamic, 0) 443 444 got.AddUint32(ctxt.Arch, 0) 445 got.AddUint32(ctxt.Arch, 0) 446 } 447 } 448 449 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) { 450 if ldr.SymPlt(s) >= 0 { 451 return 452 } 453 454 ld.Adddynsym(ldr, target, syms, s) 455 456 if target.IsElf() { 457 plt := ldr.MakeSymbolUpdater(syms.PLT) 458 got := ldr.MakeSymbolUpdater(syms.GOTPLT) 459 rel := ldr.MakeSymbolUpdater(syms.RelPLT) 460 if plt.Size() == 0 { 461 panic("plt is not set up") 462 } 463 464 // jmpq *got+size 465 plt.AddUint8(0xff) 466 467 plt.AddUint8(0x25) 468 plt.AddAddrPlus(target.Arch, got.Sym(), got.Size()) 469 470 // add to got: pointer to current pos in plt 471 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size()) 472 473 // pushl $x 474 plt.AddUint8(0x68) 475 476 plt.AddUint32(target.Arch, uint32(rel.Size())) 477 478 // jmp .plt 479 plt.AddUint8(0xe9) 480 481 plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4))) 482 483 // rel 484 rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4) 485 486 sDynid := ldr.SymDynid(s) 487 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(sDynid), uint32(elf.R_386_JMP_SLOT))) 488 489 ldr.SetPlt(s, int32(plt.Size()-16)) 490 } else { 491 ldr.Errorf(s, "addpltsym: unsupported binary format") 492 } 493 }