| ... | @@ -316,6 +316,7 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { | ... | @@ -316,6 +316,7 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { |
| 316 | } | 316 | } |
| 317 | | 317 | |
| 318 | pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { | 318 | pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { |
| | 319 | const is_static = elf_file.isStatic(); |
| 319 | const is_dyn_lib = elf_file.isDynLib(); | 320 | const is_dyn_lib = elf_file.isDynLib(); |
| 320 | const file_ptr = self.file(elf_file).?; | 321 | const file_ptr = self.file(elf_file).?; |
| 321 | const rels = self.relocs(elf_file); | 322 | const rels = self.relocs(elf_file); |
| ... | @@ -348,14 +349,23 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -348,14 +349,23 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 348 | // Report an undefined symbol. | 349 | // Report an undefined symbol. |
| 349 | try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs); | 350 | try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs); |
| 350 | | 351 | |
| | 352 | if (symbol.isIFunc(elf_file)) { |
| | 353 | symbol.flags.needs_got = true; |
| | 354 | symbol.flags.needs_plt = true; |
| | 355 | } |
| | 356 | |
| 351 | // While traversing relocations, mark symbols that require special handling such as | 357 | // While traversing relocations, mark symbols that require special handling such as |
| 352 | // pointer indirection via GOT, or a stub trampoline via PLT. | 358 | // pointer indirection via GOT, or a stub trampoline via PLT. |
| 353 | switch (rel.r_type()) { | 359 | switch (rel.r_type()) { |
| 354 | elf.R_X86_64_64 => {}, | 360 | elf.R_X86_64_64 => { |
| | 361 | try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); |
| | 362 | }, |
| 355 | | 363 | |
| 356 | elf.R_X86_64_32, | 364 | elf.R_X86_64_32, |
| 357 | elf.R_X86_64_32S, | 365 | elf.R_X86_64_32S, |
| 358 | => {}, | 366 | => { |
| | 367 | try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); |
| | 368 | }, |
| 359 | | 369 | |
| 360 | elf.R_X86_64_GOT32, | 370 | elf.R_X86_64_GOT32, |
| 361 | elf.R_X86_64_GOT64, | 371 | elf.R_X86_64_GOT64, |
| ... | @@ -377,23 +387,14 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -377,23 +387,14 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 377 | } | 387 | } |
| 378 | }, | 388 | }, |
| 379 | | 389 | |
| 380 | elf.R_X86_64_PC32 => {}, | 390 | elf.R_X86_64_PC32 => { |
| 381 | | 391 | try self.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file); |
| 382 | elf.R_X86_64_TPOFF32, | | |
| 383 | elf.R_X86_64_TPOFF64, | | |
| 384 | => { | | |
| 385 | if (is_dyn_lib) { | | |
| 386 | // TODO | | |
| 387 | // self.picError(symbol, rel, elf_file); | | |
| 388 | } | | |
| 389 | }, | 392 | }, |
| 390 | | 393 | |
| 391 | elf.R_X86_64_TLSGD => { | 394 | elf.R_X86_64_TLSGD => { |
| 392 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr | 395 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr |
| 393 | | 396 | |
| 394 | if (elf_file.isStatic() or | 397 | if (is_static or (!symbol.flags.import and !is_dyn_lib)) { |
| 395 | (!symbol.flags.import and !is_dyn_lib)) | | |
| 396 | { | | |
| 397 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a | 398 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a |
| 398 | // We skip the next relocation. | 399 | // We skip the next relocation. |
| 399 | i += 1; | 400 | i += 1; |
| ... | @@ -405,9 +406,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -405,9 +406,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 405 | } | 406 | } |
| 406 | }, | 407 | }, |
| 407 | | 408 | |
| | 409 | elf.R_X86_64_TLSLD => { |
| | 410 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr |
| | 411 | |
| | 412 | if (is_static or !is_dyn_lib) { |
| | 413 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a |
| | 414 | // We skip the next relocation. |
| | 415 | i += 1; |
| | 416 | } else { |
| | 417 | elf_file.got.flags.needs_tlsld = true; |
| | 418 | } |
| | 419 | }, |
| | 420 | |
| 408 | elf.R_X86_64_GOTTPOFF => { | 421 | elf.R_X86_64_GOTTPOFF => { |
| 409 | const should_relax = blk: { | 422 | const should_relax = blk: { |
| 410 | // if (!elf_file.options.relax or is_shared or symbol.flags.import) break :blk false; | 423 | if (is_dyn_lib or symbol.flags.import) break :blk false; |
| 411 | if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false; | 424 | if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false; |
| 412 | break :blk true; | 425 | break :blk true; |
| 413 | }; | 426 | }; |
| ... | @@ -416,21 +429,245 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype | ... | @@ -416,21 +429,245 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype |
| 416 | } | 429 | } |
| 417 | }, | 430 | }, |
| 418 | | 431 | |
| 419 | else => { | 432 | elf.R_X86_64_GOTPC32_TLSDESC => { |
| 420 | var err = try elf_file.addErrorWithNotes(1); | 433 | const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import); |
| 421 | try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {}", .{ | 434 | if (!should_relax) { |
| 422 | fmtRelocType(rel.r_type()), | 435 | symbol.flags.needs_tlsdesc = true; |
| 423 | }); | 436 | } |
| 424 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ | | |
| 425 | self.file(elf_file).?.fmtPath(), | | |
| 426 | self.name(elf_file), | | |
| 427 | r_offset, | | |
| 428 | }); | | |
| 429 | }, | 437 | }, |
| | 438 | |
| | 439 | elf.R_X86_64_TPOFF32, |
| | 440 | elf.R_X86_64_TPOFF64, |
| | 441 | => { |
| | 442 | if (is_dyn_lib) try self.reportPicError(symbol, rel, elf_file); |
| | 443 | }, |
| | 444 | |
| | 445 | elf.R_X86_64_GOTOFF64, |
| | 446 | elf.R_X86_64_DTPOFF32, |
| | 447 | elf.R_X86_64_DTPOFF64, |
| | 448 | elf.R_X86_64_SIZE32, |
| | 449 | elf.R_X86_64_SIZE64, |
| | 450 | elf.R_X86_64_TLSDESC_CALL, |
| | 451 | => {}, |
| | 452 | |
| | 453 | else => try self.reportUnhandledRelocError(rel, elf_file), |
| 430 | } | 454 | } |
| 431 | } | 455 | } |
| 432 | } | 456 | } |
| 433 | | 457 | |
| | 458 | fn scanReloc( |
| | 459 | self: Atom, |
| | 460 | symbol: *Symbol, |
| | 461 | rel: elf.Elf64_Rela, |
| | 462 | action: RelocAction, |
| | 463 | elf_file: *Elf, |
| | 464 | ) error{OutOfMemory}!void { |
| | 465 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; |
| | 466 | const object = self.file(elf_file).?.object; |
| | 467 | |
| | 468 | switch (action) { |
| | 469 | .none => {}, |
| | 470 | |
| | 471 | .@"error" => if (symbol.isAbs(elf_file)) |
| | 472 | try self.reportNoPicError(symbol, rel, elf_file) |
| | 473 | else |
| | 474 | try self.reportPicError(symbol, rel, elf_file), |
| | 475 | |
| | 476 | .copyrel => { |
| | 477 | if (elf_file.base.options.z_nocopyreloc) { |
| | 478 | if (symbol.isAbs(elf_file)) |
| | 479 | try self.reportNoPicError(symbol, rel, elf_file) |
| | 480 | else |
| | 481 | try self.reportPicError(symbol, rel, elf_file); |
| | 482 | } else { |
| | 483 | symbol.flags.needs_copy_rel = true; |
| | 484 | } |
| | 485 | }, |
| | 486 | |
| | 487 | .dyn_copyrel => { |
| | 488 | if (is_writeable or elf_file.base.options.z_nocopyreloc) { |
| | 489 | if (!is_writeable) { |
| | 490 | if (elf_file.base.options.z_notext) { |
| | 491 | elf_file.has_text_reloc = true; |
| | 492 | } else { |
| | 493 | try self.reportTextRelocError(symbol, rel, elf_file); |
| | 494 | } |
| | 495 | } |
| | 496 | object.num_dynrelocs += 1; |
| | 497 | } else { |
| | 498 | symbol.flags.needs_copy_rel = true; |
| | 499 | } |
| | 500 | }, |
| | 501 | |
| | 502 | .plt => { |
| | 503 | symbol.flags.needs_plt = true; |
| | 504 | }, |
| | 505 | |
| | 506 | .cplt => { |
| | 507 | symbol.flags.needs_plt = true; |
| | 508 | symbol.flags.is_canonical = true; |
| | 509 | }, |
| | 510 | |
| | 511 | .dyn_cplt => { |
| | 512 | if (is_writeable) { |
| | 513 | object.num_dynrelocs += 1; |
| | 514 | } else { |
| | 515 | symbol.flags.needs_plt = true; |
| | 516 | symbol.flags.is_canonical = true; |
| | 517 | } |
| | 518 | }, |
| | 519 | |
| | 520 | .dynrel, .baserel, .ifunc => { |
| | 521 | if (!is_writeable) { |
| | 522 | if (elf_file.base.options.z_notext) { |
| | 523 | elf_file.has_text_reloc = true; |
| | 524 | } else { |
| | 525 | try self.reportTextRelocError(symbol, rel, elf_file); |
| | 526 | } |
| | 527 | } |
| | 528 | object.num_dynrelocs += 1; |
| | 529 | |
| | 530 | if (action == .ifunc) elf_file.num_ifunc_dynrelocs += 1; |
| | 531 | }, |
| | 532 | } |
| | 533 | } |
| | 534 | |
| | 535 | const RelocAction = enum { |
| | 536 | none, |
| | 537 | @"error", |
| | 538 | copyrel, |
| | 539 | dyn_copyrel, |
| | 540 | plt, |
| | 541 | dyn_cplt, |
| | 542 | cplt, |
| | 543 | dynrel, |
| | 544 | baserel, |
| | 545 | ifunc, |
| | 546 | }; |
| | 547 | |
| | 548 | fn pcRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { |
| | 549 | // zig fmt: off |
| | 550 | const table: [3][4]RelocAction = .{ |
| | 551 | // Abs Local Import data Import func |
| | 552 | .{ .@"error", .none, .@"error", .plt }, // Shared object |
| | 553 | .{ .@"error", .none, .copyrel, .plt }, // PIE |
| | 554 | .{ .none, .none, .copyrel, .cplt }, // Non-PIE |
| | 555 | }; |
| | 556 | // zig fmt: on |
| | 557 | const output = outputType(elf_file); |
| | 558 | const data = dataType(symbol, elf_file); |
| | 559 | return table[output][data]; |
| | 560 | } |
| | 561 | |
| | 562 | fn absRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { |
| | 563 | // zig fmt: off |
| | 564 | const table: [3][4]RelocAction = .{ |
| | 565 | // Abs Local Import data Import func |
| | 566 | .{ .none, .@"error", .@"error", .@"error" }, // Shared object |
| | 567 | .{ .none, .@"error", .@"error", .@"error" }, // PIE |
| | 568 | .{ .none, .none, .copyrel, .cplt }, // Non-PIE |
| | 569 | }; |
| | 570 | // zig fmt: on |
| | 571 | const output = outputType(elf_file); |
| | 572 | const data = dataType(symbol, elf_file); |
| | 573 | return table[output][data]; |
| | 574 | } |
| | 575 | |
| | 576 | fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { |
| | 577 | if (symbol.isIFunc(elf_file)) return .ifunc; |
| | 578 | // zig fmt: off |
| | 579 | const table: [3][4]RelocAction = .{ |
| | 580 | // Abs Local Import data Import func |
| | 581 | .{ .none, .baserel, .dynrel, .dynrel }, // Shared object |
| | 582 | .{ .none, .baserel, .dynrel, .dynrel }, // PIE |
| | 583 | .{ .none, .none, .dyn_copyrel, .dyn_cplt }, // Non-PIE |
| | 584 | }; |
| | 585 | // zig fmt: on |
| | 586 | const output = outputType(elf_file); |
| | 587 | const data = dataType(symbol, elf_file); |
| | 588 | return table[output][data]; |
| | 589 | } |
| | 590 | |
| | 591 | fn outputType(elf_file: *Elf) u2 { |
| | 592 | return switch (elf_file.base.options.output_mode) { |
| | 593 | .Obj => unreachable, |
| | 594 | .Lib => 0, |
| | 595 | .Exe => if (elf_file.base.options.pie) 1 else 2, |
| | 596 | }; |
| | 597 | } |
| | 598 | |
| | 599 | fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 { |
| | 600 | if (symbol.isAbs(elf_file)) return 0; |
| | 601 | if (!symbol.flags.import) return 1; |
| | 602 | if (symbol.type(elf_file) != elf.STT_FUNC) return 2; |
| | 603 | return 3; |
| | 604 | } |
| | 605 | |
| | 606 | fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) error{OutOfMemory}!void { |
| | 607 | var err = try elf_file.addErrorWithNotes(1); |
| | 608 | try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {} at offset 0x{x}", .{ |
| | 609 | fmtRelocType(rel.r_type()), |
| | 610 | rel.r_offset, |
| | 611 | }); |
| | 612 | try err.addNote(elf_file, "in {}:{s}", .{ |
| | 613 | self.file(elf_file).?.fmtPath(), |
| | 614 | self.name(elf_file), |
| | 615 | }); |
| | 616 | } |
| | 617 | |
| | 618 | fn reportTextRelocError( |
| | 619 | self: Atom, |
| | 620 | symbol: *const Symbol, |
| | 621 | rel: elf.Elf64_Rela, |
| | 622 | elf_file: *Elf, |
| | 623 | ) error{OutOfMemory}!void { |
| | 624 | var err = try elf_file.addErrorWithNotes(1); |
| | 625 | try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{ |
| | 626 | rel.r_offset, |
| | 627 | symbol.name(elf_file), |
| | 628 | }); |
| | 629 | try err.addNote(elf_file, "in {}:{s}", .{ |
| | 630 | self.file(elf_file).?.fmtPath(), |
| | 631 | self.name(elf_file), |
| | 632 | }); |
| | 633 | } |
| | 634 | |
| | 635 | fn reportPicError( |
| | 636 | self: Atom, |
| | 637 | symbol: *const Symbol, |
| | 638 | rel: elf.Elf64_Rela, |
| | 639 | elf_file: *Elf, |
| | 640 | ) error{OutOfMemory}!void { |
| | 641 | var err = try elf_file.addErrorWithNotes(2); |
| | 642 | try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{ |
| | 643 | rel.r_offset, |
| | 644 | symbol.name(elf_file), |
| | 645 | }); |
| | 646 | try err.addNote(elf_file, "in {}:{s}", .{ |
| | 647 | self.file(elf_file).?.fmtPath(), |
| | 648 | self.name(elf_file), |
| | 649 | }); |
| | 650 | try err.addNote(elf_file, "recompile with -fPIC", .{}); |
| | 651 | } |
| | 652 | |
| | 653 | fn reportNoPicError( |
| | 654 | self: Atom, |
| | 655 | symbol: *const Symbol, |
| | 656 | rel: elf.Elf64_Rela, |
| | 657 | elf_file: *Elf, |
| | 658 | ) error{OutOfMemory}!void { |
| | 659 | var err = try elf_file.addErrorWithNotes(2); |
| | 660 | try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{ |
| | 661 | rel.r_offset, |
| | 662 | symbol.name(elf_file), |
| | 663 | }); |
| | 664 | try err.addNote(elf_file, "in {}:{s}", .{ |
| | 665 | self.file(elf_file).?.fmtPath(), |
| | 666 | self.name(elf_file), |
| | 667 | }); |
| | 668 | try err.addNote(elf_file, "recompile with -fno-PIC", .{}); |
| | 669 | } |
| | 670 | |
| 434 | // This function will report any undefined non-weak symbols that are not imports. | 671 | // This function will report any undefined non-weak symbols that are not imports. |
| 435 | fn reportUndefined( | 672 | fn reportUndefined( |
| 436 | self: Atom, | 673 | self: Atom, |
| ... | @@ -504,7 +741,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -504,7 +741,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 504 | const TP = @as(i64, @intCast(elf_file.tpAddress())); | 741 | const TP = @as(i64, @intCast(elf_file.tpAddress())); |
| 505 | // Address of the dynamic thread pointer. | 742 | // Address of the dynamic thread pointer. |
| 506 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | 743 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); |
| 507 | _ = DTP; | | |
| 508 | | 744 | |
| 509 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ({s})", .{ | 745 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ({s})", .{ |
| 510 | fmtRelocType(r_type), | 746 | fmtRelocType(r_type), |
| ... | @@ -520,18 +756,20 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -520,18 +756,20 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 520 | switch (rel.r_type()) { | 756 | switch (rel.r_type()) { |
| 521 | elf.R_X86_64_NONE => unreachable, | 757 | elf.R_X86_64_NONE => unreachable, |
| 522 | | 758 | |
| 523 | elf.R_X86_64_64 => try cwriter.writeIntLittle(i64, S + A), | 759 | elf.R_X86_64_64 => { |
| 524 | | 760 | try self.resolveDynAbsReloc( |
| 525 | elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))), | 761 | target, |
| 526 | elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))), | 762 | rel, |
| | 763 | dynAbsRelocAction(target, elf_file), |
| | 764 | elf_file, |
| | 765 | cwriter, |
| | 766 | ); |
| | 767 | }, |
| 527 | | 768 | |
| 528 | elf.R_X86_64_PLT32, | 769 | elf.R_X86_64_PLT32, |
| 529 | elf.R_X86_64_PC32, | 770 | elf.R_X86_64_PC32, |
| 530 | => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), | 771 | => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), |
| 531 | | 772 | |
| 532 | elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(G + GOT + A))), | | |
| 533 | elf.R_X86_64_GOT64 => try cwriter.writeIntLittle(u64, @as(u64, @intCast(G + GOT + A))), | | |
| 534 | | | |
| 535 | elf.R_X86_64_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))), | 773 | elf.R_X86_64_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))), |
| 536 | elf.R_X86_64_GOTPC32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(GOT + A - P))), | 774 | elf.R_X86_64_GOTPC32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(GOT + A - P))), |
| 537 | elf.R_X86_64_GOTPC64 => try cwriter.writeIntLittle(i64, GOT + A - P), | 775 | elf.R_X86_64_GOTPC64 => try cwriter.writeIntLittle(i64, GOT + A - P), |
| ... | @@ -554,18 +792,25 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -554,18 +792,25 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 554 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))); | 792 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))); |
| 555 | }, | 793 | }, |
| 556 | | 794 | |
| | 795 | elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))), |
| | 796 | elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))), |
| | 797 | |
| | 798 | elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(G + GOT + A))), |
| | 799 | elf.R_X86_64_GOT64 => try cwriter.writeIntLittle(u64, @as(u64, @intCast(G + GOT + A))), |
| | 800 | |
| 557 | elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))), | 801 | elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))), |
| 558 | elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP), | 802 | elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP), |
| 559 | | 803 | |
| | 804 | elf.R_X86_64_DTPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - DTP))), |
| | 805 | elf.R_X86_64_DTPOFF64 => try cwriter.writeIntLittle(i64, S + A - DTP), |
| | 806 | |
| 560 | elf.R_X86_64_TLSGD => { | 807 | elf.R_X86_64_TLSGD => { |
| 561 | if (target.flags.has_tlsgd) { | 808 | if (target.flags.has_tlsgd) { |
| 562 | // TODO | 809 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); |
| 563 | // const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); | 810 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); |
| 564 | // try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); | | |
| 565 | } else if (target.flags.has_gottp) { | 811 | } else if (target.flags.has_gottp) { |
| 566 | // TODO | 812 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); |
| 567 | // const S_ = @as(i64, @intCast(target.getGotTpAddress(elf_file))); | 813 | try x86_64.relaxTlsGdToIe(self, rels[i .. i + 2], @intCast(S_ - P), elf_file, &stream); |
| 568 | // try relaxTlsGdToIe(relocs[i .. i + 2], @intCast(S_ - P), elf_file, &stream); | | |
| 569 | i += 1; | 814 | i += 1; |
| 570 | } else { | 815 | } else { |
| 571 | try x86_64.relaxTlsGdToLe( | 816 | try x86_64.relaxTlsGdToLe( |
| ... | @@ -579,11 +824,42 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -579,11 +824,42 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 579 | } | 824 | } |
| 580 | }, | 825 | }, |
| 581 | | 826 | |
| | 827 | elf.R_X86_64_TLSLD => { |
| | 828 | if (elf_file.got.tlsld_index) |entry_index| { |
| | 829 | const tlsld_entry = elf_file.got.entries.items[entry_index]; |
| | 830 | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); |
| | 831 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); |
| | 832 | } else { |
| | 833 | try x86_64.relaxTlsLdToLe( |
| | 834 | self, |
| | 835 | rels[i .. i + 2], |
| | 836 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), |
| | 837 | elf_file, |
| | 838 | &stream, |
| | 839 | ); |
| | 840 | i += 1; |
| | 841 | } |
| | 842 | }, |
| | 843 | |
| | 844 | elf.R_X86_64_GOTPC32_TLSDESC => { |
| | 845 | if (target.flags.has_tlsdesc) { |
| | 846 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); |
| | 847 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); |
| | 848 | } else { |
| | 849 | try x86_64.relaxGotPcTlsDesc(code[rel.r_offset - 3 ..]); |
| | 850 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S - TP))); |
| | 851 | } |
| | 852 | }, |
| | 853 | |
| | 854 | elf.R_X86_64_TLSDESC_CALL => if (!target.flags.has_tlsdesc) { |
| | 855 | // call -> nop |
| | 856 | try cwriter.writeAll(&.{ 0x66, 0x90 }); |
| | 857 | }, |
| | 858 | |
| 582 | elf.R_X86_64_GOTTPOFF => { | 859 | elf.R_X86_64_GOTTPOFF => { |
| 583 | if (target.flags.has_gottp) { | 860 | if (target.flags.has_gottp) { |
| 584 | // TODO | 861 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); |
| 585 | // const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | 862 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); |
| 586 | // try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P))); | | |
| 587 | } else { | 863 | } else { |
| 588 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable; | 864 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable; |
| 589 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S - TP))); | 865 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S - TP))); |
| ... | @@ -595,6 +871,98 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -595,6 +871,98 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 595 | } | 871 | } |
| 596 | } | 872 | } |
| 597 | | 873 | |
| | 874 | fn resolveDynAbsReloc( |
| | 875 | self: Atom, |
| | 876 | target: *const Symbol, |
| | 877 | rel: elf.Elf64_Rela, |
| | 878 | action: RelocAction, |
| | 879 | elf_file: *Elf, |
| | 880 | writer: anytype, |
| | 881 | ) !void { |
| | 882 | const P = self.value + rel.r_offset; |
| | 883 | const A = rel.r_addend; |
| | 884 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); |
| | 885 | const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0; |
| | 886 | const object = self.file(elf_file).?.object; |
| | 887 | |
| | 888 | try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, object.num_dynrelocs); |
| | 889 | |
| | 890 | switch (action) { |
| | 891 | .@"error", |
| | 892 | .plt, |
| | 893 | => unreachable, |
| | 894 | |
| | 895 | .copyrel, |
| | 896 | .cplt, |
| | 897 | .none, |
| | 898 | => try writer.writeIntLittle(i32, @as(i32, @truncate(S + A))), |
| | 899 | |
| | 900 | .dyn_copyrel => { |
| | 901 | if (is_writeable or elf_file.base.options.z_nocopyreloc) { |
| | 902 | elf_file.addRelaDynAssumeCapacity(.{ |
| | 903 | .offset = P, |
| | 904 | .sym = target.extra(elf_file).?.dynamic, |
| | 905 | .type = elf.R_X86_64_64, |
| | 906 | .addend = A, |
| | 907 | }); |
| | 908 | try applyDynamicReloc(A, elf_file, writer); |
| | 909 | } else { |
| | 910 | try writer.writeIntLittle(i32, @as(i32, @truncate(S + A))); |
| | 911 | } |
| | 912 | }, |
| | 913 | |
| | 914 | .dyn_cplt => { |
| | 915 | if (is_writeable) { |
| | 916 | elf_file.addRelaDynAssumeCapacity(.{ |
| | 917 | .offset = P, |
| | 918 | .sym = target.extra(elf_file).?.dynamic, |
| | 919 | .type = elf.R_X86_64_64, |
| | 920 | .addend = A, |
| | 921 | }); |
| | 922 | try applyDynamicReloc(A, elf_file, writer); |
| | 923 | } else { |
| | 924 | try writer.writeIntLittle(i32, @as(i32, @truncate(S + A))); |
| | 925 | } |
| | 926 | }, |
| | 927 | |
| | 928 | .dynrel => { |
| | 929 | elf_file.addRelaDynAssumeCapacity(.{ |
| | 930 | .offset = P, |
| | 931 | .sym = target.extra(elf_file).?.dynamic, |
| | 932 | .type = elf.R_X86_64_64, |
| | 933 | .addend = A, |
| | 934 | }); |
| | 935 | try applyDynamicReloc(A, elf_file, writer); |
| | 936 | }, |
| | 937 | |
| | 938 | .baserel => { |
| | 939 | elf_file.addRelaDynAssumeCapacity(.{ |
| | 940 | .offset = P, |
| | 941 | .type = elf.R_X86_64_RELATIVE, |
| | 942 | .addend = S + A, |
| | 943 | }); |
| | 944 | try applyDynamicReloc(S + A, elf_file, writer); |
| | 945 | }, |
| | 946 | |
| | 947 | .ifunc => { |
| | 948 | const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file))); |
| | 949 | elf_file.addRelaDynAssumeCapacity(.{ |
| | 950 | .offset = P, |
| | 951 | .type = elf.R_X86_64_IRELATIVE, |
| | 952 | .addend = S_ + A, |
| | 953 | }); |
| | 954 | try applyDynamicReloc(S_ + A, elf_file, writer); |
| | 955 | }, |
| | 956 | } |
| | 957 | } |
| | 958 | |
| | 959 | fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void { |
| | 960 | _ = elf_file; |
| | 961 | // if (elf_file.options.apply_dynamic_relocs) { |
| | 962 | try writer.writeIntLittle(i64, value); |
| | 963 | // } |
| | 964 | } |
| | 965 | |
| 598 | pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { | 966 | pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { |
| 599 | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); | 967 | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); |
| 600 | | 968 | |
| ... | @@ -682,17 +1050,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any | ... | @@ -682,17 +1050,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 682 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | 1050 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); |
| 683 | try cwriter.writeIntLittle(i64, @as(i64, @intCast(size + A))); | 1051 | try cwriter.writeIntLittle(i64, @as(i64, @intCast(size + A))); |
| 684 | }, | 1052 | }, |
| 685 | else => { | 1053 | else => try self.reportUnhandledRelocError(rel, elf_file), |
| 686 | var err = try elf_file.addErrorWithNotes(1); | | |
| 687 | try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {}", .{ | | |
| 688 | fmtRelocType(r_type), | | |
| 689 | }); | | |
| 690 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ | | |
| 691 | self.file(elf_file).?.fmtPath(), | | |
| 692 | self.name(elf_file), | | |
| 693 | r_offset, | | |
| 694 | }); | | |
| 695 | }, | | |
| 696 | } | 1054 | } |
| 697 | } | 1055 | } |
| 698 | } | 1056 | } |
| ... | @@ -854,6 +1212,95 @@ const x86_64 = struct { | ... | @@ -854,6 +1212,95 @@ const x86_64 = struct { |
| 854 | } | 1212 | } |
| 855 | } | 1213 | } |
| 856 | | 1214 | |
| | 1215 | pub fn relaxTlsGdToIe( |
| | 1216 | self: Atom, |
| | 1217 | rels: []align(1) const elf.Elf64_Rela, |
| | 1218 | value: i32, |
| | 1219 | elf_file: *Elf, |
| | 1220 | stream: anytype, |
| | 1221 | ) !void { |
| | 1222 | assert(rels.len == 2); |
| | 1223 | const writer = stream.writer(); |
| | 1224 | switch (rels[1].r_type()) { |
| | 1225 | elf.R_X86_64_PC32, |
| | 1226 | elf.R_X86_64_PLT32, |
| | 1227 | => { |
| | 1228 | var insts = [_]u8{ |
| | 1229 | 0x64, 0x48, 0x8b, 0x04, 0x25, 0, 0, 0, 0, // movq %fs:0,%rax |
| | 1230 | 0x48, 0x03, 0x05, 0, 0, 0, 0, // add foo@gottpoff(%rip), %rax |
| | 1231 | }; |
| | 1232 | std.mem.writeIntLittle(i32, insts[12..][0..4], value - 12); |
| | 1233 | try stream.seekBy(-4); |
| | 1234 | try writer.writeAll(&insts); |
| | 1235 | }, |
| | 1236 | |
| | 1237 | else => { |
| | 1238 | var err = try elf_file.addErrorWithNotes(1); |
| | 1239 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ |
| | 1240 | fmtRelocType(rels[0].r_type()), |
| | 1241 | fmtRelocType(rels[1].r_type()), |
| | 1242 | }); |
| | 1243 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ |
| | 1244 | self.file(elf_file).?.fmtPath(), |
| | 1245 | self.name(elf_file), |
| | 1246 | rels[0].r_offset, |
| | 1247 | }); |
| | 1248 | }, |
| | 1249 | } |
| | 1250 | } |
| | 1251 | |
| | 1252 | pub fn relaxTlsLdToLe( |
| | 1253 | self: Atom, |
| | 1254 | rels: []align(1) const elf.Elf64_Rela, |
| | 1255 | value: i32, |
| | 1256 | elf_file: *Elf, |
| | 1257 | stream: anytype, |
| | 1258 | ) !void { |
| | 1259 | assert(rels.len == 2); |
| | 1260 | const writer = stream.writer(); |
| | 1261 | switch (rels[1].r_type()) { |
| | 1262 | elf.R_X86_64_PC32, |
| | 1263 | elf.R_X86_64_PLT32, |
| | 1264 | => { |
| | 1265 | var insts = [_]u8{ |
| | 1266 | 0x31, 0xc0, // xor %eax, %eax |
| | 1267 | 0x64, 0x48, 0x8b, 0, // mov %fs:(%rax), %rax |
| | 1268 | 0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax |
| | 1269 | }; |
| | 1270 | std.mem.writeIntLittle(i32, insts[8..][0..4], value); |
| | 1271 | try stream.seekBy(-3); |
| | 1272 | try writer.writeAll(&insts); |
| | 1273 | }, |
| | 1274 | |
| | 1275 | elf.R_X86_64_GOTPCREL, |
| | 1276 | elf.R_X86_64_GOTPCRELX, |
| | 1277 | => { |
| | 1278 | var insts = [_]u8{ |
| | 1279 | 0x31, 0xc0, // xor %eax, %eax |
| | 1280 | 0x64, 0x48, 0x8b, 0, // mov %fs:(%rax), %rax |
| | 1281 | 0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax |
| | 1282 | 0x90, // nop |
| | 1283 | }; |
| | 1284 | std.mem.writeIntLittle(i32, insts[8..][0..4], value); |
| | 1285 | try stream.seekBy(-3); |
| | 1286 | try writer.writeAll(&insts); |
| | 1287 | }, |
| | 1288 | |
| | 1289 | else => { |
| | 1290 | var err = try elf_file.addErrorWithNotes(1); |
| | 1291 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ |
| | 1292 | fmtRelocType(rels[0].r_type()), |
| | 1293 | fmtRelocType(rels[1].r_type()), |
| | 1294 | }); |
| | 1295 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ |
| | 1296 | self.file(elf_file).?.fmtPath(), |
| | 1297 | self.name(elf_file), |
| | 1298 | rels[0].r_offset, |
| | 1299 | }); |
| | 1300 | }, |
| | 1301 | } |
| | 1302 | } |
| | 1303 | |
| 857 | pub fn canRelaxGotTpOff(code: []const u8) bool { | 1304 | pub fn canRelaxGotTpOff(code: []const u8) bool { |
| 858 | const old_inst = disassemble(code) orelse return false; | 1305 | const old_inst = disassemble(code) orelse return false; |
| 859 | switch (old_inst.encoding.mnemonic) { | 1306 | switch (old_inst.encoding.mnemonic) { |
| ... | @@ -885,6 +1332,22 @@ const x86_64 = struct { | ... | @@ -885,6 +1332,22 @@ const x86_64 = struct { |
| 885 | } | 1332 | } |
| 886 | } | 1333 | } |
| 887 | | 1334 | |
| | 1335 | pub fn relaxGotPcTlsDesc(code: []u8) !void { |
| | 1336 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| | 1337 | switch (old_inst.encoding.mnemonic) { |
| | 1338 | .lea => { |
| | 1339 | const inst = try Instruction.new(old_inst.prefix, .mov, &.{ |
| | 1340 | old_inst.ops[0], |
| | 1341 | // TODO: hack to force imm32s in the assembler |
| | 1342 | .{ .imm = Immediate.s(-129) }, |
| | 1343 | }); |
| | 1344 | relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); |
| | 1345 | encode(&.{inst}, code) catch return error.RelaxFail; |
| | 1346 | }, |
| | 1347 | else => return error.RelaxFail, |
| | 1348 | } |
| | 1349 | } |
| | 1350 | |
| 888 | pub fn relaxTlsGdToLe( | 1351 | pub fn relaxTlsGdToLe( |
| 889 | self: Atom, | 1352 | self: Atom, |
| 890 | rels: []align(1) const elf.Elf64_Rela, | 1353 | rels: []align(1) const elf.Elf64_Rela, |