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