authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-01 00:24:06+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-07 22:42:55+02:00
logaac4c1d3b225ff4cd7138d9aae599c9540c7f04e
tree69930c62692421f54d7e3587ceaf12370bf6ca16
parent0ebeb58d91b23acbd2ad3a168af19459af63a8f6

coff: fix contents of IAT, and ensure codegen loads addr into reg

As far as I can see, unlike with MachO, we don't have any stubs helper routines available and need to load a bound pointer into a register to then call it.

4 files changed, 140 insertions(+), 27 deletions(-)

src/arch/x86_64/CodeGen.zig+60-16
...@@ -137,6 +137,7 @@ pub const MCValue = union(enum) {...@@ -137,6 +137,7 @@ pub const MCValue = union(enum) {
137 /// If the type is a pointer, it means the pointer is referenced indirectly via GOT.137 /// If the type is a pointer, it means the pointer is referenced indirectly via GOT.
138 /// When lowered, linker will emit a relocation of type X86_64_RELOC_GOT.138 /// When lowered, linker will emit a relocation of type X86_64_RELOC_GOT.
139 got_load: u32,139 got_load: u32,
140 imports_load: u32,
140 /// The value is in memory referenced directly via symbol index.141 /// The value is in memory referenced directly via symbol index.
141 /// If the type is a pointer, it means the pointer is referenced directly via symbol index.142 /// If the type is a pointer, it means the pointer is referenced directly via symbol index.
142 /// When lowered, linker will emit a relocation of type X86_64_RELOC_SIGNED.143 /// When lowered, linker will emit a relocation of type X86_64_RELOC_SIGNED.
...@@ -156,6 +157,7 @@ pub const MCValue = union(enum) {...@@ -156,6 +157,7 @@ pub const MCValue = union(enum) {
156 .ptr_stack_offset,157 .ptr_stack_offset,
157 .direct_load,158 .direct_load,
158 .got_load,159 .got_load,
160 .imports_load,
159 => true,161 => true,
160 else => false,162 else => false,
161 };163 };
...@@ -2274,6 +2276,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2274,6 +2276,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2274 .memory,2276 .memory,
2275 .got_load,2277 .got_load,
2276 .direct_load,2278 .direct_load,
2279 .imports_load,
2277 => {2280 => {
2278 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);2281 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
2279 },2282 },
...@@ -2618,6 +2621,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2618,6 +2621,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2618 .memory,2621 .memory,
2619 .got_load,2622 .got_load,
2620 .direct_load,2623 .direct_load,
2624 .imports_load,
2621 => {2625 => {
2622 const reg = try self.copyToTmpRegister(ptr_ty, ptr);2626 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
2623 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);2627 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
...@@ -2655,6 +2659,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2655,6 +2659,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2655 switch (ptr) {2659 switch (ptr) {
2656 .got_load,2660 .got_load,
2657 .direct_load,2661 .direct_load,
2662 .imports_load,
2658 => |sym_index| {2663 => |sym_index| {
2659 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));2664 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2660 const mod = self.bin_file.options.module.?;2665 const mod = self.bin_file.options.module.?;
...@@ -2666,6 +2671,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2666,6 +2671,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2666 const flags: u2 = switch (ptr) {2671 const flags: u2 = switch (ptr) {
2667 .got_load => 0b00,2672 .got_load => 0b00,
2668 .direct_load => 0b01,2673 .direct_load => 0b01,
2674 .imports_load => 0b10,
2669 else => unreachable,2675 else => unreachable,
2670 };2676 };
2671 _ = try self.addInst(.{2677 _ = try self.addInst(.{
...@@ -2763,6 +2769,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2763,6 +2769,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2763 },2769 },
2764 .got_load,2770 .got_load,
2765 .direct_load,2771 .direct_load,
2772 .imports_load,
2766 .memory,2773 .memory,
2767 .stack_offset,2774 .stack_offset,
2768 => {2775 => {
...@@ -2783,6 +2790,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2783,6 +2790,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2783 },2790 },
2784 .got_load,2791 .got_load,
2785 .direct_load,2792 .direct_load,
2793 .imports_load,
2786 .memory,2794 .memory,
2787 => {2795 => {
2788 const value_lock: ?RegisterLock = switch (value) {2796 const value_lock: ?RegisterLock = switch (value) {
...@@ -2854,6 +2862,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2854,6 +2862,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2854 },2862 },
2855 .got_load,2863 .got_load,
2856 .direct_load,2864 .direct_load,
2865 .imports_load,
2857 .memory,2866 .memory,
2858 => {2867 => {
2859 if (abi_size <= 8) {2868 if (abi_size <= 8) {
...@@ -3565,6 +3574,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3565,6 +3574,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3565 .memory,3574 .memory,
3566 .got_load,3575 .got_load,
3567 .direct_load,3576 .direct_load,
3577 .imports_load,
3568 .eflags,3578 .eflags,
3569 => {3579 => {
3570 assert(abi_size <= 8);3580 assert(abi_size <= 8);
...@@ -3650,7 +3660,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3650,7 +3660,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3650 => {3660 => {
3651 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});3661 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
3652 },3662 },
3653 .got_load, .direct_load => {3663 .got_load,
3664 .direct_load,
3665 .imports_load,
3666 => {
3654 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});3667 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
3655 },3668 },
3656 .eflags => {3669 .eflags => {
...@@ -3661,7 +3674,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3661,7 +3674,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3661 .memory => {3674 .memory => {
3662 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});3675 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
3663 },3676 },
3664 .got_load, .direct_load => {3677 .got_load,
3678 .direct_load,
3679 .imports_load,
3680 => {
3665 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});3681 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});
3666 },3682 },
3667 }3683 }
...@@ -3729,7 +3745,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3729,7 +3745,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3729 .memory => {3745 .memory => {
3730 return self.fail("TODO implement x86 multiply source memory", .{});3746 return self.fail("TODO implement x86 multiply source memory", .{});
3731 },3747 },
3732 .got_load, .direct_load => {3748 .got_load,
3749 .direct_load,
3750 .imports_load,
3751 => {
3733 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3752 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3734 },3753 },
3735 .eflags => {3754 .eflags => {
...@@ -3773,7 +3792,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3773,7 +3792,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3773 .memory, .stack_offset => {3792 .memory, .stack_offset => {
3774 return self.fail("TODO implement x86 multiply source memory", .{});3793 return self.fail("TODO implement x86 multiply source memory", .{});
3775 },3794 },
3776 .got_load, .direct_load => {3795 .got_load,
3796 .direct_load,
3797 .imports_load,
3798 => {
3777 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3799 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3778 },3800 },
3779 .eflags => {3801 .eflags => {
...@@ -3784,7 +3806,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3784,7 +3806,10 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3784 .memory => {3806 .memory => {
3785 return self.fail("TODO implement x86 multiply destination memory", .{});3807 return self.fail("TODO implement x86 multiply destination memory", .{});
3786 },3808 },
3787 .got_load, .direct_load => {3809 .got_load,
3810 .direct_load,
3811 .imports_load,
3812 => {
3788 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});3813 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});
3789 },3814 },
3790 }3815 }
...@@ -3948,6 +3973,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3948,6 +3973,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3948 .memory => unreachable,3973 .memory => unreachable,
3949 .got_load => unreachable,3974 .got_load => unreachable,
3950 .direct_load => unreachable,3975 .direct_load => unreachable,
3976 .imports_load => unreachable,
3951 .eflags => unreachable,3977 .eflags => unreachable,
3952 .register_overflow => unreachable,3978 .register_overflow => unreachable,
3953 }3979 }
...@@ -4025,15 +4051,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4025,15 +4051,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4025 });4051 });
4026 }4052 }
4027 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4053 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4054 try self.genSetReg(Type.initTag(.usize), .rax, .{
4055 .imports_load = sym_index,
4056 });
4028 _ = try self.addInst(.{4057 _ = try self.addInst(.{
4029 .tag = .call_extern,4058 .tag = .call,
4030 .ops = undefined,4059 .ops = Mir.Inst.Ops.encode(.{
4031 .data = .{4060 .reg1 = .rax,
4032 .relocation = .{4061 .flags = 0b01,
4033 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.coff.sym_index,4062 }),
4034 .sym_index = sym_index,4063 .data = undefined,
4035 },
4036 },
4037 });4064 });
4038 } else {4065 } else {
4039 return self.fail("TODO implement calling bitcasted functions", .{});4066 return self.fail("TODO implement calling bitcasted functions", .{});
...@@ -4443,7 +4470,11 @@ fn genVarDbgInfo(...@@ -4443,7 +4470,11 @@ fn genVarDbgInfo(
4443 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;4470 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
4444 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);4471 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4445 },4472 },
4446 .memory, .got_load, .direct_load => {4473 .memory,
4474 .got_load,
4475 .direct_load,
4476 .imports_load,
4477 => {
4447 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));4478 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
4448 const is_ptr = switch (tag) {4479 const is_ptr = switch (tag) {
4449 .dbg_var_ptr => true,4480 .dbg_var_ptr => true,
...@@ -4474,7 +4505,10 @@ fn genVarDbgInfo(...@@ -4474,7 +4505,10 @@ fn genVarDbgInfo(
4474 try dbg_info.append(DW.OP.deref);4505 try dbg_info.append(DW.OP.deref);
4475 }4506 }
4476 switch (mcv) {4507 switch (mcv) {
4477 .got_load, .direct_load => |index| try dw.addExprlocReloc(index, offset, is_ptr),4508 .got_load,
4509 .direct_load,
4510 .imports_load,
4511 => |index| try dw.addExprlocReloc(index, offset, is_ptr),
4478 else => {},4512 else => {},
4479 }4513 }
4480 },4514 },
...@@ -5474,6 +5508,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5474,6 +5508,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5474 .memory,5508 .memory,
5475 .direct_load,5509 .direct_load,
5476 .got_load,5510 .got_load,
5511 .imports_load,
5477 => {5512 => {
5478 if (abi_size <= 8) {5513 if (abi_size <= 8) {
5479 const reg = try self.copyToTmpRegister(ty, mcv);5514 const reg = try self.copyToTmpRegister(ty, mcv);
...@@ -5721,6 +5756,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5721,6 +5756,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5721 .memory,5756 .memory,
5722 .got_load,5757 .got_load,
5723 .direct_load,5758 .direct_load,
5759 .imports_load,
5724 => {5760 => {
5725 if (abi_size <= 8) {5761 if (abi_size <= 8) {
5726 const reg = try self.copyToTmpRegister(ty, mcv);5762 const reg = try self.copyToTmpRegister(ty, mcv);
...@@ -5848,6 +5884,7 @@ fn genInlineMemcpy(...@@ -5848,6 +5884,7 @@ fn genInlineMemcpy(
5848 .memory,5884 .memory,
5849 .got_load,5885 .got_load,
5850 .direct_load,5886 .direct_load,
5887 .imports_load,
5851 => {5888 => {
5852 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);5889 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
5853 },5890 },
...@@ -5883,6 +5920,7 @@ fn genInlineMemcpy(...@@ -5883,6 +5920,7 @@ fn genInlineMemcpy(
5883 .memory,5920 .memory,
5884 .got_load,5921 .got_load,
5885 .direct_load,5922 .direct_load,
5923 .imports_load,
5886 => {5924 => {
5887 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);5925 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);
5888 },5926 },
...@@ -6021,6 +6059,7 @@ fn genInlineMemset(...@@ -6021,6 +6059,7 @@ fn genInlineMemset(
6021 .memory,6059 .memory,
6022 .got_load,6060 .got_load,
6023 .direct_load,6061 .direct_load,
6062 .imports_load,
6024 => {6063 => {
6025 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);6064 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);
6026 },6065 },
...@@ -6261,6 +6300,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6261,6 +6300,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6261 },6300 },
6262 .direct_load,6301 .direct_load,
6263 .got_load,6302 .got_load,
6303 .imports_load,
6264 => {6304 => {
6265 switch (ty.zigTypeTag()) {6305 switch (ty.zigTypeTag()) {
6266 .Float => {6306 .Float => {
...@@ -6655,7 +6695,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -6655,7 +6695,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6655 // TODO Is this the only condition for pointer dereference for memcpy?6695 // TODO Is this the only condition for pointer dereference for memcpy?
6656 const src: MCValue = blk: {6696 const src: MCValue = blk: {
6657 switch (src_ptr) {6697 switch (src_ptr) {
6658 .got_load, .direct_load, .memory => {6698 .got_load,
6699 .direct_load,
6700 .imports_load,
6701 .memory,
6702 => {
6659 const reg = try self.register_manager.allocReg(null, gp);6703 const reg = try self.register_manager.allocReg(null, gp);
6660 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);6704 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
6661 _ = try self.addInst(.{6705 _ = try self.addInst(.{
src/arch/x86_64/Emit.zig+3-2
...@@ -985,8 +985,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -985,8 +985,8 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
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) {987 switch (ops.flags) {
988 0b00, 0b01 => {},988 0b00, 0b01, 0b10 => {},
989 else => return emit.fail("TODO unused LEA PIC variants 0b10 and 0b11", .{}),989 else => return emit.fail("TODO unused LEA PIC variant 0b11", .{}),
990 }990 }
991991
992 // lea reg1, [rip + reloc]992 // lea reg1, [rip + reloc]
...@@ -1024,6 +1024,7 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1024,6 +1024,7 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1024 .@"type" = switch (ops.flags) {1024 .@"type" = switch (ops.flags) {
1025 0b00 => .got,1025 0b00 => .got,
1026 0b01 => .direct,1026 0b01 => .direct,
1027 0b10 => .imports,
1027 else => unreachable,1028 else => unreachable,
1028 },1029 },
1029 .target = .{ .sym_index = relocation.sym_index, .file = null },1030 .target = .{ .sym_index = relocation.sym_index, .file = null },
src/arch/x86_64/Mir.zig+1
...@@ -180,6 +180,7 @@ pub const Inst = struct {...@@ -180,6 +180,7 @@ pub const Inst = struct {
180 /// ops flags: form:180 /// ops flags: form:
181 /// 0b00 reg1, [rip + reloc] // via GOT PIC181 /// 0b00 reg1, [rip + reloc] // via GOT PIC
182 /// 0b01 reg1, [rip + reloc] // direct load PIC182 /// 0b01 reg1, [rip + reloc] // direct load PIC
183 /// 0b10 reg1, [rip + reloc] // via imports table PIC
183 /// Notes:184 /// Notes:
184 /// * `Data` contains `relocation`185 /// * `Data` contains `relocation`
185 lea_pic,186 lea_pic,
src/link/Coff.zig+76-9
...@@ -123,6 +123,7 @@ pub const Reloc = struct {...@@ -123,6 +123,7 @@ pub const Reloc = struct {
123 @"type": enum {123 @"type": enum {
124 got,124 got,
125 direct,125 direct,
126 imports,
126 },127 },
127 target: SymbolWithLoc,128 target: SymbolWithLoc,
128 offset: u32,129 offset: u32,
...@@ -812,18 +813,18 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -812,18 +813,18 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
812 break :blk got_atom.getSymbol(self).value;813 break :blk got_atom.getSymbol(self).value;
813 },814 },
814 .direct => blk: {815 .direct => blk: {
815 if (self.getImportAtomForSymbol(reloc.target)) |import_atom| {
816 break :blk import_atom.getSymbol(self).value;
817 }
818 break :blk self.getSymbol(reloc.target).value;816 break :blk self.getSymbol(reloc.target).value;
819 },817 },
818 .imports => blk: {
819 const import_atom = self.getImportAtomForSymbol(reloc.target) orelse continue;
820 break :blk import_atom.getSymbol(self).value;
821 },
820 };822 };
821 const target_vaddr_with_addend = target_vaddr + reloc.addend;823 const target_vaddr_with_addend = target_vaddr + reloc.addend;
822
823 if (target_vaddr_with_addend == reloc.prev_vaddr) continue;824 if (target_vaddr_with_addend == reloc.prev_vaddr) continue;
824825
825 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{826 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
826 reloc.offset,827 source_sym.value + reloc.offset,
827 target_vaddr_with_addend,828 target_vaddr_with_addend,
828 self.getSymbolName(reloc.target),829 self.getSymbolName(reloc.target),
829 @tagName(reloc.@"type"),830 @tagName(reloc.@"type"),
...@@ -833,7 +834,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -833,7 +834,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
833 const source_vaddr = source_sym.value + reloc.offset;834 const source_vaddr = source_sym.value + reloc.offset;
834 const disp = target_vaddr_with_addend - source_vaddr - 4;835 const disp = target_vaddr_with_addend - source_vaddr - 4;
835 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);836 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);
836 return;837 continue;
837 }838 }
838839
839 switch (self.ptr_width) {840 switch (self.ptr_width) {
...@@ -1345,8 +1346,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1345,8 +1346,8 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1345 try self.resolveRelocs(atom.*);1346 try self.resolveRelocs(atom.*);
1346 }1347 }
1347 }1348 }
1348 try self.writeBaseRelocations();
1349 try self.writeImportTable();1349 try self.writeImportTable();
1350 try self.writeBaseRelocations();
13501351
1351 if (self.getEntryPoint()) |entry_sym_loc| {1352 if (self.getEntryPoint()) |entry_sym_loc| {
1352 self.entry_addr = self.getSymbol(entry_sym_loc).value;1353 self.entry_addr = self.getSymbol(entry_sym_loc).value;
...@@ -1487,14 +1488,80 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1487,14 +1488,80 @@ fn writeBaseRelocations(self: *Coff) !void {
14871488
1488fn writeImportTable(self: *Coff) !void {1489fn writeImportTable(self: *Coff) !void {
1489 const gpa = self.base.allocator;1490 const gpa = self.base.allocator;
1490 _ = gpa;
14911491
1492 const section = self.sections.get(self.idata_section_index.?);1492 const section = self.sections.get(self.idata_section_index.?);
1493 const iat_rva = section.header.virtual_address;1493 const iat_rva = section.header.virtual_address;
1494 const iat_size = blk: {1494 const iat_size = blk: {
1495 const last_atom = section.last_atom.?;1495 const last_atom = section.last_atom.?;
1496 break :blk last_atom.getSymbol(self).value + last_atom.size - iat_rva;1496 break :blk last_atom.getSymbol(self).value + last_atom.size * 2 - iat_rva; // account for sentinel zero pointer
1497 };
1498
1499 const dll_name = "KERNEL32.dll";
1500
1501 var import_dir_entry = coff.ImportDirectoryEntry{
1502 .import_lookup_table_rva = @sizeOf(coff.ImportDirectoryEntry) * 2,
1503 .time_date_stamp = 0,
1504 .forwarder_chain = 0,
1505 .name_rva = 0,
1506 .import_address_table_rva = iat_rva,
1507 };
1508
1509 // TODO: we currently assume there's only one (implicit) DLL - ntdll
1510 var lookup_table = std.ArrayList(coff.ImportLookupEntry64.ByName).init(gpa);
1511 defer lookup_table.deinit();
1512
1513 var names_table = std.ArrayList(u8).init(gpa);
1514 defer names_table.deinit();
1515
1516 // TODO: check if import is still valid
1517 for (self.imports_table.keys()) |target| {
1518 const target_name = self.getSymbolName(target);
1519 const start = names_table.items.len;
1520 mem.writeIntLittle(u16, try names_table.addManyAsArray(2), 0); // TODO: currently, hint is set to 0 as we haven't yet parsed any DLL
1521 try names_table.appendSlice(target_name);
1522 try names_table.append(0);
1523 const end = names_table.items.len;
1524 if (!mem.isAlignedGeneric(usize, end - start, @sizeOf(u16))) {
1525 try names_table.append(0);
1526 }
1527 try lookup_table.append(.{ .name_table_rva = @intCast(u31, start) });
1528 }
1529 try lookup_table.append(.{ .name_table_rva = 0 }); // the sentinel
1530
1531 const dir_entry_size = @sizeOf(coff.ImportDirectoryEntry) + lookup_table.items.len * @sizeOf(coff.ImportLookupEntry64.ByName) + names_table.items.len + dll_name.len + 1;
1532 const needed_size = iat_size + dir_entry_size + @sizeOf(coff.ImportDirectoryEntry);
1533 const sect_capacity = self.allocatedSize(section.header.pointer_to_raw_data);
1534 assert(needed_size < sect_capacity); // TODO: implement expanding .idata section
1535
1536 // Fixup offsets
1537 const base_rva = iat_rva + iat_size;
1538 import_dir_entry.import_lookup_table_rva += base_rva;
1539 import_dir_entry.name_rva = @intCast(u32, base_rva + dir_entry_size + @sizeOf(coff.ImportDirectoryEntry) - dll_name.len - 1);
1540
1541 for (lookup_table.items[0 .. lookup_table.items.len - 1]) |*lk| {
1542 lk.name_table_rva += @intCast(u31, base_rva + @sizeOf(coff.ImportDirectoryEntry) * 2 + lookup_table.items.len * @sizeOf(coff.ImportLookupEntry64.ByName));
1543 }
1544
1545 var buffer = std.ArrayList(u8).init(gpa);
1546 defer buffer.deinit();
1547 try buffer.ensureTotalCapacity(dir_entry_size + @sizeOf(coff.ImportDirectoryEntry));
1548 buffer.appendSliceAssumeCapacity(mem.asBytes(&import_dir_entry));
1549 buffer.appendNTimesAssumeCapacity(0, @sizeOf(coff.ImportDirectoryEntry)); // the sentinel; TODO: I think doing all of the above on bytes directly might be cleaner
1550 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(lookup_table.items));
1551 buffer.appendSliceAssumeCapacity(names_table.items);
1552 buffer.appendSliceAssumeCapacity(dll_name);
1553 buffer.appendAssumeCapacity(0);
1554
1555 try self.base.file.?.pwriteAll(buffer.items, section.header.pointer_to_raw_data + iat_size);
1556 // Override the IAT atoms
1557 // TODO: we should rewrite only dirtied atoms, but that's for way later
1558 try self.base.file.?.pwriteAll(mem.sliceAsBytes(lookup_table.items), section.header.pointer_to_raw_data);
1559
1560 self.data_directories[@enumToInt(coff.DirectoryEntry.IMPORT)] = .{
1561 .virtual_address = iat_rva + iat_size,
1562 .size = @intCast(u32, @sizeOf(coff.ImportDirectoryEntry) * 2),
1497 };1563 };
1564
1498 self.data_directories[@enumToInt(coff.DirectoryEntry.IAT)] = .{1565 self.data_directories[@enumToInt(coff.DirectoryEntry.IAT)] = .{
1499 .virtual_address = iat_rva,1566 .virtual_address = iat_rva,
1500 .size = iat_size,1567 .size = iat_size,