github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/amd64/asm.go (about) 1 // Inferno utils/6l/asm.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/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 amd64 32 33 import ( 34 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 35 "github.com/gagliardetto/golang-go/cmd/internal/sys" 36 "github.com/gagliardetto/golang-go/cmd/link/internal/ld" 37 "github.com/gagliardetto/golang-go/cmd/link/internal/sym" 38 "debug/elf" 39 "log" 40 ) 41 42 func PADDR(x uint32) uint32 { 43 return x &^ 0x80000000 44 } 45 46 func Addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) int64 { 47 s.Attr |= sym.AttrReachable 48 i := s.Size 49 s.Size += 4 50 s.Grow(s.Size) 51 r := s.AddRel() 52 r.Sym = t 53 r.Off = int32(i) 54 r.Type = objabi.R_CALL 55 r.Siz = 4 56 return i + int64(r.Siz) 57 } 58 59 func gentext(ctxt *ld.Link) { 60 if !ctxt.DynlinkingGo() { 61 return 62 } 63 addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0) 64 if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin { 65 // we're linking a module containing the runtime -> no need for 66 // an init function 67 return 68 } 69 addmoduledata.Attr |= sym.AttrReachable 70 initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0) 71 initfunc.Type = sym.STEXT 72 initfunc.Attr |= sym.AttrLocal 73 initfunc.Attr |= sym.AttrReachable 74 o := func(op ...uint8) { 75 for _, op1 := range op { 76 initfunc.AddUint8(op1) 77 } 78 } 79 // 0000000000000000 <local.dso_init>: 80 // 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 <local.dso_init+0x7> 81 // 3: R_X86_64_PC32 runtime.firstmoduledata-0x4 82 o(0x48, 0x8d, 0x3d) 83 initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0) 84 // 7: e8 00 00 00 00 callq c <local.dso_init+0xc> 85 // 8: R_X86_64_PLT32 runtime.addmoduledata-0x4 86 o(0xe8) 87 Addcall(ctxt, initfunc, addmoduledata) 88 // c: c3 retq 89 o(0xc3) 90 if ctxt.BuildMode == ld.BuildModePlugin { 91 ctxt.Textp = append(ctxt.Textp, addmoduledata) 92 } 93 ctxt.Textp = append(ctxt.Textp, initfunc) 94 initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0) 95 initarray_entry.Attr |= sym.AttrReachable 96 initarray_entry.Attr |= sym.AttrLocal 97 initarray_entry.Type = sym.SINITARR 98 initarray_entry.AddAddr(ctxt.Arch, initfunc) 99 } 100 101 func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { 102 targ := r.Sym 103 104 switch r.Type { 105 default: 106 if r.Type >= objabi.ElfRelocOffset { 107 ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type)) 108 return false 109 } 110 111 // Handle relocations found in ELF object files. 112 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32): 113 if targ.Type == sym.SDYNIMPORT { 114 ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name) 115 } 116 // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make 117 // sense and should be removed when someone has thought about it properly. 118 if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() { 119 ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) 120 } 121 r.Type = objabi.R_PCREL 122 r.Add += 4 123 return true 124 125 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64): 126 if targ.Type == sym.SDYNIMPORT { 127 ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name) 128 } 129 if targ.Type == 0 || targ.Type == sym.SXREF { 130 ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) 131 } 132 r.Type = objabi.R_PCREL 133 r.Add += 8 134 return true 135 136 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32): 137 r.Type = objabi.R_PCREL 138 r.Add += 4 139 if targ.Type == sym.SDYNIMPORT { 140 addpltsym(ctxt, targ) 141 r.Sym = ctxt.Syms.Lookup(".plt", 0) 142 r.Add += int64(targ.Plt()) 143 } 144 145 return true 146 147 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL), 148 objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX), 149 objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX): 150 if targ.Type != sym.SDYNIMPORT { 151 // have symbol 152 if r.Off >= 2 && s.P[r.Off-2] == 0x8b { 153 // turn MOVQ of GOT entry into LEAQ of symbol itself 154 s.P[r.Off-2] = 0x8d 155 156 r.Type = objabi.R_PCREL 157 r.Add += 4 158 return true 159 } 160 } 161 162 // fall back to using GOT and hope for the best (CMOV*) 163 // TODO: just needs relocation, no need to put in .dynsym 164 addgotsym(ctxt, targ) 165 166 r.Type = objabi.R_PCREL 167 r.Sym = ctxt.Syms.Lookup(".got", 0) 168 r.Add += 4 169 r.Add += int64(targ.Got()) 170 return true 171 172 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64): 173 if targ.Type == sym.SDYNIMPORT { 174 ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name) 175 } 176 r.Type = objabi.R_ADDR 177 return true 178 179 // Handle relocations found in Mach-O object files. 180 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0, 181 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0, 182 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0: 183 // TODO: What is the difference between all these? 184 r.Type = objabi.R_ADDR 185 186 if targ.Type == sym.SDYNIMPORT { 187 ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name) 188 } 189 return true 190 191 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1: 192 if targ.Type == sym.SDYNIMPORT { 193 addpltsym(ctxt, targ) 194 r.Sym = ctxt.Syms.Lookup(".plt", 0) 195 r.Add = int64(targ.Plt()) 196 r.Type = objabi.R_PCREL 197 return true 198 } 199 fallthrough 200 201 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1, 202 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1, 203 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1, 204 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1, 205 objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1: 206 r.Type = objabi.R_PCREL 207 208 if targ.Type == sym.SDYNIMPORT { 209 ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name) 210 } 211 return true 212 213 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: 214 if targ.Type != sym.SDYNIMPORT { 215 // have symbol 216 // turn MOVQ of GOT entry into LEAQ of symbol itself 217 if r.Off < 2 || s.P[r.Off-2] != 0x8b { 218 ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name) 219 return false 220 } 221 222 s.P[r.Off-2] = 0x8d 223 r.Type = objabi.R_PCREL 224 return true 225 } 226 fallthrough 227 228 case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1: 229 if targ.Type != sym.SDYNIMPORT { 230 ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) 231 } 232 addgotsym(ctxt, targ) 233 r.Type = objabi.R_PCREL 234 r.Sym = ctxt.Syms.Lookup(".got", 0) 235 r.Add += int64(targ.Got()) 236 return true 237 } 238 239 switch r.Type { 240 case objabi.R_CALL, 241 objabi.R_PCREL: 242 if targ.Type != sym.SDYNIMPORT { 243 // nothing to do, the relocation will be laid out in reloc 244 return true 245 } 246 if ctxt.LinkMode == ld.LinkExternal { 247 // External linker will do this relocation. 248 return true 249 } 250 // Internal linking, for both ELF and Mach-O. 251 // Build a PLT entry and change the relocation target to that entry. 252 addpltsym(ctxt, targ) 253 r.Sym = ctxt.Syms.Lookup(".plt", 0) 254 r.Add = int64(targ.Plt()) 255 return true 256 257 case objabi.R_ADDR: 258 if s.Type == sym.STEXT && ctxt.IsELF { 259 if ctxt.HeadType == objabi.Hsolaris { 260 addpltsym(ctxt, targ) 261 r.Sym = ctxt.Syms.Lookup(".plt", 0) 262 r.Add += int64(targ.Plt()) 263 return true 264 } 265 // The code is asking for the address of an external 266 // function. We provide it with the address of the 267 // correspondent GOT symbol. 268 addgotsym(ctxt, targ) 269 270 r.Sym = ctxt.Syms.Lookup(".got", 0) 271 r.Add += int64(targ.Got()) 272 return true 273 } 274 275 // Process dynamic relocations for the data sections. 276 if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal { 277 // When internally linking, generate dynamic relocations 278 // for all typical R_ADDR relocations. The exception 279 // are those R_ADDR that are created as part of generating 280 // the dynamic relocations and must be resolved statically. 281 // 282 // There are three phases relevant to understanding this: 283 // 284 // dodata() // we are here 285 // address() // symbol address assignment 286 // reloc() // resolution of static R_ADDR relocs 287 // 288 // At this point symbol addresses have not been 289 // assigned yet (as the final size of the .rela section 290 // will affect the addresses), and so we cannot write 291 // the Elf64_Rela.r_offset now. Instead we delay it 292 // until after the 'address' phase of the linker is 293 // complete. We do this via Addaddrplus, which creates 294 // a new R_ADDR relocation which will be resolved in 295 // the 'reloc' phase. 296 // 297 // These synthetic static R_ADDR relocs must be skipped 298 // now, or else we will be caught in an infinite loop 299 // of generating synthetic relocs for our synthetic 300 // relocs. 301 // 302 // Furthermore, the rela sections contain dynamic 303 // relocations with R_ADDR relocations on 304 // Elf64_Rela.r_offset. This field should contain the 305 // symbol offset as determined by reloc(), not the 306 // final dynamically linked address as a dynamic 307 // relocation would provide. 308 switch s.Name { 309 case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic": 310 return false 311 } 312 } else { 313 // Either internally linking a static executable, 314 // in which case we can resolve these relocations 315 // statically in the 'reloc' phase, or externally 316 // linking, in which case the relocation will be 317 // prepared in the 'reloc' phase and passed to the 318 // external linker in the 'asmb' phase. 319 if s.Type != sym.SDATA && s.Type != sym.SRODATA { 320 break 321 } 322 } 323 324 if ctxt.IsELF { 325 // TODO: We generate a R_X86_64_64 relocation for every R_ADDR, even 326 // though it would be more efficient (for the dynamic linker) if we 327 // generated R_X86_RELATIVE instead. 328 ld.Adddynsym(ctxt, targ) 329 rela := ctxt.Syms.Lookup(".rela", 0) 330 rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off)) 331 if r.Siz == 8 { 332 rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_64))) 333 } else { 334 // TODO: never happens, remove. 335 rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_32))) 336 } 337 rela.AddUint64(ctxt.Arch, uint64(r.Add)) 338 r.Type = objabi.ElfRelocOffset // ignore during relocsym 339 return true 340 } 341 342 if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 { 343 // Mach-O relocations are a royal pain to lay out. 344 // They use a compact stateful bytecode representation 345 // that is too much bother to deal with. 346 // Instead, interpret the C declaration 347 // void *_Cvar_stderr = &stderr; 348 // as making _Cvar_stderr the name of a GOT entry 349 // for stderr. This is separate from the usual GOT entry, 350 // just in case the C code assigns to the variable, 351 // and of course it only works for single pointers, 352 // but we only need to support cgo and that's all it needs. 353 ld.Adddynsym(ctxt, targ) 354 355 got := ctxt.Syms.Lookup(".got", 0) 356 s.Type = got.Type 357 s.Attr |= sym.AttrSubSymbol 358 s.Outer = got 359 s.Sub = got.Sub 360 got.Sub = s 361 s.Value = got.Size 362 got.AddUint64(ctxt.Arch, 0) 363 ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid)) 364 r.Type = objabi.ElfRelocOffset // ignore during relocsym 365 return true 366 } 367 } 368 369 return false 370 } 371 372 func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { 373 ctxt.Out.Write64(uint64(sectoff)) 374 375 elfsym := r.Xsym.ElfsymForReloc() 376 switch r.Type { 377 default: 378 return false 379 case objabi.R_ADDR: 380 if r.Siz == 4 { 381 ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32) 382 } else if r.Siz == 8 { 383 ctxt.Out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32) 384 } else { 385 return false 386 } 387 case objabi.R_TLS_LE: 388 if r.Siz == 4 { 389 ctxt.Out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32) 390 } else { 391 return false 392 } 393 case objabi.R_TLS_IE: 394 if r.Siz == 4 { 395 ctxt.Out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32) 396 } else { 397 return false 398 } 399 case objabi.R_CALL: 400 if r.Siz == 4 { 401 if r.Xsym.Type == sym.SDYNIMPORT { 402 if ctxt.DynlinkingGo() { 403 ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32) 404 } else { 405 ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32) 406 } 407 } else { 408 ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32) 409 } 410 } else { 411 return false 412 } 413 case objabi.R_PCREL: 414 if r.Siz == 4 { 415 if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType() == elf.STT_FUNC { 416 ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32) 417 } else { 418 ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32) 419 } 420 } else { 421 return false 422 } 423 case objabi.R_GOTPCREL: 424 if r.Siz == 4 { 425 ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32) 426 } else { 427 return false 428 } 429 } 430 431 ctxt.Out.Write64(uint64(r.Xadd)) 432 return true 433 } 434 435 func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { 436 var v uint32 437 438 rs := r.Xsym 439 440 if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_PCREL || r.Type == objabi.R_GOTPCREL || r.Type == objabi.R_CALL { 441 if rs.Dynid < 0 { 442 ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type) 443 return false 444 } 445 446 v = uint32(rs.Dynid) 447 v |= 1 << 27 // external relocation 448 } else { 449 v = uint32(rs.Sect.Extnum) 450 if v == 0 { 451 ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type) 452 return false 453 } 454 } 455 456 switch r.Type { 457 default: 458 return false 459 460 case objabi.R_ADDR: 461 v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28 462 463 case objabi.R_CALL: 464 v |= 1 << 24 // pc-relative bit 465 v |= ld.MACHO_X86_64_RELOC_BRANCH << 28 466 467 // NOTE: Only works with 'external' relocation. Forced above. 468 case objabi.R_PCREL: 469 v |= 1 << 24 // pc-relative bit 470 v |= ld.MACHO_X86_64_RELOC_SIGNED << 28 471 case objabi.R_GOTPCREL: 472 v |= 1 << 24 // pc-relative bit 473 v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28 474 } 475 476 switch r.Siz { 477 default: 478 return false 479 480 case 1: 481 v |= 0 << 25 482 483 case 2: 484 v |= 1 << 25 485 486 case 4: 487 v |= 2 << 25 488 489 case 8: 490 v |= 3 << 25 491 } 492 493 out.Write32(uint32(sectoff)) 494 out.Write32(v) 495 return true 496 } 497 498 func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { 499 var v uint32 500 501 rs := r.Xsym 502 503 if rs.Dynid < 0 { 504 ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type) 505 return false 506 } 507 508 out.Write32(uint32(sectoff)) 509 out.Write32(uint32(rs.Dynid)) 510 511 switch r.Type { 512 default: 513 return false 514 515 case objabi.R_DWARFSECREF: 516 v = ld.IMAGE_REL_AMD64_SECREL 517 518 case objabi.R_ADDR: 519 if r.Siz == 8 { 520 v = ld.IMAGE_REL_AMD64_ADDR64 521 } else { 522 v = ld.IMAGE_REL_AMD64_ADDR32 523 } 524 525 case objabi.R_CALL, 526 objabi.R_PCREL: 527 v = ld.IMAGE_REL_AMD64_REL32 528 } 529 530 out.Write16(uint16(v)) 531 532 return true 533 } 534 535 func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { 536 return val, false 537 } 538 539 func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { 540 log.Fatalf("unexpected relocation variant") 541 return t 542 } 543 544 func elfsetupplt(ctxt *ld.Link) { 545 plt := ctxt.Syms.Lookup(".plt", 0) 546 got := ctxt.Syms.Lookup(".got.plt", 0) 547 if plt.Size == 0 { 548 // pushq got+8(IP) 549 plt.AddUint8(0xff) 550 551 plt.AddUint8(0x35) 552 plt.AddPCRelPlus(ctxt.Arch, got, 8) 553 554 // jmpq got+16(IP) 555 plt.AddUint8(0xff) 556 557 plt.AddUint8(0x25) 558 plt.AddPCRelPlus(ctxt.Arch, got, 16) 559 560 // nopl 0(AX) 561 plt.AddUint32(ctxt.Arch, 0x00401f0f) 562 563 // assume got->size == 0 too 564 got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0) 565 566 got.AddUint64(ctxt.Arch, 0) 567 got.AddUint64(ctxt.Arch, 0) 568 } 569 } 570 571 func addpltsym(ctxt *ld.Link, s *sym.Symbol) { 572 if s.Plt() >= 0 { 573 return 574 } 575 576 ld.Adddynsym(ctxt, s) 577 578 if ctxt.IsELF { 579 plt := ctxt.Syms.Lookup(".plt", 0) 580 got := ctxt.Syms.Lookup(".got.plt", 0) 581 rela := ctxt.Syms.Lookup(".rela.plt", 0) 582 if plt.Size == 0 { 583 elfsetupplt(ctxt) 584 } 585 586 // jmpq *got+size(IP) 587 plt.AddUint8(0xff) 588 589 plt.AddUint8(0x25) 590 plt.AddPCRelPlus(ctxt.Arch, got, got.Size) 591 592 // add to got: pointer to current pos in plt 593 got.AddAddrPlus(ctxt.Arch, plt, plt.Size) 594 595 // pushq $x 596 plt.AddUint8(0x68) 597 598 plt.AddUint32(ctxt.Arch, uint32((got.Size-24-8)/8)) 599 600 // jmpq .plt 601 plt.AddUint8(0xe9) 602 603 plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4))) 604 605 // rela 606 rela.AddAddrPlus(ctxt.Arch, got, got.Size-8) 607 608 rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT))) 609 rela.AddUint64(ctxt.Arch, 0) 610 611 s.SetPlt(int32(plt.Size - 16)) 612 } else if ctxt.HeadType == objabi.Hdarwin { 613 // To do lazy symbol lookup right, we're supposed 614 // to tell the dynamic loader which library each 615 // symbol comes from and format the link info 616 // section just so. I'm too lazy (ha!) to do that 617 // so for now we'll just use non-lazy pointers, 618 // which don't need to be told which library to use. 619 // 620 // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html 621 // has details about what we're avoiding. 622 623 addgotsym(ctxt, s) 624 plt := ctxt.Syms.Lookup(".plt", 0) 625 626 ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) 627 628 // jmpq *got+size(IP) 629 s.SetPlt(int32(plt.Size)) 630 631 plt.AddUint8(0xff) 632 plt.AddUint8(0x25) 633 plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got())) 634 } else { 635 ld.Errorf(s, "addpltsym: unsupported binary format") 636 } 637 } 638 639 func addgotsym(ctxt *ld.Link, s *sym.Symbol) { 640 if s.Got() >= 0 { 641 return 642 } 643 644 ld.Adddynsym(ctxt, s) 645 got := ctxt.Syms.Lookup(".got", 0) 646 s.SetGot(int32(got.Size)) 647 got.AddUint64(ctxt.Arch, 0) 648 649 if ctxt.IsELF { 650 rela := ctxt.Syms.Lookup(".rela", 0) 651 rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) 652 rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT))) 653 rela.AddUint64(ctxt.Arch, 0) 654 } else if ctxt.HeadType == objabi.Hdarwin { 655 ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) 656 } else { 657 ld.Errorf(s, "addgotsym: unsupported binary format") 658 } 659 } 660 661 func asmb(ctxt *ld.Link) { 662 if ctxt.IsELF { 663 ld.Asmbelfsetup() 664 } 665 666 sect := ld.Segtext.Sections[0] 667 ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 668 // 0xCC is INT $3 - breakpoint instruction 669 ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) 670 for _, sect = range ld.Segtext.Sections[1:] { 671 ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 672 ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) 673 } 674 675 if ld.Segrodata.Filelen > 0 { 676 ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff)) 677 ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) 678 } 679 if ld.Segrelrodata.Filelen > 0 { 680 ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff)) 681 ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) 682 } 683 684 ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff)) 685 ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 686 687 ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff)) 688 ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) 689 } 690 691 func asmb2(ctxt *ld.Link) { 692 machlink := int64(0) 693 if ctxt.HeadType == objabi.Hdarwin { 694 machlink = ld.Domacholink(ctxt) 695 } 696 697 switch ctxt.HeadType { 698 default: 699 ld.Errorf(nil, "unknown header type %v", ctxt.HeadType) 700 fallthrough 701 702 case objabi.Hplan9: 703 break 704 705 case objabi.Hdarwin: 706 ld.Flag8 = true /* 64-bit addresses */ 707 708 case objabi.Hlinux, 709 objabi.Hfreebsd, 710 objabi.Hnetbsd, 711 objabi.Hopenbsd, 712 objabi.Hdragonfly, 713 objabi.Hsolaris: 714 ld.Flag8 = true /* 64-bit addresses */ 715 716 case objabi.Hwindows: 717 break 718 } 719 720 ld.Symsize = 0 721 ld.Spsize = 0 722 ld.Lcsize = 0 723 symo := int64(0) 724 if !*ld.FlagS { 725 switch ctxt.HeadType { 726 default: 727 case objabi.Hplan9: 728 *ld.FlagS = true 729 symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) 730 731 case objabi.Hdarwin: 732 symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink)) 733 734 case objabi.Hlinux, 735 objabi.Hfreebsd, 736 objabi.Hnetbsd, 737 objabi.Hopenbsd, 738 objabi.Hdragonfly, 739 objabi.Hsolaris: 740 symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) 741 symo = ld.Rnd(symo, int64(*ld.FlagRound)) 742 743 case objabi.Hwindows: 744 symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) 745 symo = ld.Rnd(symo, ld.PEFILEALIGN) 746 } 747 748 ctxt.Out.SeekSet(symo) 749 switch ctxt.HeadType { 750 default: 751 if ctxt.IsELF { 752 ctxt.Out.SeekSet(symo) 753 ld.Asmelfsym(ctxt) 754 ctxt.Out.Flush() 755 ctxt.Out.Write(ld.Elfstrdat) 756 757 if ctxt.LinkMode == ld.LinkExternal { 758 ld.Elfemitreloc(ctxt) 759 } 760 } 761 762 case objabi.Hplan9: 763 ld.Asmplan9sym(ctxt) 764 ctxt.Out.Flush() 765 766 sym := ctxt.Syms.Lookup("pclntab", 0) 767 if sym != nil { 768 ld.Lcsize = int32(len(sym.P)) 769 ctxt.Out.Write(sym.P) 770 ctxt.Out.Flush() 771 } 772 773 case objabi.Hwindows: 774 // Do nothing 775 776 case objabi.Hdarwin: 777 if ctxt.LinkMode == ld.LinkExternal { 778 ld.Machoemitreloc(ctxt) 779 } 780 } 781 } 782 783 ctxt.Out.SeekSet(0) 784 switch ctxt.HeadType { 785 default: 786 case objabi.Hplan9: /* plan9 */ 787 magic := int32(4*26*26 + 7) 788 789 magic |= 0x00008000 /* fat header */ 790 ctxt.Out.Write32b(uint32(magic)) /* magic */ 791 ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */ 792 ctxt.Out.Write32b(uint32(ld.Segdata.Filelen)) 793 ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 794 ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */ 795 vl := ld.Entryvalue(ctxt) 796 ctxt.Out.Write32b(PADDR(uint32(vl))) /* va of entry */ 797 ctxt.Out.Write32b(uint32(ld.Spsize)) /* sp offsets */ 798 ctxt.Out.Write32b(uint32(ld.Lcsize)) /* line offsets */ 799 ctxt.Out.Write64b(uint64(vl)) /* va of entry */ 800 801 case objabi.Hdarwin: 802 ld.Asmbmacho(ctxt) 803 804 case objabi.Hlinux, 805 objabi.Hfreebsd, 806 objabi.Hnetbsd, 807 objabi.Hopenbsd, 808 objabi.Hdragonfly, 809 objabi.Hsolaris: 810 ld.Asmbelf(ctxt, symo) 811 812 case objabi.Hwindows: 813 ld.Asmbpe(ctxt) 814 } 815 816 ctxt.Out.Flush() 817 } 818 819 func tlsIEtoLE(s *sym.Symbol, off, size int) { 820 // Transform the PC-relative instruction into a constant load. 821 // That is, 822 // 823 // MOVQ X(IP), REG -> MOVQ $Y, REG 824 // 825 // To determine the instruction and register, we study the op codes. 826 // Consult an AMD64 instruction encoding guide to decipher this. 827 if off < 3 { 828 log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction") 829 } 830 op := s.P[off-3 : off] 831 reg := op[2] >> 3 832 833 if op[1] == 0x8b || reg == 4 { 834 // MOVQ 835 if op[0] == 0x4c { 836 op[0] = 0x49 837 } else if size == 4 && op[0] == 0x44 { 838 op[0] = 0x41 839 } 840 if op[1] == 0x8b { 841 op[1] = 0xc7 842 } else { 843 op[1] = 0x81 // special case for SP 844 } 845 op[2] = 0xc0 | reg 846 } else { 847 // An alternate op is ADDQ. This is handled by GNU gold, 848 // but right now is not generated by the Go compiler: 849 // ADDQ X(IP), REG -> ADDQ $Y, REG 850 // Consider adding support for it here. 851 log.Fatalf("expected TLS IE op to be MOVQ, got %v", op) 852 } 853 }