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