1 // Inferno utils/8l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/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 x86 32 33 import ( 34 "cmd/internal/obj" 35 "cmd/link/internal/ld" 36 "fmt" 37 "log" 38 ) 39 40 func gentext() { 41 } 42 43 func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) { 44 log.Fatalf("adddynrela not implemented") 45 } 46 47 func adddynrel(s *ld.LSym, r *ld.Reloc) { 48 targ := r.Sym 49 ld.Ctxt.Cursym = s 50 51 switch r.Type { 52 default: 53 if r.Type >= 256 { 54 ld.Diag("unexpected relocation type %d", r.Type) 55 return 56 } 57 58 // Handle relocations found in ELF object files. 59 case 256 + ld.R_386_PC32: 60 if targ.Type == obj.SDYNIMPORT { 61 ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name) 62 } 63 if targ.Type == 0 || targ.Type == obj.SXREF { 64 ld.Diag("unknown symbol %s in pcrel", targ.Name) 65 } 66 r.Type = obj.R_PCREL 67 r.Add += 4 68 return 69 70 case 256 + ld.R_386_PLT32: 71 r.Type = obj.R_PCREL 72 r.Add += 4 73 if targ.Type == obj.SDYNIMPORT { 74 addpltsym(ld.Ctxt, targ) 75 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0) 76 r.Add += int64(targ.Plt) 77 } 78 79 return 80 81 case 256 + ld.R_386_GOT32: 82 if targ.Type != obj.SDYNIMPORT { 83 // have symbol 84 if r.Off >= 2 && s.P[r.Off-2] == 0x8b { 85 // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. 86 s.P[r.Off-2] = 0x8d 87 88 r.Type = obj.R_GOTOFF 89 return 90 } 91 92 if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 { 93 // turn PUSHL of GOT entry into PUSHL of symbol itself. 94 // use unnecessary SS prefix to keep instruction same length. 95 s.P[r.Off-2] = 0x36 96 97 s.P[r.Off-1] = 0x68 98 r.Type = obj.R_ADDR 99 return 100 } 101 102 ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name) 103 return 104 } 105 106 addgotsym(ld.Ctxt, targ) 107 r.Type = obj.R_CONST // write r->add during relocsym 108 r.Sym = nil 109 r.Add += int64(targ.Got) 110 return 111 112 case 256 + ld.R_386_GOTOFF: 113 r.Type = obj.R_GOTOFF 114 return 115 116 case 256 + ld.R_386_GOTPC: 117 r.Type = obj.R_PCREL 118 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0) 119 r.Add += 4 120 return 121 122 case 256 + ld.R_386_32: 123 if targ.Type == obj.SDYNIMPORT { 124 ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name) 125 } 126 r.Type = obj.R_ADDR 127 return 128 129 case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0: 130 r.Type = obj.R_ADDR 131 if targ.Type == obj.SDYNIMPORT { 132 ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name) 133 } 134 return 135 136 case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1: 137 if targ.Type == obj.SDYNIMPORT { 138 addpltsym(ld.Ctxt, targ) 139 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0) 140 r.Add = int64(targ.Plt) 141 r.Type = obj.R_PCREL 142 return 143 } 144 145 r.Type = obj.R_PCREL 146 return 147 148 case 512 + ld.MACHO_FAKE_GOTPCREL: 149 if targ.Type != obj.SDYNIMPORT { 150 // have symbol 151 // turn MOVL of GOT entry into LEAL of symbol itself 152 if r.Off < 2 || s.P[r.Off-2] != 0x8b { 153 ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name) 154 return 155 } 156 157 s.P[r.Off-2] = 0x8d 158 r.Type = obj.R_PCREL 159 return 160 } 161 162 addgotsym(ld.Ctxt, targ) 163 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0) 164 r.Add += int64(targ.Got) 165 r.Type = obj.R_PCREL 166 return 167 } 168 169 // Handle references to ELF symbols from our own object files. 170 if targ.Type != obj.SDYNIMPORT { 171 return 172 } 173 174 switch r.Type { 175 case obj.R_CALL, 176 obj.R_PCREL: 177 addpltsym(ld.Ctxt, targ) 178 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0) 179 r.Add = int64(targ.Plt) 180 return 181 182 case obj.R_ADDR: 183 if s.Type != obj.SDATA { 184 break 185 } 186 if ld.Iself { 187 ld.Adddynsym(ld.Ctxt, targ) 188 rel := ld.Linklookup(ld.Ctxt, ".rel", 0) 189 ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) 190 ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32)) 191 r.Type = obj.R_CONST // write r->add during relocsym 192 r.Sym = nil 193 return 194 } 195 196 if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 { 197 // Mach-O relocations are a royal pain to lay out. 198 // They use a compact stateful bytecode representation 199 // that is too much bother to deal with. 200 // Instead, interpret the C declaration 201 // void *_Cvar_stderr = &stderr; 202 // as making _Cvar_stderr the name of a GOT entry 203 // for stderr. This is separate from the usual GOT entry, 204 // just in case the C code assigns to the variable, 205 // and of course it only works for single pointers, 206 // but we only need to support cgo and that's all it needs. 207 ld.Adddynsym(ld.Ctxt, targ) 208 209 got := ld.Linklookup(ld.Ctxt, ".got", 0) 210 s.Type = got.Type | obj.SSUB 211 s.Outer = got 212 s.Sub = got.Sub 213 got.Sub = s 214 s.Value = got.Size 215 ld.Adduint32(ld.Ctxt, got, 0) 216 ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid)) 217 r.Type = 256 // ignore during relocsym 218 return 219 } 220 221 if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize { 222 // nothing to do, the relocation will be laid out in pereloc1 223 return 224 } 225 } 226 227 ld.Ctxt.Cursym = s 228 ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type) 229 } 230 231 func elfreloc1(r *ld.Reloc, sectoff int64) int { 232 ld.Thearch.Lput(uint32(sectoff)) 233 234 elfsym := r.Xsym.Elfsym 235 switch r.Type { 236 default: 237 return -1 238 239 case obj.R_ADDR: 240 if r.Siz == 4 { 241 ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8) 242 } else { 243 return -1 244 } 245 246 case obj.R_CALL, 247 obj.R_PCREL: 248 if r.Siz == 4 { 249 ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8) 250 } else { 251 return -1 252 } 253 254 case obj.R_TLS_LE: 255 if r.Siz == 4 { 256 ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8) 257 } else { 258 return -1 259 } 260 } 261 262 return 0 263 } 264 265 func machoreloc1(r *ld.Reloc, sectoff int64) int { 266 var v uint32 267 268 rs := r.Xsym 269 270 if rs.Type == obj.SHOSTOBJ { 271 if rs.Dynid < 0 { 272 ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type) 273 return -1 274 } 275 276 v = uint32(rs.Dynid) 277 v |= 1 << 27 // external relocation 278 } else { 279 v = uint32(rs.Sect.Extnum) 280 if v == 0 { 281 ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) 282 return -1 283 } 284 } 285 286 switch r.Type { 287 default: 288 return -1 289 290 case obj.R_ADDR: 291 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28 292 293 case obj.R_CALL, 294 obj.R_PCREL: 295 v |= 1 << 24 // pc-relative bit 296 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28 297 } 298 299 switch r.Siz { 300 default: 301 return -1 302 303 case 1: 304 v |= 0 << 25 305 306 case 2: 307 v |= 1 << 25 308 309 case 4: 310 v |= 2 << 25 311 312 case 8: 313 v |= 3 << 25 314 } 315 316 ld.Thearch.Lput(uint32(sectoff)) 317 ld.Thearch.Lput(v) 318 return 0 319 } 320 321 func pereloc1(r *ld.Reloc, sectoff int64) bool { 322 var v uint32 323 324 rs := r.Xsym 325 326 if rs.Dynid < 0 { 327 ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type) 328 return false 329 } 330 331 ld.Thearch.Lput(uint32(sectoff)) 332 ld.Thearch.Lput(uint32(rs.Dynid)) 333 334 switch r.Type { 335 default: 336 return false 337 338 case obj.R_ADDR: 339 v = ld.IMAGE_REL_I386_DIR32 340 341 case obj.R_CALL, 342 obj.R_PCREL: 343 v = ld.IMAGE_REL_I386_REL32 344 } 345 346 ld.Thearch.Wput(uint16(v)) 347 348 return true 349 } 350 351 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { 352 if ld.Linkmode == ld.LinkExternal { 353 return -1 354 } 355 switch r.Type { 356 case obj.R_CONST: 357 *val = r.Add 358 return 0 359 360 case obj.R_GOTOFF: 361 *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) 362 return 0 363 } 364 365 return -1 366 } 367 368 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { 369 log.Fatalf("unexpected relocation variant") 370 return t 371 } 372 373 func elfsetupplt() { 374 plt := ld.Linklookup(ld.Ctxt, ".plt", 0) 375 got := ld.Linklookup(ld.Ctxt, ".got.plt", 0) 376 if plt.Size == 0 { 377 // pushl got+4 378 ld.Adduint8(ld.Ctxt, plt, 0xff) 379 380 ld.Adduint8(ld.Ctxt, plt, 0x35) 381 ld.Addaddrplus(ld.Ctxt, plt, got, 4) 382 383 // jmp *got+8 384 ld.Adduint8(ld.Ctxt, plt, 0xff) 385 386 ld.Adduint8(ld.Ctxt, plt, 0x25) 387 ld.Addaddrplus(ld.Ctxt, plt, got, 8) 388 389 // zero pad 390 ld.Adduint32(ld.Ctxt, plt, 0) 391 392 // assume got->size == 0 too 393 ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0) 394 395 ld.Adduint32(ld.Ctxt, got, 0) 396 ld.Adduint32(ld.Ctxt, got, 0) 397 } 398 } 399 400 func addpltsym(ctxt *ld.Link, s *ld.LSym) { 401 if s.Plt >= 0 { 402 return 403 } 404 405 ld.Adddynsym(ctxt, s) 406 407 if ld.Iself { 408 plt := ld.Linklookup(ctxt, ".plt", 0) 409 got := ld.Linklookup(ctxt, ".got.plt", 0) 410 rel := ld.Linklookup(ctxt, ".rel.plt", 0) 411 if plt.Size == 0 { 412 elfsetupplt() 413 } 414 415 // jmpq *got+size 416 ld.Adduint8(ctxt, plt, 0xff) 417 418 ld.Adduint8(ctxt, plt, 0x25) 419 ld.Addaddrplus(ctxt, plt, got, got.Size) 420 421 // add to got: pointer to current pos in plt 422 ld.Addaddrplus(ctxt, got, plt, plt.Size) 423 424 // pushl $x 425 ld.Adduint8(ctxt, plt, 0x68) 426 427 ld.Adduint32(ctxt, plt, uint32(rel.Size)) 428 429 // jmp .plt 430 ld.Adduint8(ctxt, plt, 0xe9) 431 432 ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4))) 433 434 // rel 435 ld.Addaddrplus(ctxt, rel, got, got.Size-4) 436 437 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT)) 438 439 s.Plt = int32(plt.Size - 16) 440 } else if ld.HEADTYPE == obj.Hdarwin { 441 // Same laziness as in 6l. 442 443 plt := ld.Linklookup(ctxt, ".plt", 0) 444 445 addgotsym(ctxt, s) 446 447 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid)) 448 449 // jmpq *got+size(IP) 450 s.Plt = int32(plt.Size) 451 452 ld.Adduint8(ctxt, plt, 0xff) 453 ld.Adduint8(ctxt, plt, 0x25) 454 ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got)) 455 } else { 456 ld.Diag("addpltsym: unsupported binary format") 457 } 458 } 459 460 func addgotsym(ctxt *ld.Link, s *ld.LSym) { 461 if s.Got >= 0 { 462 return 463 } 464 465 ld.Adddynsym(ctxt, s) 466 got := ld.Linklookup(ctxt, ".got", 0) 467 s.Got = int32(got.Size) 468 ld.Adduint32(ctxt, got, 0) 469 470 if ld.Iself { 471 rel := ld.Linklookup(ctxt, ".rel", 0) 472 ld.Addaddrplus(ctxt, rel, got, int64(s.Got)) 473 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT)) 474 } else if ld.HEADTYPE == obj.Hdarwin { 475 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid)) 476 } else { 477 ld.Diag("addgotsym: unsupported binary format") 478 } 479 } 480 481 func asmb() { 482 if ld.Debug['v'] != 0 { 483 fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) 484 } 485 ld.Bso.Flush() 486 487 if ld.Iself { 488 ld.Asmbelfsetup() 489 } 490 491 sect := ld.Segtext.Sect 492 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 493 ld.Codeblk(int64(sect.Vaddr), int64(sect.Length)) 494 for sect = sect.Next; sect != nil; sect = sect.Next { 495 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff)) 496 ld.Datblk(int64(sect.Vaddr), int64(sect.Length)) 497 } 498 499 if ld.Segrodata.Filelen > 0 { 500 if ld.Debug['v'] != 0 { 501 fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) 502 } 503 ld.Bso.Flush() 504 505 ld.Cseek(int64(ld.Segrodata.Fileoff)) 506 ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen)) 507 } 508 509 if ld.Debug['v'] != 0 { 510 fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) 511 } 512 ld.Bso.Flush() 513 514 ld.Cseek(int64(ld.Segdata.Fileoff)) 515 ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) 516 517 machlink := uint32(0) 518 if ld.HEADTYPE == obj.Hdarwin { 519 if ld.Debug['v'] != 0 { 520 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 521 } 522 523 dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) 524 ld.Cseek(int64(dwarfoff)) 525 526 ld.Segdwarf.Fileoff = uint64(ld.Cpos()) 527 ld.Dwarfemitdebugsections() 528 ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff 529 530 machlink = uint32(ld.Domacholink()) 531 } 532 533 ld.Symsize = 0 534 ld.Spsize = 0 535 ld.Lcsize = 0 536 symo := uint32(0) 537 if ld.Debug['s'] == 0 { 538 // TODO: rationalize 539 if ld.Debug['v'] != 0 { 540 fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) 541 } 542 ld.Bso.Flush() 543 switch ld.HEADTYPE { 544 default: 545 if ld.Iself { 546 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 547 symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) 548 } 549 550 case obj.Hplan9: 551 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 552 553 case obj.Hdarwin: 554 symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) 555 556 case obj.Hwindows: 557 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) 558 symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN)) 559 } 560 561 ld.Cseek(int64(symo)) 562 switch ld.HEADTYPE { 563 default: 564 if ld.Iself { 565 if ld.Debug['v'] != 0 { 566 fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) 567 } 568 ld.Asmelfsym() 569 ld.Cflush() 570 ld.Cwrite(ld.Elfstrdat) 571 572 if ld.Debug['v'] != 0 { 573 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 574 } 575 ld.Dwarfemitdebugsections() 576 577 if ld.Linkmode == ld.LinkExternal { 578 ld.Elfemitreloc() 579 } 580 } 581 582 case obj.Hplan9: 583 ld.Asmplan9sym() 584 ld.Cflush() 585 586 sym := ld.Linklookup(ld.Ctxt, "pclntab", 0) 587 if sym != nil { 588 ld.Lcsize = int32(len(sym.P)) 589 for i := 0; int32(i) < ld.Lcsize; i++ { 590 ld.Cput(uint8(sym.P[i])) 591 } 592 593 ld.Cflush() 594 } 595 596 case obj.Hwindows: 597 if ld.Debug['v'] != 0 { 598 fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) 599 } 600 ld.Dwarfemitdebugsections() 601 602 case obj.Hdarwin: 603 if ld.Linkmode == ld.LinkExternal { 604 ld.Machoemitreloc() 605 } 606 } 607 } 608 609 if ld.Debug['v'] != 0 { 610 fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime()) 611 } 612 ld.Bso.Flush() 613 ld.Cseek(0) 614 switch ld.HEADTYPE { 615 default: 616 case obj.Hplan9: /* plan9 */ 617 magic := int32(4*11*11 + 7) 618 619 ld.Lputb(uint32(magic)) /* magic */ 620 ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */ 621 ld.Lputb(uint32(ld.Segdata.Filelen)) 622 ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) 623 ld.Lputb(uint32(ld.Symsize)) /* nsyms */ 624 ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */ 625 ld.Lputb(uint32(ld.Spsize)) /* sp offsets */ 626 ld.Lputb(uint32(ld.Lcsize)) /* line offsets */ 627 628 case obj.Hdarwin: 629 ld.Asmbmacho() 630 631 case obj.Hlinux, 632 obj.Hfreebsd, 633 obj.Hnetbsd, 634 obj.Hopenbsd, 635 obj.Hnacl: 636 ld.Asmbelf(int64(symo)) 637 638 case obj.Hwindows: 639 ld.Asmbpe() 640 } 641 642 ld.Cflush() 643 } 644