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 (a] 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 (a] 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/obj" 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 = obj.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 == obj.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 = obj.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 = obj.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 == obj.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 == obj.SXREF { 115 ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name) 116 } 117 r.Type = obj.R_PCREL 118 r.Add += 4 119 return true 120 121 case 256 + ld.R_X86_64_PLT32: 122 r.Type = obj.R_PCREL 123 r.Add += 4 124 if targ.Type == obj.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 != obj.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 = obj.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 = obj.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 == obj.SDYNIMPORT { 157 ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name) 158 } 159 r.Type = obj.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 = obj.R_ADDR 168 169 if targ.Type == obj.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 == obj.SDYNIMPORT { 176 addpltsym(ctxt, targ) 177 r.Sym = ctxt.Syms.Lookup(".plt", 0) 178 r.Add = int64(targ.Plt) 179 r.Type = obj.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 = obj.R_PCREL 191 192 if targ.Type == obj.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 != obj.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 = obj.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 != obj.SDYNIMPORT { 215 ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) 216 } 217 addgotsym(ctxt, targ) 218 r.Type = obj.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 obj.R_CALL, 226 obj.R_PCREL: 227 if targ.Type != obj.SDYNIMPORT { 228 // nothing to do, the relocation will be laid out in reloc 229 return true 230 } 231 if ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui { 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 obj.R_ADDR: 243 if s.Type == obj.STEXT && ld.Iself { 244 if ld.Headtype == obj.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 != obj.SDATA && s.Type != obj.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 == obj.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 | obj.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 == obj.Hwindows || ld.Headtype == obj.Hwindowsgui { 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 obj.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 obj.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 obj.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 obj.R_CALL: 386 if r.Siz == 4 { 387 if r.Xsym.Type == obj.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 obj.R_PCREL: 401 if r.Siz == 4 { 402 if r.Xsym.Type == obj.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 obj.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 == obj.SHOSTOBJ || r.Type == obj.R_PCREL || r.Type == obj.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 obj.R_ADDR: 449 v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28 450 451 case obj.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 obj.R_PCREL: 457 v |= 1 << 24 // pc-relative bit 458 v |= ld.MACHO_X86_64_RELOC_SIGNED << 28 459 case obj.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 obj.R_ADDR: 504 if r.Siz == 8 { 505 v = ld.IMAGE_REL_AMD64_ADDR64 506 } else { 507 v = ld.IMAGE_REL_AMD64_ADDR32 508 } 509 510 case obj.R_CALL, 511 obj.R_PCREL: 512 v = ld.IMAGE_REL_AMD64_REL32 513 } 514 515 ld.Thearch.Wput(uint16(v)) 516 517 return true 518 } 519 520 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { 521 return -1 522 } 523 524 func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 { 525 log.Fatalf("unexpected relocation variant") 526 return t 527 } 528 529 func elfsetupplt(ctxt *ld.Link) { 530 plt := ctxt.Syms.Lookup(".plt", 0) 531 got := ctxt.Syms.Lookup(".got.plt", 0) 532 if plt.Size == 0 { 533 // pushq got+8(IP) 534 ld.Adduint8(ctxt, plt, 0xff) 535 536 ld.Adduint8(ctxt, plt, 0x35) 537 ld.Addpcrelplus(ctxt, plt, got, 8) 538 539 // jmpq got+16(IP) 540 ld.Adduint8(ctxt, plt, 0xff) 541 542 ld.Adduint8(ctxt, plt, 0x25) 543 ld.Addpcrelplus(ctxt, plt, got, 16) 544 545 // nopl 0(AX) 546 ld.Adduint32(ctxt, plt, 0x00401f0f) 547 548 // assume got->size == 0 too 549 ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0) 550 551 ld.Adduint64(ctxt, got, 0) 552 ld.Adduint64(ctxt, got, 0) 553 } 554 } 555 556 func addpltsym(ctxt *ld.Link, s *ld.Symbol) { 557 if s.Plt >= 0 { 558 return 559 } 560 561 ld.Adddynsym(ctxt, s) 562 563 if ld.Iself { 564 plt := ctxt.Syms.Lookup(".plt", 0) 565 got := ctxt.Syms.Lookup(".got.plt", 0) 566 rela := ctxt.Syms.Lookup(".rela.plt", 0) 567 if plt.Size == 0 { 568 elfsetupplt(ctxt) 569 } 570 571 // jmpq *got+size(IP) 572 ld.Adduint8(ctxt, plt, 0xff) 573 574 ld.Adduint8(ctxt, plt, 0x25) 575 ld.Addpcrelplus(ctxt, plt, got, got.Size) 576 577 // add to got: pointer to current pos in plt 578 ld.Addaddrplus(ctxt, got, plt, plt.Size) 579 580 // pushq $x 581 ld.Adduint8(ctxt, plt, 0x68) 582 583 ld.Adduint32(ctxt, plt, uint32((got.Size-24-8)/8)) 584 585 // jmpq .plt 586 ld.Adduint8(ctxt, plt, 0xe9) 587 588 ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4))) 589 590 // rela 591 ld.Addaddrplus(ctxt, rela, got, got.Size-8) 592 593 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT)) 594 ld.Adduint64(ctxt, rela, 0) 595 596 s.Plt = int32(plt.Size - 16) 597 } else if ld.Headtype == obj.Hdarwin { 598 // To do lazy symbol lookup right, we're supposed 599 // to tell the dynamic loader which library each 600 // symbol comes from and format the link info 601 // section just so. I'm too lazy (ha!) to do that 602 // so for now we'll just use non-lazy pointers, 603 // which don't need to be told which library to use. 604 // 605 // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html 606 // has details about what we're avoiding. 607 608 addgotsym(ctxt, s) 609 plt := ctxt.Syms.Lookup(".plt", 0) 610 611 ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.plt", 0), uint32(s.Dynid)) 612 613 // jmpq *got+size(IP) 614 s.Plt = int32(plt.Size) 615 616 ld.Adduint8(ctxt, plt, 0xff) 617 ld.Adduint8(ctxt, plt, 0x25) 618 ld.Addpcrelplus(ctxt, plt, ctxt.Syms.Lookup(".got", 0), int64(s.Got)) 619 } else { 620 ld.Errorf(s, "addpltsym: unsupported binary format") 621 } 622 } 623 624 func addgotsym(ctxt *ld.Link, s *ld.Symbol) { 625 if s.Got >= 0 { 626 return 627 } 628 629 ld.Adddynsym(ctxt, s) 630 got := ctxt.Syms.Lookup(".got", 0) 631 s.Got = int32(got.Size) 632 ld.Adduint64(ctxt, got, 0) 633 634 if ld.Iself { 635 rela := ctxt.Syms.Lookup(".rela", 0) 636 ld.Addaddrplus(ctxt, rela, got, int64(s.Got)) 637 ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT)) 638 ld.Adduint64(ctxt, rela, 0) 639 } else if ld.Headtype == obj.Hdarwin { 640 ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(s.Dynid)) 641 } else { 642 ld.Errorf(s, "addgotsym: unsupported binary format") 643 } 644 } 645 646 func asmb(ctxt *ld.Link) { 647 if ctxt.Debugvlog != 0 { 648 ctxt.Logf("%5.2f asmb\n", obj.Cputime()) 649 } 650 651 if ctxt.Debugvlog != 0 { 652 ctxt.Logf("%5.2f codeblk\n", obj.Cputime()) 653 } 654 655 if ld.Iself { 656 ld.Asmbelfsetup() 657 } 658 659 sect := ld.Segtext.Sect 660 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 661 // 0xCC is INT $3 - breakpoint instruction 662 ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC}) 663 for sect = sect.Next; sect != nil; sect = sect.Next { 664 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 665 ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length)) 666 } 667 668 if ld.Segrodata.Filelen > 0 { 669 if ctxt.Debugvlog != 0 { 670 ctxt.Logf("%5.2f rodatblk\n", obj.Cputime()) 671 } 672 ld.Cseek(int64(ld.Segrodata.Fileoff)) 673 ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) 674 } 675 if ld.Segrelrodata.Filelen > 0 { 676 if ctxt.Debugvlog != 0 { 677 ctxt.Logf("%5.2f relrodatblk\n", obj.Cputime()) 678 } 679 ld.Cseek(int64(ld.Segrelrodata.Fileoff)) 680 ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen)) 681 } 682 683 if ctxt.Debugvlog != 0 { 684 ctxt.Logf("%5.2f datblk\n", obj.Cputime()) 685 } 686 687 ld.Cseek(int64(ld.Segdata.Fileoff)) 688 ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 689 690 ld.Cseek(int64(ld.Segdwarf.Fileoff)) 691 ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) 692 693 machlink := int64(0) 694 if ld.Headtype == obj.Hdarwin { 695 machlink = ld.Domacholink(ctxt) 696 } 697 698 switch ld.Headtype { 699 default: 700 ld.Errorf(nil, "unknown header type %v", ld.Headtype) 701 fallthrough 702 703 case obj.Hplan9: 704 break 705 706 case obj.Hdarwin: 707 ld.Flag8 = true /* 64-bit addresses */ 708 709 case obj.Hlinux, 710 obj.Hfreebsd, 711 obj.Hnetbsd, 712 obj.Hopenbsd, 713 obj.Hdragonfly, 714 obj.Hsolaris: 715 ld.Flag8 = true /* 64-bit addresses */ 716 717 case obj.Hnacl, 718 obj.Hwindows, 719 obj.Hwindowsgui: 720 break 721 } 722 723 ld.Symsize = 0 724 ld.Spsize = 0 725 ld.Lcsize = 0 726 symo := int64(0) 727 if !*ld.FlagS { 728 if ctxt.Debugvlog != 0 { 729 ctxt.Logf("%5.2f sym\n", obj.Cputime()) 730 } 731 switch ld.Headtype { 732 default: 733 case obj.Hplan9: 734 *ld.FlagS = true 735 symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) 736 737 case obj.Hdarwin: 738 symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink)) 739 740 case obj.Hlinux, 741 obj.Hfreebsd, 742 obj.Hnetbsd, 743 obj.Hopenbsd, 744 obj.Hdragonfly, 745 obj.Hsolaris, 746 obj.Hnacl: 747 symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) 748 symo = ld.Rnd(symo, int64(*ld.FlagRound)) 749 750 case obj.Hwindows, 751 obj.Hwindowsgui: 752 symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) 753 symo = ld.Rnd(symo, ld.PEFILEALIGN) 754 } 755 756 ld.Cseek(symo) 757 switch ld.Headtype { 758 default: 759 if ld.Iself { 760 ld.Cseek(symo) 761 ld.Asmelfsym(ctxt) 762 ld.Cflush() 763 ld.Cwrite(ld.Elfstrdat) 764 765 if ctxt.Debugvlog != 0 { 766 ctxt.Logf("%5.2f dwarf\n", obj.Cputime()) 767 } 768 769 if ld.Linkmode == ld.LinkExternal { 770 ld.Elfemitreloc(ctxt) 771 } 772 } 773 774 case obj.Hplan9: 775 ld.Asmplan9sym(ctxt) 776 ld.Cflush() 777 778 sym := ctxt.Syms.Lookup("pclntab", 0) 779 if sym != nil { 780 ld.Lcsize = int32(len(sym.P)) 781 for i := 0; int32(i) < ld.Lcsize; i++ { 782 ld.Cput(sym.P[i]) 783 } 784 785 ld.Cflush() 786 } 787 788 case obj.Hwindows, obj.Hwindowsgui: 789 if ctxt.Debugvlog != 0 { 790 ctxt.Logf("%5.2f dwarf\n", obj.Cputime()) 791 } 792 793 case obj.Hdarwin: 794 if ld.Linkmode == ld.LinkExternal { 795 ld.Machoemitreloc(ctxt) 796 } 797 } 798 } 799 800 if ctxt.Debugvlog != 0 { 801 ctxt.Logf("%5.2f headr\n", obj.Cputime()) 802 } 803 ld.Cseek(0) 804 switch ld.Headtype { 805 default: 806 case obj.Hplan9: /* plan9 */ 807 magic := int32(4*26*26 + 7) 808 809 magic |= 0x00008000 /* fat header */ 810 ld.Lputb(uint32(magic)) /* magic */ 811 ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */ 812 ld.Lputb(uint32(ld.Segdata.Filelen)) 813 ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 814 ld.Lputb(uint32(ld.Symsize)) /* nsyms */ 815 vl := ld.Entryvalue(ctxt) 816 ld.Lputb(PADDR(uint32(vl))) /* va of entry */ 817 ld.Lputb(uint32(ld.Spsize)) /* sp offsets */ 818 ld.Lputb(uint32(ld.Lcsize)) /* line offsets */ 819 ld.Vputb(uint64(vl)) /* va of entry */ 820 821 case obj.Hdarwin: 822 ld.Asmbmacho(ctxt) 823 824 case obj.Hlinux, 825 obj.Hfreebsd, 826 obj.Hnetbsd, 827 obj.Hopenbsd, 828 obj.Hdragonfly, 829 obj.Hsolaris, 830 obj.Hnacl: 831 ld.Asmbelf(ctxt, symo) 832 833 case obj.Hwindows, 834 obj.Hwindowsgui: 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 } 876