| ... | @@ -460,10 +460,35 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { | ... | @@ -460,10 +460,35 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 460 | | 460 | |
| 461 | elf.R_X86_64_64 => try cwriter.writeIntLittle(i64, S + A), | 461 | elf.R_X86_64_64 => try cwriter.writeIntLittle(i64, S + A), |
| 462 | | 462 | |
| | 463 | elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))), |
| | 464 | elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))), |
| | 465 | |
| 463 | elf.R_X86_64_PLT32, | 466 | elf.R_X86_64_PLT32, |
| 464 | elf.R_X86_64_PC32, | 467 | elf.R_X86_64_PC32, |
| 465 | => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), | 468 | => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), |
| 466 | | 469 | |
| | 470 | elf.R_X86_64_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))), |
| | 471 | elf.R_X86_64_GOTPC32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(GOT + A - P))), |
| | 472 | elf.R_X86_64_GOTPC64 => try cwriter.writeIntLittle(i64, GOT + A - P), |
| | 473 | |
| | 474 | elf.R_X86_64_GOTPCRELX => { |
| | 475 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { |
| | 476 | x86_64.relaxGotpcrelx(code[rel.r_offset - 2 ..]) catch break :blk; |
| | 477 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))); |
| | 478 | continue; |
| | 479 | } |
| | 480 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))); |
| | 481 | }, |
| | 482 | |
| | 483 | elf.R_X86_64_REX_GOTPCRELX => { |
| | 484 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { |
| | 485 | x86_64.relaxRexGotpcrelx(code[rel.r_offset - 3 ..]) catch break :blk; |
| | 486 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))); |
| | 487 | continue; |
| | 488 | } |
| | 489 | try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))); |
| | 490 | }, |
| | 491 | |
| 467 | else => { | 492 | else => { |
| 468 | log.err("TODO: unhandled relocation type {}", .{fmtRelocType(rel.r_type())}); | 493 | log.err("TODO: unhandled relocation type {}", .{fmtRelocType(rel.r_type())}); |
| 469 | @panic("TODO unhandled relocation type"); | 494 | @panic("TODO unhandled relocation type"); |
| ... | @@ -591,6 +616,58 @@ fn format2( | ... | @@ -591,6 +616,58 @@ fn format2( |
| 591 | // future. | 616 | // future. |
| 592 | pub const Index = u16; | 617 | pub const Index = u16; |
| 593 | | 618 | |
| | 619 | const x86_64 = struct { |
| | 620 | pub fn relaxGotpcrelx(code: []u8) !void { |
| | 621 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| | 622 | const inst = switch (old_inst.encoding.mnemonic) { |
| | 623 | .call => try Instruction.new(old_inst.prefix, .call, &.{ |
| | 624 | // TODO: hack to force imm32s in the assembler |
| | 625 | .{ .imm = Immediate.s(-129) }, |
| | 626 | }), |
| | 627 | .jmp => try Instruction.new(old_inst.prefix, .jmp, &.{ |
| | 628 | // TODO: hack to force imm32s in the assembler |
| | 629 | .{ .imm = Immediate.s(-129) }, |
| | 630 | }), |
| | 631 | else => return error.RelaxFail, |
| | 632 | }; |
| | 633 | relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); |
| | 634 | const nop = try Instruction.new(.none, .nop, &.{}); |
| | 635 | encode(&.{ nop, inst }, code) catch return error.RelaxFail; |
| | 636 | } |
| | 637 | |
| | 638 | pub fn relaxRexGotpcrelx(code: []u8) !void { |
| | 639 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| | 640 | switch (old_inst.encoding.mnemonic) { |
| | 641 | .mov => { |
| | 642 | const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops); |
| | 643 | relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); |
| | 644 | encode(&.{inst}, code) catch return error.RelaxFail; |
| | 645 | }, |
| | 646 | else => return error.RelaxFail, |
| | 647 | } |
| | 648 | } |
| | 649 | |
| | 650 | fn disassemble(code: []const u8) ?Instruction { |
| | 651 | var disas = Disassembler.init(code); |
| | 652 | const inst = disas.next() catch return null; |
| | 653 | return inst; |
| | 654 | } |
| | 655 | |
| | 656 | fn encode(insts: []const Instruction, code: []u8) !void { |
| | 657 | var stream = std.io.fixedBufferStream(code); |
| | 658 | const writer = stream.writer(); |
| | 659 | for (insts) |inst| { |
| | 660 | try inst.encode(writer, .{}); |
| | 661 | } |
| | 662 | } |
| | 663 | |
| | 664 | const bits = @import("../../arch/x86_64/bits.zig"); |
| | 665 | const encoder = @import("../../arch/x86_64/encoder.zig"); |
| | 666 | const Disassembler = @import("../../arch/x86_64/Disassembler.zig"); |
| | 667 | const Immediate = bits.Immediate; |
| | 668 | const Instruction = encoder.Instruction; |
| | 669 | }; |
| | 670 | |
| 594 | const std = @import("std"); | 671 | const std = @import("std"); |
| 595 | const assert = std.debug.assert; | 672 | const assert = std.debug.assert; |
| 596 | const elf = std.elf; | 673 | const elf = std.elf; |