github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 // 287 // Furthermore, the rela sections contain dynamic 288 // relocations with R_ADDR relocations on 289 // Elf64_Rela.r_offset. This field should contain the 290 // symbol offset as determined by reloc(), not the 291 // final dynamically linked address as a dynamic 292 // relocation would provide. 293 switch s.Name { 294 case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic": 295 return false 296 } 297 } else { 298 // Either internally linking a static executable, 299 // in which case we can resolve these relocations 300 // statically in the 'reloc' phase, or externally 301 // linking, in which case the relocation will be 302 // prepared in the 'reloc' phase and passed to the 303 // external linker in the 'asmb' phase. 304 if s.Type != ld.SDATA && s.Type != ld.SRODATA { 305 break 306 } 307 } 308 309 if ld.Iself { 310 // TODO: We generate a R_X86_64_64 relocation for every R_ADDR, even 311 // though it would be more efficient (for the dynamic linker) if we 312 // generated R_X86_RELATIVE instead. 313 ld.Adddynsym(ctxt, targ) 314 rela := ctxt.Syms.Lookup(".rela", 0) 315 ld.Addaddrplus(ctxt, rela, s, int64(r.Off)) 316 if r.Siz == 8 { 317 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64)) 318 } else { 319 // TODO: never happens, remove. 320 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32)) 321 } 322 ld.Adduint64(ctxt, rela, uint64(r.Add)) 323 r.Type = 256 // ignore during relocsym 324 return true 325 } 326 327 if ld.Headtype == objabi.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 { 328 // Mach-O relocations are a royal pain to lay out. 329 // They use a compact stateful bytecode representation 330 // that is too much bother to deal with. 331 // Instead, interpret the C declaration 332 // void *_Cvar_stderr = &stderr; 333 // as making _Cvar_stderr the name of a GOT entry 334 // for stderr. This is separate from the usual GOT entry, 335 // just in case the C code assigns to the variable, 336 // and of course it only works for single pointers, 337 // but we only need to support cgo and that's all it needs. 338 ld.Adddynsym(ctxt, targ) 339 340 got := ctxt.Syms.Lookup(".got", 0) 341 s.Type = got.Type | ld.SSUB 342 s.Outer = got 343 s.Sub = got.Sub 344 got.Sub = s 345 s.Value = got.Size 346 ld.Adduint64(ctxt, got, 0) 347 ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(targ.Dynid)) 348 r.Type = 256 // ignore during relocsym 349 return true 350 } 351 352 if ld.Headtype == objabi.Hwindows { 353 // nothing to do, the relocation will be laid out in pereloc1 354 return true 355 } 356 } 357 358 return false 359 } 360 361 func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int { 362 ld.Thearch.Vput(uint64(sectoff)) 363 364 elfsym := r.Xsym.ElfsymForReloc() 365 switch r.Type { 366 default: 367 return -1 368 369 case objabi.R_ADDR: 370 if r.Siz == 4 { 371 ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32) 372 } else if r.Siz == 8 { 373 ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32) 374 } else { 375 return -1 376 } 377 378 case objabi.R_TLS_LE: 379 if r.Siz == 4 { 380 ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32) 381 } else { 382 return -1 383 } 384 385 case objabi.R_TLS_IE: 386 if r.Siz == 4 { 387 ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32) 388 } else { 389 return -1 390 } 391 392 case objabi.R_CALL: 393 if r.Siz == 4 { 394 if r.Xsym.Type == ld.SDYNIMPORT { 395 if ctxt.DynlinkingGo() { 396 ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32) 397 } else { 398 ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32) 399 } 400 } else { 401 ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32) 402 } 403 } else { 404 return -1 405 } 406 407 case objabi.R_PCREL: 408 if r.Siz == 4 { 409 if r.Xsym.Type == ld.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC { 410 ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32) 411 } else { 412 ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32) 413 } 414 } else { 415 return -1 416 } 417 418 case objabi.R_GOTPCREL: 419 if r.Siz == 4 { 420 ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32) 421 } else { 422 return -1 423 } 424 } 425 426 ld.Thearch.Vput(uint64(r.Xadd)) 427 return 0 428 } 429 430 func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int { 431 var v uint32 432 433 rs := r.Xsym 434 435 if rs.Type == ld.SHOSTOBJ || r.Type == objabi.R_PCREL || r.Type == objabi.R_GOTPCREL { 436 if rs.Dynid < 0 { 437 ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type) 438 return -1 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 to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) 447 return -1 448 } 449 } 450 451 switch r.Type { 452 default: 453 return -1 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 -1 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 ld.Thearch.Lput(uint32(sectoff)) 489 ld.Thearch.Lput(v) 490 return 0 491 } 492 493 func pereloc1(s *ld.Symbol, r *ld.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 to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type) 500 return false 501 } 502 503 ld.Thearch.Lput(uint32(sectoff)) 504 ld.Thearch.Lput(uint32(rs.Dynid)) 505 506 switch r.Type { 507 default: 508 return false 509 510 case objabi.R_DWARFREF: 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 ld.Thearch.Wput(uint16(v)) 526 527 return true 528 } 529 530 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { 531 return -1 532 } 533 534 func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.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 ld.Adduint8(ctxt, plt, 0xff) 545 546 ld.Adduint8(ctxt, plt, 0x35) 547 ld.Addpcrelplus(ctxt, plt, got, 8) 548 549 // jmpq got+16(IP) 550 ld.Adduint8(ctxt, plt, 0xff) 551 552 ld.Adduint8(ctxt, plt, 0x25) 553 ld.Addpcrelplus(ctxt, plt, got, 16) 554 555 // nopl 0(AX) 556 ld.Adduint32(ctxt, plt, 0x00401f0f) 557 558 // assume got->size == 0 too 559 ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0) 560 561 ld.Adduint64(ctxt, got, 0) 562 ld.Adduint64(ctxt, got, 0) 563 } 564 } 565 566 func addpltsym(ctxt *ld.Link, s *ld.Symbol) { 567 if s.Plt >= 0 { 568 return 569 } 570 571 ld.Adddynsym(ctxt, s) 572 573 if ld.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 ld.Adduint8(ctxt, plt, 0xff) 583 584 ld.Adduint8(ctxt, plt, 0x25) 585 ld.Addpcrelplus(ctxt, plt, got, got.Size) 586 587 // add to got: pointer to current pos in plt 588 ld.Addaddrplus(ctxt, got, plt, plt.Size) 589 590 // pushq $x 591 ld.Adduint8(ctxt, plt, 0x68) 592 593 ld.Adduint32(ctxt, plt, uint32((got.Size-24-8)/8)) 594 595 // jmpq .plt 596 ld.Adduint8(ctxt, plt, 0xe9) 597 598 ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4))) 599 600 // rela 601 ld.Addaddrplus(ctxt, rela, got, got.Size-8) 602 603 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT)) 604 ld.Adduint64(ctxt, rela, 0) 605 606 s.Plt = int32(plt.Size - 16) 607 } else if ld.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 ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.plt", 0), uint32(s.Dynid)) 622 623 // jmpq *got+size(IP) 624 s.Plt = int32(plt.Size) 625 626 ld.Adduint8(ctxt, plt, 0xff) 627 ld.Adduint8(ctxt, plt, 0x25) 628 ld.Addpcrelplus(ctxt, plt, 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 *ld.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 ld.Adduint64(ctxt, got, 0) 643 644 if ld.Iself { 645 rela := ctxt.Syms.Lookup(".rela", 0) 646 ld.Addaddrplus(ctxt, rela, got, int64(s.Got)) 647 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT)) 648 ld.Adduint64(ctxt, rela, 0) 649 } else if ld.Headtype == objabi.Hdarwin { 650 ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), 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 ld.Iself { 666 ld.Asmbelfsetup() 667 } 668 669 sect := ld.Segtext.Sections[0] 670 ld.Cseek(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 ld.Cseek(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 ld.Cseek(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 ld.Cseek(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 ld.Cseek(int64(ld.Segdata.Fileoff)) 698 ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 699 700 ld.Cseek(int64(ld.Segdwarf.Fileoff)) 701 ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) 702 703 machlink := int64(0) 704 if ld.Headtype == objabi.Hdarwin { 705 machlink = ld.Domacholink(ctxt) 706 } 707 708 switch ld.Headtype { 709 default: 710 ld.Errorf(nil, "unknown header type %v", ld.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 ld.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 ld.Cseek(symo) 765 switch ld.Headtype { 766 default: 767 if ld.Iself { 768 ld.Cseek(symo) 769 ld.Asmelfsym(ctxt) 770 ld.Cflush() 771 ld.Cwrite(ld.Elfstrdat) 772 773 if ctxt.Debugvlog != 0 { 774 ctxt.Logf("%5.2f dwarf\n", ld.Cputime()) 775 } 776 777 if ld.Linkmode == ld.LinkExternal { 778 ld.Elfemitreloc(ctxt) 779 } 780 } 781 782 case objabi.Hplan9: 783 ld.Asmplan9sym(ctxt) 784 ld.Cflush() 785 786 sym := ctxt.Syms.Lookup("pclntab", 0) 787 if sym != nil { 788 ld.Lcsize = int32(len(sym.P)) 789 for i := 0; int32(i) < ld.Lcsize; i++ { 790 ld.Cput(sym.P[i]) 791 } 792 793 ld.Cflush() 794 } 795 796 case objabi.Hwindows: 797 if ctxt.Debugvlog != 0 { 798 ctxt.Logf("%5.2f dwarf\n", ld.Cputime()) 799 } 800 801 case objabi.Hdarwin: 802 if ld.Linkmode == ld.LinkExternal { 803 ld.Machoemitreloc(ctxt) 804 } 805 } 806 } 807 808 if ctxt.Debugvlog != 0 { 809 ctxt.Logf("%5.2f headr\n", ld.Cputime()) 810 } 811 ld.Cseek(0) 812 switch ld.Headtype { 813 default: 814 case objabi.Hplan9: /* plan9 */ 815 magic := int32(4*26*26 + 7) 816 817 magic |= 0x00008000 /* fat header */ 818 ld.Lputb(uint32(magic)) /* magic */ 819 ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */ 820 ld.Lputb(uint32(ld.Segdata.Filelen)) 821 ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 822 ld.Lputb(uint32(ld.Symsize)) /* nsyms */ 823 vl := ld.Entryvalue(ctxt) 824 ld.Lputb(PADDR(uint32(vl))) /* va of entry */ 825 ld.Lputb(uint32(ld.Spsize)) /* sp offsets */ 826 ld.Lputb(uint32(ld.Lcsize)) /* line offsets */ 827 ld.Vputb(uint64(vl)) /* va of entry */ 828 829 case objabi.Hdarwin: 830 ld.Asmbmacho(ctxt) 831 832 case objabi.Hlinux, 833 objabi.Hfreebsd, 834 objabi.Hnetbsd, 835 objabi.Hopenbsd, 836 objabi.Hdragonfly, 837 objabi.Hsolaris, 838 objabi.Hnacl: 839 ld.Asmbelf(ctxt, symo) 840 841 case objabi.Hwindows: 842 ld.Asmbpe(ctxt) 843 } 844 845 ld.Cflush() 846 } 847 848 func tlsIEtoLE(s *ld.Symbol, off, size int) { 849 // Transform the PC-relative instruction into a constant load. 850 // That is, 851 // 852 // MOVQ X(IP), REG -> MOVQ $Y, REG 853 // 854 // To determine the instruction and register, we study the op codes. 855 // Consult an AMD64 instruction encoding guide to decipher this. 856 if off < 3 { 857 log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction") 858 } 859 op := s.P[off-3 : off] 860 reg := op[2] >> 3 861 862 if op[1] == 0x8b || reg == 4 { 863 // MOVQ 864 if op[0] == 0x4c { 865 op[0] = 0x49 866 } else if size == 4 && op[0] == 0x44 { 867 op[0] = 0x41 868 } 869 if op[1] == 0x8b { 870 op[1] = 0xc7 871 } else { 872 op[1] = 0x81 // special case for SP 873 } 874 op[2] = 0xc0 | reg 875 } else { 876 // An alternate op is ADDQ. This is handled by GNU gold, 877 // but right now is not generated by the Go compiler: 878 // ADDQ X(IP), REG -> ADDQ $Y, REG 879 // Consider adding support for it here. 880 log.Fatalf("expected TLS IE op to be MOVQ, got %v", op) 881 } 882 }