| author | |
| committer | |
| log | 83d89a05b7670c5c25d4f0f717ac5168a9cb6557 |
| tree | 66e0874d751a6c8773d8b07cf7ac960f0d3f9fff |
| parent | 205421c3117dbcd819dc636a7485e3cfeec0be20 |
* make image base target dependent
* fix relocs to imports5 files changed, 163 insertions(+), 112 deletions(-)
lib/std/io.zig+3-3| ... | @@ -36,7 +36,7 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking | ... | @@ -36,7 +36,7 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking |
| 36 | 36 | ||
| 37 | fn getStdOutHandle() os.fd_t { | 37 | fn getStdOutHandle() os.fd_t { |
| 38 | if (builtin.os.tag == .windows) { | 38 | if (builtin.os.tag == .windows) { |
| 39 | if (builtin.zig_backend == .stage2_x86_64) { | 39 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) { |
| 40 | // TODO: this is just a temporary workaround until we advance x86 backend further along. | 40 | // TODO: this is just a temporary workaround until we advance x86 backend further along. |
| 41 | return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; | 41 | return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; |
| 42 | } | 42 | } |
| ... | @@ -62,7 +62,7 @@ pub fn getStdOut() File { | ... | @@ -62,7 +62,7 @@ pub fn getStdOut() File { |
| 62 | 62 | ||
| 63 | fn getStdErrHandle() os.fd_t { | 63 | fn getStdErrHandle() os.fd_t { |
| 64 | if (builtin.os.tag == .windows) { | 64 | if (builtin.os.tag == .windows) { |
| 65 | if (builtin.zig_backend == .stage2_x86_64) { | 65 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) { |
| 66 | // TODO: this is just a temporary workaround until we advance x86 backend further along. | 66 | // TODO: this is just a temporary workaround until we advance x86 backend further along. |
| 67 | return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; | 67 | return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; |
| 68 | } | 68 | } |
| ... | @@ -88,7 +88,7 @@ pub fn getStdErr() File { | ... | @@ -88,7 +88,7 @@ pub fn getStdErr() File { |
| 88 | 88 | ||
| 89 | fn getStdInHandle() os.fd_t { | 89 | fn getStdInHandle() os.fd_t { |
| 90 | if (builtin.os.tag == .windows) { | 90 | if (builtin.os.tag == .windows) { |
| 91 | if (builtin.zig_backend == .stage2_x86_64) { | 91 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) { |
| 92 | // TODO: this is just a temporary workaround until we advance x86 backend further along. | 92 | // TODO: this is just a temporary workaround until we advance x86 backend further along. |
| 93 | return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; | 93 | return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE; |
| 94 | } | 94 | } |
src/arch/aarch64/CodeGen.zig+26-13| ... | @@ -142,7 +142,8 @@ const MCValue = union(enum) { | ... | @@ -142,7 +142,8 @@ const MCValue = union(enum) { |
| 142 | /// The value is in memory but requires a linker relocation fixup: | 142 | /// The value is in memory but requires a linker relocation fixup: |
| 143 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | 143 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) |
| 144 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | 144 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) |
| 145 | linker_load: struct { @"type": enum { got, direct }, sym_index: u32 }, | 145 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) |
| 146 | linker_load: struct { @"type": enum { got, direct, import }, sym_index: u32 }, | ||
| 146 | /// The value is one of the stack variables. | 147 | /// The value is one of the stack variables. |
| 147 | /// | 148 | /// |
| 148 | /// If the type is a pointer, it means the pointer address is in | 149 | /// If the type is a pointer, it means the pointer address is in |
| ... | @@ -3717,6 +3718,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3717,6 +3718,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3717 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { | 3718 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { |
| 3718 | .got => .load_memory_ptr_got, | 3719 | .got => .load_memory_ptr_got, |
| 3719 | .direct => .load_memory_ptr_direct, | 3720 | .direct => .load_memory_ptr_direct, |
| 3721 | .import => unreachable, | ||
| 3720 | }; | 3722 | }; |
| 3721 | const mod = self.bin_file.options.module.?; | 3723 | const mod = self.bin_file.options.module.?; |
| 3722 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); | 3724 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); |
| ... | @@ -4086,16 +4088,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -4086,16 +4088,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 4086 | }); | 4088 | }); |
| 4087 | } | 4089 | } |
| 4088 | const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); | 4090 | const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0)); |
| 4089 | 4091 | try self.genSetReg(Type.initTag(.u64), .x30, .{ | |
| 4090 | _ = try self.addInst(.{ | 4092 | .linker_load = .{ |
| 4091 | .tag = .call_extern, | 4093 | .@"type" = .import, |
| 4092 | .data = .{ | 4094 | .sym_index = sym_index, |
| 4093 | .relocation = .{ | ||
| 4094 | .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.coff.sym_index, | ||
| 4095 | .sym_index = sym_index, | ||
| 4096 | }, | ||
| 4097 | }, | 4095 | }, |
| 4098 | }); | 4096 | }); |
| 4097 | // blr x30 | ||
| 4098 | _ = try self.addInst(.{ | ||
| 4099 | .tag = .blr, | ||
| 4100 | .data = .{ .reg = .x30 }, | ||
| 4101 | }); | ||
| 4099 | } else { | 4102 | } else { |
| 4100 | return self.fail("TODO implement calling bitcasted functions", .{}); | 4103 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4101 | } | 4104 | } |
| ... | @@ -4119,8 +4122,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -4119,8 +4122,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 4119 | } else { | 4122 | } else { |
| 4120 | return self.fail("TODO implement calling bitcasted functions", .{}); | 4123 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4121 | } | 4124 | } |
| 4122 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 4123 | return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch}); | ||
| 4124 | } else unreachable; | 4125 | } else unreachable; |
| 4125 | } else { | 4126 | } else { |
| 4126 | assert(ty.zigTypeTag() == .Pointer); | 4127 | assert(ty.zigTypeTag() == .Pointer); |
| ... | @@ -5203,6 +5204,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5203,6 +5204,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5203 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { | 5204 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { |
| 5204 | .got => .load_memory_ptr_got, | 5205 | .got => .load_memory_ptr_got, |
| 5205 | .direct => .load_memory_ptr_direct, | 5206 | .direct => .load_memory_ptr_direct, |
| 5207 | .import => unreachable, | ||
| 5206 | }; | 5208 | }; |
| 5207 | const mod = self.bin_file.options.module.?; | 5209 | const mod = self.bin_file.options.module.?; |
| 5208 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); | 5210 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); |
| ... | @@ -5316,6 +5318,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5316,6 +5318,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5316 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { | 5318 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { |
| 5317 | .got => .load_memory_got, | 5319 | .got => .load_memory_got, |
| 5318 | .direct => .load_memory_direct, | 5320 | .direct => .load_memory_direct, |
| 5321 | .import => .load_memory_import, | ||
| 5319 | }; | 5322 | }; |
| 5320 | const mod = self.bin_file.options.module.?; | 5323 | const mod = self.bin_file.options.module.?; |
| 5321 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); | 5324 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); |
| ... | @@ -5509,6 +5512,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5509,6 +5512,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5509 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { | 5512 | const tag: Mir.Inst.Tag = switch (load_struct.@"type") { |
| 5510 | .got => .load_memory_ptr_got, | 5513 | .got => .load_memory_ptr_got, |
| 5511 | .direct => .load_memory_ptr_direct, | 5514 | .direct => .load_memory_ptr_direct, |
| 5515 | .import => unreachable, | ||
| 5512 | }; | 5516 | }; |
| 5513 | const mod = self.bin_file.options.module.?; | 5517 | const mod = self.bin_file.options.module.?; |
| 5514 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); | 5518 | const owner_decl = mod.declPtr(self.mod_fn.owner_decl); |
| ... | @@ -5835,7 +5839,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne | ... | @@ -5835,7 +5839,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne |
| 5835 | .sym_index = decl.link.macho.sym_index, | 5839 | .sym_index = decl.link.macho.sym_index, |
| 5836 | } }; | 5840 | } }; |
| 5837 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | 5841 | } else if (self.bin_file.cast(link.File.Coff)) |_| { |
| 5838 | return self.fail("TODO codegen COFF const Decl pointer", .{}); | 5842 | // Because COFF is PIE-always-on, we defer memory address resolution until |
| 5843 | // the linker has enough info to perform relocations. | ||
| 5844 | assert(decl.link.coff.sym_index != 0); | ||
| 5845 | return MCValue{ .linker_load = .{ | ||
| 5846 | .@"type" = .got, | ||
| 5847 | .sym_index = decl.link.coff.sym_index, | ||
| 5848 | } }; | ||
| 5839 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | 5849 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 5840 | try p9.seeDecl(decl_index); | 5850 | try p9.seeDecl(decl_index); |
| 5841 | const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; | 5851 | const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes; |
| ... | @@ -5859,7 +5869,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | ... | @@ -5859,7 +5869,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { |
| 5859 | .sym_index = local_sym_index, | 5869 | .sym_index = local_sym_index, |
| 5860 | } }; | 5870 | } }; |
| 5861 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | 5871 | } else if (self.bin_file.cast(link.File.Coff)) |_| { |
| 5862 | return self.fail("TODO lower unnamed const in COFF", .{}); | 5872 | return MCValue{ .linker_load = .{ |
| 5873 | .@"type" = .direct, | ||
| 5874 | .sym_index = local_sym_index, | ||
| 5875 | } }; | ||
| 5863 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { | 5876 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { |
| 5864 | return self.fail("TODO lower unnamed const in Plan9", .{}); | 5877 | return self.fail("TODO lower unnamed const in Plan9", .{}); |
| 5865 | } else { | 5878 | } else { |
src/arch/aarch64/Emit.zig+19-15| ... | @@ -145,6 +145,7 @@ pub fn emitMir( | ... | @@ -145,6 +145,7 @@ pub fn emitMir( |
| 145 | 145 | ||
| 146 | .load_memory_got => try emit.mirLoadMemoryPie(inst), | 146 | .load_memory_got => try emit.mirLoadMemoryPie(inst), |
| 147 | .load_memory_direct => try emit.mirLoadMemoryPie(inst), | 147 | .load_memory_direct => try emit.mirLoadMemoryPie(inst), |
| 148 | .load_memory_import => try emit.mirLoadMemoryPie(inst), | ||
| 148 | .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst), | 149 | .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst), |
| 149 | .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst), | 150 | .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst), |
| 150 | 151 | ||
| ... | @@ -693,18 +694,8 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -693,18 +694,8 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 693 | .pcrel = true, | 694 | .pcrel = true, |
| 694 | .length = 2, | 695 | .length = 2, |
| 695 | }); | 696 | }); |
| 696 | } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { | 697 | } else if (emit.bin_file.cast(link.File.Coff)) |_| { |
| 697 | // Add relocation to the decl. | 698 | unreachable; // Calling imports is handled via `.load_memory_import` |
| 698 | const atom = coff_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; | ||
| 699 | const target = coff_file.getGlobalByIndex(relocation.sym_index); | ||
| 700 | try atom.addRelocation(coff_file, .{ | ||
| 701 | .@"type" = .branch_26, | ||
| 702 | .target = target, | ||
| 703 | .offset = offset, | ||
| 704 | .addend = 0, | ||
| 705 | .pcrel = true, | ||
| 706 | .length = 2, | ||
| 707 | }); | ||
| 708 | } else { | 699 | } else { |
| 709 | return emit.fail("Implement call_extern for linking backends != {{ COFF, MachO }}", .{}); | 700 | return emit.fail("Implement call_extern for linking backends != {{ COFF, MachO }}", .{}); |
| 710 | } | 701 | } |
| ... | @@ -868,7 +859,9 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -868,7 +859,9 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 868 | try emit.writeInstruction(Instruction.adrp(reg.toX(), 0)); | 859 | try emit.writeInstruction(Instruction.adrp(reg.toX(), 0)); |
| 869 | 860 | ||
| 870 | switch (tag) { | 861 | switch (tag) { |
| 871 | .load_memory_got => { | 862 | .load_memory_got, |
| 863 | .load_memory_import, | ||
| 864 | => { | ||
| 872 | // ldr reg, reg, offset | 865 | // ldr reg, reg, offset |
| 873 | try emit.writeInstruction(Instruction.ldr( | 866 | try emit.writeInstruction(Instruction.ldr( |
| 874 | reg, | 867 | reg, |
| ... | @@ -941,8 +934,17 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -941,8 +934,17 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 941 | }); | 934 | }); |
| 942 | } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { | 935 | } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { |
| 943 | const atom = coff_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; | 936 | const atom = coff_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; |
| 937 | const target = switch (tag) { | ||
| 938 | .load_memory_got, | ||
| 939 | .load_memory_ptr_got, | ||
| 940 | .load_memory_direct, | ||
| 941 | .load_memory_ptr_direct, | ||
| 942 | => link.File.Coff.SymbolWithLoc{ .sym_index = data.sym_index, .file = null }, | ||
| 943 | .load_memory_import => coff_file.getGlobalByIndex(data.sym_index), | ||
| 944 | else => unreachable, | ||
| 945 | }; | ||
| 944 | try atom.addRelocation(coff_file, .{ | 946 | try atom.addRelocation(coff_file, .{ |
| 945 | .target = .{ .sym_index = data.sym_index, .file = null }, | 947 | .target = target, |
| 946 | .offset = offset, | 948 | .offset = offset, |
| 947 | .addend = 0, | 949 | .addend = 0, |
| 948 | .pcrel = true, | 950 | .pcrel = true, |
| ... | @@ -954,11 +956,12 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -954,11 +956,12 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 954 | .load_memory_direct, | 956 | .load_memory_direct, |
| 955 | .load_memory_ptr_direct, | 957 | .load_memory_ptr_direct, |
| 956 | => .page, | 958 | => .page, |
| 959 | .load_memory_import => .import_page, | ||
| 957 | else => unreachable, | 960 | else => unreachable, |
| 958 | }, | 961 | }, |
| 959 | }); | 962 | }); |
| 960 | try atom.addRelocation(coff_file, .{ | 963 | try atom.addRelocation(coff_file, .{ |
| 961 | .target = .{ .sym_index = data.sym_index, .file = null }, | 964 | .target = target, |
| 962 | .offset = offset + 4, | 965 | .offset = offset + 4, |
| 963 | .addend = 0, | 966 | .addend = 0, |
| 964 | .pcrel = false, | 967 | .pcrel = false, |
| ... | @@ -970,6 +973,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -970,6 +973,7 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 970 | .load_memory_direct, | 973 | .load_memory_direct, |
| 971 | .load_memory_ptr_direct, | 974 | .load_memory_ptr_direct, |
| 972 | => .pageoff, | 975 | => .pageoff, |
| 976 | .load_memory_import => .import_pageoff, | ||
| 973 | else => unreachable, | 977 | else => unreachable, |
| 974 | }, | 978 | }, |
| 975 | }); | 979 | }); |
src/arch/aarch64/Mir.zig+4| ... | @@ -84,6 +84,10 @@ pub const Inst = struct { | ... | @@ -84,6 +84,10 @@ pub const Inst = struct { |
| 84 | /// | 84 | /// |
| 85 | /// Payload is `LoadMemoryPie` | 85 | /// Payload is `LoadMemoryPie` |
| 86 | load_memory_direct, | 86 | load_memory_direct, |
| 87 | /// Loads the contents into a register | ||
| 88 | /// | ||
| 89 | /// Payload is `LoadMemoryPie` | ||
| 90 | load_memory_import, | ||
| 87 | /// Loads the address into a register | 91 | /// Loads the address into a register |
| 88 | /// | 92 | /// |
| 89 | /// Payload is `LoadMemoryPie` | 93 | /// Payload is `LoadMemoryPie` |
src/link/Coff.zig+111-81| ... | @@ -128,18 +128,28 @@ const Entry = struct { | ... | @@ -128,18 +128,28 @@ const Entry = struct { |
| 128 | pub const Reloc = struct { | 128 | pub const Reloc = struct { |
| 129 | @"type": enum { | 129 | @"type": enum { |
| 130 | // x86, x86_64 | 130 | // x86, x86_64 |
| 131 | /// RIP-relative displacement to a GOT pointer | ||
| 131 | got, | 132 | got, |
| 133 | /// RIP-relative displacement to an import pointer | ||
| 134 | import, | ||
| 132 | 135 | ||
| 133 | // aarch64 | 136 | // aarch64 |
| 134 | branch_26, | 137 | /// PC-relative distance to target page in GOT section |
| 135 | got_page, | 138 | got_page, |
| 139 | /// Offset to a GOT pointer relative to the start of a page in GOT section | ||
| 136 | got_pageoff, | 140 | got_pageoff, |
| 141 | /// PC-relative distance to target page in a section (e.g., .rdata) | ||
| 137 | page, | 142 | page, |
| 143 | /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata) | ||
| 138 | pageoff, | 144 | pageoff, |
| 145 | /// PC-relative distance to target page in a import section | ||
| 146 | import_page, | ||
| 147 | /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata) | ||
| 148 | import_pageoff, | ||
| 139 | 149 | ||
| 140 | // common | 150 | // common |
| 141 | import, | 151 | /// Absolute pointer value |
| 142 | direct, // as unsigned, TODO split into signed for x86 | 152 | direct, |
| 143 | }, | 153 | }, |
| 144 | target: SymbolWithLoc, | 154 | target: SymbolWithLoc, |
| 145 | offset: u32, | 155 | offset: u32, |
| ... | @@ -157,12 +167,14 @@ pub const Reloc = struct { | ... | @@ -157,12 +167,14 @@ pub const Reloc = struct { |
| 157 | => return coff_file.getGotAtomForSymbol(self.target), | 167 | => return coff_file.getGotAtomForSymbol(self.target), |
| 158 | 168 | ||
| 159 | .direct, | 169 | .direct, |
| 160 | .branch_26, | ||
| 161 | .page, | 170 | .page, |
| 162 | .pageoff, | 171 | .pageoff, |
| 163 | => return coff_file.getAtomForSymbol(self.target), | 172 | => return coff_file.getAtomForSymbol(self.target), |
| 164 | 173 | ||
| 165 | .import => return coff_file.getImportAtomForSymbol(self.target), | 174 | .import, |
| 175 | .import_page, | ||
| 176 | .import_pageoff, | ||
| 177 | => return coff_file.getImportAtomForSymbol(self.target), | ||
| 166 | } | 178 | } |
| 167 | } | 179 | } |
| 168 | }; | 180 | }; |
| ... | @@ -172,8 +184,6 @@ const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanag | ... | @@ -172,8 +184,6 @@ const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanag |
| 172 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); | 184 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 173 | 185 | ||
| 174 | const default_file_alignment: u16 = 0x200; | 186 | const default_file_alignment: u16 = 0x200; |
| 175 | const default_image_base_dll: u64 = 0x10000000; | ||
| 176 | const default_image_base_exe: u64 = 0x400000; | ||
| 177 | const default_size_of_stack_reserve: u32 = 0x1000000; | 187 | const default_size_of_stack_reserve: u32 = 0x1000000; |
| 178 | const default_size_of_stack_commit: u32 = 0x1000; | 188 | const default_size_of_stack_commit: u32 = 0x1000; |
| 179 | const default_size_of_heap_reserve: u32 = 0x100000; | 189 | const default_size_of_heap_reserve: u32 = 0x100000; |
| ... | @@ -891,6 +901,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -891,6 +901,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 891 | const target_atom = reloc.getTargetAtom(self) orelse continue; | 901 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 892 | const target_vaddr = target_atom.getSymbol(self).value; | 902 | const target_vaddr = target_atom.getSymbol(self).value; |
| 893 | const target_vaddr_with_addend = target_vaddr + reloc.addend; | 903 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 904 | const image_base = self.getImageBase(); | ||
| 894 | 905 | ||
| 895 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ | 906 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ |
| 896 | source_vaddr, | 907 | source_vaddr, |
| ... | @@ -902,31 +913,23 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -902,31 +913,23 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 902 | 913 | ||
| 903 | reloc.dirty = false; | 914 | reloc.dirty = false; |
| 904 | 915 | ||
| 905 | var buffer: [@sizeOf(u32)]u8 = undefined; | 916 | switch (self.base.options.target.cpu.arch) { |
| 906 | switch (reloc.@"type") { | 917 | .aarch64 => { |
| 907 | .branch_26, | 918 | var buffer: [@sizeOf(u64)]u8 = undefined; |
| 908 | .got_page, | 919 | switch (reloc.length) { |
| 909 | .got_pageoff, | 920 | 2 => { |
| 910 | .page, | 921 | const amt = try self.base.file.?.preadAll(buffer[0..4], file_offset + reloc.offset); |
| 911 | .pageoff, | 922 | if (amt != 4) return error.InputOutput; |
| 912 | => { | 923 | }, |
| 913 | const amt = try self.base.file.?.preadAll(&buffer, file_offset + reloc.offset); | 924 | 3 => { |
| 914 | if (amt != buffer.len) return error.InputOutput; | 925 | const amt = try self.base.file.?.preadAll(&buffer, file_offset + reloc.offset); |
| 926 | if (amt != 8) return error.InputOutput; | ||
| 927 | }, | ||
| 928 | else => unreachable, | ||
| 929 | } | ||
| 915 | 930 | ||
| 916 | switch (reloc.@"type") { | 931 | switch (reloc.@"type") { |
| 917 | .branch_26 => { | 932 | .got_page, .import_page, .page => { |
| 918 | const displacement = math.cast(i28, @intCast(i64, target_vaddr_with_addend) - @intCast(i64, source_vaddr)) orelse | ||
| 919 | unreachable; // TODO generate thunks | ||
| 920 | var inst = aarch64.Instruction{ | ||
| 921 | .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload( | ||
| 922 | aarch64.Instruction, | ||
| 923 | aarch64.Instruction.unconditional_branch_immediate, | ||
| 924 | ), &buffer), | ||
| 925 | }; | ||
| 926 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); | ||
| 927 | mem.writeIntLittle(u32, &buffer, inst.toU32()); | ||
| 928 | }, | ||
| 929 | .got_page, .page => { | ||
| 930 | const source_page = @intCast(i32, source_vaddr >> 12); | 933 | const source_page = @intCast(i32, source_vaddr >> 12); |
| 931 | const target_page = @intCast(i32, target_vaddr_with_addend >> 12); | 934 | const target_page = @intCast(i32, target_vaddr_with_addend >> 12); |
| 932 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | 935 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); |
| ... | @@ -934,31 +937,31 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -934,31 +937,31 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 934 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( | 937 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( |
| 935 | aarch64.Instruction, | 938 | aarch64.Instruction, |
| 936 | aarch64.Instruction.pc_relative_address, | 939 | aarch64.Instruction.pc_relative_address, |
| 937 | ), &buffer), | 940 | ), buffer[0..4]), |
| 938 | }; | 941 | }; |
| 939 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | 942 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 940 | inst.pc_relative_address.immlo = @truncate(u2, pages); | 943 | inst.pc_relative_address.immlo = @truncate(u2, pages); |
| 941 | mem.writeIntLittle(u32, &buffer, inst.toU32()); | 944 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); |
| 942 | }, | 945 | }, |
| 943 | .got_pageoff, .pageoff => { | 946 | .got_pageoff, .import_pageoff, .pageoff => { |
| 944 | assert(!reloc.pcrel); | 947 | assert(!reloc.pcrel); |
| 945 | 948 | ||
| 946 | const narrowed = @truncate(u12, @intCast(u64, target_vaddr_with_addend)); | 949 | const narrowed = @truncate(u12, @intCast(u64, target_vaddr_with_addend)); |
| 947 | if (isArithmeticOp(&buffer)) { | 950 | if (isArithmeticOp(buffer[0..4])) { |
| 948 | var inst = aarch64.Instruction{ | 951 | var inst = aarch64.Instruction{ |
| 949 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( | 952 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( |
| 950 | aarch64.Instruction, | 953 | aarch64.Instruction, |
| 951 | aarch64.Instruction.add_subtract_immediate, | 954 | aarch64.Instruction.add_subtract_immediate, |
| 952 | ), &buffer), | 955 | ), buffer[0..4]), |
| 953 | }; | 956 | }; |
| 954 | inst.add_subtract_immediate.imm12 = narrowed; | 957 | inst.add_subtract_immediate.imm12 = narrowed; |
| 955 | mem.writeIntLittle(u32, &buffer, inst.toU32()); | 958 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); |
| 956 | } else { | 959 | } else { |
| 957 | var inst = aarch64.Instruction{ | 960 | var inst = aarch64.Instruction{ |
| 958 | .load_store_register = mem.bytesToValue(meta.TagPayload( | 961 | .load_store_register = mem.bytesToValue(meta.TagPayload( |
| 959 | aarch64.Instruction, | 962 | aarch64.Instruction, |
| 960 | aarch64.Instruction.load_store_register, | 963 | aarch64.Instruction.load_store_register, |
| 961 | ), &buffer), | 964 | ), buffer[0..4]), |
| 962 | }; | 965 | }; |
| 963 | const offset: u12 = blk: { | 966 | const offset: u12 = blk: { |
| 964 | if (inst.load_store_register.size == 0) { | 967 | if (inst.load_store_register.size == 0) { |
| ... | @@ -974,55 +977,73 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { | ... | @@ -974,55 +977,73 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 974 | } | 977 | } |
| 975 | }; | 978 | }; |
| 976 | inst.load_store_register.offset = offset; | 979 | inst.load_store_register.offset = offset; |
| 977 | mem.writeIntLittle(u32, &buffer, inst.toU32()); | 980 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); |
| 981 | } | ||
| 982 | }, | ||
| 983 | .direct => { | ||
| 984 | assert(!reloc.pcrel); | ||
| 985 | switch (reloc.length) { | ||
| 986 | 2 => mem.writeIntLittle( | ||
| 987 | u32, | ||
| 988 | buffer[0..4], | ||
| 989 | @truncate(u32, target_vaddr_with_addend + image_base), | ||
| 990 | ), | ||
| 991 | 3 => mem.writeIntLittle(u64, &buffer, target_vaddr_with_addend + image_base), | ||
| 992 | else => unreachable, | ||
| 978 | } | 993 | } |
| 979 | }, | 994 | }, |
| 980 | 995 | ||
| 981 | else => unreachable, | 996 | .got => unreachable, |
| 997 | .import => unreachable, | ||
| 982 | } | 998 | } |
| 983 | 999 | ||
| 984 | try self.base.file.?.pwriteAll(&buffer, file_offset + reloc.offset); | 1000 | switch (reloc.length) { |
| 985 | 1001 | 2 => try self.base.file.?.pwriteAll(buffer[0..4], file_offset + reloc.offset), | |
| 986 | return; | 1002 | 3 => try self.base.file.?.pwriteAll(&buffer, file_offset + reloc.offset), |
| 1003 | else => unreachable, | ||
| 1004 | } | ||
| 987 | }, | 1005 | }, |
| 988 | 1006 | ||
| 989 | else => {}, | 1007 | .x86_64, .i386 => { |
| 990 | } | 1008 | switch (reloc.@"type") { |
| 991 | 1009 | .got_page => unreachable, | |
| 992 | switch (reloc.@"type") { | 1010 | .got_pageoff => unreachable, |
| 993 | .branch_26 => unreachable, | 1011 | .page => unreachable, |
| 994 | .got_page => unreachable, | 1012 | .pageoff => unreachable, |
| 995 | .got_pageoff => unreachable, | 1013 | .import_page => unreachable, |
| 996 | .page => unreachable, | 1014 | .import_pageoff => unreachable, |
| 997 | .pageoff => unreachable, | 1015 | |
| 998 | 1016 | .got, .import => { | |
| 999 | .got, .import => { | 1017 | assert(reloc.pcrel); |
| 1000 | assert(reloc.pcrel); | 1018 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 1001 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; | 1019 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); |
| 1002 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); | 1020 | }, |
| 1003 | }, | 1021 | .direct => { |
| 1004 | .direct => { | 1022 | if (reloc.pcrel) { |
| 1005 | if (reloc.pcrel) { | 1023 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 1006 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; | 1024 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); |
| 1007 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); | 1025 | } else switch (self.ptr_width) { |
| 1008 | } else switch (self.ptr_width) { | 1026 | .p32 => try self.base.file.?.pwriteAll( |
| 1009 | .p32 => try self.base.file.?.pwriteAll( | 1027 | mem.asBytes(&@intCast(u32, target_vaddr_with_addend + image_base)), |
| 1010 | mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)), | 1028 | file_offset + reloc.offset, |
| 1011 | file_offset + reloc.offset, | 1029 | ), |
| 1012 | ), | 1030 | .p64 => switch (reloc.length) { |
| 1013 | .p64 => switch (reloc.length) { | 1031 | 2 => try self.base.file.?.pwriteAll( |
| 1014 | 2 => try self.base.file.?.pwriteAll( | 1032 | mem.asBytes(&@truncate(u32, target_vaddr_with_addend + image_base)), |
| 1015 | mem.asBytes(&@truncate(u32, target_vaddr_with_addend + default_image_base_exe)), | 1033 | file_offset + reloc.offset, |
| 1016 | file_offset + reloc.offset, | 1034 | ), |
| 1017 | ), | 1035 | 3 => try self.base.file.?.pwriteAll( |
| 1018 | 3 => try self.base.file.?.pwriteAll( | 1036 | mem.asBytes(&(target_vaddr_with_addend + image_base)), |
| 1019 | mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)), | 1037 | file_offset + reloc.offset, |
| 1020 | file_offset + reloc.offset, | 1038 | ), |
| 1021 | ), | 1039 | else => unreachable, |
| 1022 | else => unreachable, | 1040 | }, |
| 1041 | } | ||
| 1023 | }, | 1042 | }, |
| 1024 | } | 1043 | } |
| 1025 | }, | 1044 | }, |
| 1045 | |||
| 1046 | else => unreachable, // unhandled target architecture | ||
| 1026 | } | 1047 | } |
| 1027 | } | 1048 | } |
| 1028 | } | 1049 | } |
| ... | @@ -1950,11 +1971,7 @@ fn writeHeader(self: *Coff) !void { | ... | @@ -1950,11 +1971,7 @@ fn writeHeader(self: *Coff) !void { |
| 1950 | const subsystem: coff.Subsystem = .WINDOWS_CUI; | 1971 | const subsystem: coff.Subsystem = .WINDOWS_CUI; |
| 1951 | const size_of_image: u32 = self.getSizeOfImage(); | 1972 | const size_of_image: u32 = self.getSizeOfImage(); |
| 1952 | const size_of_headers: u32 = mem.alignForwardGeneric(u32, self.getSizeOfHeaders(), default_file_alignment); | 1973 | const size_of_headers: u32 = mem.alignForwardGeneric(u32, self.getSizeOfHeaders(), default_file_alignment); |
| 1953 | const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) { | 1974 | const image_base = self.getImageBase(); |
| 1954 | .Exe => default_image_base_exe, | ||
| 1955 | .Lib => default_image_base_dll, | ||
| 1956 | else => unreachable, | ||
| 1957 | }; | ||
| 1958 | 1975 | ||
| 1959 | const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address; | 1976 | const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address; |
| 1960 | const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address; | 1977 | const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address; |
| ... | @@ -2161,6 +2178,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { | ... | @@ -2161,6 +2178,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc { |
| 2161 | return self.globals.items[global_index]; | 2178 | return self.globals.items[global_index]; |
| 2162 | } | 2179 | } |
| 2163 | 2180 | ||
| 2181 | pub fn getImageBase(self: Coff) u64 { | ||
| 2182 | const image_base: u64 = self.base.options.image_base_override orelse switch (self.base.options.output_mode) { | ||
| 2183 | .Exe => switch (self.base.options.target.cpu.arch) { | ||
| 2184 | .aarch64 => 0x140000000, | ||
| 2185 | .x86_64, .i386 => 0x400000, | ||
| 2186 | else => unreachable, // unsupported target architecture | ||
| 2187 | }, | ||
| 2188 | .Lib => 0x10000000, | ||
| 2189 | else => unreachable, | ||
| 2190 | }; | ||
| 2191 | return image_base; | ||
| 2192 | } | ||
| 2193 | |||
| 2164 | /// Returns pointer-to-symbol described by `sym_loc` descriptor. | 2194 | /// Returns pointer-to-symbol described by `sym_loc` descriptor. |
| 2165 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { | 2195 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 2166 | assert(sym_loc.file == null); // TODO linking object files | 2196 | assert(sym_loc.file == null); // TODO linking object files |