| author | |
| committer | |
| log | 601f2147e0344621d238e5209e0d36c69be3cc03 |
| tree | f7addabfa5d2ae5575532d5957fd1aa6333b57f0 |
| parent | ebdb2867363256a265646f2a1b66d3762a51b7ba |
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; | ||
| 3483 | 3479 | ||
| 3484 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); | 3480 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); |
| 3485 | 3481 | ||
| ... | @@ -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 depends | 3698 | // 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 MachO | 3749 | .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 MachO | 5547 | 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. |
| 1718 | 1718 | ||
| 1719 | // Due to incremental compilation, how function calls are generated depends | 1719 | // 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; | ||
| 1763 | 1759 | ||
| 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 MachO | 1780 | 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 storing | 2590 | // 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_index | 2663 | fn_owner_decl.link.macho.sym_index |
| 2669 | else | 2664 | 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 *%rax | 4009 | }); |
| 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), |
| 138 | 138 | ||
| 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), |
| 141 | 141 | ||
| 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 | } |
| 344 | 344 | ||
| ... | @@ -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 | // FD | 784 | // 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 | } |
| 790 | 790 | ||
| ... | @@ -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 | } |
| 980 | 980 | ||
| 981 | fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 981 | fn 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; |
| 986 | 986 | ||
| 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 | // RM | 993 | // 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 | } |
| 1041 | 1040 |
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, |
| 179 | 179 | ||
| 180 | /// ops flags: form: | 180 | /// ops flags: form: |
| 181 | /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation | 181 | /// 0b00 reg1, [rip + reloc] // via GOT PIC |
| 182 | /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation | 182 | /// 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, |
| 186 | 186 | ||
| 187 | /// ops flags: form: | 187 | /// ops flags: form: |
| 188 | /// 0b00 reg1, 1 | 188 | /// 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, |
| 243 | 243 | ||
| 244 | /// ops flags: form: | 244 | /// ops flags: form: |
| 245 | /// 0bX0 reg1, imm64 | 245 | /// 0b00 reg1, imm64 |
| 246 | /// 0bX1 rax, moffs64 | 246 | /// 0b01 rax, moffs64 |
| 247 | /// Notes: | 247 | /// Notes: |
| 248 | /// * If reg1 is 64-bit, the immediate is 64-bit and stored | 248 | /// * 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 be | 250 | /// * 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, |
| 255 | 254 | ||
| 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. |
| 104 | relocs: RelocTable = .{}, | 104 | relocs: RelocTable = .{}, |
| 105 | 105 | ||
| 106 | const Reloc = struct { | 106 | pub 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 | }; |
| 116 | 118 | ||
| ... | @@ -593,15 +595,13 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | ... | @@ -593,15 +595,13 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 593 | 595 | ||
| 594 | log.debug("allocated GOT atom at 0x{x}", .{sym.value}); | 596 | log.debug("allocated GOT atom at 0x{x}", .{sym.value}); |
| 595 | 597 | ||
| 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 | }); |
| 607 | 607 | ||
| ... | @@ -656,7 +656,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -656,7 +656,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 656 | 656 | ||
| 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 | }); |
| 675 | 675 | ||
| 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 | } |
| 693 | 700 | ||
| ... | @@ -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; |
| 1271 | 1278 | ||
| 1272 | const dll_flags: coff.DllFlags = .{ | 1279 | const dll_flags: coff.DllFlags = .{ |
| 1273 | .HIGH_ENTROPY_VA = 0, // TODO handle ASLR | 1280 | .HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie), |
| 1274 | .DYNAMIC_BASE = 0, // TODO handle ASLR | 1281 | .DYNAMIC_BASE = 0, |
| 1275 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app | 1282 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app |
| 1276 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention | 1283 | .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; |
| 6 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 7 | 7 | ||
| 8 | const Coff = @import("../Coff.zig"); | 8 | const Coff = @import("../Coff.zig"); |
| 9 | const Reloc = Coff.Reloc; | ||
| 9 | const SymbolWithLoc = Coff.SymbolWithLoc; | 10 | const SymbolWithLoc = Coff.SymbolWithLoc; |
| 10 | 11 | ||
| 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 | |||
| 101 | pub 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 | } |