authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-13 22:54:55+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-13 22:54:55+02:00
log5e19250a1251e7857b5679949085fa1fb3f9bdcd
tree0aae5737ccb62456fcb4b099a07ff015a82c1989
parent25e3851fe0f7fe254b48c2242ab8d4ef89165fd5
parenta34752c941c81e600c56670abb612fc86d0a2b73
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15185 from ziglang/macho-tls

macho: add TLS support

18 files changed, 878 insertions(+), 530 deletions(-)

ci/x86_64-macos-debug.sh-1
...@@ -51,7 +51,6 @@ stage3/bin/zig build test docs \...@@ -51,7 +51,6 @@ stage3/bin/zig build test docs \
51 --zig-lib-dir "$(pwd)/../lib" \51 --zig-lib-dir "$(pwd)/../lib" \
52 -Denable-macos-sdk \52 -Denable-macos-sdk \
53 -Dstatic-llvm \53 -Dstatic-llvm \
54 -Dskip-non-native \
55 --search-prefix "$PREFIX"54 --search-prefix "$PREFIX"
5655
57# Produce the experimental std lib documentation.56# Produce the experimental std lib documentation.
ci/x86_64-macos-release.sh-1
...@@ -51,7 +51,6 @@ stage3/bin/zig build test docs \...@@ -51,7 +51,6 @@ stage3/bin/zig build test docs \
51 --zig-lib-dir "$(pwd)/../lib" \51 --zig-lib-dir "$(pwd)/../lib" \
52 -Denable-macos-sdk \52 -Denable-macos-sdk \
53 -Dstatic-llvm \53 -Dstatic-llvm \
54 -Dskip-non-native \
55 --search-prefix "$PREFIX"54 --search-prefix "$PREFIX"
5655
57# Produce the experimental std lib documentation.56# Produce the experimental std lib documentation.
src/arch/aarch64/CodeGen.zig+1
...@@ -6171,6 +6171,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {...@@ -6171,6 +6171,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
6171 .linker_load => |ll| .{ .linker_load = ll },6171 .linker_load => |ll| .{ .linker_load = ll },
6172 .immediate => |imm| .{ .immediate = imm },6172 .immediate => |imm| .{ .immediate = imm },
6173 .memory => |addr| .{ .memory = addr },6173 .memory => |addr| .{ .memory = addr },
6174 .tlv_reloc => unreachable, // TODO
6174 },6175 },
6175 .fail => |msg| {6176 .fail => |msg| {
6176 self.err_msg = msg;6177 self.err_msg = msg;
src/arch/aarch64/Emit.zig+10-19
...@@ -673,7 +673,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -673,7 +673,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
673 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;673 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
674 const target = macho_file.getGlobalByIndex(relocation.sym_index);674 const target = macho_file.getGlobalByIndex(relocation.sym_index);
675 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{675 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
676 .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),676 .type = .branch,
677 .target = target,677 .target = target,
678 .offset = offset,678 .offset = offset,
679 .addend = 0,679 .addend = 0,
...@@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
883 }883 }
884884
885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
886 const Atom = link.File.MachO.Atom;
887 const Relocation = Atom.Relocation;
886 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;888 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
887 // TODO this causes segfault in stage1889 try Atom.addRelocations(macho_file, atom_index, &[_]Relocation{ .{
888 // try atom.addRelocations(macho_file, 2, .{
889 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
890 .target = .{ .sym_index = data.sym_index, .file = null },890 .target = .{ .sym_index = data.sym_index, .file = null },
891 .offset = offset,891 .offset = offset,
892 .addend = 0,892 .addend = 0,
893 .pcrel = true,893 .pcrel = true,
894 .length = 2,894 .length = 2,
895 .type = switch (tag) {895 .type = switch (tag) {
896 .load_memory_got,896 .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_page,
897 .load_memory_ptr_got,897 .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.page,
898 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
899 .load_memory_direct,
900 .load_memory_ptr_direct,
901 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
902 else => unreachable,898 else => unreachable,
903 },899 },
904 });900 }, .{
905 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
906 .target = .{ .sym_index = data.sym_index, .file = null },901 .target = .{ .sym_index = data.sym_index, .file = null },
907 .offset = offset + 4,902 .offset = offset + 4,
908 .addend = 0,903 .addend = 0,
909 .pcrel = false,904 .pcrel = false,
910 .length = 2,905 .length = 2,
911 .type = switch (tag) {906 .type = switch (tag) {
912 .load_memory_got,907 .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_pageoff,
913 .load_memory_ptr_got,908 .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.pageoff,
914 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),
915 .load_memory_direct,
916 .load_memory_ptr_direct,
917 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),
918 else => unreachable,909 else => unreachable,
919 },910 },
920 });911 } });
921 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {912 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
922 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;913 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
923 const target = switch (tag) {914 const target = switch (tag) {
src/arch/arm/CodeGen.zig+1-1
...@@ -6114,7 +6114,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {...@@ -6114,7 +6114,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
6114 .mcv => |mcv| switch (mcv) {6114 .mcv => |mcv| switch (mcv) {
6115 .none => .none,6115 .none => .none,
6116 .undef => .undef,6116 .undef => .undef,
6117 .linker_load => unreachable, // TODO6117 .tlv_reloc, .linker_load => unreachable, // TODO
6118 .immediate => |imm| .{ .immediate = @truncate(u32, imm) },6118 .immediate => |imm| .{ .immediate = @truncate(u32, imm) },
6119 .memory => |addr| .{ .memory = addr },6119 .memory => |addr| .{ .memory = addr },
6120 },6120 },
src/arch/riscv64/CodeGen.zig+1-1
...@@ -2572,7 +2572,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2572,7 +2572,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2572 .mcv => |mcv| switch (mcv) {2572 .mcv => |mcv| switch (mcv) {
2573 .none => .none,2573 .none => .none,
2574 .undef => .undef,2574 .undef => .undef,
2575 .linker_load => unreachable, // TODO2575 .tlv_reloc, .linker_load => unreachable, // TODO
2576 .immediate => |imm| .{ .immediate = imm },2576 .immediate => |imm| .{ .immediate = imm },
2577 .memory => |addr| .{ .memory = addr },2577 .memory => |addr| .{ .memory = addr },
2578 },2578 },
src/arch/sparc64/CodeGen.zig+1-1
...@@ -3931,7 +3931,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3931,7 +3931,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3931 .mcv => |mcv| switch (mcv) {3931 .mcv => |mcv| switch (mcv) {
3932 .none => .none,3932 .none => .none,
3933 .undef => .undef,3933 .undef => .undef,
3934 .linker_load => unreachable, // TODO3934 .tlv_reloc, .linker_load => unreachable, // TODO
3935 .immediate => |imm| .{ .immediate = imm },3935 .immediate => |imm| .{ .immediate = imm },
3936 .memory => |addr| .{ .memory = addr },3936 .memory => |addr| .{ .memory = addr },
3937 },3937 },
src/arch/x86_64/CodeGen.zig+406-94
...@@ -132,6 +132,10 @@ pub const MCValue = union(enum) {...@@ -132,6 +132,10 @@ pub const MCValue = union(enum) {
132 memory: u64,132 memory: u64,
133 /// The value is in memory but requires a linker relocation fixup.133 /// The value is in memory but requires a linker relocation fixup.
134 linker_load: codegen.LinkerLoad,134 linker_load: codegen.LinkerLoad,
135 /// Pointer to a threadlocal variable.
136 /// The address resolution will be deferred until the linker allocates everything in virtual memory.
137 /// Payload is a symbol index.
138 tlv_reloc: u32,
135 /// The value is one of the stack variables.139 /// The value is one of the stack variables.
136 /// If the type is a pointer, it means the pointer address is in the stack at this offset.140 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
137 stack_offset: i32,141 stack_offset: i32,
...@@ -146,6 +150,7 @@ pub const MCValue = union(enum) {...@@ -146,6 +150,7 @@ pub const MCValue = union(enum) {
146 .stack_offset,150 .stack_offset,
147 .ptr_stack_offset,151 .ptr_stack_offset,
148 .linker_load,152 .linker_load,
153 .tlv_reloc,
149 => true,154 => true,
150 else => false,155 else => false,
151 };156 };
...@@ -731,6 +736,40 @@ fn asmMemoryRegisterImmediate(...@@ -731,6 +736,40 @@ fn asmMemoryRegisterImmediate(
731 });736 });
732}737}
733738
739fn asmMovLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codegen.LinkerLoad) !void {
740 const ops: Mir.Inst.Ops = switch (linker_load.type) {
741 .got => .got_reloc,
742 .direct => .direct_reloc,
743 .import => .import_reloc,
744 };
745 _ = try self.addInst(.{
746 .tag = .mov_linker,
747 .ops = ops,
748 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
749 .reg = @enumToInt(reg),
750 .atom_index = atom_index,
751 .sym_index = linker_load.sym_index,
752 }) },
753 });
754}
755
756fn asmLeaLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codegen.LinkerLoad) !void {
757 const ops: Mir.Inst.Ops = switch (linker_load.type) {
758 .got => .got_reloc,
759 .direct => .direct_reloc,
760 .import => .import_reloc,
761 };
762 _ = try self.addInst(.{
763 .tag = .lea_linker,
764 .ops = ops,
765 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
766 .reg = @enumToInt(reg),
767 .atom_index = atom_index,
768 .sym_index = linker_load.sym_index,
769 }) },
770 });
771}
772
734fn gen(self: *Self) InnerError!void {773fn gen(self: *Self) InnerError!void {
735 const cc = self.fn_type.fnCallingConvention();774 const cc = self.fn_type.fnCallingConvention();
736 if (cc != .Naked) {775 if (cc != .Naked) {
...@@ -2863,7 +2902,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2863,7 +2902,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2863 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2902 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2864 defer self.register_manager.unlockReg(offset_reg_lock);2903 defer self.register_manager.unlockReg(offset_reg_lock);
28652904
2866 const addr_reg = try self.register_manager.allocReg(null, gp);2905 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
2867 switch (array) {2906 switch (array) {
2868 .register => {2907 .register => {
2869 const off = @intCast(i32, try self.allocMem(2908 const off = @intCast(i32, try self.allocMem(
...@@ -2872,19 +2911,33 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2872,19 +2911,33 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2872 array_ty.abiAlignment(self.target.*),2911 array_ty.abiAlignment(self.target.*),
2873 ));2912 ));
2874 try self.genSetStack(array_ty, off, array, .{});2913 try self.genSetStack(array_ty, off, array, .{});
2875 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{2914 try self.asmRegisterMemory(.lea, addr_reg, Memory.sib(.qword, .{
2876 .base = .rbp,2915 .base = .rbp,
2877 .disp = -off,2916 .disp = -off,
2878 }));2917 }));
2879 },2918 },
2880 .stack_offset => |off| {2919 .stack_offset => |off| {
2881 try self.asmRegisterMemory(.lea, addr_reg.to64(), Memory.sib(.qword, .{2920 try self.asmRegisterMemory(.lea, addr_reg, Memory.sib(.qword, .{
2882 .base = .rbp,2921 .base = .rbp,
2883 .disp = -off,2922 .disp = -off,
2884 }));2923 }));
2885 },2924 },
2886 .memory, .linker_load => {2925 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
2887 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);2926 .tlv_reloc => try self.genSetReg(array_ty, addr_reg, array),
2927 .linker_load => |load_struct| {
2928 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
2929 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2930 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
2931 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
2932 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
2933 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
2934 } else unreachable;
2935
2936 switch (load_struct.type) {
2937 .import => unreachable,
2938 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
2939 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
2940 }
2888 },2941 },
2889 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),2942 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
2890 }2943 }
...@@ -3597,10 +3650,30 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -3597,10 +3650,30 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
3597 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),3650 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
3598 }3651 }
3599 },3652 },
3600 .memory, .linker_load => {3653 .memory, .tlv_reloc => {
3601 const reg = try self.copyToTmpRegister(ptr_ty, ptr);3654 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
3602 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);3655 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
3603 },3656 },
3657 .linker_load => |load_struct| {
3658 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
3659 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3660 defer self.register_manager.unlockReg(addr_reg_lock);
3661
3662 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
3663 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3664 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
3665 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3666 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3667 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
3668 } else unreachable;
3669
3670 switch (load_struct.type) {
3671 .import => unreachable,
3672 .got, .direct => try self.asmMovLinker(addr_reg, atom_index, load_struct),
3673 }
3674
3675 try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty);
3676 },
3604 }3677 }
3605}3678}
36063679
...@@ -3630,41 +3703,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3630,41 +3703,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
3630 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3703 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3631}3704}
36323705
3633fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue) InnerError!void {
3634 switch (ptr) {
3635 .linker_load => |load_struct| {
3636 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
3637 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
3638 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3639 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
3640 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3641 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3642 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
3643 } else unreachable;
3644 const ops: Mir.Inst.Ops = switch (load_struct.type) {
3645 .got => .got_reloc,
3646 .direct => .direct_reloc,
3647 .import => .import_reloc,
3648 };
3649 _ = try self.addInst(.{
3650 .tag = .lea_linker,
3651 .ops = ops,
3652 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
3653 .reg = @enumToInt(registerAlias(reg, abi_size)),
3654 .atom_index = atom_index,
3655 .sym_index = load_struct.sym_index,
3656 }) },
3657 });
3658 },
3659 .memory => |addr| {
3660 // TODO: in case the address fits in an imm32 we can use [ds:imm32]
3661 // instead of wasting an instruction copying the address to a register
3662 try self.genSetReg(ptr_ty, reg, .{ .immediate = addr });
3663 },
3664 else => unreachable,
3665 }
3666}
3667
3668fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {3706fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
3669 const abi_size = @intCast(u32, value_ty.abiSize(self.target.*));3707 const abi_size = @intCast(u32, value_ty.abiSize(self.target.*));
3670 switch (ptr) {3708 switch (ptr) {
...@@ -3775,11 +3813,29 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3775,11 +3813,29 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37753813
3776 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);3814 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
3777 } else {3815 } else {
3778 const addr_reg = try self.register_manager.allocReg(null, gp);3816 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
3779 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);3817 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3780 defer self.register_manager.unlockReg(addr_lock);3818 defer self.register_manager.unlockReg(addr_lock);
37813819
3782 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, value);3820 switch (value) {
3821 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
3822 .linker_load => |load_struct| {
3823 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
3824 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3825 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
3826 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3827 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3828 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
3829 } else unreachable;
3830 switch (load_struct.type) {
3831 .import => unreachable,
3832 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
3833 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
3834 }
3835 },
3836 else => unreachable,
3837 }
3838
3783 try self.genInlineMemcpy(3839 try self.genInlineMemcpy(
3784 ptr,3840 ptr,
3785 .{ .register = addr_reg },3841 .{ .register = addr_reg },
...@@ -3799,7 +3855,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3799,7 +3855,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3799 .{ .immediate = abi_size },3855 .{ .immediate = abi_size },
3800 .{},3856 .{},
3801 ),3857 ),
3802 .ptr_stack_offset => {3858 .ptr_stack_offset, .tlv_reloc => {
3803 const tmp_reg = try self.copyToTmpRegister(value_ty, value);3859 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
3804 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);3860 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
3805 defer self.register_manager.unlockReg(tmp_lock);3861 defer self.register_manager.unlockReg(tmp_lock);
...@@ -3815,19 +3871,41 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3815,19 +3871,41 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3815 };3871 };
3816 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);3872 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
38173873
3818 const addr_reg = try self.register_manager.allocReg(null, gp);3874 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
3819 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);3875 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3820 defer self.register_manager.unlockReg(addr_reg_lock);3876 defer self.register_manager.unlockReg(addr_reg_lock);
38213877
3822 try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr);3878 switch (ptr) {
3823 // Load the pointer, which is stored in memory3879 .memory => |addr| {
3824 try self.asmRegisterMemory(3880 try self.genSetReg(ptr_ty, addr_reg, .{ .immediate = addr });
3825 .mov,3881 // Load the pointer, which is stored in memory
3826 addr_reg.to64(),3882 try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ .base = addr_reg }));
3827 Memory.sib(.qword, .{ .base = addr_reg.to64() }),3883 },
3828 );3884 .linker_load => |load_struct| {
3885 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
3886 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3887 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
3888 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3889 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
3890 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
3891 } else unreachable;
3892 switch (load_struct.type) {
3893 .import => unreachable,
3894 .got, .direct => try self.asmMovLinker(addr_reg, atom_index, load_struct),
3895 }
3896 },
3897 else => unreachable,
3898 }
38293899
3830 const new_ptr = MCValue{ .register = addr_reg.to64() };3900 const new_ptr = MCValue{ .register = addr_reg };
3901 try self.store(new_ptr, value, ptr_ty, value_ty);
3902 },
3903 .tlv_reloc => {
3904 const addr_reg = try self.copyToTmpRegister(Type.usize, ptr);
3905 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3906 defer self.register_manager.unlockReg(addr_reg_lock);
3907
3908 const new_ptr = MCValue{ .register = addr_reg };
3831 try self.store(new_ptr, value, ptr_ty, value_ty);3909 try self.store(new_ptr, value, ptr_ty, value_ty);
3832 },3910 },
3833 }3911 }
...@@ -3875,7 +3953,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32...@@ -3875,7 +3953,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
38753953
3876 const dst_mcv: MCValue = result: {3954 const dst_mcv: MCValue = result: {
3877 switch (mcv) {3955 switch (mcv) {
3878 .stack_offset => {3956 .stack_offset, .tlv_reloc => {
3879 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{3957 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
3880 .immediate = field_offset,3958 .immediate = field_offset,
3881 });3959 });
...@@ -4157,12 +4235,31 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue...@@ -4157,12 +4235,31 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
4157 }));4235 }));
4158 },4236 },
4159 .ptr_stack_offset => unreachable,4237 .ptr_stack_offset => unreachable,
4238 .tlv_reloc => unreachable,
4160 .memory, .linker_load => {4239 .memory, .linker_load => {
4161 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();4240 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4162 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);4241 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4163 defer self.register_manager.unlockReg(addr_reg_lock);4242 defer self.register_manager.unlockReg(addr_reg_lock);
41644243
4165 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);4244 switch (dst_mcv) {
4245 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
4246 .linker_load => |load_struct| {
4247 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
4248 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4249 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
4250 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
4251 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4252 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
4253 } else unreachable;
4254
4255 switch (load_struct.type) {
4256 .import => unreachable,
4257 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
4258 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
4259 }
4260 },
4261 else => unreachable,
4262 }
4166 try self.asmMemory(4263 try self.asmMemory(
4167 mir_tag,4264 mir_tag,
4168 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),4265 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }),
...@@ -4800,6 +4897,7 @@ fn genBinOp(...@@ -4800,6 +4897,7 @@ fn genBinOp(
4800 .eflags,4897 .eflags,
4801 .register_overflow,4898 .register_overflow,
4802 .ptr_stack_offset,4899 .ptr_stack_offset,
4900 .tlv_reloc,
4803 => unreachable,4901 => unreachable,
4804 .register => |src_reg| try self.asmCmovccRegisterRegister(4902 .register => |src_reg| try self.asmCmovccRegisterRegister(
4805 registerAlias(tmp_reg, cmov_abi_size),4903 registerAlias(tmp_reg, cmov_abi_size),
...@@ -4819,7 +4917,26 @@ fn genBinOp(...@@ -4819,7 +4917,26 @@ fn genBinOp(
4819 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);4917 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
4820 defer self.register_manager.unlockReg(addr_reg_lock);4918 defer self.register_manager.unlockReg(addr_reg_lock);
48214919
4822 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv);4920 switch (mat_src_mcv) {
4921 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
4922 .linker_load => |load_struct| {
4923 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
4924 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4925 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
4926 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
4927 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
4928 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
4929 } else unreachable;
4930
4931 switch (load_struct.type) {
4932 .import => unreachable,
4933 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
4934 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
4935 }
4936 },
4937 else => unreachable,
4938 }
4939
4823 try self.asmCmovccRegisterMemory(4940 try self.asmCmovccRegisterMemory(
4824 registerAlias(tmp_reg, cmov_abi_size),4941 registerAlias(tmp_reg, cmov_abi_size),
4825 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{ .base = addr_reg }),4942 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{ .base = addr_reg }),
...@@ -4865,7 +4982,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4865,7 +4982,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4865 .undef => unreachable,4982 .undef => unreachable,
4866 .dead, .unreach => unreachable,4983 .dead, .unreach => unreachable,
4867 .register_overflow => unreachable,4984 .register_overflow => unreachable,
4868 .ptr_stack_offset => {4985 .ptr_stack_offset, .tlv_reloc => {
4869 const dst_reg_lock = self.register_manager.lockReg(dst_reg);4986 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
4870 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);4987 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
48714988
...@@ -4942,11 +5059,30 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4942,11 +5059,30 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4942 } = switch (dst_mcv) {5059 } = switch (dst_mcv) {
4943 else => unreachable,5060 else => unreachable,
4944 .memory, .linker_load => dst: {5061 .memory, .linker_load => dst: {
4945 const dst_addr_reg = try self.register_manager.allocReg(null, gp);5062 const dst_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4946 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);5063 const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
4947 errdefer self.register_manager.unlockReg(dst_addr_lock);5064 errdefer self.register_manager.unlockReg(dst_addr_lock);
49485065
4949 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_mcv);5066 switch (dst_mcv) {
5067 .memory => |addr| try self.genSetReg(Type.usize, dst_addr_reg, .{ .immediate = addr }),
5068 .linker_load => |load_struct| {
5069 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
5070 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5071 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
5072 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
5073 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5074 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5075 } else unreachable;
5076
5077 switch (load_struct.type) {
5078 .import => unreachable,
5079 .got => try self.asmMovLinker(dst_addr_reg, atom_index, load_struct),
5080 .direct => try self.asmLeaLinker(dst_addr_reg, atom_index, load_struct),
5081 }
5082 },
5083 else => unreachable,
5084 }
5085
4950 break :dst .{5086 break :dst .{
4951 .addr_reg = dst_addr_reg,5087 .addr_reg = dst_addr_reg,
4952 .addr_lock = dst_addr_lock,5088 .addr_lock = dst_addr_lock,
...@@ -4968,11 +5104,30 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -4968,11 +5104,30 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
4968 const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg);5104 const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg);
4969 errdefer self.register_manager.unlockReg(src_limb_lock);5105 errdefer self.register_manager.unlockReg(src_limb_lock);
49705106
4971 const src_addr_reg = try self.register_manager.allocReg(null, gp);5107 const src_addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
4972 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);5108 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
4973 errdefer self.register_manager.unlockReg(src_addr_lock);5109 errdefer self.register_manager.unlockReg(src_addr_lock);
49745110
4975 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv);5111 switch (src_mcv) {
5112 .memory => |addr| try self.genSetReg(Type.usize, src_addr_reg, .{ .immediate = addr }),
5113 .linker_load => |load_struct| {
5114 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
5115 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5116 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
5117 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
5118 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
5119 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
5120 } else unreachable;
5121
5122 switch (load_struct.type) {
5123 .import => unreachable,
5124 .got => try self.asmMovLinker(src_addr_reg, atom_index, load_struct),
5125 .direct => try self.asmLeaLinker(src_addr_reg, atom_index, load_struct),
5126 }
5127 },
5128 else => unreachable,
5129 }
5130
4976 break :src .{5131 break :src .{
4977 .addr_reg = src_addr_reg,5132 .addr_reg = src_addr_reg,
4978 .addr_lock = src_addr_lock,5133 .addr_lock = src_addr_lock,
...@@ -5078,7 +5233,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -5078,7 +5233,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
5078 else => unreachable,5233 else => unreachable,
5079 }5234 }
5080 },5235 },
5081 .memory, .linker_load => {5236 .memory, .linker_load, .tlv_reloc => {
5082 try self.asmRegisterMemory(5237 try self.asmRegisterMemory(
5083 .mov,5238 .mov,
5084 registerAlias(src.?.limb_reg, limb_abi_size),5239 registerAlias(src.?.limb_reg, limb_abi_size),
...@@ -5117,6 +5272,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s...@@ -5117,6 +5272,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
5117 }5272 }
5118 },5273 },
5119 .ptr_stack_offset => unreachable,5274 .ptr_stack_offset => unreachable,
5275 .tlv_reloc => unreachable,
5120 }5276 }
5121}5277}
51225278
...@@ -5130,6 +5286,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -5130,6 +5286,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
5130 .dead, .unreach, .immediate => unreachable,5286 .dead, .unreach, .immediate => unreachable,
5131 .eflags => unreachable,5287 .eflags => unreachable,
5132 .ptr_stack_offset => unreachable,5288 .ptr_stack_offset => unreachable,
5289 .tlv_reloc => unreachable,
5133 .register_overflow => unreachable,5290 .register_overflow => unreachable,
5134 .register => |dst_reg| {5291 .register => |dst_reg| {
5135 const dst_alias = registerAlias(dst_reg, abi_size);5292 const dst_alias = registerAlias(dst_reg, abi_size);
...@@ -5141,6 +5298,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -5141,6 +5298,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
5141 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),5298 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
5142 .dead, .unreach => unreachable,5299 .dead, .unreach => unreachable,
5143 .ptr_stack_offset => unreachable,5300 .ptr_stack_offset => unreachable,
5301 .tlv_reloc => unreachable,
5144 .register_overflow => unreachable,5302 .register_overflow => unreachable,
5145 .register => |src_reg| try self.asmRegisterRegister(5303 .register => |src_reg| try self.asmRegisterRegister(
5146 .imul,5304 .imul,
...@@ -5184,6 +5342,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -5184,6 +5342,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
5184 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),5342 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),
5185 .dead, .unreach => unreachable,5343 .dead, .unreach => unreachable,
5186 .ptr_stack_offset => unreachable,5344 .ptr_stack_offset => unreachable,
5345 .tlv_reloc => unreachable,
5187 .register_overflow => unreachable,5346 .register_overflow => unreachable,
5188 .register => |src_reg| {5347 .register => |src_reg| {
5189 // copy dst to a register5348 // copy dst to a register
...@@ -5406,6 +5565,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5406,6 +5565,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5406 .linker_load => unreachable,5565 .linker_load => unreachable,
5407 .eflags => unreachable,5566 .eflags => unreachable,
5408 .register_overflow => unreachable,5567 .register_overflow => unreachable,
5568 .tlv_reloc => unreachable,
5409 }5569 }
5410 }5570 }
54115571
...@@ -5444,6 +5604,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5444,6 +5604,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5444 .linker_load => unreachable,5604 .linker_load => unreachable,
5445 .eflags => unreachable,5605 .eflags => unreachable,
5446 .register_overflow => unreachable,5606 .register_overflow => unreachable,
5607 .tlv_reloc => unreachable,
5447 }5608 }
5448 }5609 }
54495610
...@@ -5965,6 +6126,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -5965,6 +6126,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
5965 .register_overflow,6126 .register_overflow,
5966 .ptr_stack_offset,6127 .ptr_stack_offset,
5967 .eflags,6128 .eflags,
6129 .tlv_reloc,
5968 => unreachable,6130 => unreachable,
59696131
5970 .register => |opt_reg| {6132 .register => |opt_reg| {
...@@ -5990,7 +6152,25 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -5990,7 +6152,25 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
5990 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);6152 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
5991 defer self.register_manager.unlockReg(addr_reg_lock);6153 defer self.register_manager.unlockReg(addr_reg_lock);
59926154
5993 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv);6155 switch (opt_mcv) {
6156 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
6157 .linker_load => |load_struct| {
6158 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
6159 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
6160 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
6161 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
6162 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
6163 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
6164 } else unreachable;
6165
6166 switch (load_struct.type) {
6167 .import => unreachable,
6168 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
6169 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
6170 }
6171 },
6172 else => unreachable,
6173 }
59946174
5995 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));6175 const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*));
5996 try self.asmMemoryImmediate(.cmp, Memory.sib(6176 try self.asmMemoryImmediate(.cmp, Memory.sib(
...@@ -6925,11 +7105,30 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -6925,11 +7105,30 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
6925 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });7105 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
6926 }7106 }
69277107
6928 const addr_reg = try self.register_manager.allocReg(null, gp);7108 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
6929 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);7109 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6930 defer self.register_manager.unlockReg(addr_lock);7110 defer self.register_manager.unlockReg(addr_lock);
69317111
6932 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mcv);7112 switch (mcv) {
7113 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
7114 .linker_load => |load_struct| {
7115 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7116 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7117 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7118 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7119 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7120 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7121 } else unreachable;
7122
7123 switch (load_struct.type) {
7124 .import => unreachable,
7125 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
7126 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
7127 }
7128 },
7129 else => unreachable,
7130 }
7131
6933 try self.genInlineMemcpy(7132 try self.genInlineMemcpy(
6934 .{ .ptr_stack_offset = stack_offset },7133 .{ .ptr_stack_offset = stack_offset },
6935 .{ .register = addr_reg },7134 .{ .register = addr_reg },
...@@ -6971,7 +7170,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -6971,7 +7170,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
6971 },7170 },
6972 }7171 }
6973 },7172 },
6974 .ptr_stack_offset => {7173 .ptr_stack_offset, .tlv_reloc => {
6975 const reg = try self.copyToTmpRegister(ty, mcv);7174 const reg = try self.copyToTmpRegister(ty, mcv);
6976 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });7175 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
6977 },7176 },
...@@ -7133,11 +7332,30 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -7133,11 +7332,30 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
7133 const reg = try self.copyToTmpRegister(ty, mcv);7332 const reg = try self.copyToTmpRegister(ty, mcv);
7134 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);7333 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);
7135 } else {7334 } else {
7136 const addr_reg = try self.register_manager.allocReg(null, gp);7335 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
7137 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);7336 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
7138 defer self.register_manager.unlockReg(addr_lock);7337 defer self.register_manager.unlockReg(addr_lock);
71397338
7140 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mcv);7339 switch (mcv) {
7340 .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }),
7341 .linker_load => |load_struct| {
7342 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7343 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7344 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7345 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7346 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7347 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7348 } else unreachable;
7349
7350 switch (load_struct.type) {
7351 .import => unreachable,
7352 .got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
7353 .direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
7354 }
7355 },
7356 else => unreachable,
7357 }
7358
7141 try self.genInlineMemcpy(7359 try self.genInlineMemcpy(
7142 .{ .ptr_stack_offset = stack_offset },7360 .{ .ptr_stack_offset = stack_offset },
7143 .{ .register = addr_reg },7361 .{ .register = addr_reg },
...@@ -7157,7 +7375,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -7157,7 +7375,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
7157 .{ .immediate = abi_size },7375 .{ .immediate = abi_size },
7158 .{},7376 .{},
7159 ),7377 ),
7160 .ptr_stack_offset => {7378 .ptr_stack_offset, .tlv_reloc => {
7161 const tmp_reg = try self.copyToTmpRegister(ty, mcv);7379 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
7162 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7380 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7163 defer self.register_manager.unlockReg(tmp_lock);7381 defer self.register_manager.unlockReg(tmp_lock);
...@@ -7247,11 +7465,26 @@ fn genInlineMemcpy(...@@ -7247,11 +7465,26 @@ fn genInlineMemcpy(
7247 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });7465 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
72487466
7249 switch (dst_ptr) {7467 switch (dst_ptr) {
7250 .memory, .linker_load => {7468 .memory => |addr| {
7251 try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr);7469 try self.genSetReg(Type.usize, .rdi, .{ .immediate = addr });
7252 // Load the pointer, which is stored in memory7470 // Load the pointer, which is stored in memory
7253 try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));7471 try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));
7254 },7472 },
7473 .linker_load => |load_struct| {
7474 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7475 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7476 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7477 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7478 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7479 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7480 } else unreachable;
7481
7482 switch (load_struct.type) {
7483 .import => unreachable,
7484 .got, .direct => try self.asmMovLinker(.rdi, atom_index, load_struct),
7485 }
7486 },
7487 .tlv_reloc => try self.genSetReg(Type.usize, .rdi, dst_ptr),
7255 .stack_offset, .ptr_stack_offset => |off| {7488 .stack_offset, .ptr_stack_offset => |off| {
7256 try self.asmRegisterMemory(switch (dst_ptr) {7489 try self.asmRegisterMemory(switch (dst_ptr) {
7257 .stack_offset => .mov,7490 .stack_offset => .mov,
...@@ -7275,11 +7508,26 @@ fn genInlineMemcpy(...@@ -7275,11 +7508,26 @@ fn genInlineMemcpy(
7275 }7508 }
72767509
7277 switch (src_ptr) {7510 switch (src_ptr) {
7278 .memory, .linker_load => {7511 .memory => |addr| {
7279 try self.loadMemPtrIntoRegister(.rsi, Type.usize, src_ptr);7512 try self.genSetReg(Type.usize, .rsi, .{ .immediate = addr });
7280 // Load the pointer, which is stored in memory7513 // Load the pointer, which is stored in memory
7281 try self.asmRegisterMemory(.mov, .rsi, Memory.sib(.qword, .{ .base = .rsi }));7514 try self.asmRegisterMemory(.mov, .rsi, Memory.sib(.qword, .{ .base = .rsi }));
7282 },7515 },
7516 .linker_load => |load_struct| {
7517 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7518 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7519 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7520 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7521 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7522 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7523 } else unreachable;
7524
7525 switch (load_struct.type) {
7526 .import => unreachable,
7527 .got, .direct => try self.asmMovLinker(.rsi, atom_index, load_struct),
7528 }
7529 },
7530 .tlv_reloc => try self.genSetReg(Type.usize, .rsi, src_ptr),
7283 .stack_offset, .ptr_stack_offset => |off| {7531 .stack_offset, .ptr_stack_offset => |off| {
7284 try self.asmRegisterMemory(switch (src_ptr) {7532 try self.asmRegisterMemory(switch (src_ptr) {
7285 .stack_offset => .mov,7533 .stack_offset => .mov,
...@@ -7326,11 +7574,26 @@ fn genInlineMemset(...@@ -7326,11 +7574,26 @@ fn genInlineMemset(
7326 try self.spillRegisters(&.{ .rdi, .al, .rcx });7574 try self.spillRegisters(&.{ .rdi, .al, .rcx });
73277575
7328 switch (dst_ptr) {7576 switch (dst_ptr) {
7329 .memory, .linker_load => {7577 .memory => |addr| {
7330 try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr);7578 try self.genSetReg(Type.usize, .rdi, .{ .immediate = addr });
7331 // Load the pointer, which is stored in memory7579 // Load the pointer, which is stored in memory
7332 try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));7580 try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));
7333 },7581 },
7582 .linker_load => |load_struct| {
7583 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7584 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7585 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7586 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7587 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7588 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7589 } else unreachable;
7590
7591 switch (load_struct.type) {
7592 .import => unreachable,
7593 .got, .direct => try self.asmMovLinker(.rdi, atom_index, load_struct),
7594 }
7595 },
7596 .tlv_reloc => try self.genSetReg(Type.usize, .rdi, dst_ptr),
7334 .stack_offset, .ptr_stack_offset => |off| {7597 .stack_offset, .ptr_stack_offset => |off| {
7335 try self.asmRegisterMemory(switch (dst_ptr) {7598 try self.asmRegisterMemory(switch (dst_ptr) {
7336 .stack_offset => .mov,7599 .stack_offset => .mov,
...@@ -7454,10 +7717,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7454,10 +7717,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
74547717
7455 try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size));7718 try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size));
7456 },7719 },
7457 .memory, .linker_load => switch (ty.zigTypeTag()) {7720 .memory => |addr| switch (ty.zigTypeTag()) {
7458 .Float => {7721 .Float => {
7459 const base_reg = try self.register_manager.allocReg(null, gp);7722 const base_reg = (try self.register_manager.allocReg(null, gp)).to64();
7460 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);7723 try self.genSetReg(Type.usize, base_reg, .{ .immediate = addr });
74617724
7462 if (intrinsicsAllowed(self.target.*, ty)) {7725 if (intrinsicsAllowed(self.target.*, ty)) {
7463 return self.asmRegisterMemory(7726 return self.asmRegisterMemory(
...@@ -7469,29 +7732,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7469,29 +7732,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
7469 }),7732 }),
7470 },7733 },
7471 reg.to128(),7734 reg.to128(),
7472 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }),7735 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg }),
7473 );7736 );
7474 }7737 }
74757738
7476 return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});7739 return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
7477 },7740 },
7478 else => switch (mcv) {7741 else => {
7479 else => unreachable,7742 if (addr <= math.maxInt(i32)) {
7480 .linker_load => {
7481 try self.loadMemPtrIntoRegister(reg, Type.usize, mcv);
7482 try self.asmRegisterMemory(
7483 .mov,
7484 registerAlias(reg, abi_size),
7485 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
7486 );
7487 },
7488 .memory => |x| if (x <= math.maxInt(i32)) {
7489 try self.asmRegisterMemory(7743 try self.asmRegisterMemory(
7490 .mov,7744 .mov,
7491 registerAlias(reg, abi_size),7745 registerAlias(reg, abi_size),
7492 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{7746 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
7493 .base = .ds,7747 .base = .ds,
7494 .disp = @intCast(i32, x),7748 .disp = @intCast(i32, addr),
7495 }),7749 }),
7496 );7750 );
7497 } else {7751 } else {
...@@ -7501,20 +7755,77 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7501,20 +7755,77 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
7501 _ = try self.addInst(.{7755 _ = try self.addInst(.{
7502 .tag = .mov_moffs,7756 .tag = .mov_moffs,
7503 .ops = .rax_moffs,7757 .ops = .rax_moffs,
7504 .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, x)) },7758 .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, addr)) },
7505 });7759 });
7506 } else {7760 } else {
7507 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.7761 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
7508 try self.genSetReg(ty, reg, MCValue{ .immediate = x });7762 try self.genSetReg(Type.usize, reg, MCValue{ .immediate = addr });
7509 try self.asmRegisterMemory(7763 try self.asmRegisterMemory(
7510 .mov,7764 .mov,
7511 registerAlias(reg, abi_size),7765 registerAlias(reg, abi_size),
7512 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),7766 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
7513 );7767 );
7514 }7768 }
7515 },7769 }
7516 },7770 },
7517 },7771 },
7772 .tlv_reloc => |sym_index| {
7773 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7774 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7775 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7776 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7777 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7778 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7779 } else unreachable;
7780
7781 if (self.bin_file.cast(link.File.MachO)) |_| {
7782 _ = try self.addInst(.{
7783 .tag = .mov_linker,
7784 .ops = .tlv_reloc,
7785 .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
7786 .reg = @enumToInt(Register.rdi),
7787 .atom_index = atom_index,
7788 .sym_index = sym_index,
7789 }) },
7790 });
7791 // TODO: spill registers before calling
7792 try self.asmMemory(.call, Memory.sib(.qword, .{ .base = .rdi }));
7793 try self.genSetReg(Type.usize, reg, .{ .register = .rax });
7794 } else return self.fail("TODO emit ptr to TLV sequence on {s}", .{@tagName(self.bin_file.tag)});
7795 },
7796 .linker_load => |load_struct| {
7797 const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
7798 const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7799 break :blk macho_file.getAtom(atom).getSymbolIndex().?;
7800 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
7801 const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
7802 break :blk coff_file.getAtom(atom).getSymbolIndex().?;
7803 } else unreachable;
7804
7805 switch (ty.zigTypeTag()) {
7806 .Float => {
7807 const base_reg = (try self.register_manager.allocReg(null, gp)).to64();
7808 try self.asmLeaLinker(base_reg, atom_index, load_struct);
7809
7810 if (intrinsicsAllowed(self.target.*, ty)) {
7811 return self.asmRegisterMemory(
7812 switch (ty.tag()) {
7813 .f32 => .movss,
7814 .f64 => .movsd,
7815 else => return self.fail("TODO genSetReg from memory for {}", .{
7816 ty.fmt(self.bin_file.options.module.?),
7817 }),
7818 },
7819 reg.to128(),
7820 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }),
7821 );
7822 }
7823
7824 return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
7825 },
7826 else => try self.asmMovLinker(registerAlias(reg, abi_size), atom_index, load_struct),
7827 }
7828 },
7518 .stack_offset => |off| {7829 .stack_offset => |off| {
7519 switch (ty.zigTypeTag()) {7830 switch (ty.zigTypeTag()) {
7520 .Int => switch (ty.intInfo(self.target.*).signedness) {7831 .Int => switch (ty.intInfo(self.target.*).signedness) {
...@@ -8468,6 +8779,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {...@@ -8468,6 +8779,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
8468 .linker_load => |ll| .{ .linker_load = ll },8779 .linker_load => |ll| .{ .linker_load = ll },
8469 .immediate => |imm| .{ .immediate = imm },8780 .immediate => |imm| .{ .immediate = imm },
8470 .memory => |addr| .{ .memory = addr },8781 .memory => |addr| .{ .memory = addr },
8782 .tlv_reloc => |sym_index| .{ .tlv_reloc = sym_index },
8471 },8783 },
8472 .fail => |msg| {8784 .fail => |msg| {
8473 self.err_msg = msg;8785 self.err_msg = msg;
src/arch/x86_64/Emit.zig+8-8
...@@ -42,7 +42,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -42,7 +42,7 @@ pub fn emitMir(emit: *Emit) Error!void {
42 ).?;42 ).?;
43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);
44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
45 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),45 .type = .branch,
46 .target = target,46 .target = target,
47 .offset = end_offset - 4,47 .offset = end_offset - 4,
48 .addend = 0,48 .addend = 0,
...@@ -65,20 +65,20 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -65,20 +65,20 @@ pub fn emitMir(emit: *Emit) Error!void {
65 });65 });
66 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),66 } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
6767
68 .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {68 .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
69 const metadata =69 const metadata =
70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
71 const reloc_type = switch (inst.ops) {
72 .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
73 .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
74 else => unreachable,
75 };
76 const atom_index = macho_file.getAtomIndexForSymbol(.{71 const atom_index = macho_file.getAtomIndexForSymbol(.{
77 .sym_index = metadata.atom_index,72 .sym_index = metadata.atom_index,
78 .file = null,73 .file = null,
79 }).?;74 }).?;
80 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{75 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
81 .type = reloc_type,76 .type = switch (inst.ops) {
77 .got_reloc => .got,
78 .direct_reloc => .signed,
79 .tlv_reloc => .tlv,
80 else => unreachable,
81 },
82 .target = .{ .sym_index = metadata.sym_index, .file = null },82 .target = .{ .sym_index = metadata.sym_index, .file = null },
83 .offset = @intCast(u32, end_offset - 4),83 .offset = @intCast(u32, end_offset - 4),
84 .addend = 0,84 .addend = 0,
src/arch/x86_64/Lower.zig+10
...@@ -127,6 +127,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -127,6 +127,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
127 .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),127 .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),
128128
129 .lea_linker => try lower.mirLeaLinker(inst),129 .lea_linker => try lower.mirLeaLinker(inst),
130 .mov_linker => try lower.mirMovLinker(inst),
130131
131 .mov_moffs => try lower.mirMovMoffs(inst),132 .mov_moffs => try lower.mirMovMoffs(inst),
132133
...@@ -444,6 +445,15 @@ fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -444,6 +445,15 @@ fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {
444 });445 });
445}446}
446447
448fn mirMovLinker(lower: *Lower, inst: Mir.Inst) Error!void {
449 const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
450 const reg = @intToEnum(Register, metadata.reg);
451 try lower.emit(.none, .mov, &.{
452 .{ .reg = reg },
453 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
454 });
455}
456
447const abi = @import("abi.zig");457const abi = @import("abi.zig");
448const assert = std.debug.assert;458const assert = std.debug.assert;
449const bits = @import("bits.zig");459const bits = @import("bits.zig");
src/arch/x86_64/Mir.zig+5
...@@ -233,6 +233,8 @@ pub const Inst = struct {...@@ -233,6 +233,8 @@ pub const Inst = struct {
233233
234 /// Load effective address of a symbol not yet allocated in VM.234 /// Load effective address of a symbol not yet allocated in VM.
235 lea_linker,235 lea_linker,
236 /// Move address of a symbol not yet allocated in VM.
237 mov_linker,
236238
237 /// End of prologue239 /// End of prologue
238 dbg_prologue_end,240 dbg_prologue_end,
...@@ -402,6 +404,9 @@ pub const Inst = struct {...@@ -402,6 +404,9 @@ pub const Inst = struct {
402 /// Linker relocation - imports table indirection (binding).404 /// Linker relocation - imports table indirection (binding).
403 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.405 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
404 import_reloc,406 import_reloc,
407 /// Linker relocation - threadlocal variable via GOT indirection.
408 /// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
409 tlv_reloc,
405 };410 };
406411
407 pub const Data = union {412 pub const Data = union {
src/codegen.zig+19-5
...@@ -493,7 +493,7 @@ pub fn generateSymbol(...@@ -493,7 +493,7 @@ pub fn generateSymbol(
493 bin_file.allocator,493 bin_file.allocator,
494 src_loc,494 src_loc,
495 "TODO implement generateSymbol for big int enums ('{}')",495 "TODO implement generateSymbol for big int enums ('{}')",
496 .{typed_value.ty.fmtDebug()},496 .{typed_value.ty.fmt(mod)},
497 ),497 ),
498 };498 };
499 }499 }
...@@ -932,6 +932,10 @@ pub const GenResult = union(enum) {...@@ -932,6 +932,10 @@ pub const GenResult = union(enum) {
932 /// such as ARM, the immediate will never exceed 32-bits.932 /// such as ARM, the immediate will never exceed 32-bits.
933 immediate: u64,933 immediate: u64,
934 linker_load: LinkerLoad,934 linker_load: LinkerLoad,
935 /// Pointer to a threadlocal variable.
936 /// The address resolution will be deferred until the linker allocates everything in virtual memory.
937 /// Payload is a symbol index.
938 tlv_reloc: u32,
935 /// Direct by-address reference to memory location.939 /// Direct by-address reference to memory location.
936 memory: u64,940 memory: u64,
937 };941 };
...@@ -957,13 +961,13 @@ fn genDeclRef(...@@ -957,13 +961,13 @@ fn genDeclRef(
957 tv: TypedValue,961 tv: TypedValue,
958 decl_index: Module.Decl.Index,962 decl_index: Module.Decl.Index,
959) CodeGenError!GenResult {963) CodeGenError!GenResult {
960 log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() });964 const module = bin_file.options.module.?;
965 log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(module), tv.val.fmtValue(tv.ty, module) });
961966
962 const target = bin_file.options.target;967 const target = bin_file.options.target;
963 const ptr_bits = target.cpu.arch.ptrBitWidth();968 const ptr_bits = target.cpu.arch.ptrBitWidth();
964 const ptr_bytes: u64 = @divExact(ptr_bits, 8);969 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
965970
966 const module = bin_file.options.module.?;
967 const decl = module.declPtr(decl_index);971 const decl = module.declPtr(decl_index);
968972
969 if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime()) {973 if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
...@@ -991,6 +995,8 @@ fn genDeclRef(...@@ -991,6 +995,8 @@ fn genDeclRef(
991995
992 module.markDeclAlive(decl);996 module.markDeclAlive(decl);
993997
998 const is_threadlocal = tv.val.isPtrToThreadLocal(module) and !bin_file.options.single_threaded;
999
994 if (bin_file.cast(link.File.Elf)) |elf_file| {1000 if (bin_file.cast(link.File.Elf)) |elf_file| {
995 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);1001 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
996 const atom = elf_file.getAtom(atom_index);1002 const atom = elf_file.getAtom(atom_index);
...@@ -998,6 +1004,9 @@ fn genDeclRef(...@@ -998,6 +1004,9 @@ fn genDeclRef(
998 } else if (bin_file.cast(link.File.MachO)) |macho_file| {1004 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
999 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);1005 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
1000 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;1006 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
1007 if (is_threadlocal) {
1008 return GenResult.mcv(.{ .tlv_reloc = sym_index });
1009 }
1001 return GenResult.mcv(.{ .linker_load = .{1010 return GenResult.mcv(.{ .linker_load = .{
1002 .type = .got,1011 .type = .got,
1003 .sym_index = sym_index,1012 .sym_index = sym_index,
...@@ -1025,7 +1034,8 @@ fn genUnnamedConst(...@@ -1025,7 +1034,8 @@ fn genUnnamedConst(
1025 tv: TypedValue,1034 tv: TypedValue,
1026 owner_decl_index: Module.Decl.Index,1035 owner_decl_index: Module.Decl.Index,
1027) CodeGenError!GenResult {1036) CodeGenError!GenResult {
1028 log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() });1037 const mod = bin_file.options.module.?;
1038 log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmt(mod), tv.val.fmtValue(tv.ty, mod) });
10291039
1030 const target = bin_file.options.target;1040 const target = bin_file.options.target;
1031 const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| {1041 const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| {
...@@ -1065,7 +1075,11 @@ pub fn genTypedValue(...@@ -1065,7 +1075,11 @@ pub fn genTypedValue(
1065 typed_value.val = rt.data;1075 typed_value.val = rt.data;
1066 }1076 }
10671077
1068 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });1078 const mod = bin_file.options.module.?;
1079 log.debug("genTypedValue: ty = {}, val = {}", .{
1080 typed_value.ty.fmt(mod),
1081 typed_value.val.fmtValue(typed_value.ty, mod),
1082 });
10691083
1070 if (typed_value.val.isUndef())1084 if (typed_value.val.isUndef())
1071 return GenResult.mcv(.undef);1085 return GenResult.mcv(.undef);
src/link.zig+2-2
...@@ -540,7 +540,7 @@ pub const File = struct {...@@ -540,7 +540,7 @@ pub const File = struct {
540 /// May be called before or after updateDeclExports for any given Decl.540 /// May be called before or after updateDeclExports for any given Decl.
541 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {541 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
542 const decl = module.declPtr(decl_index);542 const decl = module.declPtr(decl_index);
543 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() });543 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmt(module) });
544 assert(decl.has_tv);544 assert(decl.has_tv);
545 if (build_options.only_c) {545 if (build_options.only_c) {
546 assert(base.tag == .c);546 assert(base.tag == .c);
...@@ -564,7 +564,7 @@ pub const File = struct {...@@ -564,7 +564,7 @@ pub const File = struct {
564 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void {564 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void {
565 const owner_decl = module.declPtr(func.owner_decl);565 const owner_decl = module.declPtr(func.owner_decl);
566 log.debug("updateFunc {*} ({s}), type={}", .{566 log.debug("updateFunc {*} ({s}), type={}", .{
567 owner_decl, owner_decl.name, owner_decl.ty.fmtDebug(),567 owner_decl, owner_decl.name, owner_decl.ty.fmt(module),
568 });568 });
569 if (build_options.only_c) {569 if (build_options.only_c) {
570 assert(base.tag == .c);570 assert(base.tag == .c);
src/link/Dwarf.zig+12-3
...@@ -150,7 +150,7 @@ pub const DeclState = struct {...@@ -150,7 +150,7 @@ pub const DeclState = struct {
150 .type = ty,150 .type = ty,
151 .offset = undefined,151 .offset = undefined,
152 });152 });
153 log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() });153 log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) });
154 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{154 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{
155 .mod = self.mod,155 .mod = self.mod,
156 });156 });
...@@ -570,7 +570,7 @@ pub const DeclState = struct {...@@ -570,7 +570,7 @@ pub const DeclState = struct {
570 try dbg_info_buffer.append(0);570 try dbg_info_buffer.append(0);
571 },571 },
572 else => {572 else => {
573 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()});573 log.debug("TODO implement .debug_info for type '{}'", .{ty.fmt(self.mod)});
574 try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1));574 try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1));
575 },575 },
576 }576 }
...@@ -1055,6 +1055,10 @@ pub fn commitDeclState(...@@ -1055,6 +1055,10 @@ pub fn commitDeclState(
1055 },1055 },
1056 }1056 }
1057 {1057 {
1058 log.debug("relocating subprogram high PC value: {x} => {x}", .{
1059 self.getRelocDbgInfoSubprogramHighPC(),
1060 sym_size,
1061 });
1058 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];1062 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
1059 mem.writeInt(u32, ptr, @intCast(u32, sym_size), target_endian);1063 mem.writeInt(u32, ptr, @intCast(u32, sym_size), target_endian);
1060 }1064 }
...@@ -1263,7 +1267,12 @@ pub fn commitDeclState(...@@ -1263,7 +1267,12 @@ pub fn commitDeclState(
1263 } else {1267 } else {
1264 const atom = self.getAtom(.di_atom, symbol.atom_index);1268 const atom = self.getAtom(.di_atom, symbol.atom_index);
1265 const value = atom.off + symbol.offset + reloc.addend;1269 const value = atom.off + symbol.offset + reloc.addend;
1266 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });1270 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{
1271 reloc.offset,
1272 value,
1273 target,
1274 ty.fmt(module),
1275 });
1267 mem.writeInt(1276 mem.writeInt(
1268 u32,1277 u32,
1269 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],1278 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
src/link/MachO.zig+298-228
...@@ -5,7 +5,6 @@ const build_options = @import("build_options");...@@ -5,7 +5,6 @@ const build_options = @import("build_options");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const dwarf = std.dwarf;7const dwarf = std.dwarf;
8const fmt = std.fmt;
9const fs = std.fs;8const fs = std.fs;
10const log = std.log.scoped(.link);9const log = std.log.scoped(.link);
11const macho = std.macho;10const macho = std.macho;
...@@ -138,6 +137,8 @@ got_section_index: ?u8 = null,...@@ -138,6 +137,8 @@ got_section_index: ?u8 = null,
138data_const_section_index: ?u8 = null,137data_const_section_index: ?u8 = null,
139la_symbol_ptr_section_index: ?u8 = null,138la_symbol_ptr_section_index: ?u8 = null,
140data_section_index: ?u8 = null,139data_section_index: ?u8 = null,
140thread_vars_section_index: ?u8 = null,
141thread_data_section_index: ?u8 = null,
141142
142locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},143locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
143globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},144globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
...@@ -153,13 +154,9 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,...@@ -153,13 +154,9 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,
153154
154strtab: StringTable(.strtab) = .{},155strtab: StringTable(.strtab) = .{},
155156
156got_entries: std.ArrayListUnmanaged(Entry) = .{},157got_table: SectionTable = .{},
157got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},158stubs_table: SectionTable = .{},
158got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},159tlv_table: SectionTable = .{},
159
160stubs: std.ArrayListUnmanaged(Entry) = .{},
161stubs_free_list: std.ArrayListUnmanaged(u32) = .{},
162stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
163160
164error_flags: File.ErrorFlags = File.ErrorFlags{},161error_flags: File.ErrorFlags = File.ErrorFlags{},
165162
...@@ -268,26 +265,120 @@ const DeclMetadata = struct {...@@ -268,26 +265,120 @@ const DeclMetadata = struct {
268 }265 }
269};266};
270267
271const Entry = struct {268const SectionTable = struct {
272 target: SymbolWithLoc,269 entries: std.ArrayListUnmanaged(Entry) = .{},
273 // Index into the synthetic symbol table (i.e., file == null).270 free_list: std.ArrayListUnmanaged(u32) = .{},
274 sym_index: u32,271 lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
272
273 pub fn deinit(st: *ST, allocator: Allocator) void {
274 st.entries.deinit(allocator);
275 st.free_list.deinit(allocator);
276 st.lookup.deinit(allocator);
277 }
278
279 pub fn allocateEntry(st: *ST, allocator: Allocator, target: SymbolWithLoc) !u32 {
280 try st.entries.ensureUnusedCapacity(allocator, 1);
281 const index = blk: {
282 if (st.free_list.popOrNull()) |index| {
283 log.debug(" (reusing entry index {d})", .{index});
284 break :blk index;
285 } else {
286 log.debug(" (allocating entry at index {d})", .{st.entries.items.len});
287 const index = @intCast(u32, st.entries.items.len);
288 _ = st.entries.addOneAssumeCapacity();
289 break :blk index;
290 }
291 };
292 st.entries.items[index] = .{ .target = target, .sym_index = 0 };
293 try st.lookup.putNoClobber(allocator, target, index);
294 return index;
295 }
296
297 pub fn freeEntry(st: *ST, allocator: Allocator, target: SymbolWithLoc) void {
298 const index = st.lookup.get(target) orelse return;
299 st.free_list.append(allocator, index) catch {};
300 st.entries.items[index] = .{
301 .target = .{ .sym_index = 0 },
302 .sym_index = 0,
303 };
304 _ = st.lookup.remove(target);
305 }
275306
276 pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 {307 pub fn getAtomIndex(st: *const ST, macho_file: *MachO, target: SymbolWithLoc) ?Atom.Index {
277 return macho_file.getSymbol(.{ .sym_index = entry.sym_index, .file = null });308 const index = st.lookup.get(target) orelse return null;
309 return st.entries.items[index].getAtomIndex(macho_file);
278 }310 }
279311
280 pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 {312 const FormatContext = struct {
281 return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null });313 macho_file: *MachO,
314 st: *const ST,
315 };
316
317 fn fmt(
318 ctx: FormatContext,
319 comptime unused_format_string: []const u8,
320 options: std.fmt.FormatOptions,
321 writer: anytype,
322 ) @TypeOf(writer).Error!void {
323 _ = options;
324 comptime assert(unused_format_string.len == 0);
325 try writer.writeAll("SectionTable:\n");
326 for (ctx.st.entries.items, 0..) |entry, i| {
327 const atom_sym = entry.getSymbol(ctx.macho_file);
328 const target_sym = ctx.macho_file.getSymbol(entry.target);
329 try writer.print(" {d}@{x} => ", .{ i, atom_sym.n_value });
330 if (target_sym.undf()) {
331 try writer.print("import('{s}')", .{
332 ctx.macho_file.getSymbolName(entry.target),
333 });
334 } else {
335 try writer.print("local(%{d}) in object({?d})", .{
336 entry.target.sym_index,
337 entry.target.file,
338 });
339 }
340 try writer.writeByte('\n');
341 }
282 }342 }
283343
284 pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {344 fn format(st: *const ST, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
285 return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null });345 _ = st;
346 _ = unused_format_string;
347 _ = options;
348 _ = writer;
349 @compileError("do not format SectionTable directly; use st.fmtDebug()");
286 }350 }
287351
288 pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {352 pub fn fmtDebug(st: *const ST, macho_file: *MachO) std.fmt.Formatter(fmt) {
289 return macho_file.getSymbolName(.{ .sym_index = entry.sym_index, .file = null });353 return .{ .data = .{
354 .macho_file = macho_file,
355 .st = st,
356 } };
290 }357 }
358
359 const ST = @This();
360
361 const Entry = struct {
362 target: SymbolWithLoc,
363 // Index into the synthetic symbol table (i.e., file == null).
364 sym_index: u32,
365
366 pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 {
367 return macho_file.getSymbol(.{ .sym_index = entry.sym_index });
368 }
369
370 pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 {
371 return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index });
372 }
373
374 pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {
375 return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index });
376 }
377
378 pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {
379 return macho_file.getSymbolName(.{ .sym_index = entry.sym_index });
380 }
381 };
291};382};
292383
293const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));384const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
...@@ -397,7 +488,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -397,7 +488,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
397 // Create dSYM bundle.488 // Create dSYM bundle.
398 log.debug("creating {s}.dSYM bundle", .{sub_path});489 log.debug("creating {s}.dSYM bundle", .{sub_path});
399490
400 const d_sym_path = try fmt.allocPrint(491 const d_sym_path = try std.fmt.allocPrint(
401 allocator,492 allocator,
402 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",493 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
403 .{sub_path},494 .{sub_path},
...@@ -611,6 +702,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -611,6 +702,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
611 if (self.dyld_stub_binder_index == null) {702 if (self.dyld_stub_binder_index == null) {
612 self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);703 self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);
613 }704 }
705 if (!self.base.options.single_threaded) {
706 _ = try self.addUndefined("__tlv_bootstrap", .none);
707 }
614708
615 try self.createMhExecuteHeaderSymbol();709 try self.createMhExecuteHeaderSymbol();
616710
...@@ -619,6 +713,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -619,6 +713,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
619 try self.resolveSymbolsInDylibs(&actions);713 try self.resolveSymbolsInDylibs(&actions);
620714
621 if (self.unresolved.count() > 0) {715 if (self.unresolved.count() > 0) {
716 for (self.unresolved.keys()) |index| {
717 // TODO: convert into compiler errors.
718 const global = self.globals.items[index];
719 const sym_name = self.getSymbolName(global);
720 log.err("undefined symbol reference '{s}'", .{sym_name});
721 }
622 return error.UndefinedSymbolReference;722 return error.UndefinedSymbolReference;
623 }723 }
624724
...@@ -1237,22 +1337,17 @@ pub fn createAtom(self: *MachO) !Atom.Index {...@@ -1237,22 +1337,17 @@ pub fn createAtom(self: *MachO) !Atom.Index {
12371337
1238pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {1338pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1239 const atom_index = try self.createAtom();1339 const atom_index = try self.createAtom();
1240 const atom = self.getAtomPtr(atom_index);1340 self.getAtomPtr(atom_index).size = @sizeOf(u64);
1241 atom.size = @sizeOf(u64);
12421341
1243 const sym = atom.getSymbolPtr(self);1342 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1244 sym.n_type = macho.N_SECT;1343 sym.n_type = macho.N_SECT;
1245 sym.n_sect = self.got_section_index.? + 1;1344 sym.n_sect = self.got_section_index.? + 1;
1246 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));1345 sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
12471346
1248 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});1347 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
12491348
1250 try Atom.addRelocation(self, atom_index, .{1349 try Atom.addRelocation(self, atom_index, .{
1251 .type = switch (self.base.options.target.cpu.arch) {1350 .type = .unsigned,
1252 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1253 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1254 else => unreachable,
1255 },
1256 .target = target,1351 .target = target,
1257 .offset = 0,1352 .offset = 0,
1258 .addend = 0,1353 .addend = 0,
...@@ -1269,6 +1364,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {...@@ -1269,6 +1364,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1269 } else {1364 } else {
1270 try Atom.addRebase(self, atom_index, 0);1365 try Atom.addRebase(self, atom_index, 0);
1271 }1366 }
1367 try self.writePtrWidthAtom(atom_index);
12721368
1273 return atom_index;1369 return atom_index;
1274}1370}
...@@ -1334,15 +1430,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1334,15 +1430,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
1334 code[9] = 0xff;1430 code[9] = 0xff;
1335 code[10] = 0x25;1431 code[10] = 0x25;
13361432
1337 try Atom.addRelocations(self, atom_index, 2, .{ .{1433 try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{
1338 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1434 .type = .signed,
1339 .target = dyld_private,1435 .target = dyld_private,
1340 .offset = 3,1436 .offset = 3,
1341 .addend = 0,1437 .addend = 0,
1342 .pcrel = true,1438 .pcrel = true,
1343 .length = 2,1439 .length = 2,
1344 }, .{1440 }, .{
1345 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT),1441 .type = .got,
1346 .target = dyld_stub_binder,1442 .target = dyld_stub_binder,
1347 .offset = 11,1443 .offset = 11,
1348 .addend = 0,1444 .addend = 0,
...@@ -1374,29 +1470,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1374,29 +1470,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
1374 // br x161470 // br x16
1375 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());1471 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());
13761472
1377 try Atom.addRelocations(self, atom_index, 4, .{ .{1473 try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{
1378 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1474 .type = .page,
1379 .target = dyld_private,1475 .target = dyld_private,
1380 .offset = 0,1476 .offset = 0,
1381 .addend = 0,1477 .addend = 0,
1382 .pcrel = true,1478 .pcrel = true,
1383 .length = 2,1479 .length = 2,
1384 }, .{1480 }, .{
1385 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),1481 .type = .pageoff,
1386 .target = dyld_private,1482 .target = dyld_private,
1387 .offset = 4,1483 .offset = 4,
1388 .addend = 0,1484 .addend = 0,
1389 .pcrel = false,1485 .pcrel = false,
1390 .length = 2,1486 .length = 2,
1391 }, .{1487 }, .{
1392 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),1488 .type = .got_page,
1393 .target = dyld_stub_binder,1489 .target = dyld_stub_binder,
1394 .offset = 12,1490 .offset = 12,
1395 .addend = 0,1491 .addend = 0,
1396 .pcrel = true,1492 .pcrel = true,
1397 .length = 2,1493 .length = 2,
1398 }, .{1494 }, .{
1399 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),1495 .type = .got_pageoff,
1400 .target = dyld_stub_binder,1496 .target = dyld_stub_binder,
1401 .offset = 16,1497 .offset = 16,
1402 .addend = 0,1498 .addend = 0,
...@@ -1454,8 +1550,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {...@@ -1454,8 +1550,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
1454 code[5] = 0xe9;1550 code[5] = 0xe9;
14551551
1456 try Atom.addRelocation(self, atom_index, .{1552 try Atom.addRelocation(self, atom_index, .{
1457 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1553 .type = .branch,
1458 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },1554 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
1459 .offset = 6,1555 .offset = 6,
1460 .addend = 0,1556 .addend = 0,
1461 .pcrel = true,1557 .pcrel = true,
...@@ -1477,8 +1573,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {...@@ -1477,8 +1573,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
1477 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.1573 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
14781574
1479 try Atom.addRelocation(self, atom_index, .{1575 try Atom.addRelocation(self, atom_index, .{
1480 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),1576 .type = .branch,
1481 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },1577 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
1482 .offset = 4,1578 .offset = 4,
1483 .addend = 0,1579 .addend = 0,
1484 .pcrel = true,1580 .pcrel = true,
...@@ -1505,12 +1601,8 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo...@@ -1505,12 +1601,8 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo
1505 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;1601 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;
15061602
1507 try Atom.addRelocation(self, atom_index, .{1603 try Atom.addRelocation(self, atom_index, .{
1508 .type = switch (self.base.options.target.cpu.arch) {1604 .type = .unsigned,
1509 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),1605 .target = .{ .sym_index = stub_sym_index },
1510 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1511 else => unreachable,
1512 },
1513 .target = .{ .sym_index = stub_sym_index, .file = null },
1514 .offset = 0,1606 .offset = 0,
1515 .addend = 0,1607 .addend = 0,
1516 .pcrel = false,1608 .pcrel = false,
...@@ -1563,8 +1655,8 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1563,8 +1655,8 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1563 code[1] = 0x25;1655 code[1] = 0x25;
15641656
1565 try Atom.addRelocation(self, atom_index, .{1657 try Atom.addRelocation(self, atom_index, .{
1566 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1658 .type = .branch,
1567 .target = .{ .sym_index = laptr_sym_index, .file = null },1659 .target = .{ .sym_index = laptr_sym_index },
1568 .offset = 2,1660 .offset = 2,
1569 .addend = 0,1661 .addend = 0,
1570 .pcrel = true,1662 .pcrel = true,
...@@ -1583,18 +1675,18 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1583,18 +1675,18 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1583 // br x161675 // br x16
1584 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());1676 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
15851677
1586 try Atom.addRelocations(self, atom_index, 2, .{1678 try Atom.addRelocations(self, atom_index, &[_]Relocation{
1587 .{1679 .{
1588 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1680 .type = .page,
1589 .target = .{ .sym_index = laptr_sym_index, .file = null },1681 .target = .{ .sym_index = laptr_sym_index },
1590 .offset = 0,1682 .offset = 0,
1591 .addend = 0,1683 .addend = 0,
1592 .pcrel = true,1684 .pcrel = true,
1593 .length = 2,1685 .length = 2,
1594 },1686 },
1595 .{1687 .{
1596 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),1688 .type = .pageoff,
1597 .target = .{ .sym_index = laptr_sym_index, .file = null },1689 .target = .{ .sym_index = laptr_sym_index },
1598 .offset = 4,1690 .offset = 4,
1599 .addend = 0,1691 .addend = 0,
1600 .pcrel = false,1692 .pcrel = false,
...@@ -1612,6 +1704,42 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1612,6 +1704,42 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1612 return atom_index;1704 return atom_index;
1613}1705}
16141706
1707fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1708 const gpa = self.base.allocator;
1709 const size = 3 * @sizeOf(u64);
1710 const required_alignment: u32 = 1;
1711 const atom_index = try self.createAtom();
1712 self.getAtomPtr(atom_index).size = size;
1713
1714 const target_sym_name = self.getSymbolName(target);
1715 const name_delimiter = mem.indexOf(u8, target_sym_name, "$").?;
1716 const sym_name = try gpa.dupe(u8, target_sym_name[0..name_delimiter]);
1717 defer gpa.free(sym_name);
1718
1719 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1720 sym.n_type = macho.N_SECT;
1721 sym.n_sect = self.thread_vars_section_index.? + 1;
1722 sym.n_strx = try self.strtab.insert(gpa, sym_name);
1723 sym.n_value = try self.allocateAtom(atom_index, size, required_alignment);
1724
1725 log.debug("allocated threadlocal descriptor atom '{s}' at 0x{x}", .{ sym_name, sym.n_value });
1726
1727 try Atom.addRelocation(self, atom_index, .{
1728 .type = .tlv_initializer,
1729 .target = target,
1730 .offset = 0x10,
1731 .addend = 0,
1732 .pcrel = false,
1733 .length = 3,
1734 });
1735
1736 var code: [size]u8 = undefined;
1737 mem.set(u8, &code, 0);
1738 try self.writeAtom(atom_index, &code);
1739
1740 return atom_index;
1741}
1742
1615fn createMhExecuteHeaderSymbol(self: *MachO) !void {1743fn createMhExecuteHeaderSymbol(self: *MachO) !void {
1616 if (self.base.options.output_mode != .Exe) return;1744 if (self.base.options.output_mode != .Exe) return;
1617 if (self.getGlobal("__mh_execute_header")) |global| {1745 if (self.getGlobal("__mh_execute_header")) |global| {
...@@ -1760,12 +1888,9 @@ pub fn deinit(self: *MachO) void {...@@ -1760,12 +1888,9 @@ pub fn deinit(self: *MachO) void {
1760 d_sym.deinit();1888 d_sym.deinit();
1761 }1889 }
17621890
1763 self.got_entries.deinit(gpa);1891 self.got_table.deinit(gpa);
1764 self.got_entries_free_list.deinit(gpa);
1765 self.got_entries_table.deinit(gpa);
1766 self.stubs.deinit(gpa);
1767 self.stubs_free_list.deinit(gpa);
1768 self.stubs_table.deinit(gpa);1892 self.stubs_table.deinit(gpa);
1893 self.tlv_table.deinit(gpa);
1769 self.strtab.deinit(gpa);1894 self.strtab.deinit(gpa);
17701895
1771 self.locals.deinit(gpa);1896 self.locals.deinit(gpa);
...@@ -1898,20 +2023,10 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void {...@@ -1898,20 +2023,10 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
1898 self.locals_free_list.append(gpa, sym_index) catch {};2023 self.locals_free_list.append(gpa, sym_index) catch {};
18992024
1900 // Try freeing GOT atom if this decl had one2025 // Try freeing GOT atom if this decl had one
1901 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2026 self.got_table.freeEntry(gpa, .{ .sym_index = sym_index });
1902 if (self.got_entries_table.get(got_target)) |got_index| {
1903 self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
1904 self.got_entries.items[got_index] = .{
1905 .target = .{ .sym_index = 0, .file = null },
1906 .sym_index = 0,
1907 };
1908 _ = self.got_entries_table.remove(got_target);
1909
1910 if (self.d_sym) |*d_sym| {
1911 d_sym.swapRemoveRelocs(sym_index);
1912 }
19132027
1914 log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });2028 if (self.d_sym) |*d_sym| {
2029 d_sym.swapRemoveRelocs(sym_index);
1915 }2030 }
19162031
1917 self.locals.items[sym_index].n_type = 0;2032 self.locals.items[sym_index].n_type = 0;
...@@ -1986,70 +2101,34 @@ fn allocateGlobal(self: *MachO) !u32 {...@@ -1986,70 +2101,34 @@ fn allocateGlobal(self: *MachO) !u32 {
1986 return index;2101 return index;
1987}2102}
19882103
1989fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
1990 const gpa = self.base.allocator;
1991 try self.got_entries.ensureUnusedCapacity(gpa, 1);
1992
1993 const index = blk: {
1994 if (self.got_entries_free_list.popOrNull()) |index| {
1995 log.debug(" (reusing GOT entry index {d})", .{index});
1996 break :blk index;
1997 } else {
1998 log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.items.len});
1999 const index = @intCast(u32, self.got_entries.items.len);
2000 _ = self.got_entries.addOneAssumeCapacity();
2001 break :blk index;
2002 }
2003 };
2004
2005 self.got_entries.items[index] = .{ .target = target, .sym_index = 0 };
2006 try self.got_entries_table.putNoClobber(gpa, target, index);
2007
2008 return index;
2009}
2010
2011fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {2104fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
2012 if (self.got_entries_table.contains(target)) return;2105 if (self.got_table.lookup.contains(target)) return;
20132106 const got_index = try self.got_table.allocateEntry(self.base.allocator, target);
2014 const got_index = try self.allocateGotEntry(target);
2015 const got_atom_index = try self.createGotAtom(target);2107 const got_atom_index = try self.createGotAtom(target);
2016 const got_atom = self.getAtom(got_atom_index);2108 const got_atom = self.getAtom(got_atom_index);
2017 self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;2109 self.got_table.entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
2018 try self.writePtrWidthAtom(got_atom_index);2110 self.markRelocsDirtyByTarget(target);
2019}
2020
2021fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {
2022 try self.stubs.ensureUnusedCapacity(self.base.allocator, 1);
2023
2024 const index = blk: {
2025 if (self.stubs_free_list.popOrNull()) |index| {
2026 log.debug(" (reusing stub entry index {d})", .{index});
2027 break :blk index;
2028 } else {
2029 log.debug(" (allocating stub entry at index {d})", .{self.stubs.items.len});
2030 const index = @intCast(u32, self.stubs.items.len);
2031 _ = self.stubs.addOneAssumeCapacity();
2032 break :blk index;
2033 }
2034 };
2035
2036 self.stubs.items[index] = .{ .target = target, .sym_index = 0 };
2037 try self.stubs_table.putNoClobber(self.base.allocator, target, index);
2038
2039 return index;
2040}2111}
20412112
2042fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {2113fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
2043 if (self.stubs_table.contains(target)) return;2114 if (self.stubs_table.lookup.contains(target)) return;
20442115 const stub_index = try self.stubs_table.allocateEntry(self.base.allocator, target);
2045 const stub_index = try self.allocateStubEntry(target);
2046 const stub_helper_atom_index = try self.createStubHelperAtom();2116 const stub_helper_atom_index = try self.createStubHelperAtom();
2047 const stub_helper_atom = self.getAtom(stub_helper_atom_index);2117 const stub_helper_atom = self.getAtom(stub_helper_atom_index);
2048 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target);2118 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target);
2049 const laptr_atom = self.getAtom(laptr_atom_index);2119 const laptr_atom = self.getAtom(laptr_atom_index);
2050 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);2120 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
2051 const stub_atom = self.getAtom(stub_atom_index);2121 const stub_atom = self.getAtom(stub_atom_index);
2052 self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;2122 self.stubs_table.entries.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
2123 self.markRelocsDirtyByTarget(target);
2124}
2125
2126fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
2127 if (self.tlv_table.lookup.contains(target)) return;
2128 const tlv_index = try self.tlv_table.allocateEntry(self.base.allocator, target);
2129 const tlv_atom_index = try self.createThreadLocalDescriptorAtom(target);
2130 const tlv_atom = self.getAtom(tlv_atom_index);
2131 self.tlv_table.entries.items[tlv_index].sym_index = tlv_atom.getSymbolIndex().?;
2053 self.markRelocsDirtyByTarget(target);2132 self.markRelocsDirtyByTarget(target);
2054}2133}
20552134
...@@ -2070,8 +2149,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -2070,8 +2149,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
2070 self.freeUnnamedConsts(decl_index);2149 self.freeUnnamedConsts(decl_index);
2071 Atom.freeRelocations(self, atom_index);2150 Atom.freeRelocations(self, atom_index);
20722151
2073 const atom = self.getAtom(atom_index);
2074
2075 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2152 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2076 defer code_buffer.deinit();2153 defer code_buffer.deinit();
20772154
...@@ -2100,7 +2177,13 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -2100,7 +2177,13 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
2100 const addr = try self.updateDeclCode(decl_index, code);2177 const addr = try self.updateDeclCode(decl_index, code);
21012178
2102 if (decl_state) |*ds| {2179 if (decl_state) |*ds| {
2103 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);2180 try self.d_sym.?.dwarf.commitDeclState(
2181 module,
2182 decl_index,
2183 addr,
2184 self.getAtom(atom_index).size,
2185 ds,
2186 );
2104 }2187 }
21052188
2106 // Since we updated the vaddr and the size, each corresponding export symbol also2189 // Since we updated the vaddr and the size, each corresponding export symbol also
...@@ -2196,8 +2279,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2196,8 +2279,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2196 }2279 }
21972280
2198 const atom_index = try self.getOrCreateAtomForDecl(decl_index);2281 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2282 const sym_index = self.getAtom(atom_index).getSymbolIndex().?;
2199 Atom.freeRelocations(self, atom_index);2283 Atom.freeRelocations(self, atom_index);
2200 const atom = self.getAtom(atom_index);
22012284
2202 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2285 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2203 defer code_buffer.deinit();2286 defer code_buffer.deinit();
...@@ -2216,14 +2299,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2216,14 +2299,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2216 }, &code_buffer, .{2299 }, &code_buffer, .{
2217 .dwarf = ds,2300 .dwarf = ds,
2218 }, .{2301 }, .{
2219 .parent_atom_index = atom.getSymbolIndex().?,2302 .parent_atom_index = sym_index,
2220 })2303 })
2221 else2304 else
2222 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2305 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2223 .ty = decl.ty,2306 .ty = decl.ty,
2224 .val = decl_val,2307 .val = decl_val,
2225 }, &code_buffer, .none, .{2308 }, &code_buffer, .none, .{
2226 .parent_atom_index = atom.getSymbolIndex().?,2309 .parent_atom_index = sym_index,
2227 });2310 });
22282311
2229 var code = switch (res) {2312 var code = switch (res) {
...@@ -2237,7 +2320,13 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2237,7 +2320,13 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2237 const addr = try self.updateDeclCode(decl_index, code);2320 const addr = try self.updateDeclCode(decl_index, code);
22382321
2239 if (decl_state) |*ds| {2322 if (decl_state) |*ds| {
2240 try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds);2323 try self.d_sym.?.dwarf.commitDeclState(
2324 module,
2325 decl_index,
2326 addr,
2327 self.getAtom(atom_index).size,
2328 ds,
2329 );
2241 }2330 }
22422331
2243 // Since we updated the vaddr and the size, each corresponding export symbol also2332 // Since we updated the vaddr and the size, each corresponding export symbol also
...@@ -2322,7 +2411,6 @@ fn updateLazySymbolAtom(...@@ -2322,7 +2411,6 @@ fn updateLazySymbolAtom(
2322 symbol.n_value = vaddr;2411 symbol.n_value = vaddr;
23232412
2324 try self.addGotEntry(.{ .sym_index = local_sym_index });2413 try self.addGotEntry(.{ .sym_index = local_sym_index });
2325 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2326 try self.writeAtom(atom_index, code);2414 try self.writeAtom(atom_index, code);
2327}2415}
23282416
...@@ -2356,6 +2444,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {...@@ -2356,6 +2444,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {
2356 const val = decl.val;2444 const val = decl.val;
2357 const zig_ty = ty.zigTypeTag();2445 const zig_ty = ty.zigTypeTag();
2358 const mode = self.base.options.optimize_mode;2446 const mode = self.base.options.optimize_mode;
2447 const single_threaded = self.base.options.single_threaded;
2359 const sect_id: u8 = blk: {2448 const sect_id: u8 = blk: {
2360 // TODO finish and audit this function2449 // TODO finish and audit this function
2361 if (val.isUndefDeep()) {2450 if (val.isUndefDeep()) {
...@@ -2366,7 +2455,10 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {...@@ -2366,7 +2455,10 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {
2366 }2455 }
2367 }2456 }
23682457
2369 if (val.castTag(.variable)) |_| {2458 if (val.castTag(.variable)) |variable| {
2459 if (variable.data.is_threadlocal and !single_threaded) {
2460 break :blk self.thread_data_section_index.?;
2461 }
2370 break :blk self.data_section_index.?;2462 break :blk self.data_section_index.?;
2371 }2463 }
23722464
...@@ -2391,16 +2483,28 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2391,16 +2483,28 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
23912483
2392 const required_alignment = decl.getAlignment(self.base.options.target);2484 const required_alignment = decl.getAlignment(self.base.options.target);
23932485
2394 const sym_name = try decl.getFullyQualifiedName(mod);2486 const decl_name = try decl.getFullyQualifiedName(mod);
2395 defer self.base.allocator.free(sym_name);2487 defer gpa.free(decl_name);
23962488
2397 const decl_metadata = self.decls.get(decl_index).?;2489 const decl_metadata = self.decls.get(decl_index).?;
2398 const atom_index = decl_metadata.atom;2490 const atom_index = decl_metadata.atom;
2399 const atom = self.getAtom(atom_index);2491 const atom = self.getAtom(atom_index);
2400 const sym_index = atom.getSymbolIndex().?;2492 const sym_index = atom.getSymbolIndex().?;
2401 const sect_id = decl_metadata.section;2493 const sect_id = decl_metadata.section;
2494 const header = &self.sections.items(.header)[sect_id];
2495 const segment = self.getSegment(sect_id);
2496 const is_threadlocal = if (!self.base.options.single_threaded)
2497 header.flags == macho.S_THREAD_LOCAL_REGULAR or header.flags == macho.S_THREAD_LOCAL_ZEROFILL
2498 else
2499 false;
2402 const code_len = code.len;2500 const code_len = code.len;
24032501
2502 const sym_name = if (is_threadlocal)
2503 try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name})
2504 else
2505 decl_name;
2506 defer if (is_threadlocal) gpa.free(sym_name);
2507
2404 if (atom.size != 0) {2508 if (atom.size != 0) {
2405 const sym = atom.getSymbolPtr(self);2509 const sym = atom.getSymbolPtr(self);
2406 sym.n_strx = try self.strtab.insert(gpa, sym_name);2510 sym.n_strx = try self.strtab.insert(gpa, sym_name);
...@@ -2418,25 +2522,29 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2418,25 +2522,29 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
24182522
2419 if (vaddr != sym.n_value) {2523 if (vaddr != sym.n_value) {
2420 sym.n_value = vaddr;2524 sym.n_value = vaddr;
2525 // TODO: I think we should update the offset to the initializer here too.
2526 const target: SymbolWithLoc = if (is_threadlocal) blk: {
2527 const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{
2528 .sym_index = sym_index,
2529 }).?;
2530 const tlv_atom = self.getAtom(tlv_atom_index);
2531 break :blk tlv_atom.getSymbolWithLoc();
2532 } else .{ .sym_index = sym_index };
2533 self.markRelocsDirtyByTarget(target);
2421 log.debug(" (updating GOT entry)", .{});2534 log.debug(" (updating GOT entry)", .{});
2422 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };2535 const got_atom_index = self.got_table.getAtomIndex(self, target).?;
2423 const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?;
2424 self.markRelocsDirtyByTarget(got_target);
2425 try self.writePtrWidthAtom(got_atom_index);2536 try self.writePtrWidthAtom(got_atom_index);
2426 }2537 }
2427 } else if (code_len < atom.size) {2538 } else if (code_len < atom.size) {
2428 self.shrinkAtom(atom_index, code_len);2539 self.shrinkAtom(atom_index, code_len);
2429 } else if (atom.next_index == null) {2540 } else if (atom.next_index == null) {
2430 const header = &self.sections.items(.header)[sect_id];
2431 const segment = self.getSegment(sect_id);
2432 const needed_size = (sym.n_value + code_len) - segment.vmaddr;2541 const needed_size = (sym.n_value + code_len) - segment.vmaddr;
2433 header.size = needed_size;2542 header.size = needed_size;
2434 }2543 }
2435 self.getAtomPtr(atom_index).size = code_len;2544 self.getAtomPtr(atom_index).size = code_len;
2436 } else {2545 } else {
2437 const name_str_index = try self.strtab.insert(gpa, sym_name);
2438 const sym = atom.getSymbolPtr(self);2546 const sym = atom.getSymbolPtr(self);
2439 sym.n_strx = name_str_index;2547 sym.n_strx = try self.strtab.insert(gpa, sym_name);
2440 sym.n_type = macho.N_SECT;2548 sym.n_type = macho.N_SECT;
2441 sym.n_sect = sect_id + 1;2549 sym.n_sect = sect_id + 1;
2442 sym.n_desc = 0;2550 sym.n_desc = 0;
...@@ -2450,10 +2558,17 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2450,10 +2558,17 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
2450 self.getAtomPtr(atom_index).size = code_len;2558 self.getAtomPtr(atom_index).size = code_len;
2451 sym.n_value = vaddr;2559 sym.n_value = vaddr;
24522560
2453 try self.addGotEntry(.{ .sym_index = sym_index });2561 if (is_threadlocal) {
2562 try self.addTlvEntry(.{ .sym_index = sym_index });
2563 }
2564 const target: SymbolWithLoc = if (is_threadlocal) blk: {
2565 const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{ .sym_index = sym_index }).?;
2566 const tlv_atom = self.getAtom(tlv_atom_index);
2567 break :blk tlv_atom.getSymbolWithLoc();
2568 } else .{ .sym_index = sym_index };
2569 try self.addGotEntry(target);
2454 }2570 }
24552571
2456 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
2457 try self.writeAtom(atom_index, code);2572 try self.writeAtom(atom_index, code);
24582573
2459 return atom.getSymbol(self).n_value;2574 return atom.getSymbol(self).n_value;
...@@ -2647,11 +2762,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2647,11 +2762,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2647 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;2762 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
2648 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;2763 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2649 try Atom.addRelocation(self, atom_index, .{2764 try Atom.addRelocation(self, atom_index, .{
2650 .type = switch (self.base.options.target.cpu.arch) {2765 .type = .unsigned,
2651 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
2652 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
2653 else => unreachable,
2654 },
2655 .target = .{ .sym_index = sym_index, .file = null },2766 .target = .{ .sym_index = sym_index, .file = null },
2656 .offset = @intCast(u32, reloc_info.offset),2767 .offset = @intCast(u32, reloc_info.offset),
2657 .addend = reloc_info.addend,2768 .addend = reloc_info.addend,
...@@ -2790,6 +2901,28 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -2790,6 +2901,28 @@ fn populateMissingMetadata(self: *MachO) !void {
2790 self.segment_table_dirty = true;2901 self.segment_table_dirty = true;
2791 }2902 }
27922903
2904 if (!self.base.options.single_threaded) {
2905 if (self.thread_vars_section_index == null) {
2906 self.thread_vars_section_index = try self.allocateSection("__DATA2", "__thread_vars", .{
2907 .size = @sizeOf(u64) * 3,
2908 .alignment = @sizeOf(u64),
2909 .flags = macho.S_THREAD_LOCAL_VARIABLES,
2910 .prot = macho.PROT.READ | macho.PROT.WRITE,
2911 });
2912 self.segment_table_dirty = true;
2913 }
2914
2915 if (self.thread_data_section_index == null) {
2916 self.thread_data_section_index = try self.allocateSection("__DATA3", "__thread_data", .{
2917 .size = @sizeOf(u64),
2918 .alignment = @alignOf(u64),
2919 .flags = macho.S_THREAD_LOCAL_REGULAR,
2920 .prot = macho.PROT.READ | macho.PROT.WRITE,
2921 });
2922 self.segment_table_dirty = true;
2923 }
2924 }
2925
2793 if (self.linkedit_segment_cmd_index == null) {2926 if (self.linkedit_segment_cmd_index == null) {
2794 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);2927 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
27952928
...@@ -3077,28 +3210,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm...@@ -3077,28 +3210,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
3077 return vaddr;3210 return vaddr;
3078}3211}
30793212
3080fn getSectionPrecedence(header: macho.section_64) u4 {
3081 if (header.isCode()) {
3082 if (mem.eql(u8, "__text", header.sectName())) return 0x0;
3083 if (header.type() == macho.S_SYMBOL_STUBS) return 0x1;
3084 return 0x2;
3085 }
3086 switch (header.type()) {
3087 macho.S_NON_LAZY_SYMBOL_POINTERS,
3088 macho.S_LAZY_SYMBOL_POINTERS,
3089 => return 0x0,
3090 macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
3091 macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
3092 macho.S_ZEROFILL => return 0xf,
3093 macho.S_THREAD_LOCAL_REGULAR => return 0xd,
3094 macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,
3095 else => if (mem.eql(u8, "__eh_frame", header.sectName()))
3096 return 0xf
3097 else
3098 return 0x3,
3099 }
3100}
3101
3102pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {3213pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
3103 _ = lib_name;3214 _ = lib_name;
3104 const gpa = self.base.allocator;3215 const gpa = self.base.allocator;
...@@ -3474,8 +3585,8 @@ const SymtabCtx = struct {...@@ -3474,8 +3585,8 @@ const SymtabCtx = struct {
34743585
3475fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {3586fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3476 const gpa = self.base.allocator;3587 const gpa = self.base.allocator;
3477 const nstubs = @intCast(u32, self.stubs_table.count());3588 const nstubs = @intCast(u32, self.stubs_table.lookup.count());
3478 const ngot_entries = @intCast(u32, self.got_entries_table.count());3589 const ngot_entries = @intCast(u32, self.got_table.lookup.count());
3479 const nindirectsyms = nstubs * 2 + ngot_entries;3590 const nindirectsyms = nstubs * 2 + ngot_entries;
3480 const iextdefsym = ctx.nlocalsym;3591 const iextdefsym = ctx.nlocalsym;
3481 const iundefsym = iextdefsym + ctx.nextdefsym;3592 const iundefsym = iextdefsym + ctx.nextdefsym;
...@@ -3497,7 +3608,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {...@@ -3497,7 +3608,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3497 if (self.stubs_section_index) |sect_id| {3608 if (self.stubs_section_index) |sect_id| {
3498 const stubs = &self.sections.items(.header)[sect_id];3609 const stubs = &self.sections.items(.header)[sect_id];
3499 stubs.reserved1 = 0;3610 stubs.reserved1 = 0;
3500 for (self.stubs.items) |entry| {3611 for (self.stubs_table.entries.items) |entry| {
3501 if (entry.sym_index == 0) continue;3612 if (entry.sym_index == 0) continue;
3502 const target_sym = self.getSymbol(entry.target);3613 const target_sym = self.getSymbol(entry.target);
3503 assert(target_sym.undf());3614 assert(target_sym.undf());
...@@ -3508,7 +3619,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {...@@ -3508,7 +3619,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3508 if (self.got_section_index) |sect_id| {3619 if (self.got_section_index) |sect_id| {
3509 const got = &self.sections.items(.header)[sect_id];3620 const got = &self.sections.items(.header)[sect_id];
3510 got.reserved1 = nstubs;3621 got.reserved1 = nstubs;
3511 for (self.got_entries.items) |entry| {3622 for (self.got_table.entries.items) |entry| {
3512 if (entry.sym_index == 0) continue;3623 if (entry.sym_index == 0) continue;
3513 const target_sym = self.getSymbol(entry.target);3624 const target_sym = self.getSymbol(entry.target);
3514 if (target_sym.undf()) {3625 if (target_sym.undf()) {
...@@ -3522,7 +3633,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {...@@ -3522,7 +3633,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3522 if (self.la_symbol_ptr_section_index) |sect_id| {3633 if (self.la_symbol_ptr_section_index) |sect_id| {
3523 const la_symbol_ptr = &self.sections.items(.header)[sect_id];3634 const la_symbol_ptr = &self.sections.items(.header)[sect_id];
3524 la_symbol_ptr.reserved1 = nstubs + ngot_entries;3635 la_symbol_ptr.reserved1 = nstubs + ngot_entries;
3525 for (self.stubs.items) |entry| {3636 for (self.stubs_table.entries.items) |entry| {
3526 if (entry.sym_index == 0) continue;3637 if (entry.sym_index == 0) continue;
3527 const target_sym = self.getSymbol(entry.target);3638 const target_sym = self.getSymbol(entry.target);
3528 assert(target_sym.undf());3639 assert(target_sym.undf());
...@@ -3593,6 +3704,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {...@@ -3593,6 +3704,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
3593 var header: macho.mach_header_64 = .{};3704 var header: macho.mach_header_64 = .{};
3594 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;3705 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
35953706
3707 if (!self.base.options.single_threaded) {
3708 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
3709 }
3710
3596 switch (self.base.options.target.cpu.arch) {3711 switch (self.base.options.target.cpu.arch) {
3597 .aarch64 => {3712 .aarch64 => {
3598 header.cputype = macho.CPU_TYPE_ARM64;3713 header.cputype = macho.CPU_TYPE_ARM64;
...@@ -3617,12 +3732,6 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {...@@ -3617,12 +3732,6 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
3617 else => unreachable,3732 else => unreachable,
3618 }3733 }
36193734
3620 if (self.getSectionByName("__DATA", "__thread_vars")) |sect_id| {
3621 if (self.sections.items(.header)[sect_id].size > 0) {
3622 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
3623 }
3624 }
3625
3626 header.ncmds = ncmds;3735 header.ncmds = ncmds;
3627 header.sizeofcmds = sizeofcmds;3736 header.sizeofcmds = sizeofcmds;
36283737
...@@ -3802,8 +3911,7 @@ pub fn getSymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) macho.nlist_64...@@ -3802,8 +3911,7 @@ pub fn getSymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) macho.nlist_64
38023911
3803/// Returns name of the symbol described by `sym_with_loc` descriptor.3912/// Returns name of the symbol described by `sym_with_loc` descriptor.
3804pub fn getSymbolName(self: *const MachO, sym_with_loc: SymbolWithLoc) []const u8 {3913pub fn getSymbolName(self: *const MachO, sym_with_loc: SymbolWithLoc) []const u8 {
3805 assert(sym_with_loc.file == null);3914 const sym = self.getSymbol(sym_with_loc);
3806 const sym = self.locals.items[sym_with_loc.sym_index];
3807 return self.strtab.get(sym.n_strx).?;3915 return self.strtab.get(sym.n_strx).?;
3808}3916}
38093917
...@@ -3867,20 +3975,6 @@ pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.In...@@ -3867,20 +3975,6 @@ pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.In
3867 return self.atom_by_index_table.get(sym_with_loc.sym_index);3975 return self.atom_by_index_table.get(sym_with_loc.sym_index);
3868}3976}
38693977
3870/// Returns GOT atom that references `sym_with_loc` if one exists.
3871/// Returns null otherwise.
3872pub fn getGotAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
3873 const got_index = self.got_entries_table.get(sym_with_loc) orelse return null;
3874 return self.got_entries.items[got_index].getAtomIndex(self);
3875}
3876
3877/// Returns stubs atom that references `sym_with_loc` if one exists.
3878/// Returns null otherwise.
3879pub fn getStubsAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
3880 const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null;
3881 return self.stubs.items[stubs_index].getAtomIndex(self);
3882}
3883
3884/// Returns symbol location corresponding to the set entrypoint.3978/// Returns symbol location corresponding to the set entrypoint.
3885/// Asserts output mode is executable.3979/// Asserts output mode is executable.
3886pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {3980pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
...@@ -4227,37 +4321,13 @@ pub fn logSymtab(self: *MachO) void {...@@ -4227,37 +4321,13 @@ pub fn logSymtab(self: *MachO) void {
4227 }4321 }
42284322
4229 log.debug("GOT entries:", .{});4323 log.debug("GOT entries:", .{});
4230 for (self.got_entries.items, 0..) |entry, i| {4324 log.debug("{}", .{self.got_table.fmtDebug(self)});
4231 const atom_sym = entry.getSymbol(self);
4232 const target_sym = self.getSymbol(entry.target);
4233 if (target_sym.undf()) {
4234 log.debug(" {d}@{x} => import('{s}')", .{
4235 i,
4236 atom_sym.n_value,
4237 self.getSymbolName(entry.target),
4238 });
4239 } else {
4240 log.debug(" {d}@{x} => local(%{d}) in object({?d}) {s}", .{
4241 i,
4242 atom_sym.n_value,
4243 entry.target.sym_index,
4244 entry.target.file,
4245 logSymAttributes(target_sym, &buf),
4246 });
4247 }
4248 }
42494325
4250 log.debug("stubs entries:", .{});4326 log.debug("stubs entries:", .{});
4251 for (self.stubs.items, 0..) |entry, i| {4327 log.debug("{}", .{self.stubs_table.fmtDebug(self)});
4252 const target_sym = self.getSymbol(entry.target);4328
4253 const atom_sym = entry.getSymbol(self);4329 log.debug("threadlocal entries:", .{});
4254 assert(target_sym.undf());4330 log.debug("{}", .{self.tlv_table.fmtDebug(self)});
4255 log.debug(" {d}@{x} => import('{s}')", .{
4256 i,
4257 atom_sym.n_value,
4258 self.getSymbolName(entry.target),
4259 });
4260 }
4261}4331}
42624332
4263pub fn logAtoms(self: *MachO) void {4333pub fn logAtoms(self: *MachO) void {
src/link/MachO/Atom.zig+5-11
...@@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace;...@@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace;
14const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
15const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
16const MachO = @import("../MachO.zig");16const MachO = @import("../MachO.zig");
17const Relocation = @import("Relocation.zig");17pub const Relocation = @import("Relocation.zig");
18const SymbolWithLoc = MachO.SymbolWithLoc;18const SymbolWithLoc = MachO.SymbolWithLoc;
1919
20/// Each decl always gets a local symbol with the fully qualified name.20/// Each decl always gets a local symbol with the fully qualified name.
...@@ -113,25 +113,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {...@@ -113,25 +113,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
113}113}
114114
115pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {115pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {
116 return addRelocations(macho_file, atom_index, 1, .{reloc});116 return addRelocations(macho_file, atom_index, &[_]Relocation{reloc});
117}117}
118118
119pub fn addRelocations(119pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation) !void {
120 macho_file: *MachO,
121 atom_index: Index,
122 comptime count: comptime_int,
123 relocs: [count]Relocation,
124) !void {
125 const gpa = macho_file.base.allocator;120 const gpa = macho_file.base.allocator;
126 const target = macho_file.base.options.target;
127 const gop = try macho_file.relocs.getOrPut(gpa, atom_index);121 const gop = try macho_file.relocs.getOrPut(gpa, atom_index);
128 if (!gop.found_existing) {122 if (!gop.found_existing) {
129 gop.value_ptr.* = .{};123 gop.value_ptr.* = .{};
130 }124 }
131 try gop.value_ptr.ensureUnusedCapacity(gpa, count);125 try gop.value_ptr.ensureUnusedCapacity(gpa, relocs.len);
132 for (relocs) |reloc| {126 for (relocs) |reloc| {
133 log.debug(" (adding reloc of type {s} to target %{d})", .{127 log.debug(" (adding reloc of type {s} to target %{d})", .{
134 reloc.fmtType(target),128 @tagName(reloc.type),
135 reloc.target.sym_index,129 reloc.target.sym_index,
136 });130 });
137 gop.value_ptr.appendAssumeCapacity(reloc);131 gop.value_ptr.appendAssumeCapacity(reloc);
src/link/MachO/DebugSymbols.zig+6-12
...@@ -226,26 +226,20 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -226,26 +226,20 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
226226
227 for (self.relocs.items) |*reloc| {227 for (self.relocs.items) |*reloc| {
228 const sym = switch (reloc.type) {228 const sym = switch (reloc.type) {
229 .direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target, .file = null }),229 .direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target }),
230 .got_load => blk: {230 .got_load => blk: {
231 const got_index = macho_file.got_entries_table.get(.{231 const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
232 .sym_index = reloc.target,232 const got_entry = macho_file.got_table.entries.items[got_index];
233 .file = null,
234 }).?;
235 const got_entry = macho_file.got_entries.items[got_index];
236 break :blk got_entry.getSymbol(macho_file);233 break :blk got_entry.getSymbol(macho_file);
237 },234 },
238 };235 };
239 if (sym.n_value == reloc.prev_vaddr) continue;236 if (sym.n_value == reloc.prev_vaddr) continue;
240237
241 const sym_name = switch (reloc.type) {238 const sym_name = switch (reloc.type) {
242 .direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target, .file = null }),239 .direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target }),
243 .got_load => blk: {240 .got_load => blk: {
244 const got_index = macho_file.got_entries_table.get(.{241 const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
245 .sym_index = reloc.target,242 const got_entry = macho_file.got_table.entries.items[got_index];
246 .file = null,
247 }).?;
248 const got_entry = macho_file.got_entries.items[got_index];
249 break :blk got_entry.getName(macho_file);243 break :blk got_entry.getName(macho_file);
250 },244 },
251 };245 };
src/link/MachO/Relocation.zig+93-143
...@@ -1,19 +1,7 @@...@@ -1,19 +1,7 @@
1const Relocation = @This();1//! Relocation used by the self-hosted backends to instruct the linker where and how to
2//! fixup the values when flushing the contents to file and/or memory.
23
3const std = @import("std");4type: Type,
4const aarch64 = @import("../../arch/aarch64/bits.zig");
5const assert = std.debug.assert;
6const log = std.log.scoped(.link);
7const macho = std.macho;
8const math = std.math;
9const mem = std.mem;
10const meta = std.meta;
11
12const Atom = @import("Atom.zig");
13const MachO = @import("../MachO.zig");
14const SymbolWithLoc = MachO.SymbolWithLoc;
15
16type: u4,
17target: SymbolWithLoc,5target: SymbolWithLoc,
18offset: u32,6offset: u32,
19addend: i64,7addend: i64,
...@@ -21,39 +9,55 @@ pcrel: bool,...@@ -21,39 +9,55 @@ pcrel: bool,
21length: u2,9length: u2,
22dirty: bool = true,10dirty: bool = true,
2311
12pub const Type = enum {
13 // x86, x86_64
14 /// RIP-relative displacement to a GOT pointer
15 got,
16 /// RIP-relative displacement
17 signed,
18 /// RIP-relative displacement to GOT pointer to TLV thunk
19 tlv,
20
21 // aarch64
22 /// PC-relative distance to target page in GOT section
23 got_page,
24 /// Offset to a GOT pointer relative to the start of a page in GOT section
25 got_pageoff,
26 /// PC-relative distance to target page in a section
27 page,
28 /// Offset to a pointer relative to the start of a page in a section
29 pageoff,
30
31 // common
32 /// PC/RIP-relative displacement B/BL/CALL
33 branch,
34 /// Absolute pointer value
35 unsigned,
36 /// Relative offset to TLV initializer
37 tlv_initializer,
38};
39
24/// Returns true if and only if the reloc is dirty AND the target address is available.40/// Returns true if and only if the reloc is dirty AND the target address is available.
25pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {41pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
26 _ = self.getTargetAtomIndex(macho_file) orelse return false;42 _ = self.getTargetAtomIndex(macho_file) orelse return false;
27 return self.dirty;43 return self.dirty;
28}44}
2945
30pub fn fmtType(self: Relocation, target: std.Target) []const u8 {
31 switch (target.cpu.arch) {
32 .aarch64 => return @tagName(@intToEnum(macho.reloc_type_arm64, self.type)),
33 .x86_64 => return @tagName(@intToEnum(macho.reloc_type_x86_64, self.type)),
34 else => unreachable,
35 }
36}
37
38pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {46pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
39 switch (macho_file.base.options.target.cpu.arch) {47 return switch (self.type) {
40 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) {48 .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
41 .ARM64_RELOC_GOT_LOAD_PAGE21,49 .tlv => {
42 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,50 const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse
43 .ARM64_RELOC_POINTER_TO_GOT,51 return null;
44 => return macho_file.getGotAtomIndexForSymbol(self.target),52 const thunk_atom = macho_file.getAtom(thunk_atom_index);
45 else => {},53 return macho_file.got_table.getAtomIndex(macho_file, thunk_atom.getSymbolWithLoc());
46 },54 },
47 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) {55 .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
48 .X86_64_RELOC_GOT,56 index
49 .X86_64_RELOC_GOT_LOAD,57 else
50 => return macho_file.getGotAtomIndexForSymbol(self.target),58 macho_file.getAtomIndexForSymbol(self.target),
51 else => {},59 else => macho_file.getAtomIndexForSymbol(self.target),
52 },60 };
53 else => unreachable,
54 }
55 if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;
56 return macho_file.getAtomIndexForSymbol(self.target);
57}61}
5862
59pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {63pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {
...@@ -64,13 +68,22 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -64,13 +68,22 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
6468
65 const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().69 const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
66 const target_atom = macho_file.getAtom(target_atom_index);70 const target_atom = macho_file.getAtom(target_atom_index);
67 const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend;71
72 const target_addr: i64 = switch (self.type) {
73 .tlv_initializer => blk: {
74 assert(self.addend == 0); // Addend here makes no sense.
75 const header = macho_file.sections.items(.header)[macho_file.thread_data_section_index.?];
76 const target_sym = target_atom.getSymbol(macho_file);
77 break :blk @intCast(i64, target_sym.n_value - header.addr);
78 },
79 else => @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend,
80 };
6881
69 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{82 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
70 source_addr,83 source_addr,
71 target_addr,84 target_addr,
72 macho_file.getSymbolName(self.target),85 macho_file.getSymbolName(self.target),
73 self.fmtType(macho_file.base.options.target),86 @tagName(self.type),
74 });87 });
7588
76 switch (arch) {89 switch (arch) {
...@@ -81,18 +94,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -81,18 +94,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
81}94}
8295
83fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {96fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
84 const rel_type = @intToEnum(macho.reloc_type_arm64, self.type);97 var buffer = code[self.offset..];
85 if (rel_type == .ARM64_RELOC_UNSIGNED) {98 switch (self.type) {
86 return switch (self.length) {99 .branch => {
87 2 => mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr))),
88 3 => mem.writeIntLittle(u64, code[self.offset..][0..8], @bitCast(u64, target_addr)),
89 else => unreachable,
90 };
91 }
92
93 var buffer = code[self.offset..][0..4];
94 switch (rel_type) {
95 .ARM64_RELOC_BRANCH26 => {
96 const displacement = math.cast(100 const displacement = math.cast(
97 i28,101 i28,
98 @intCast(i64, target_addr) - @intCast(i64, source_addr),102 @intCast(i64, target_addr) - @intCast(i64, source_addr),
...@@ -101,15 +105,12 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -101,15 +105,12 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
101 .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(105 .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(
102 aarch64.Instruction,106 aarch64.Instruction,
103 aarch64.Instruction.unconditional_branch_immediate,107 aarch64.Instruction.unconditional_branch_immediate,
104 ), buffer),108 ), buffer[0..4]),
105 };109 };
106 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));110 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
107 mem.writeIntLittle(u32, buffer, inst.toU32());111 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
108 },112 },
109 .ARM64_RELOC_PAGE21,113 .page, .got_page => {
110 .ARM64_RELOC_GOT_LOAD_PAGE21,
111 .ARM64_RELOC_TLVP_LOAD_PAGE21,
112 => {
113 const source_page = @intCast(i32, source_addr >> 12);114 const source_page = @intCast(i32, source_addr >> 12);
114 const target_page = @intCast(i32, target_addr >> 12);115 const target_page = @intCast(i32, target_addr >> 12);
115 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));116 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
...@@ -117,31 +118,29 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -117,31 +118,29 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
117 .pc_relative_address = mem.bytesToValue(meta.TagPayload(118 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
118 aarch64.Instruction,119 aarch64.Instruction,
119 aarch64.Instruction.pc_relative_address,120 aarch64.Instruction.pc_relative_address,
120 ), buffer),121 ), buffer[0..4]),
121 };122 };
122 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);123 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
123 inst.pc_relative_address.immlo = @truncate(u2, pages);124 inst.pc_relative_address.immlo = @truncate(u2, pages);
124 mem.writeIntLittle(u32, buffer, inst.toU32());125 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
125 },126 },
126 .ARM64_RELOC_PAGEOFF12,127 .pageoff, .got_pageoff => {
127 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
128 => {
129 const narrowed = @truncate(u12, @intCast(u64, target_addr));128 const narrowed = @truncate(u12, @intCast(u64, target_addr));
130 if (isArithmeticOp(buffer)) {129 if (isArithmeticOp(buffer[0..4])) {
131 var inst = aarch64.Instruction{130 var inst = aarch64.Instruction{
132 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(131 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
133 aarch64.Instruction,132 aarch64.Instruction,
134 aarch64.Instruction.add_subtract_immediate,133 aarch64.Instruction.add_subtract_immediate,
135 ), buffer),134 ), buffer[0..4]),
136 };135 };
137 inst.add_subtract_immediate.imm12 = narrowed;136 inst.add_subtract_immediate.imm12 = narrowed;
138 mem.writeIntLittle(u32, buffer, inst.toU32());137 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
139 } else {138 } else {
140 var inst = aarch64.Instruction{139 var inst = aarch64.Instruction{
141 .load_store_register = mem.bytesToValue(meta.TagPayload(140 .load_store_register = mem.bytesToValue(meta.TagPayload(
142 aarch64.Instruction,141 aarch64.Instruction,
143 aarch64.Instruction.load_store_register,142 aarch64.Instruction.load_store_register,
144 ), buffer),143 ), buffer[0..4]),
145 };144 };
146 const offset: u12 = blk: {145 const offset: u12 = blk: {
147 if (inst.load_store_register.size == 0) {146 if (inst.load_store_register.size == 0) {
...@@ -157,89 +156,25 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -157,89 +156,25 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
157 }156 }
158 };157 };
159 inst.load_store_register.offset = offset;158 inst.load_store_register.offset = offset;
160 mem.writeIntLittle(u32, buffer, inst.toU32());159 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
161 }160 }
162 },161 },
163 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {162 .tlv_initializer, .unsigned => switch (self.length) {
164 const RegInfo = struct {163 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
165 rd: u5,164 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
166 rn: u5,165 else => unreachable,
167 size: u2,
168 };
169 const reg_info: RegInfo = blk: {
170 if (isArithmeticOp(buffer)) {
171 const inst = mem.bytesToValue(meta.TagPayload(
172 aarch64.Instruction,
173 aarch64.Instruction.add_subtract_immediate,
174 ), buffer);
175 break :blk .{
176 .rd = inst.rd,
177 .rn = inst.rn,
178 .size = inst.sf,
179 };
180 } else {
181 const inst = mem.bytesToValue(meta.TagPayload(
182 aarch64.Instruction,
183 aarch64.Instruction.load_store_register,
184 ), buffer);
185 break :blk .{
186 .rd = inst.rt,
187 .rn = inst.rn,
188 .size = inst.size,
189 };
190 }
191 };
192 const narrowed = @truncate(u12, @intCast(u64, target_addr));
193 var inst = aarch64.Instruction{
194 .add_subtract_immediate = .{
195 .rd = reg_info.rd,
196 .rn = reg_info.rn,
197 .imm12 = narrowed,
198 .sh = 0,
199 .s = 0,
200 .op = 0,
201 .sf = @truncate(u1, reg_info.size),
202 },
203 };
204 mem.writeIntLittle(u32, buffer, inst.toU32());
205 },
206 .ARM64_RELOC_POINTER_TO_GOT => {
207 const result = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr));
208 mem.writeIntLittle(i32, buffer, result);
209 },166 },
210 .ARM64_RELOC_SUBTRACTOR => unreachable,167 .got, .signed, .tlv => unreachable, // Invalid target architecture.
211 .ARM64_RELOC_ADDEND => unreachable,
212 .ARM64_RELOC_UNSIGNED => unreachable,
213 }168 }
214}169}
215170
216fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {171fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
217 const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type);172 switch (self.type) {
218 switch (rel_type) {173 .branch, .got, .tlv, .signed => {
219 .X86_64_RELOC_BRANCH,
220 .X86_64_RELOC_GOT,
221 .X86_64_RELOC_GOT_LOAD,
222 .X86_64_RELOC_TLV,
223 => {
224 const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);174 const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);
225 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));175 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
226 },176 },
227 .X86_64_RELOC_SIGNED,177 .tlv_initializer, .unsigned => {
228 .X86_64_RELOC_SIGNED_1,
229 .X86_64_RELOC_SIGNED_2,
230 .X86_64_RELOC_SIGNED_4,
231 => {
232 const correction: u3 = switch (rel_type) {
233 .X86_64_RELOC_SIGNED => 0,
234 .X86_64_RELOC_SIGNED_1 => 1,
235 .X86_64_RELOC_SIGNED_2 => 2,
236 .X86_64_RELOC_SIGNED_4 => 4,
237 else => unreachable,
238 };
239 const displacement = @intCast(i32, target_addr - @intCast(i64, source_addr + correction + 4));
240 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
241 },
242 .X86_64_RELOC_UNSIGNED => {
243 switch (self.length) {178 switch (self.length) {
244 2 => {179 2 => {
245 mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));180 mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));
...@@ -250,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8...@@ -250,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
250 else => unreachable,185 else => unreachable,
251 }186 }
252 },187 },
253 .X86_64_RELOC_SUBTRACTOR => unreachable,188 .got_page, .got_pageoff, .page, .pageoff => unreachable, // Invalid target architecture.
254 }189 }
255}190}
256191
...@@ -258,3 +193,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool {...@@ -258,3 +193,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool {
258 const group_decode = @truncate(u5, inst[3]);193 const group_decode = @truncate(u5, inst[3]);
259 return ((group_decode >> 2) == 4);194 return ((group_decode >> 2) == 4);
260}195}
196
197const Relocation = @This();
198
199const std = @import("std");
200const aarch64 = @import("../../arch/aarch64/bits.zig");
201const assert = std.debug.assert;
202const log = std.log.scoped(.link);
203const macho = std.macho;
204const math = std.math;
205const mem = std.mem;
206const meta = std.meta;
207
208const Atom = @import("Atom.zig");
209const MachO = @import("../MachO.zig");
210const SymbolWithLoc = MachO.SymbolWithLoc;