| ... | ... | @@ -460,10 +460,7 @@ fn reportUndefined( |
| 460 | 460 | } |
| 461 | 461 | } |
| 462 | 462 | |
| 463 | | /// TODO mark relocs dirty |
| 464 | | pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 465 | | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); |
| 466 | | |
| 463 | pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 467 | 464 | const file_ptr = self.file(elf_file).?; |
| 468 | 465 | var stream = std.io.fixedBufferStream(code); |
| 469 | 466 | const cwriter = stream.writer(); |
| ... | ... | @@ -505,8 +502,9 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 505 | 502 | const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT; |
| 506 | 503 | // // Address of the thread pointer. |
| 507 | 504 | const TP = @as(i64, @intCast(elf_file.tpAddress())); |
| 508 | | // // Address of the dynamic thread pointer. |
| 509 | | // const DTP = @as(i64, @intCast(elf_file.dtpAddress())); |
| 505 | // Address of the dynamic thread pointer. |
| 506 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); |
| 507 | _ = DTP; |
| 510 | 508 | |
| 511 | 509 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ({s})", .{ |
| 512 | 510 | fmtRelocType(r_type), |
| ... | ... | @@ -597,6 +595,108 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 597 | 595 | } |
| 598 | 596 | } |
| 599 | 597 | |
| 598 | 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) }); |
| 600 | |
| 601 | const file_ptr = self.file(elf_file).?; |
| 602 | var stream = std.io.fixedBufferStream(code); |
| 603 | const cwriter = stream.writer(); |
| 604 | |
| 605 | const rels = self.relocs(elf_file); |
| 606 | var i: usize = 0; |
| 607 | while (i < rels.len) : (i += 1) { |
| 608 | const rel = rels[i]; |
| 609 | const r_type = rel.r_type(); |
| 610 | if (r_type == elf.R_X86_64_NONE) continue; |
| 611 | |
| 612 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 613 | |
| 614 | const target_index = switch (file_ptr) { |
| 615 | .zig_module => |x| x.symbol(rel.r_sym()), |
| 616 | .object => |x| x.symbols.items[rel.r_sym()], |
| 617 | else => unreachable, |
| 618 | }; |
| 619 | const target = elf_file.symbol(target_index); |
| 620 | |
| 621 | // Check for violation of One Definition Rule for COMDATs. |
| 622 | if (target.file(elf_file) == null) { |
| 623 | // TODO convert into an error |
| 624 | log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ |
| 625 | file_ptr.fmtPath(), |
| 626 | self.name(elf_file), |
| 627 | target.name(elf_file), |
| 628 | }); |
| 629 | continue; |
| 630 | } |
| 631 | |
| 632 | // Report an undefined symbol. |
| 633 | try self.reportUndefined(elf_file, target, target_index, rel, undefs); |
| 634 | |
| 635 | // We will use equation format to resolve relocations: |
| 636 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ |
| 637 | // |
| 638 | const P = @as(i64, @intCast(self.value + rel.r_offset)); |
| 639 | // Addend from the relocation. |
| 640 | const A = rel.r_addend; |
| 641 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. |
| 642 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); |
| 643 | // Address of the global offset table. |
| 644 | const GOT = blk: { |
| 645 | const shndx = if (elf_file.got_plt_section_index) |shndx| |
| 646 | shndx |
| 647 | else if (elf_file.got_section_index) |shndx| |
| 648 | shndx |
| 649 | else |
| 650 | null; |
| 651 | break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0; |
| 652 | }; |
| 653 | // Address of the dynamic thread pointer. |
| 654 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); |
| 655 | |
| 656 | relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ |
| 657 | fmtRelocType(r_type), |
| 658 | rel.r_offset, |
| 659 | P, |
| 660 | S + A, |
| 661 | target.name(elf_file), |
| 662 | }); |
| 663 | |
| 664 | try stream.seekTo(r_offset); |
| 665 | |
| 666 | switch (r_type) { |
| 667 | elf.R_X86_64_NONE => unreachable, |
| 668 | elf.R_X86_64_8 => try cwriter.writeIntLittle(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A))))), |
| 669 | elf.R_X86_64_16 => try cwriter.writeIntLittle(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A))))), |
| 670 | elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A))))), |
| 671 | elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A))), |
| 672 | elf.R_X86_64_64 => try cwriter.writeIntLittle(i64, S + A), |
| 673 | elf.R_X86_64_DTPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - DTP))), |
| 674 | elf.R_X86_64_DTPOFF64 => try cwriter.writeIntLittle(i64, S + A - DTP), |
| 675 | elf.R_X86_64_GOTOFF64 => try cwriter.writeIntLittle(i64, S + A - GOT), |
| 676 | elf.R_X86_64_GOTPC64 => try cwriter.writeIntLittle(i64, GOT + A), |
| 677 | elf.R_X86_64_SIZE32 => { |
| 678 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); |
| 679 | try cwriter.writeIntLittle(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A))))); |
| 680 | }, |
| 681 | elf.R_X86_64_SIZE64 => { |
| 682 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); |
| 683 | try cwriter.writeIntLittle(i64, @as(i64, @intCast(size + A))); |
| 684 | }, |
| 685 | else => { |
| 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 | } |
| 697 | } |
| 698 | } |
| 699 | |
| 600 | 700 | pub fn fmtRelocType(r_type: u32) std.fmt.Formatter(formatRelocType) { |
| 601 | 701 | return .{ .data = r_type }; |
| 602 | 702 | } |
| ... | ... | @@ -696,17 +796,16 @@ fn format2( |
| 696 | 796 | atom.atom_index, atom.name(elf_file), atom.value, |
| 697 | 797 | atom.output_section_index, atom.alignment, atom.size, |
| 698 | 798 | }); |
| 699 | | // if (atom.fde_start != atom.fde_end) { |
| 700 | | // try writer.writeAll(" : fdes{ "); |
| 701 | | // for (atom.getFdes(elf_file), atom.fde_start..) |fde, i| { |
| 702 | | // try writer.print("{d}", .{i}); |
| 703 | | // if (!fde.alive) try writer.writeAll("([*])"); |
| 704 | | // if (i < atom.fde_end - 1) try writer.writeAll(", "); |
| 705 | | // } |
| 706 | | // try writer.writeAll(" }"); |
| 707 | | // } |
| 708 | | const gc_sections = if (elf_file.base.options.gc_sections) |gc_sections| gc_sections else false; |
| 709 | | if (gc_sections and !atom.flags.alive) { |
| 799 | if (atom.fde_start != atom.fde_end) { |
| 800 | try writer.writeAll(" : fdes{ "); |
| 801 | for (atom.fdes(elf_file), atom.fde_start..) |fde, i| { |
| 802 | try writer.print("{d}", .{i}); |
| 803 | if (!fde.alive) try writer.writeAll("([*])"); |
| 804 | if (i < atom.fde_end - 1) try writer.writeAll(", "); |
| 805 | } |
| 806 | try writer.writeAll(" }"); |
| 807 | } |
| 808 | if (!atom.flags.alive) { |
| 710 | 809 | try writer.writeAll(" : [*]"); |
| 711 | 810 | } |
| 712 | 811 | } |