authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 00:35:14+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
log601f2147e0344621d238e5209e0d36c69be3cc03
treef7addabfa5d2ae5575532d5957fd1aa6333b57f0
parentebdb2867363256a265646f2a1b66d3762a51b7ba

coff: cleanup relocations; remove COFF support from other backends

Given that COFF will want to support PIC from ground-up, there is no point in leaving outdated code for COFF in other backends such as arm or aarch64. Instead, when we are ready to look into those, we can start figuring out what to add and where.

8 files changed, 89 insertions(+), 88 deletions(-)

src/arch/aarch64/CodeGen.zig+7-11
...@@ -3466,20 +3466,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3466,20 +3466,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3466 // on linking.3466 // on linking.
3467 const mod = self.bin_file.options.module.?;3467 const mod = self.bin_file.options.module.?;
3468 if (self.air.value(callee)) |func_value| {3468 if (self.air.value(callee)) |func_value| {
3469 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {3469 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3470 if (func_value.castTag(.function)) |func_payload| {3470 if (func_value.castTag(.function)) |func_payload| {
3471 const func = func_payload.data;3471 const func = func_payload.data;
3472 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3472 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3473 const ptr_bytes: u64 = @divExact(ptr_bits, 8);3473 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3474 const fn_owner_decl = mod.declPtr(func.owner_decl);3474 const fn_owner_decl = mod.declPtr(func.owner_decl);
3475 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {3475 const got_addr = blk: {
3476 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];3476 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3477 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);3477 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
3478 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {3478 };
3479 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
3480 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
3481 break :blk got_sym.value;
3482 } else unreachable;
34833479
3484 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });3480 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
34853481
...@@ -3547,6 +3543,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3547,6 +3543,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3547 } else {3543 } else {
3548 return self.fail("TODO implement calling bitcasted functions", .{});3544 return self.fail("TODO implement calling bitcasted functions", .{});
3549 }3545 }
3546 } else if (self.bin_file.cast(link.File.Coff)) |_| {
3547 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
3550 } else unreachable;3548 } else unreachable;
3551 } else {3549 } else {
3552 assert(ty.zigTypeTag() == .Pointer);3550 assert(ty.zigTypeTag() == .Pointer);
...@@ -5110,10 +5108,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -5110,10 +5108,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
5110 // the linker has enough info to perform relocations.5108 // the linker has enough info to perform relocations.
5111 assert(decl.link.macho.sym_index != 0);5109 assert(decl.link.macho.sym_index != 0);
5112 return MCValue{ .got_load = decl.link.macho.sym_index };5110 return MCValue{ .got_load = decl.link.macho.sym_index };
5113 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {5111 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5114 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;5112 return self.fail("TODO codegen COFF const Decl pointer", .{});
5115 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
5116 return MCValue{ .memory = got_sym.value };
5117 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {5113 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
5118 try p9.seeDecl(decl_index);5114 try p9.seeDecl(decl_index);
5119 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;5115 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/arm/CodeGen.zig+4-10
...@@ -3698,7 +3698,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3698,7 +3698,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3698 // Due to incremental compilation, how function calls are generated depends3698 // Due to incremental compilation, how function calls are generated depends
3699 // on linking.3699 // on linking.
3700 switch (self.bin_file.tag) {3700 switch (self.bin_file.tag) {
3701 .elf, .coff => {3701 .elf => {
3702 if (self.air.value(callee)) |func_value| {3702 if (self.air.value(callee)) |func_value| {
3703 if (func_value.castTag(.function)) |func_payload| {3703 if (func_value.castTag(.function)) |func_payload| {
3704 const func = func_payload.data;3704 const func = func_payload.data;
...@@ -3709,12 +3709,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3709,12 +3709,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3709 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {3709 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
3710 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];3710 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3711 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);3711 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
3712 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3713 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
3714 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
3715 break :blk @intCast(u32, got_sym.value);
3716 } else unreachable;3712 } else unreachable;
3717
3718 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });3713 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
3719 } else if (func_value.castTag(.extern_fn)) |_| {3714 } else if (func_value.castTag(.extern_fn)) |_| {
3720 return self.fail("TODO implement calling extern functions", .{});3715 return self.fail("TODO implement calling extern functions", .{});
...@@ -3752,6 +3747,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3752,6 +3747,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3752 }3747 }
3753 },3748 },
3754 .macho => unreachable, // unsupported architecture for MachO3749 .macho => unreachable, // unsupported architecture for MachO
3750 .coff => return self.fail("TODO implement call in COFF for {}", .{self.target.cpu.arch}),
3755 .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),3751 .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
3756 else => unreachable,3752 else => unreachable,
3757 }3753 }
...@@ -5549,10 +5545,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -5549,10 +5545,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
5549 return MCValue{ .memory = got_addr };5545 return MCValue{ .memory = got_addr };
5550 } else if (self.bin_file.cast(link.File.MachO)) |_| {5546 } else if (self.bin_file.cast(link.File.MachO)) |_| {
5551 unreachable; // unsupported architecture for MachO5547 unreachable; // unsupported architecture for MachO
5552 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {5548 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5553 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;5549 return self.fail("TODO codegen COFF const Decl pointer", .{});
5554 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
5555 return MCValue{ .memory = got_sym.value };
5556 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {5550 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
5557 try p9.seeDecl(decl_index);5551 try p9.seeDecl(decl_index);
5558 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;5552 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/riscv64/CodeGen.zig+7-11
...@@ -1718,7 +1718,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1718,7 +1718,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17181718
1719 // Due to incremental compilation, how function calls are generated depends1719 // Due to incremental compilation, how function calls are generated depends
1720 // on linking.1720 // on linking.
1721 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {1721 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
1722 for (info.args) |mc_arg, arg_i| {1722 for (info.args) |mc_arg, arg_i| {
1723 const arg = args[arg_i];1723 const arg = args[arg_i];
1724 const arg_ty = self.air.typeOf(arg);1724 const arg_ty = self.air.typeOf(arg);
...@@ -1752,14 +1752,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1752,14 +1752,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1752 const ptr_bytes: u64 = @divExact(ptr_bits, 8);1752 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1753 const mod = self.bin_file.options.module.?;1753 const mod = self.bin_file.options.module.?;
1754 const fn_owner_decl = mod.declPtr(func.owner_decl);1754 const fn_owner_decl = mod.declPtr(func.owner_decl);
1755 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1755 const got_addr = blk: {
1756 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];1756 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1757 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);1757 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
1758 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {1758 };
1759 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
1760 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
1761 break :blk got_sym.value;
1762 } else unreachable;
17631759
1764 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });1760 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
1765 _ = try self.addInst(.{1761 _ = try self.addInst(.{
...@@ -1778,6 +1774,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1778,6 +1774,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1778 } else {1774 } else {
1779 return self.fail("TODO implement calling runtime known function pointer", .{});1775 return self.fail("TODO implement calling runtime known function pointer", .{});
1780 }1776 }
1777 } else if (self.bin_file.cast(link.File.Coff)) |_| {
1778 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
1781 } else if (self.bin_file.cast(link.File.MachO)) |_| {1779 } else if (self.bin_file.cast(link.File.MachO)) |_| {
1782 unreachable; // unsupported architecture for MachO1780 unreachable; // unsupported architecture for MachO
1783 } else if (self.bin_file.cast(link.File.Plan9)) |_| {1781 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
...@@ -2592,10 +2590,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -2592,10 +2590,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
2592 // TODO I'm hacking my way through here by repurposing .memory for storing2590 // TODO I'm hacking my way through here by repurposing .memory for storing
2593 // index to the GOT target symbol index.2591 // index to the GOT target symbol index.
2594 return MCValue{ .memory = decl.link.macho.sym_index };2592 return MCValue{ .memory = decl.link.macho.sym_index };
2595 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {2593 } else if (self.bin_file.cast(link.File.Coff)) |_| {
2596 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;2594 return self.fail("TODO codegen COFF const Decl pointer", .{});
2597 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
2598 return MCValue{ .memory = got_sym.value };
2599 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {2595 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2600 try p9.seeDecl(decl_index);2596 try p9.seeDecl(decl_index);
2601 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;2597 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/x86_64/CodeGen.zig+9-11
...@@ -2657,19 +2657,19 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2657,19 +2657,19 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2657 .direct_load,2657 .direct_load,
2658 => |sym_index| {2658 => |sym_index| {
2659 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));2659 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2660 const flags: u2 = switch (ptr) {
2661 .got_load => 0b00,
2662 .direct_load => 0b01,
2663 else => unreachable,
2664 };
2665 const mod = self.bin_file.options.module.?;2660 const mod = self.bin_file.options.module.?;
2666 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);2661 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
2667 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)2662 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)
2668 fn_owner_decl.link.macho.sym_index2663 fn_owner_decl.link.macho.sym_index
2669 else2664 else
2670 fn_owner_decl.link.coff.sym_index;2665 fn_owner_decl.link.coff.sym_index;
2666 const flags: u2 = switch (ptr) {
2667 .got_load => 0b00,
2668 .direct_load => 0b01,
2669 else => unreachable,
2670 };
2671 _ = try self.addInst(.{2671 _ = try self.addInst(.{
2672 .tag = .lea_pie,2672 .tag = .lea_pic,
2673 .ops = Mir.Inst.Ops.encode(.{2673 .ops = Mir.Inst.Ops.encode(.{
2674 .reg1 = registerAlias(reg, abi_size),2674 .reg1 = registerAlias(reg, abi_size),
2675 .flags = flags,2675 .flags = flags,
...@@ -4004,9 +4004,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4004,9 +4004,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4004 if (func_value.castTag(.function)) |func_payload| {4004 if (func_value.castTag(.function)) |func_payload| {
4005 const func = func_payload.data;4005 const func = func_payload.data;
4006 const fn_owner_decl = mod.declPtr(func.owner_decl);4006 const fn_owner_decl = mod.declPtr(func.owner_decl);
4007 const sym_index = fn_owner_decl.link.coff.sym_index;4007 try self.genSetReg(Type.initTag(.usize), .rax, .{
4008 try self.genSetReg(Type.initTag(.usize), .rax, .{ .got_load = sym_index });4008 .got_load = fn_owner_decl.link.coff.sym_index,
4009 // callq *%rax4009 });
4010 _ = try self.addInst(.{4010 _ = try self.addInst(.{
4011 .tag = .call,4011 .tag = .call,
4012 .ops = Mir.Inst.Ops.encode(.{4012 .ops = Mir.Inst.Ops.encode(.{
...@@ -6876,8 +6876,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6876,8 +6876,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6876 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6876 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
6877 return MCValue{ .memory = got_addr };6877 return MCValue{ .memory = got_addr };
6878 } else if (self.bin_file.cast(link.File.MachO)) |_| {6878 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6879 // Because MachO is PIE-always-on, we defer memory address resolution until
6880 // the linker has enough info to perform relocations.
6881 assert(decl.link.macho.sym_index != 0);6879 assert(decl.link.macho.sym_index != 0);
6882 return MCValue{ .got_load = decl.link.macho.sym_index };6880 return MCValue{ .got_load = decl.link.macho.sym_index };
6883 } else if (self.bin_file.cast(link.File.Coff)) |_| {6881 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/x86_64/Emit.zig+17-18
...@@ -137,7 +137,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -137,7 +137,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
137 .fld => try emit.mirFld(inst),137 .fld => try emit.mirFld(inst),
138138
139 .lea => try emit.mirLea(inst),139 .lea => try emit.mirLea(inst),
140 .lea_pie => try emit.mirLeaPie(inst),140 .lea_pic => try emit.mirLeaPic(inst),
141141
142 .shl => try emit.mirShift(.shl, inst),142 .shl => try emit.mirShift(.shl, inst),
143 .sal => try emit.mirShift(.sal, inst),143 .sal => try emit.mirShift(.sal, inst),
...@@ -338,7 +338,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -338,7 +338,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
338 .base = ops.reg1,338 .base = ops.reg1,
339 }), emit.code);339 }), emit.code);
340 },340 },
341 0b11 => return emit.fail("TODO unused JMP/CALL variant 0b11", .{}),341 0b11 => return emit.fail("TODO unused variant jmp/call 0b11", .{}),
342 }342 }
343}343}
344344
...@@ -784,7 +784,7 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -784,7 +784,7 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
784 // FD784 // FD
785 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);785 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
786 },786 },
787 else => return emit.fail("TODO unused variant: movabs 0b{b}", .{ops.flags}),787 else => return emit.fail("TODO unused movabs variant", .{}),
788 }788 }
789}789}
790790
...@@ -978,12 +978,17 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -978,12 +978,17 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
978 }978 }
979}979}
980980
981fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {981fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
982 const tag = emit.mir.instructions.items(.tag)[inst];982 const tag = emit.mir.instructions.items(.tag)[inst];
983 assert(tag == .lea_pie);983 assert(tag == .lea_pic);
984 const ops = emit.mir.instructions.items(.ops)[inst].decode();984 const ops = emit.mir.instructions.items(.ops)[inst].decode();
985 const relocation = emit.mir.instructions.items(.data)[inst].relocation;985 const relocation = emit.mir.instructions.items(.data)[inst].relocation;
986986
987 switch (ops.flags) {
988 0b00, 0b01 => {},
989 else => return emit.fail("TODO unused LEA PIC variants 0b10 and 0b11", .{}),
990 }
991
987 // lea reg1, [rip + reloc]992 // lea reg1, [rip + reloc]
988 // RM993 // RM
989 try lowerToRmEnc(994 try lowerToRmEnc(
...@@ -1000,7 +1005,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1000,7 +1005,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1000 const reloc_type = switch (ops.flags) {1005 const reloc_type = switch (ops.flags) {
1001 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),1006 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
1002 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1007 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
1003 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),1008 else => unreachable,
1004 };1009 };
1005 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;1010 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
1006 log.debug("adding reloc of type {} to local @{d}", .{ reloc_type, relocation.sym_index });1011 log.debug("adding reloc of type {} to local @{d}", .{ reloc_type, relocation.sym_index });
...@@ -1015,27 +1020,21 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1015,27 +1020,21 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1015 });1020 });
1016 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {1021 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
1017 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;1022 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;
1018 log.debug("adding reloc to local @{d}", .{relocation.sym_index});1023 try atom.addRelocation(coff_file, .{
1019 const gop = try coff_file.relocs.getOrPut(gpa, atom);
1020 if (!gop.found_existing) {
1021 gop.value_ptr.* = .{};
1022 }
1023 try gop.value_ptr.append(gpa, .{
1024 .@"type" = switch (ops.flags) {1024 .@"type" = switch (ops.flags) {
1025 0b00 => .got_pcrel,1025 0b00 => .got,
1026 0b01 => .direct,1026 0b01 => .direct,
1027 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),1027 else => unreachable,
1028 },1028 },
1029 .target = .{ .sym_index = relocation.sym_index, .file = null },1029 .target = .{ .sym_index = relocation.sym_index, .file = null },
1030 .offset = @intCast(u32, end_offset - 4),1030 .offset = @intCast(u32, end_offset - 4),
1031 .addend = 0,1031 .addend = 0,
1032 .pcrel = true,
1033 .length = 2,
1032 .prev_vaddr = atom.getSymbol(coff_file).value,1034 .prev_vaddr = atom.getSymbol(coff_file).value,
1033 });1035 });
1034 } else {1036 } else {
1035 return emit.fail(1037 return emit.fail("TODO implement lea reg, [rip + reloc] for linking backends different than MachO", .{});
1036 "TODO implement lea reg, [rip + reloc] for linking backends different than MachO",
1037 .{},
1038 );
1039 }1038 }
1040}1039}
10411040
src/arch/x86_64/Mir.zig+6-7
...@@ -178,11 +178,11 @@ pub const Inst = struct {...@@ -178,11 +178,11 @@ pub const Inst = struct {
178 lea,178 lea,
179179
180 /// ops flags: form:180 /// ops flags: form:
181 /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation181 /// 0b00 reg1, [rip + reloc] // via GOT PIC
182 /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation182 /// 0b01 reg1, [rip + reloc] // direct load PIC
183 /// Notes:183 /// Notes:
184 /// * `Data` contains `relocation`184 /// * `Data` contains `relocation`
185 lea_pie,185 lea_pic,
186186
187 /// ops flags: form:187 /// ops flags: form:
188 /// 0b00 reg1, 1188 /// 0b00 reg1, 1
...@@ -242,15 +242,14 @@ pub const Inst = struct {...@@ -242,15 +242,14 @@ pub const Inst = struct {
242 imul_complex,242 imul_complex,
243243
244 /// ops flags: form:244 /// ops flags: form:
245 /// 0bX0 reg1, imm64245 /// 0b00 reg1, imm64
246 /// 0bX1 rax, moffs64246 /// 0b01 rax, moffs64
247 /// Notes:247 /// Notes:
248 /// * If reg1 is 64-bit, the immediate is 64-bit and stored248 /// * If reg1 is 64-bit, the immediate is 64-bit and stored
249 /// within extra data `Imm64`.249 /// within extra data `Imm64`.
250 /// * For 0bX1, reg1 (or reg2) need to be250 /// * For 0b01, reg1 (or reg2) need to be
251 /// a version of rax. If reg1 == .none, then reg2 == .rax,251 /// a version of rax. If reg1 == .none, then reg2 == .rax,
252 /// or vice versa.252 /// or vice versa.
253 /// TODO handle scaling
254 movabs,253 movabs,
255254
256 /// ops flags: form:255 /// ops flags: form:
src/link/Coff.zig+27-20
...@@ -103,14 +103,16 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -103,14 +103,16 @@ unnamed_const_atoms: UnnamedConstTable = .{},
103/// this will be a table indexed by index into the list of Atoms.103/// this will be a table indexed by index into the list of Atoms.
104relocs: RelocTable = .{},104relocs: RelocTable = .{},
105105
106const Reloc = struct {106pub const Reloc = struct {
107 @"type": enum {107 @"type": enum {
108 got_pcrel,108 got,
109 direct,109 direct,
110 },110 },
111 target: SymbolWithLoc,111 target: SymbolWithLoc,
112 offset: u32,112 offset: u32,
113 addend: u32,113 addend: u32,
114 pcrel: bool,
115 length: u2,
114 prev_vaddr: u32,116 prev_vaddr: u32,
115};117};
116118
...@@ -593,15 +595,13 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {...@@ -593,15 +595,13 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
593595
594 log.debug("allocated GOT atom at 0x{x}", .{sym.value});596 log.debug("allocated GOT atom at 0x{x}", .{sym.value});
595597
596 const gop_relocs = try self.relocs.getOrPut(gpa, atom);598 try atom.addRelocation(self, .{
597 if (!gop_relocs.found_existing) {
598 gop_relocs.value_ptr.* = .{};
599 }
600 try gop_relocs.value_ptr.append(gpa, .{
601 .@"type" = .direct,599 .@"type" = .direct,
602 .target = target,600 .target = target,
603 .offset = 0,601 .offset = 0,
604 .addend = 0,602 .addend = 0,
603 .pcrel = false,
604 .length = 3,
605 .prev_vaddr = sym.value,605 .prev_vaddr = sym.value,
606 });606 });
607607
...@@ -656,7 +656,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -656,7 +656,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
656656
657 for (relocs.items) |*reloc| {657 for (relocs.items) |*reloc| {
658 const target_vaddr = switch (reloc.@"type") {658 const target_vaddr = switch (reloc.@"type") {
659 .got_pcrel => blk: {659 .got => blk: {
660 const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue;660 const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue;
661 break :blk got_atom.getSymbol(self).value;661 break :blk got_atom.getSymbol(self).value;
662 },662 },
...@@ -673,21 +673,28 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -673,21 +673,28 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
673 @tagName(reloc.@"type"),673 @tagName(reloc.@"type"),
674 });674 });
675675
676 switch (reloc.@"type") {676 if (reloc.pcrel) {
677 .got_pcrel => {677 const source_vaddr = source_sym.value + reloc.offset;
678 const source_vaddr = source_sym.value + reloc.offset;678 const disp = target_vaddr_with_addend - source_vaddr - 4;
679 const disp = target_vaddr_with_addend - source_vaddr - 4;679 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);
680 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);680 return;
681 },681 }
682 .direct => switch (self.ptr_width) {682
683 .p32 => try self.base.file.?.pwriteAll(683 switch (self.ptr_width) {
684 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),684 .p32 => try self.base.file.?.pwriteAll(
685 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),
686 file_offset + reloc.offset,
687 ),
688 .p64 => switch (reloc.length) {
689 2 => try self.base.file.?.pwriteAll(
690 mem.asBytes(&@truncate(u32, target_vaddr_with_addend + default_image_base_exe)),
685 file_offset + reloc.offset,691 file_offset + reloc.offset,
686 ),692 ),
687 .p64 => try self.base.file.?.pwriteAll(693 3 => try self.base.file.?.pwriteAll(
688 mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)),694 mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)),
689 file_offset + reloc.offset,695 file_offset + reloc.offset,
690 ),696 ),
697 else => unreachable,
691 },698 },
692 }699 }
693700
...@@ -1270,8 +1277,8 @@ fn writeHeader(self: *Coff) !void {...@@ -1270,8 +1277,8 @@ fn writeHeader(self: *Coff) !void {
1270 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;1277 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
12711278
1272 const dll_flags: coff.DllFlags = .{1279 const dll_flags: coff.DllFlags = .{
1273 .HIGH_ENTROPY_VA = 0, // TODO handle ASLR1280 .HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie),
1274 .DYNAMIC_BASE = 0, // TODO handle ASLR1281 .DYNAMIC_BASE = 0,
1275 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app1282 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
1276 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention1283 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
1277 };1284 };
src/link/Coff/Atom.zig+12
...@@ -6,6 +6,7 @@ const coff = std.coff;...@@ -6,6 +6,7 @@ const coff = std.coff;
6const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
77
8const Coff = @import("../Coff.zig");8const Coff = @import("../Coff.zig");
9const Reloc = Coff.Reloc;
9const SymbolWithLoc = Coff.SymbolWithLoc;10const SymbolWithLoc = Coff.SymbolWithLoc;
1011
11/// Each decl always gets a local symbol with the fully qualified name.12/// Each decl always gets a local symbol with the fully qualified name.
...@@ -96,3 +97,14 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {...@@ -96,3 +97,14 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
96 const surplus = cap - ideal_cap;97 const surplus = cap - ideal_cap;
97 return surplus >= Coff.min_text_capacity;98 return surplus >= Coff.min_text_capacity;
98}99}
100
101pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void {
102 const gpa = coff_file.base.allocator;
103 // TODO causes a segfault on Windows
104 // log.debug("adding reloc of type {s} to target %{d}", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
105 const gop = try coff_file.relocs.getOrPut(gpa, self);
106 if (!gop.found_existing) {
107 gop.value_ptr.* = .{};
108 }
109 try gop.value_ptr.append(gpa, reloc);
110}