| author | |
| committer | |
| log | 5e19250a1251e7857b5679949085fa1fb3f9bdcd |
| tree | 0aae5737ccb62456fcb4b099a07ff015a82c1989 |
| parent | 25e3851fe0f7fe254b48c2242ab8d4ef89165fd5 |
| parent | a34752c941c81e600c56670abb612fc86d0a2b73 |
| signature |
macho: add TLS support18 files changed, 878 insertions(+), 530 deletions(-)
ci/x86_64-macos-debug.sh-1| ... | ... | @@ -51,7 +51,6 @@ stage3/bin/zig build test docs \ |
| 51 | 51 | --zig-lib-dir "$(pwd)/../lib" \ |
| 52 | 52 | -Denable-macos-sdk \ |
| 53 | 53 | -Dstatic-llvm \ |
| 54 | -Dskip-non-native \ | |
| 55 | 54 | --search-prefix "$PREFIX" |
| 56 | 55 | |
| 57 | 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 | 51 | --zig-lib-dir "$(pwd)/../lib" \ |
| 52 | 52 | -Denable-macos-sdk \ |
| 53 | 53 | -Dstatic-llvm \ |
| 54 | -Dskip-non-native \ | |
| 55 | 54 | --search-prefix "$PREFIX" |
| 56 | 55 | |
| 57 | 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 | 6171 | .linker_load => |ll| .{ .linker_load = ll }, |
| 6172 | 6172 | .immediate => |imm| .{ .immediate = imm }, |
| 6173 | 6173 | .memory => |addr| .{ .memory = addr }, |
| 6174 | .tlv_reloc => unreachable, // TODO | |
| 6174 | 6175 | }, |
| 6175 | 6176 | .fail => |msg| { |
| 6176 | 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 | 673 | const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; |
| 674 | 674 | const target = macho_file.getGlobalByIndex(relocation.sym_index); |
| 675 | 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 | 677 | .target = target, |
| 678 | 678 | .offset = offset, |
| 679 | 679 | .addend = 0, |
| ... | ... | @@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 883 | 883 | } |
| 884 | 884 | |
| 885 | 885 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 886 | const Atom = link.File.MachO.Atom; | |
| 887 | const Relocation = Atom.Relocation; | |
| 886 | 888 | const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; |
| 887 | // TODO this causes segfault in stage1 | |
| 888 | // try atom.addRelocations(macho_file, 2, .{ | |
| 889 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ | |
| 889 | try Atom.addRelocations(macho_file, atom_index, &[_]Relocation{ .{ | |
| 890 | 890 | .target = .{ .sym_index = data.sym_index, .file = null }, |
| 891 | 891 | .offset = offset, |
| 892 | 892 | .addend = 0, |
| 893 | 893 | .pcrel = true, |
| 894 | 894 | .length = 2, |
| 895 | 895 | .type = switch (tag) { |
| 896 | .load_memory_got, | |
| 897 | .load_memory_ptr_got, | |
| 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), | |
| 896 | .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_page, | |
| 897 | .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.page, | |
| 902 | 898 | else => unreachable, |
| 903 | 899 | }, |
| 904 | }); | |
| 905 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ | |
| 900 | }, .{ | |
| 906 | 901 | .target = .{ .sym_index = data.sym_index, .file = null }, |
| 907 | 902 | .offset = offset + 4, |
| 908 | 903 | .addend = 0, |
| 909 | 904 | .pcrel = false, |
| 910 | 905 | .length = 2, |
| 911 | 906 | .type = switch (tag) { |
| 912 | .load_memory_got, | |
| 913 | .load_memory_ptr_got, | |
| 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), | |
| 907 | .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_pageoff, | |
| 908 | .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.pageoff, | |
| 918 | 909 | else => unreachable, |
| 919 | 910 | }, |
| 920 | }); | |
| 911 | } }); | |
| 921 | 912 | } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { |
| 922 | 913 | const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; |
| 923 | 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 | 6114 | .mcv => |mcv| switch (mcv) { |
| 6115 | 6115 | .none => .none, |
| 6116 | 6116 | .undef => .undef, |
| 6117 | .linker_load => unreachable, // TODO | |
| 6117 | .tlv_reloc, .linker_load => unreachable, // TODO | |
| 6118 | 6118 | .immediate => |imm| .{ .immediate = @truncate(u32, imm) }, |
| 6119 | 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 | 2572 | .mcv => |mcv| switch (mcv) { |
| 2573 | 2573 | .none => .none, |
| 2574 | 2574 | .undef => .undef, |
| 2575 | .linker_load => unreachable, // TODO | |
| 2575 | .tlv_reloc, .linker_load => unreachable, // TODO | |
| 2576 | 2576 | .immediate => |imm| .{ .immediate = imm }, |
| 2577 | 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 | 3931 | .mcv => |mcv| switch (mcv) { |
| 3932 | 3932 | .none => .none, |
| 3933 | 3933 | .undef => .undef, |
| 3934 | .linker_load => unreachable, // TODO | |
| 3934 | .tlv_reloc, .linker_load => unreachable, // TODO | |
| 3935 | 3935 | .immediate => |imm| .{ .immediate = imm }, |
| 3936 | 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 | 132 | memory: u64, |
| 133 | 133 | /// The value is in memory but requires a linker relocation fixup. |
| 134 | 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 | 139 | /// The value is one of the stack variables. |
| 136 | 140 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 137 | 141 | stack_offset: i32, |
| ... | ... | @@ -146,6 +150,7 @@ pub const MCValue = union(enum) { |
| 146 | 150 | .stack_offset, |
| 147 | 151 | .ptr_stack_offset, |
| 148 | 152 | .linker_load, |
| 153 | .tlv_reloc, | |
| 149 | 154 | => true, |
| 150 | 155 | else => false, |
| 151 | 156 | }; |
| ... | ... | @@ -731,6 +736,40 @@ fn asmMemoryRegisterImmediate( |
| 731 | 736 | }); |
| 732 | 737 | } |
| 733 | 738 | |
| 739 | fn 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 | ||
| 756 | fn 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 | ||
| 734 | 773 | fn gen(self: *Self) InnerError!void { |
| 735 | 774 | const cc = self.fn_type.fnCallingConvention(); |
| 736 | 775 | if (cc != .Naked) { |
| ... | ... | @@ -2863,7 +2902,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2863 | 2902 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2864 | 2903 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2865 | 2904 | |
| 2866 | const addr_reg = try self.register_manager.allocReg(null, gp); | |
| 2905 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | |
| 2867 | 2906 | switch (array) { |
| 2868 | 2907 | .register => { |
| 2869 | 2908 | const off = @intCast(i32, try self.allocMem( |
| ... | ... | @@ -2872,19 +2911,33 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2872 | 2911 | array_ty.abiAlignment(self.target.*), |
| 2873 | 2912 | )); |
| 2874 | 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 | 2915 | .base = .rbp, |
| 2877 | 2916 | .disp = -off, |
| 2878 | 2917 | })); |
| 2879 | 2918 | }, |
| 2880 | 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 | 2921 | .base = .rbp, |
| 2883 | 2922 | .disp = -off, |
| 2884 | 2923 | })); |
| 2885 | 2924 | }, |
| 2886 | .memory, .linker_load => { | |
| 2887 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array); | |
| 2925 | .memory => |addr| try self.genSetReg(Type.usize, addr_reg, .{ .immediate = addr }), | |
| 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 | 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 | 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 | 3654 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 3602 | 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 | } |
| 3606 | 3679 | |
| ... | ... | @@ -3630,41 +3703,6 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3630 | 3703 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3631 | 3704 | } |
| 3632 | 3705 | |
| 3633 | fn 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 | ||
| 3668 | 3706 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 3669 | 3707 | const abi_size = @intCast(u32, value_ty.abiSize(self.target.*)); |
| 3670 | 3708 | switch (ptr) { |
| ... | ... | @@ -3775,11 +3813,29 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3775 | 3813 | |
| 3776 | 3814 | try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 3777 | 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 | 3817 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 3780 | 3818 | defer self.register_manager.unlockReg(addr_lock); |
| 3781 | 3819 | |
| 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 | 3839 | try self.genInlineMemcpy( |
| 3784 | 3840 | ptr, |
| 3785 | 3841 | .{ .register = addr_reg }, |
| ... | ... | @@ -3799,7 +3855,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3799 | 3855 | .{ .immediate = abi_size }, |
| 3800 | 3856 | .{}, |
| 3801 | 3857 | ), |
| 3802 | .ptr_stack_offset => { | |
| 3858 | .ptr_stack_offset, .tlv_reloc => { | |
| 3803 | 3859 | const tmp_reg = try self.copyToTmpRegister(value_ty, value); |
| 3804 | 3860 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 3805 | 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 | 3871 | }; |
| 3816 | 3872 | defer if (value_lock) |lock| self.register_manager.unlockReg(lock); |
| 3817 | 3873 | |
| 3818 | const addr_reg = try self.register_manager.allocReg(null, gp); | |
| 3874 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | |
| 3819 | 3875 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 3820 | 3876 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 3821 | 3877 | |
| 3822 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); | |
| 3823 | // Load the pointer, which is stored in memory | |
| 3824 | try self.asmRegisterMemory( | |
| 3825 | .mov, | |
| 3826 | addr_reg.to64(), | |
| 3827 | Memory.sib(.qword, .{ .base = addr_reg.to64() }), | |
| 3828 | ); | |
| 3878 | switch (ptr) { | |
| 3879 | .memory => |addr| { | |
| 3880 | try self.genSetReg(ptr_ty, addr_reg, .{ .immediate = addr }); | |
| 3881 | // Load the pointer, which is stored in memory | |
| 3882 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ .base = addr_reg })); | |
| 3883 | }, | |
| 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 | } | |
| 3829 | 3899 | |
| 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 | 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 | 3953 | |
| 3876 | 3954 | const dst_mcv: MCValue = result: { |
| 3877 | 3955 | switch (mcv) { |
| 3878 | .stack_offset => { | |
| 3956 | .stack_offset, .tlv_reloc => { | |
| 3879 | 3957 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| 3880 | 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 | 4235 | })); |
| 4158 | 4236 | }, |
| 4159 | 4237 | .ptr_stack_offset => unreachable, |
| 4238 | .tlv_reloc => unreachable, | |
| 4160 | 4239 | .memory, .linker_load => { |
| 4161 | 4240 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| 4162 | 4241 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4163 | 4242 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4164 | 4243 | |
| 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 | 4263 | try self.asmMemory( |
| 4167 | 4264 | mir_tag, |
| 4168 | 4265 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| ... | ... | @@ -4800,6 +4897,7 @@ fn genBinOp( |
| 4800 | 4897 | .eflags, |
| 4801 | 4898 | .register_overflow, |
| 4802 | 4899 | .ptr_stack_offset, |
| 4900 | .tlv_reloc, | |
| 4803 | 4901 | => unreachable, |
| 4804 | 4902 | .register => |src_reg| try self.asmCmovccRegisterRegister( |
| 4805 | 4903 | registerAlias(tmp_reg, cmov_abi_size), |
| ... | ... | @@ -4819,7 +4917,26 @@ fn genBinOp( |
| 4819 | 4917 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4820 | 4918 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4821 | 4919 | |
| 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 | 4940 | try self.asmCmovccRegisterMemory( |
| 4824 | 4941 | registerAlias(tmp_reg, cmov_abi_size), |
| 4825 | 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 | 4982 | .undef => unreachable, |
| 4866 | 4983 | .dead, .unreach => unreachable, |
| 4867 | 4984 | .register_overflow => unreachable, |
| 4868 | .ptr_stack_offset => { | |
| 4985 | .ptr_stack_offset, .tlv_reloc => { | |
| 4869 | 4986 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 4870 | 4987 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4871 | 4988 | |
| ... | ... | @@ -4942,11 +5059,30 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4942 | 5059 | } = switch (dst_mcv) { |
| 4943 | 5060 | else => unreachable, |
| 4944 | 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 | 5063 | const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| 4947 | 5064 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 4948 | 5065 | |
| 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 | 5086 | break :dst .{ |
| 4951 | 5087 | .addr_reg = dst_addr_reg, |
| 4952 | 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 | 5104 | const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg); |
| 4969 | 5105 | errdefer self.register_manager.unlockReg(src_limb_lock); |
| 4970 | 5106 | |
| 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 | 5108 | const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 4973 | 5109 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 4974 | 5110 | |
| 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 | 5131 | break :src .{ |
| 4977 | 5132 | .addr_reg = src_addr_reg, |
| 4978 | 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 | 5233 | else => unreachable, |
| 5079 | 5234 | } |
| 5080 | 5235 | }, |
| 5081 | .memory, .linker_load => { | |
| 5236 | .memory, .linker_load, .tlv_reloc => { | |
| 5082 | 5237 | try self.asmRegisterMemory( |
| 5083 | 5238 | .mov, |
| 5084 | 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 | 5272 | } |
| 5118 | 5273 | }, |
| 5119 | 5274 | .ptr_stack_offset => unreachable, |
| 5275 | .tlv_reloc => unreachable, | |
| 5120 | 5276 | } |
| 5121 | 5277 | } |
| 5122 | 5278 | |
| ... | ... | @@ -5130,6 +5286,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 5130 | 5286 | .dead, .unreach, .immediate => unreachable, |
| 5131 | 5287 | .eflags => unreachable, |
| 5132 | 5288 | .ptr_stack_offset => unreachable, |
| 5289 | .tlv_reloc => unreachable, | |
| 5133 | 5290 | .register_overflow => unreachable, |
| 5134 | 5291 | .register => |dst_reg| { |
| 5135 | 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 | 5298 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), |
| 5142 | 5299 | .dead, .unreach => unreachable, |
| 5143 | 5300 | .ptr_stack_offset => unreachable, |
| 5301 | .tlv_reloc => unreachable, | |
| 5144 | 5302 | .register_overflow => unreachable, |
| 5145 | 5303 | .register => |src_reg| try self.asmRegisterRegister( |
| 5146 | 5304 | .imul, |
| ... | ... | @@ -5184,6 +5342,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 5184 | 5342 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), |
| 5185 | 5343 | .dead, .unreach => unreachable, |
| 5186 | 5344 | .ptr_stack_offset => unreachable, |
| 5345 | .tlv_reloc => unreachable, | |
| 5187 | 5346 | .register_overflow => unreachable, |
| 5188 | 5347 | .register => |src_reg| { |
| 5189 | 5348 | // copy dst to a register |
| ... | ... | @@ -5406,6 +5565,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5406 | 5565 | .linker_load => unreachable, |
| 5407 | 5566 | .eflags => unreachable, |
| 5408 | 5567 | .register_overflow => unreachable, |
| 5568 | .tlv_reloc => unreachable, | |
| 5409 | 5569 | } |
| 5410 | 5570 | } |
| 5411 | 5571 | |
| ... | ... | @@ -5444,6 +5604,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5444 | 5604 | .linker_load => unreachable, |
| 5445 | 5605 | .eflags => unreachable, |
| 5446 | 5606 | .register_overflow => unreachable, |
| 5607 | .tlv_reloc => unreachable, | |
| 5447 | 5608 | } |
| 5448 | 5609 | } |
| 5449 | 5610 | |
| ... | ... | @@ -5965,6 +6126,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5965 | 6126 | .register_overflow, |
| 5966 | 6127 | .ptr_stack_offset, |
| 5967 | 6128 | .eflags, |
| 6129 | .tlv_reloc, | |
| 5968 | 6130 | => unreachable, |
| 5969 | 6131 | |
| 5970 | 6132 | .register => |opt_reg| { |
| ... | ... | @@ -5990,7 +6152,25 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5990 | 6152 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 5991 | 6153 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 5992 | 6154 | |
| 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 | } | |
| 5994 | 6174 | |
| 5995 | 6175 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); |
| 5996 | 6176 | try self.asmMemoryImmediate(.cmp, Memory.sib( |
| ... | ... | @@ -6925,11 +7105,30 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 6925 | 7105 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 6926 | 7106 | } |
| 6927 | 7107 | |
| 6928 | const addr_reg = try self.register_manager.allocReg(null, gp); | |
| 7108 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | |
| 6929 | 7109 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 6930 | 7110 | defer self.register_manager.unlockReg(addr_lock); |
| 6931 | 7111 | |
| 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 | 7132 | try self.genInlineMemcpy( |
| 6934 | 7133 | .{ .ptr_stack_offset = stack_offset }, |
| 6935 | 7134 | .{ .register = addr_reg }, |
| ... | ... | @@ -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 | 7174 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 6976 | 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 | 7332 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 7134 | 7333 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 7135 | 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 | 7336 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 7138 | 7337 | defer self.register_manager.unlockReg(addr_lock); |
| 7139 | 7338 | |
| 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 | 7359 | try self.genInlineMemcpy( |
| 7142 | 7360 | .{ .ptr_stack_offset = stack_offset }, |
| 7143 | 7361 | .{ .register = addr_reg }, |
| ... | ... | @@ -7157,7 +7375,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 7157 | 7375 | .{ .immediate = abi_size }, |
| 7158 | 7376 | .{}, |
| 7159 | 7377 | ), |
| 7160 | .ptr_stack_offset => { | |
| 7378 | .ptr_stack_offset, .tlv_reloc => { | |
| 7161 | 7379 | const tmp_reg = try self.copyToTmpRegister(ty, mcv); |
| 7162 | 7380 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 7163 | 7381 | defer self.register_manager.unlockReg(tmp_lock); |
| ... | ... | @@ -7247,11 +7465,26 @@ fn genInlineMemcpy( |
| 7247 | 7465 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); |
| 7248 | 7466 | |
| 7249 | 7467 | switch (dst_ptr) { |
| 7250 | .memory, .linker_load => { | |
| 7251 | try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr); | |
| 7468 | .memory => |addr| { | |
| 7469 | try self.genSetReg(Type.usize, .rdi, .{ .immediate = addr }); | |
| 7252 | 7470 | // Load the pointer, which is stored in memory |
| 7253 | 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 | 7488 | .stack_offset, .ptr_stack_offset => |off| { |
| 7256 | 7489 | try self.asmRegisterMemory(switch (dst_ptr) { |
| 7257 | 7490 | .stack_offset => .mov, |
| ... | ... | @@ -7275,11 +7508,26 @@ fn genInlineMemcpy( |
| 7275 | 7508 | } |
| 7276 | 7509 | |
| 7277 | 7510 | switch (src_ptr) { |
| 7278 | .memory, .linker_load => { | |
| 7279 | try self.loadMemPtrIntoRegister(.rsi, Type.usize, src_ptr); | |
| 7511 | .memory => |addr| { | |
| 7512 | try self.genSetReg(Type.usize, .rsi, .{ .immediate = addr }); | |
| 7280 | 7513 | // Load the pointer, which is stored in memory |
| 7281 | 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 | 7531 | .stack_offset, .ptr_stack_offset => |off| { |
| 7284 | 7532 | try self.asmRegisterMemory(switch (src_ptr) { |
| 7285 | 7533 | .stack_offset => .mov, |
| ... | ... | @@ -7326,11 +7574,26 @@ fn genInlineMemset( |
| 7326 | 7574 | try self.spillRegisters(&.{ .rdi, .al, .rcx }); |
| 7327 | 7575 | |
| 7328 | 7576 | switch (dst_ptr) { |
| 7329 | .memory, .linker_load => { | |
| 7330 | try self.loadMemPtrIntoRegister(.rdi, Type.usize, dst_ptr); | |
| 7577 | .memory => |addr| { | |
| 7578 | try self.genSetReg(Type.usize, .rdi, .{ .immediate = addr }); | |
| 7331 | 7579 | // Load the pointer, which is stored in memory |
| 7332 | 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 | 7597 | .stack_offset, .ptr_stack_offset => |off| { |
| 7335 | 7598 | try self.asmRegisterMemory(switch (dst_ptr) { |
| 7336 | 7599 | .stack_offset => .mov, |
| ... | ... | @@ -7454,10 +7717,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7454 | 7717 | |
| 7455 | 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 | 7721 | .Float => { |
| 7459 | const base_reg = try self.register_manager.allocReg(null, gp); | |
| 7460 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); | |
| 7722 | const base_reg = (try self.register_manager.allocReg(null, gp)).to64(); | |
| 7723 | try self.genSetReg(Type.usize, base_reg, .{ .immediate = addr }); | |
| 7461 | 7724 | |
| 7462 | 7725 | if (intrinsicsAllowed(self.target.*, ty)) { |
| 7463 | 7726 | return self.asmRegisterMemory( |
| ... | ... | @@ -7469,29 +7732,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7469 | 7732 | }), |
| 7470 | 7733 | }, |
| 7471 | 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 | } |
| 7475 | 7738 | |
| 7476 | 7739 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| 7477 | 7740 | }, |
| 7478 | else => switch (mcv) { | |
| 7479 | else => unreachable, | |
| 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)) { | |
| 7741 | else => { | |
| 7742 | if (addr <= math.maxInt(i32)) { | |
| 7489 | 7743 | try self.asmRegisterMemory( |
| 7490 | 7744 | .mov, |
| 7491 | 7745 | registerAlias(reg, abi_size), |
| 7492 | 7746 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ |
| 7493 | 7747 | .base = .ds, |
| 7494 | .disp = @intCast(i32, x), | |
| 7748 | .disp = @intCast(i32, addr), | |
| 7495 | 7749 | }), |
| 7496 | 7750 | ); |
| 7497 | 7751 | } else { |
| ... | ... | @@ -7501,20 +7755,77 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7501 | 7755 | _ = try self.addInst(.{ |
| 7502 | 7756 | .tag = .mov_moffs, |
| 7503 | 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 | 7760 | } else { |
| 7507 | 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 | 7763 | try self.asmRegisterMemory( |
| 7510 | 7764 | .mov, |
| 7511 | 7765 | registerAlias(reg, abi_size), |
| 7512 | 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 | 7829 | .stack_offset => |off| { |
| 7519 | 7830 | switch (ty.zigTypeTag()) { |
| 7520 | 7831 | .Int => switch (ty.intInfo(self.target.*).signedness) { |
| ... | ... | @@ -8468,6 +8779,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 8468 | 8779 | .linker_load => |ll| .{ .linker_load = ll }, |
| 8469 | 8780 | .immediate => |imm| .{ .immediate = imm }, |
| 8470 | 8781 | .memory => |addr| .{ .memory = addr }, |
| 8782 | .tlv_reloc => |sym_index| .{ .tlv_reloc = sym_index }, | |
| 8471 | 8783 | }, |
| 8472 | 8784 | .fail => |msg| { |
| 8473 | 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 | 42 | ).?; |
| 43 | 43 | const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index); |
| 44 | 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 | 46 | .target = target, |
| 47 | 47 | .offset = end_offset - 4, |
| 48 | 48 | .addend = 0, |
| ... | ... | @@ -65,20 +65,20 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 65 | 65 | }); |
| 66 | 66 | } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }), |
| 67 | 67 | |
| 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 | 69 | const metadata = |
| 70 | 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 | 71 | const atom_index = macho_file.getAtomIndexForSymbol(.{ |
| 77 | 72 | .sym_index = metadata.atom_index, |
| 78 | 73 | .file = null, |
| 79 | 74 | }).?; |
| 80 | 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 | 82 | .target = .{ .sym_index = metadata.sym_index, .file = null }, |
| 83 | 83 | .offset = @intCast(u32, end_offset - 4), |
| 84 | 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 | 127 | .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}), |
| 128 | 128 | |
| 129 | 129 | .lea_linker => try lower.mirLeaLinker(inst), |
| 130 | .mov_linker => try lower.mirMovLinker(inst), | |
| 130 | 131 | |
| 131 | 132 | .mov_moffs => try lower.mirMovMoffs(inst), |
| 132 | 133 | |
| ... | ... | @@ -444,6 +445,15 @@ fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void { |
| 444 | 445 | }); |
| 445 | 446 | } |
| 446 | 447 | |
| 448 | fn 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 | ||
| 447 | 457 | const abi = @import("abi.zig"); |
| 448 | 458 | const assert = std.debug.assert; |
| 449 | 459 | const bits = @import("bits.zig"); |
src/arch/x86_64/Mir.zig+5| ... | ... | @@ -233,6 +233,8 @@ pub const Inst = struct { |
| 233 | 233 | |
| 234 | 234 | /// Load effective address of a symbol not yet allocated in VM. |
| 235 | 235 | lea_linker, |
| 236 | /// Move address of a symbol not yet allocated in VM. | |
| 237 | mov_linker, | |
| 236 | 238 | |
| 237 | 239 | /// End of prologue |
| 238 | 240 | dbg_prologue_end, |
| ... | ... | @@ -402,6 +404,9 @@ pub const Inst = struct { |
| 402 | 404 | /// Linker relocation - imports table indirection (binding). |
| 403 | 405 | /// Uses `payload` payload with extra data of type `LeaRegisterReloc`. |
| 404 | 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 | }; |
| 406 | 411 | |
| 407 | 412 | pub const Data = union { |
src/codegen.zig+19-5| ... | ... | @@ -493,7 +493,7 @@ pub fn generateSymbol( |
| 493 | 493 | bin_file.allocator, |
| 494 | 494 | src_loc, |
| 495 | 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 | 932 | /// such as ARM, the immediate will never exceed 32-bits. |
| 933 | 933 | immediate: u64, |
| 934 | 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 | 939 | /// Direct by-address reference to memory location. |
| 936 | 940 | memory: u64, |
| 937 | 941 | }; |
| ... | ... | @@ -957,13 +961,13 @@ fn genDeclRef( |
| 957 | 961 | tv: TypedValue, |
| 958 | 962 | decl_index: Module.Decl.Index, |
| 959 | 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) }); | |
| 961 | 966 | |
| 962 | 967 | const target = bin_file.options.target; |
| 963 | 968 | const ptr_bits = target.cpu.arch.ptrBitWidth(); |
| 964 | 969 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 965 | 970 | |
| 966 | const module = bin_file.options.module.?; | |
| 967 | 971 | const decl = module.declPtr(decl_index); |
| 968 | 972 | |
| 969 | 973 | if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| ... | ... | @@ -991,6 +995,8 @@ fn genDeclRef( |
| 991 | 995 | |
| 992 | 996 | module.markDeclAlive(decl); |
| 993 | 997 | |
| 998 | const is_threadlocal = tv.val.isPtrToThreadLocal(module) and !bin_file.options.single_threaded; | |
| 999 | ||
| 994 | 1000 | if (bin_file.cast(link.File.Elf)) |elf_file| { |
| 995 | 1001 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); |
| 996 | 1002 | const atom = elf_file.getAtom(atom_index); |
| ... | ... | @@ -998,6 +1004,9 @@ fn genDeclRef( |
| 998 | 1004 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { |
| 999 | 1005 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); |
| 1000 | 1006 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 1007 | if (is_threadlocal) { | |
| 1008 | return GenResult.mcv(.{ .tlv_reloc = sym_index }); | |
| 1009 | } | |
| 1001 | 1010 | return GenResult.mcv(.{ .linker_load = .{ |
| 1002 | 1011 | .type = .got, |
| 1003 | 1012 | .sym_index = sym_index, |
| ... | ... | @@ -1025,7 +1034,8 @@ fn genUnnamedConst( |
| 1025 | 1034 | tv: TypedValue, |
| 1026 | 1035 | owner_decl_index: Module.Decl.Index, |
| 1027 | 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) }); | |
| 1029 | 1039 | |
| 1030 | 1040 | const target = bin_file.options.target; |
| 1031 | 1041 | const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| { |
| ... | ... | @@ -1065,7 +1075,11 @@ pub fn genTypedValue( |
| 1065 | 1075 | typed_value.val = rt.data; |
| 1066 | 1076 | } |
| 1067 | 1077 | |
| 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 | }); | |
| 1069 | 1083 | |
| 1070 | 1084 | if (typed_value.val.isUndef()) |
| 1071 | 1085 | return GenResult.mcv(.undef); |
src/link.zig+2-2| ... | ... | @@ -540,7 +540,7 @@ pub const File = struct { |
| 540 | 540 | /// May be called before or after updateDeclExports for any given Decl. |
| 541 | 541 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
| 542 | 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 | 544 | assert(decl.has_tv); |
| 545 | 545 | if (build_options.only_c) { |
| 546 | 546 | assert(base.tag == .c); |
| ... | ... | @@ -564,7 +564,7 @@ pub const File = struct { |
| 564 | 564 | pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void { |
| 565 | 565 | const owner_decl = module.declPtr(func.owner_decl); |
| 566 | 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 | 569 | if (build_options.only_c) { |
| 570 | 570 | assert(base.tag == .c); |
src/link/Dwarf.zig+12-3| ... | ... | @@ -150,7 +150,7 @@ pub const DeclState = struct { |
| 150 | 150 | .type = ty, |
| 151 | 151 | .offset = undefined, |
| 152 | 152 | }); |
| 153 | log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() }); | |
| 153 | log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) }); | |
| 154 | 154 | try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ |
| 155 | 155 | .mod = self.mod, |
| 156 | 156 | }); |
| ... | ... | @@ -570,7 +570,7 @@ pub const DeclState = struct { |
| 570 | 570 | try dbg_info_buffer.append(0); |
| 571 | 571 | }, |
| 572 | 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 | 574 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1)); |
| 575 | 575 | }, |
| 576 | 576 | } |
| ... | ... | @@ -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 | 1062 | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; |
| 1059 | 1063 | mem.writeInt(u32, ptr, @intCast(u32, sym_size), target_endian); |
| 1060 | 1064 | } |
| ... | ... | @@ -1263,7 +1267,12 @@ pub fn commitDeclState( |
| 1263 | 1267 | } else { |
| 1264 | 1268 | const atom = self.getAtom(.di_atom, symbol.atom_index); |
| 1265 | 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 | 1276 | mem.writeInt( |
| 1268 | 1277 | u32, |
| 1269 | 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 | 5 | const builtin = @import("builtin"); |
| 6 | 6 | const assert = std.debug.assert; |
| 7 | 7 | const dwarf = std.dwarf; |
| 8 | const fmt = std.fmt; | |
| 9 | 8 | const fs = std.fs; |
| 10 | 9 | const log = std.log.scoped(.link); |
| 11 | 10 | const macho = std.macho; |
| ... | ... | @@ -138,6 +137,8 @@ got_section_index: ?u8 = null, |
| 138 | 137 | data_const_section_index: ?u8 = null, |
| 139 | 138 | la_symbol_ptr_section_index: ?u8 = null, |
| 140 | 139 | data_section_index: ?u8 = null, |
| 140 | thread_vars_section_index: ?u8 = null, | |
| 141 | thread_data_section_index: ?u8 = null, | |
| 141 | 142 | |
| 142 | 143 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 143 | 144 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| ... | ... | @@ -153,13 +154,9 @@ stub_helper_preamble_atom_index: ?Atom.Index = null, |
| 153 | 154 | |
| 154 | 155 | strtab: StringTable(.strtab) = .{}, |
| 155 | 156 | |
| 156 | got_entries: std.ArrayListUnmanaged(Entry) = .{}, | |
| 157 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 158 | got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, | |
| 159 | ||
| 160 | stubs: std.ArrayListUnmanaged(Entry) = .{}, | |
| 161 | stubs_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 162 | stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{}, | |
| 157 | got_table: SectionTable = .{}, | |
| 158 | stubs_table: SectionTable = .{}, | |
| 159 | tlv_table: SectionTable = .{}, | |
| 163 | 160 | |
| 164 | 161 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 165 | 162 | |
| ... | ... | @@ -268,26 +265,120 @@ const DeclMetadata = struct { |
| 268 | 265 | } |
| 269 | 266 | }; |
| 270 | 267 | |
| 271 | const Entry = struct { | |
| 272 | target: SymbolWithLoc, | |
| 273 | // Index into the synthetic symbol table (i.e., file == null). | |
| 274 | sym_index: u32, | |
| 268 | const SectionTable = struct { | |
| 269 | entries: std.ArrayListUnmanaged(Entry) = .{}, | |
| 270 | free_list: std.ArrayListUnmanaged(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 | } | |
| 275 | 306 | |
| 276 | pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 { | |
| 277 | return macho_file.getSymbol(.{ .sym_index = entry.sym_index, .file = null }); | |
| 307 | pub fn getAtomIndex(st: *const ST, macho_file: *MachO, target: SymbolWithLoc) ?Atom.Index { | |
| 308 | const index = st.lookup.get(target) orelse return null; | |
| 309 | return st.entries.items[index].getAtomIndex(macho_file); | |
| 278 | 310 | } |
| 279 | 311 | |
| 280 | pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 { | |
| 281 | return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null }); | |
| 312 | const FormatContext = struct { | |
| 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 | } |
| 283 | 343 | |
| 284 | pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index { | |
| 285 | return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null }); | |
| 344 | fn format(st: *const ST, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | |
| 345 | _ = st; | |
| 346 | _ = unused_format_string; | |
| 347 | _ = options; | |
| 348 | _ = writer; | |
| 349 | @compileError("do not format SectionTable directly; use st.fmtDebug()"); | |
| 286 | 350 | } |
| 287 | 351 | |
| 288 | pub fn getName(entry: Entry, macho_file: *MachO) []const u8 { | |
| 289 | return macho_file.getSymbolName(.{ .sym_index = entry.sym_index, .file = null }); | |
| 352 | pub fn fmtDebug(st: *const ST, macho_file: *MachO) std.fmt.Formatter(fmt) { | |
| 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 | }; |
| 292 | 383 | |
| 293 | 384 | const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); |
| ... | ... | @@ -397,7 +488,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 397 | 488 | // Create dSYM bundle. |
| 398 | 489 | log.debug("creating {s}.dSYM bundle", .{sub_path}); |
| 399 | 490 | |
| 400 | const d_sym_path = try fmt.allocPrint( | |
| 491 | const d_sym_path = try std.fmt.allocPrint( | |
| 401 | 492 | allocator, |
| 402 | 493 | "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF", |
| 403 | 494 | .{sub_path}, |
| ... | ... | @@ -611,6 +702,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 611 | 702 | if (self.dyld_stub_binder_index == null) { |
| 612 | 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 | } | |
| 614 | 708 | |
| 615 | 709 | try self.createMhExecuteHeaderSymbol(); |
| 616 | 710 | |
| ... | ... | @@ -619,6 +713,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 619 | 713 | try self.resolveSymbolsInDylibs(&actions); |
| 620 | 714 | |
| 621 | 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 | 722 | return error.UndefinedSymbolReference; |
| 623 | 723 | } |
| 624 | 724 | |
| ... | ... | @@ -1237,22 +1337,17 @@ pub fn createAtom(self: *MachO) !Atom.Index { |
| 1237 | 1337 | |
| 1238 | 1338 | pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { |
| 1239 | 1339 | const atom_index = try self.createAtom(); |
| 1240 | const atom = self.getAtomPtr(atom_index); | |
| 1241 | atom.size = @sizeOf(u64); | |
| 1340 | self.getAtomPtr(atom_index).size = @sizeOf(u64); | |
| 1242 | 1341 | |
| 1243 | const sym = atom.getSymbolPtr(self); | |
| 1342 | const sym = self.getAtom(atom_index).getSymbolPtr(self); | |
| 1244 | 1343 | sym.n_type = macho.N_SECT; |
| 1245 | 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)); | |
| 1247 | 1346 | |
| 1248 | 1347 | log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); |
| 1249 | 1348 | |
| 1250 | 1349 | try Atom.addRelocation(self, atom_index, .{ |
| 1251 | .type = switch (self.base.options.target.cpu.arch) { | |
| 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 | }, | |
| 1350 | .type = .unsigned, | |
| 1256 | 1351 | .target = target, |
| 1257 | 1352 | .offset = 0, |
| 1258 | 1353 | .addend = 0, |
| ... | ... | @@ -1269,6 +1364,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { |
| 1269 | 1364 | } else { |
| 1270 | 1365 | try Atom.addRebase(self, atom_index, 0); |
| 1271 | 1366 | } |
| 1367 | try self.writePtrWidthAtom(atom_index); | |
| 1272 | 1368 | |
| 1273 | 1369 | return atom_index; |
| 1274 | 1370 | } |
| ... | ... | @@ -1334,15 +1430,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1334 | 1430 | code[9] = 0xff; |
| 1335 | 1431 | code[10] = 0x25; |
| 1336 | 1432 | |
| 1337 | try Atom.addRelocations(self, atom_index, 2, .{ .{ | |
| 1338 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), | |
| 1433 | try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{ | |
| 1434 | .type = .signed, | |
| 1339 | 1435 | .target = dyld_private, |
| 1340 | 1436 | .offset = 3, |
| 1341 | 1437 | .addend = 0, |
| 1342 | 1438 | .pcrel = true, |
| 1343 | 1439 | .length = 2, |
| 1344 | 1440 | }, .{ |
| 1345 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT), | |
| 1441 | .type = .got, | |
| 1346 | 1442 | .target = dyld_stub_binder, |
| 1347 | 1443 | .offset = 11, |
| 1348 | 1444 | .addend = 0, |
| ... | ... | @@ -1374,29 +1470,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1374 | 1470 | // br x16 |
| 1375 | 1471 | mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32()); |
| 1376 | 1472 | |
| 1377 | try Atom.addRelocations(self, atom_index, 4, .{ .{ | |
| 1378 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), | |
| 1473 | try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{ | |
| 1474 | .type = .page, | |
| 1379 | 1475 | .target = dyld_private, |
| 1380 | 1476 | .offset = 0, |
| 1381 | 1477 | .addend = 0, |
| 1382 | 1478 | .pcrel = true, |
| 1383 | 1479 | .length = 2, |
| 1384 | 1480 | }, .{ |
| 1385 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), | |
| 1481 | .type = .pageoff, | |
| 1386 | 1482 | .target = dyld_private, |
| 1387 | 1483 | .offset = 4, |
| 1388 | 1484 | .addend = 0, |
| 1389 | 1485 | .pcrel = false, |
| 1390 | 1486 | .length = 2, |
| 1391 | 1487 | }, .{ |
| 1392 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), | |
| 1488 | .type = .got_page, | |
| 1393 | 1489 | .target = dyld_stub_binder, |
| 1394 | 1490 | .offset = 12, |
| 1395 | 1491 | .addend = 0, |
| 1396 | 1492 | .pcrel = true, |
| 1397 | 1493 | .length = 2, |
| 1398 | 1494 | }, .{ |
| 1399 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12), | |
| 1495 | .type = .got_pageoff, | |
| 1400 | 1496 | .target = dyld_stub_binder, |
| 1401 | 1497 | .offset = 16, |
| 1402 | 1498 | .addend = 0, |
| ... | ... | @@ -1454,8 +1550,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index { |
| 1454 | 1550 | code[5] = 0xe9; |
| 1455 | 1551 | |
| 1456 | 1552 | try Atom.addRelocation(self, atom_index, .{ |
| 1457 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), | |
| 1458 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, | |
| 1553 | .type = .branch, | |
| 1554 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index }, | |
| 1459 | 1555 | .offset = 6, |
| 1460 | 1556 | .addend = 0, |
| 1461 | 1557 | .pcrel = true, |
| ... | ... | @@ -1477,8 +1573,8 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index { |
| 1477 | 1573 | // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 1478 | 1574 | |
| 1479 | 1575 | try Atom.addRelocation(self, atom_index, .{ |
| 1480 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), | |
| 1481 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, | |
| 1576 | .type = .branch, | |
| 1577 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index }, | |
| 1482 | 1578 | .offset = 4, |
| 1483 | 1579 | .addend = 0, |
| 1484 | 1580 | .pcrel = true, |
| ... | ... | @@ -1505,12 +1601,8 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo |
| 1505 | 1601 | sym.n_sect = self.la_symbol_ptr_section_index.? + 1; |
| 1506 | 1602 | |
| 1507 | 1603 | try Atom.addRelocation(self, atom_index, .{ |
| 1508 | .type = switch (self.base.options.target.cpu.arch) { | |
| 1509 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), | |
| 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 }, | |
| 1604 | .type = .unsigned, | |
| 1605 | .target = .{ .sym_index = stub_sym_index }, | |
| 1514 | 1606 | .offset = 0, |
| 1515 | 1607 | .addend = 0, |
| 1516 | 1608 | .pcrel = false, |
| ... | ... | @@ -1563,8 +1655,8 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1563 | 1655 | code[1] = 0x25; |
| 1564 | 1656 | |
| 1565 | 1657 | try Atom.addRelocation(self, atom_index, .{ |
| 1566 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), | |
| 1567 | .target = .{ .sym_index = laptr_sym_index, .file = null }, | |
| 1658 | .type = .branch, | |
| 1659 | .target = .{ .sym_index = laptr_sym_index }, | |
| 1568 | 1660 | .offset = 2, |
| 1569 | 1661 | .addend = 0, |
| 1570 | 1662 | .pcrel = true, |
| ... | ... | @@ -1583,18 +1675,18 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1583 | 1675 | // br x16 |
| 1584 | 1676 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 1585 | 1677 | |
| 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), | |
| 1589 | .target = .{ .sym_index = laptr_sym_index, .file = null }, | |
| 1680 | .type = .page, | |
| 1681 | .target = .{ .sym_index = laptr_sym_index }, | |
| 1590 | 1682 | .offset = 0, |
| 1591 | 1683 | .addend = 0, |
| 1592 | 1684 | .pcrel = true, |
| 1593 | 1685 | .length = 2, |
| 1594 | 1686 | }, |
| 1595 | 1687 | .{ |
| 1596 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), | |
| 1597 | .target = .{ .sym_index = laptr_sym_index, .file = null }, | |
| 1688 | .type = .pageoff, | |
| 1689 | .target = .{ .sym_index = laptr_sym_index }, | |
| 1598 | 1690 | .offset = 4, |
| 1599 | 1691 | .addend = 0, |
| 1600 | 1692 | .pcrel = false, |
| ... | ... | @@ -1612,6 +1704,42 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1612 | 1704 | return atom_index; |
| 1613 | 1705 | } |
| 1614 | 1706 | |
| 1707 | fn 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 | ||
| 1615 | 1743 | fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 1616 | 1744 | if (self.base.options.output_mode != .Exe) return; |
| 1617 | 1745 | if (self.getGlobal("__mh_execute_header")) |global| { |
| ... | ... | @@ -1760,12 +1888,9 @@ pub fn deinit(self: *MachO) void { |
| 1760 | 1888 | d_sym.deinit(); |
| 1761 | 1889 | } |
| 1762 | 1890 | |
| 1763 | self.got_entries.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); | |
| 1891 | self.got_table.deinit(gpa); | |
| 1768 | 1892 | self.stubs_table.deinit(gpa); |
| 1893 | self.tlv_table.deinit(gpa); | |
| 1769 | 1894 | self.strtab.deinit(gpa); |
| 1770 | 1895 | |
| 1771 | 1896 | self.locals.deinit(gpa); |
| ... | ... | @@ -1898,20 +2023,10 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void { |
| 1898 | 2023 | self.locals_free_list.append(gpa, sym_index) catch {}; |
| 1899 | 2024 | |
| 1900 | 2025 | // Try freeing GOT atom if this decl had one |
| 1901 | const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | |
| 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 | } | |
| 2026 | self.got_table.freeEntry(gpa, .{ .sym_index = sym_index }); | |
| 1913 | 2027 | |
| 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 | } |
| 1916 | 2031 | |
| 1917 | 2032 | self.locals.items[sym_index].n_type = 0; |
| ... | ... | @@ -1986,70 +2101,34 @@ fn allocateGlobal(self: *MachO) !u32 { |
| 1986 | 2101 | return index; |
| 1987 | 2102 | } |
| 1988 | 2103 | |
| 1989 | fn 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 | ||
| 2011 | 2104 | fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 2012 | if (self.got_entries_table.contains(target)) return; | |
| 2013 | ||
| 2014 | const got_index = try self.allocateGotEntry(target); | |
| 2105 | if (self.got_table.lookup.contains(target)) return; | |
| 2106 | const got_index = try self.got_table.allocateEntry(self.base.allocator, target); | |
| 2015 | 2107 | const got_atom_index = try self.createGotAtom(target); |
| 2016 | 2108 | const got_atom = self.getAtom(got_atom_index); |
| 2017 | self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; | |
| 2018 | try self.writePtrWidthAtom(got_atom_index); | |
| 2019 | } | |
| 2020 | ||
| 2021 | fn 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; | |
| 2109 | self.got_table.entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; | |
| 2110 | self.markRelocsDirtyByTarget(target); | |
| 2040 | 2111 | } |
| 2041 | 2112 | |
| 2042 | 2113 | fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 2043 | if (self.stubs_table.contains(target)) return; | |
| 2044 | ||
| 2045 | const stub_index = try self.allocateStubEntry(target); | |
| 2114 | if (self.stubs_table.lookup.contains(target)) return; | |
| 2115 | const stub_index = try self.stubs_table.allocateEntry(self.base.allocator, target); | |
| 2046 | 2116 | const stub_helper_atom_index = try self.createStubHelperAtom(); |
| 2047 | 2117 | const stub_helper_atom = self.getAtom(stub_helper_atom_index); |
| 2048 | 2118 | const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target); |
| 2049 | 2119 | const laptr_atom = self.getAtom(laptr_atom_index); |
| 2050 | 2120 | const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?); |
| 2051 | 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 | ||
| 2126 | fn 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 | 2132 | self.markRelocsDirtyByTarget(target); |
| 2054 | 2133 | } |
| 2055 | 2134 | |
| ... | ... | @@ -2070,8 +2149,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 2070 | 2149 | self.freeUnnamedConsts(decl_index); |
| 2071 | 2150 | Atom.freeRelocations(self, atom_index); |
| 2072 | 2151 | |
| 2073 | const atom = self.getAtom(atom_index); | |
| 2074 | ||
| 2075 | 2152 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2076 | 2153 | defer code_buffer.deinit(); |
| 2077 | 2154 | |
| ... | ... | @@ -2100,7 +2177,13 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 2100 | 2177 | const addr = try self.updateDeclCode(decl_index, code); |
| 2101 | 2178 | |
| 2102 | 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 | } |
| 2105 | 2188 | |
| 2106 | 2189 | // 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 | 2279 | } |
| 2197 | 2280 | |
| 2198 | 2281 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2282 | const sym_index = self.getAtom(atom_index).getSymbolIndex().?; | |
| 2199 | 2283 | Atom.freeRelocations(self, atom_index); |
| 2200 | const atom = self.getAtom(atom_index); | |
| 2201 | 2284 | |
| 2202 | 2285 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2203 | 2286 | defer code_buffer.deinit(); |
| ... | ... | @@ -2216,14 +2299,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2216 | 2299 | }, &code_buffer, .{ |
| 2217 | 2300 | .dwarf = ds, |
| 2218 | 2301 | }, .{ |
| 2219 | .parent_atom_index = atom.getSymbolIndex().?, | |
| 2302 | .parent_atom_index = sym_index, | |
| 2220 | 2303 | }) |
| 2221 | 2304 | else |
| 2222 | 2305 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 2223 | 2306 | .ty = decl.ty, |
| 2224 | 2307 | .val = decl_val, |
| 2225 | 2308 | }, &code_buffer, .none, .{ |
| 2226 | .parent_atom_index = atom.getSymbolIndex().?, | |
| 2309 | .parent_atom_index = sym_index, | |
| 2227 | 2310 | }); |
| 2228 | 2311 | |
| 2229 | 2312 | var code = switch (res) { |
| ... | ... | @@ -2237,7 +2320,13 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2237 | 2320 | const addr = try self.updateDeclCode(decl_index, code); |
| 2238 | 2321 | |
| 2239 | 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 | } |
| 2242 | 2331 | |
| 2243 | 2332 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| ... | ... | @@ -2322,7 +2411,6 @@ fn updateLazySymbolAtom( |
| 2322 | 2411 | symbol.n_value = vaddr; |
| 2323 | 2412 | |
| 2324 | 2413 | try self.addGotEntry(.{ .sym_index = local_sym_index }); |
| 2325 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | |
| 2326 | 2414 | try self.writeAtom(atom_index, code); |
| 2327 | 2415 | } |
| 2328 | 2416 | |
| ... | ... | @@ -2356,6 +2444,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2356 | 2444 | const val = decl.val; |
| 2357 | 2445 | const zig_ty = ty.zigTypeTag(); |
| 2358 | 2446 | const mode = self.base.options.optimize_mode; |
| 2447 | const single_threaded = self.base.options.single_threaded; | |
| 2359 | 2448 | const sect_id: u8 = blk: { |
| 2360 | 2449 | // TODO finish and audit this function |
| 2361 | 2450 | if (val.isUndefDeep()) { |
| ... | ... | @@ -2366,7 +2455,10 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2366 | 2455 | } |
| 2367 | 2456 | } |
| 2368 | 2457 | |
| 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 | 2462 | break :blk self.data_section_index.?; |
| 2371 | 2463 | } |
| 2372 | 2464 | |
| ... | ... | @@ -2391,16 +2483,28 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2391 | 2483 | |
| 2392 | 2484 | const required_alignment = decl.getAlignment(self.base.options.target); |
| 2393 | 2485 | |
| 2394 | const sym_name = try decl.getFullyQualifiedName(mod); | |
| 2395 | defer self.base.allocator.free(sym_name); | |
| 2486 | const decl_name = try decl.getFullyQualifiedName(mod); | |
| 2487 | defer gpa.free(decl_name); | |
| 2396 | 2488 | |
| 2397 | 2489 | const decl_metadata = self.decls.get(decl_index).?; |
| 2398 | 2490 | const atom_index = decl_metadata.atom; |
| 2399 | 2491 | const atom = self.getAtom(atom_index); |
| 2400 | 2492 | const sym_index = atom.getSymbolIndex().?; |
| 2401 | 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 | 2500 | const code_len = code.len; |
| 2403 | 2501 | |
| 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 | 2508 | if (atom.size != 0) { |
| 2405 | 2509 | const sym = atom.getSymbolPtr(self); |
| 2406 | 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 | 2522 | |
| 2419 | 2523 | if (vaddr != sym.n_value) { |
| 2420 | 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 | 2534 | log.debug(" (updating GOT entry)", .{}); |
| 2422 | const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | |
| 2423 | const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?; | |
| 2424 | self.markRelocsDirtyByTarget(got_target); | |
| 2535 | const got_atom_index = self.got_table.getAtomIndex(self, target).?; | |
| 2425 | 2536 | try self.writePtrWidthAtom(got_atom_index); |
| 2426 | 2537 | } |
| 2427 | 2538 | } else if (code_len < atom.size) { |
| 2428 | 2539 | self.shrinkAtom(atom_index, code_len); |
| 2429 | 2540 | } else if (atom.next_index == null) { |
| 2430 | const header = &self.sections.items(.header)[sect_id]; | |
| 2431 | const segment = self.getSegment(sect_id); | |
| 2432 | 2541 | const needed_size = (sym.n_value + code_len) - segment.vmaddr; |
| 2433 | 2542 | header.size = needed_size; |
| 2434 | 2543 | } |
| 2435 | 2544 | self.getAtomPtr(atom_index).size = code_len; |
| 2436 | 2545 | } else { |
| 2437 | const name_str_index = try self.strtab.insert(gpa, sym_name); | |
| 2438 | 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 | 2548 | sym.n_type = macho.N_SECT; |
| 2441 | 2549 | sym.n_sect = sect_id + 1; |
| 2442 | 2550 | sym.n_desc = 0; |
| ... | ... | @@ -2450,10 +2558,17 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2450 | 2558 | self.getAtomPtr(atom_index).size = code_len; |
| 2451 | 2559 | sym.n_value = vaddr; |
| 2452 | 2560 | |
| 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 | } |
| 2455 | 2571 | |
| 2456 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | |
| 2457 | 2572 | try self.writeAtom(atom_index, code); |
| 2458 | 2573 | |
| 2459 | 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 | 2762 | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; |
| 2648 | 2763 | const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; |
| 2649 | 2764 | try Atom.addRelocation(self, atom_index, .{ |
| 2650 | .type = switch (self.base.options.target.cpu.arch) { | |
| 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 | }, | |
| 2765 | .type = .unsigned, | |
| 2655 | 2766 | .target = .{ .sym_index = sym_index, .file = null }, |
| 2656 | 2767 | .offset = @intCast(u32, reloc_info.offset), |
| 2657 | 2768 | .addend = reloc_info.addend, |
| ... | ... | @@ -2790,6 +2901,28 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 2790 | 2901 | self.segment_table_dirty = true; |
| 2791 | 2902 | } |
| 2792 | 2903 | |
| 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 | 2926 | if (self.linkedit_segment_cmd_index == null) { |
| 2794 | 2927 | self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len); |
| 2795 | 2928 | |
| ... | ... | @@ -3077,28 +3210,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3077 | 3210 | return vaddr; |
| 3078 | 3211 | } |
| 3079 | 3212 | |
| 3080 | fn 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 | ||
| 3102 | 3213 | pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 { |
| 3103 | 3214 | _ = lib_name; |
| 3104 | 3215 | const gpa = self.base.allocator; |
| ... | ... | @@ -3474,8 +3585,8 @@ const SymtabCtx = struct { |
| 3474 | 3585 | |
| 3475 | 3586 | fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { |
| 3476 | 3587 | const gpa = self.base.allocator; |
| 3477 | const nstubs = @intCast(u32, self.stubs_table.count()); | |
| 3478 | const ngot_entries = @intCast(u32, self.got_entries_table.count()); | |
| 3588 | const nstubs = @intCast(u32, self.stubs_table.lookup.count()); | |
| 3589 | const ngot_entries = @intCast(u32, self.got_table.lookup.count()); | |
| 3479 | 3590 | const nindirectsyms = nstubs * 2 + ngot_entries; |
| 3480 | 3591 | const iextdefsym = ctx.nlocalsym; |
| 3481 | 3592 | const iundefsym = iextdefsym + ctx.nextdefsym; |
| ... | ... | @@ -3497,7 +3608,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { |
| 3497 | 3608 | if (self.stubs_section_index) |sect_id| { |
| 3498 | 3609 | const stubs = &self.sections.items(.header)[sect_id]; |
| 3499 | 3610 | stubs.reserved1 = 0; |
| 3500 | for (self.stubs.items) |entry| { | |
| 3611 | for (self.stubs_table.entries.items) |entry| { | |
| 3501 | 3612 | if (entry.sym_index == 0) continue; |
| 3502 | 3613 | const target_sym = self.getSymbol(entry.target); |
| 3503 | 3614 | assert(target_sym.undf()); |
| ... | ... | @@ -3508,7 +3619,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { |
| 3508 | 3619 | if (self.got_section_index) |sect_id| { |
| 3509 | 3620 | const got = &self.sections.items(.header)[sect_id]; |
| 3510 | 3621 | got.reserved1 = nstubs; |
| 3511 | for (self.got_entries.items) |entry| { | |
| 3622 | for (self.got_table.entries.items) |entry| { | |
| 3512 | 3623 | if (entry.sym_index == 0) continue; |
| 3513 | 3624 | const target_sym = self.getSymbol(entry.target); |
| 3514 | 3625 | if (target_sym.undf()) { |
| ... | ... | @@ -3522,7 +3633,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { |
| 3522 | 3633 | if (self.la_symbol_ptr_section_index) |sect_id| { |
| 3523 | 3634 | const la_symbol_ptr = &self.sections.items(.header)[sect_id]; |
| 3524 | 3635 | la_symbol_ptr.reserved1 = nstubs + ngot_entries; |
| 3525 | for (self.stubs.items) |entry| { | |
| 3636 | for (self.stubs_table.entries.items) |entry| { | |
| 3526 | 3637 | if (entry.sym_index == 0) continue; |
| 3527 | 3638 | const target_sym = self.getSymbol(entry.target); |
| 3528 | 3639 | assert(target_sym.undf()); |
| ... | ... | @@ -3593,6 +3704,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void { |
| 3593 | 3704 | var header: macho.mach_header_64 = .{}; |
| 3594 | 3705 | header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; |
| 3595 | 3706 | |
| 3707 | if (!self.base.options.single_threaded) { | |
| 3708 | header.flags |= macho.MH_HAS_TLV_DESCRIPTORS; | |
| 3709 | } | |
| 3710 | ||
| 3596 | 3711 | switch (self.base.options.target.cpu.arch) { |
| 3597 | 3712 | .aarch64 => { |
| 3598 | 3713 | header.cputype = macho.CPU_TYPE_ARM64; |
| ... | ... | @@ -3617,12 +3732,6 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void { |
| 3617 | 3732 | else => unreachable, |
| 3618 | 3733 | } |
| 3619 | 3734 | |
| 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 | 3735 | header.ncmds = ncmds; |
| 3627 | 3736 | header.sizeofcmds = sizeofcmds; |
| 3628 | 3737 | |
| ... | ... | @@ -3802,8 +3911,7 @@ pub fn getSymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) macho.nlist_64 |
| 3802 | 3911 | |
| 3803 | 3912 | /// Returns name of the symbol described by `sym_with_loc` descriptor. |
| 3804 | 3913 | pub fn getSymbolName(self: *const MachO, sym_with_loc: SymbolWithLoc) []const u8 { |
| 3805 | assert(sym_with_loc.file == null); | |
| 3806 | const sym = self.locals.items[sym_with_loc.sym_index]; | |
| 3914 | const sym = self.getSymbol(sym_with_loc); | |
| 3807 | 3915 | return self.strtab.get(sym.n_strx).?; |
| 3808 | 3916 | } |
| 3809 | 3917 | |
| ... | ... | @@ -3867,20 +3975,6 @@ pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.In |
| 3867 | 3975 | return self.atom_by_index_table.get(sym_with_loc.sym_index); |
| 3868 | 3976 | } |
| 3869 | 3977 | |
| 3870 | /// Returns GOT atom that references `sym_with_loc` if one exists. | |
| 3871 | /// Returns null otherwise. | |
| 3872 | pub 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. | |
| 3879 | pub 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 | 3978 | /// Returns symbol location corresponding to the set entrypoint. |
| 3885 | 3979 | /// Asserts output mode is executable. |
| 3886 | 3980 | pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc { |
| ... | ... | @@ -4227,37 +4321,13 @@ pub fn logSymtab(self: *MachO) void { |
| 4227 | 4321 | } |
| 4228 | 4322 | |
| 4229 | 4323 | log.debug("GOT entries:", .{}); |
| 4230 | for (self.got_entries.items, 0..) |entry, i| { | |
| 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 | } | |
| 4324 | log.debug("{}", .{self.got_table.fmtDebug(self)}); | |
| 4249 | 4325 | |
| 4250 | 4326 | log.debug("stubs entries:", .{}); |
| 4251 | for (self.stubs.items, 0..) |entry, i| { | |
| 4252 | const target_sym = self.getSymbol(entry.target); | |
| 4253 | const atom_sym = entry.getSymbol(self); | |
| 4254 | assert(target_sym.undf()); | |
| 4255 | log.debug(" {d}@{x} => import('{s}')", .{ | |
| 4256 | i, | |
| 4257 | atom_sym.n_value, | |
| 4258 | self.getSymbolName(entry.target), | |
| 4259 | }); | |
| 4260 | } | |
| 4327 | log.debug("{}", .{self.stubs_table.fmtDebug(self)}); | |
| 4328 | ||
| 4329 | log.debug("threadlocal entries:", .{}); | |
| 4330 | log.debug("{}", .{self.tlv_table.fmtDebug(self)}); | |
| 4261 | 4331 | } |
| 4262 | 4332 | |
| 4263 | 4333 | pub fn logAtoms(self: *MachO) void { |
src/link/MachO/Atom.zig+5-11| ... | ... | @@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace; |
| 14 | 14 | const Allocator = mem.Allocator; |
| 15 | 15 | const Arch = std.Target.Cpu.Arch; |
| 16 | 16 | const MachO = @import("../MachO.zig"); |
| 17 | const Relocation = @import("Relocation.zig"); | |
| 17 | pub const Relocation = @import("Relocation.zig"); | |
| 18 | 18 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 19 | 19 | |
| 20 | 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 | 113 | } |
| 114 | 114 | |
| 115 | 115 | pub 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 | } |
| 118 | 118 | |
| 119 | pub fn addRelocations( | |
| 120 | macho_file: *MachO, | |
| 121 | atom_index: Index, | |
| 122 | comptime count: comptime_int, | |
| 123 | relocs: [count]Relocation, | |
| 124 | ) !void { | |
| 119 | pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation) !void { | |
| 125 | 120 | const gpa = macho_file.base.allocator; |
| 126 | const target = macho_file.base.options.target; | |
| 127 | 121 | const gop = try macho_file.relocs.getOrPut(gpa, atom_index); |
| 128 | 122 | if (!gop.found_existing) { |
| 129 | 123 | gop.value_ptr.* = .{}; |
| 130 | 124 | } |
| 131 | try gop.value_ptr.ensureUnusedCapacity(gpa, count); | |
| 125 | try gop.value_ptr.ensureUnusedCapacity(gpa, relocs.len); | |
| 132 | 126 | for (relocs) |reloc| { |
| 133 | 127 | log.debug(" (adding reloc of type {s} to target %{d})", .{ |
| 134 | reloc.fmtType(target), | |
| 128 | @tagName(reloc.type), | |
| 135 | 129 | reloc.target.sym_index, |
| 136 | 130 | }); |
| 137 | 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 | 226 | |
| 227 | 227 | for (self.relocs.items) |*reloc| { |
| 228 | 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 | 230 | .got_load => blk: { |
| 231 | const got_index = macho_file.got_entries_table.get(.{ | |
| 232 | .sym_index = reloc.target, | |
| 233 | .file = null, | |
| 234 | }).?; | |
| 235 | const got_entry = macho_file.got_entries.items[got_index]; | |
| 231 | const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?; | |
| 232 | const got_entry = macho_file.got_table.entries.items[got_index]; | |
| 236 | 233 | break :blk got_entry.getSymbol(macho_file); |
| 237 | 234 | }, |
| 238 | 235 | }; |
| 239 | 236 | if (sym.n_value == reloc.prev_vaddr) continue; |
| 240 | 237 | |
| 241 | 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 | 240 | .got_load => blk: { |
| 244 | const got_index = macho_file.got_entries_table.get(.{ | |
| 245 | .sym_index = reloc.target, | |
| 246 | .file = null, | |
| 247 | }).?; | |
| 248 | const got_entry = macho_file.got_entries.items[got_index]; | |
| 241 | const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?; | |
| 242 | const got_entry = macho_file.got_table.entries.items[got_index]; | |
| 249 | 243 | break :blk got_entry.getName(macho_file); |
| 250 | 244 | }, |
| 251 | 245 | }; |
src/link/MachO/Relocation.zig+93-143| ... | ... | @@ -1,19 +1,7 @@ |
| 1 | const 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. | |
| 2 | 3 | |
| 3 | const std = @import("std"); | |
| 4 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | |
| 5 | const assert = std.debug.assert; | |
| 6 | const log = std.log.scoped(.link); | |
| 7 | const macho = std.macho; | |
| 8 | const math = std.math; | |
| 9 | const mem = std.mem; | |
| 10 | const meta = std.meta; | |
| 11 | ||
| 12 | const Atom = @import("Atom.zig"); | |
| 13 | const MachO = @import("../MachO.zig"); | |
| 14 | const SymbolWithLoc = MachO.SymbolWithLoc; | |
| 15 | ||
| 16 | type: u4, | |
| 4 | type: Type, | |
| 17 | 5 | target: SymbolWithLoc, |
| 18 | 6 | offset: u32, |
| 19 | 7 | addend: i64, |
| ... | ... | @@ -21,39 +9,55 @@ pcrel: bool, |
| 21 | 9 | length: u2, |
| 22 | 10 | dirty: bool = true, |
| 23 | 11 | |
| 12 | pub 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 | 40 | /// Returns true if and only if the reloc is dirty AND the target address is available. |
| 25 | 41 | pub fn isResolvable(self: Relocation, macho_file: *MachO) bool { |
| 26 | 42 | _ = self.getTargetAtomIndex(macho_file) orelse return false; |
| 27 | 43 | return self.dirty; |
| 28 | 44 | } |
| 29 | 45 | |
| 30 | pub 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 | ||
| 38 | 46 | pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index { |
| 39 | switch (macho_file.base.options.target.cpu.arch) { | |
| 40 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) { | |
| 41 | .ARM64_RELOC_GOT_LOAD_PAGE21, | |
| 42 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | |
| 43 | .ARM64_RELOC_POINTER_TO_GOT, | |
| 44 | => return macho_file.getGotAtomIndexForSymbol(self.target), | |
| 45 | else => {}, | |
| 47 | return switch (self.type) { | |
| 48 | .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target), | |
| 49 | .tlv => { | |
| 50 | const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse | |
| 51 | return null; | |
| 52 | const thunk_atom = macho_file.getAtom(thunk_atom_index); | |
| 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)) { | |
| 48 | .X86_64_RELOC_GOT, | |
| 49 | .X86_64_RELOC_GOT_LOAD, | |
| 50 | => return macho_file.getGotAtomIndexForSymbol(self.target), | |
| 51 | else => {}, | |
| 52 | }, | |
| 53 | else => unreachable, | |
| 54 | } | |
| 55 | if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom; | |
| 56 | return macho_file.getAtomIndexForSymbol(self.target); | |
| 55 | .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index| | |
| 56 | index | |
| 57 | else | |
| 58 | macho_file.getAtomIndexForSymbol(self.target), | |
| 59 | else => macho_file.getAtomIndexForSymbol(self.target), | |
| 60 | }; | |
| 57 | 61 | } |
| 58 | 62 | |
| 59 | 63 | pub 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 | 68 | |
| 65 | 69 | const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable(). |
| 66 | 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 | }; | |
| 68 | 81 | |
| 69 | 82 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ |
| 70 | 83 | source_addr, |
| 71 | 84 | target_addr, |
| 72 | 85 | macho_file.getSymbolName(self.target), |
| 73 | self.fmtType(macho_file.base.options.target), | |
| 86 | @tagName(self.type), | |
| 74 | 87 | }); |
| 75 | 88 | |
| 76 | 89 | switch (arch) { |
| ... | ... | @@ -81,18 +94,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod |
| 81 | 94 | } |
| 82 | 95 | |
| 83 | 96 | fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void { |
| 84 | const rel_type = @intToEnum(macho.reloc_type_arm64, self.type); | |
| 85 | if (rel_type == .ARM64_RELOC_UNSIGNED) { | |
| 86 | return switch (self.length) { | |
| 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 => { | |
| 97 | var buffer = code[self.offset..]; | |
| 98 | switch (self.type) { | |
| 99 | .branch => { | |
| 96 | 100 | const displacement = math.cast( |
| 97 | 101 | i28, |
| 98 | 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 | 105 | .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload( |
| 102 | 106 | aarch64.Instruction, |
| 103 | 107 | aarch64.Instruction.unconditional_branch_immediate, |
| 104 | ), buffer), | |
| 108 | ), buffer[0..4]), | |
| 105 | 109 | }; |
| 106 | 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, | |
| 110 | .ARM64_RELOC_GOT_LOAD_PAGE21, | |
| 111 | .ARM64_RELOC_TLVP_LOAD_PAGE21, | |
| 112 | => { | |
| 113 | .page, .got_page => { | |
| 113 | 114 | const source_page = @intCast(i32, source_addr >> 12); |
| 114 | 115 | const target_page = @intCast(i32, target_addr >> 12); |
| 115 | 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 | 118 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( |
| 118 | 119 | aarch64.Instruction, |
| 119 | 120 | aarch64.Instruction.pc_relative_address, |
| 120 | ), buffer), | |
| 121 | ), buffer[0..4]), | |
| 121 | 122 | }; |
| 122 | 123 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 123 | 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 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | |
| 128 | => { | |
| 127 | .pageoff, .got_pageoff => { | |
| 129 | 128 | const narrowed = @truncate(u12, @intCast(u64, target_addr)); |
| 130 | if (isArithmeticOp(buffer)) { | |
| 129 | if (isArithmeticOp(buffer[0..4])) { | |
| 131 | 130 | var inst = aarch64.Instruction{ |
| 132 | 131 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( |
| 133 | 132 | aarch64.Instruction, |
| 134 | 133 | aarch64.Instruction.add_subtract_immediate, |
| 135 | ), buffer), | |
| 134 | ), buffer[0..4]), | |
| 136 | 135 | }; |
| 137 | 136 | inst.add_subtract_immediate.imm12 = narrowed; |
| 138 | mem.writeIntLittle(u32, buffer, inst.toU32()); | |
| 137 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 139 | 138 | } else { |
| 140 | 139 | var inst = aarch64.Instruction{ |
| 141 | 140 | .load_store_register = mem.bytesToValue(meta.TagPayload( |
| 142 | 141 | aarch64.Instruction, |
| 143 | 142 | aarch64.Instruction.load_store_register, |
| 144 | ), buffer), | |
| 143 | ), buffer[0..4]), | |
| 145 | 144 | }; |
| 146 | 145 | const offset: u12 = blk: { |
| 147 | 146 | if (inst.load_store_register.size == 0) { |
| ... | ... | @@ -157,89 +156,25 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: [] |
| 157 | 156 | } |
| 158 | 157 | }; |
| 159 | 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 => { | |
| 164 | const RegInfo = struct { | |
| 165 | rd: u5, | |
| 166 | rn: u5, | |
| 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); | |
| 162 | .tlv_initializer, .unsigned => switch (self.length) { | |
| 163 | 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))), | |
| 164 | 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)), | |
| 165 | else => unreachable, | |
| 209 | 166 | }, |
| 210 | .ARM64_RELOC_SUBTRACTOR => unreachable, | |
| 211 | .ARM64_RELOC_ADDEND => unreachable, | |
| 212 | .ARM64_RELOC_UNSIGNED => unreachable, | |
| 167 | .got, .signed, .tlv => unreachable, // Invalid target architecture. | |
| 213 | 168 | } |
| 214 | 169 | } |
| 215 | 170 | |
| 216 | 171 | fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void { |
| 217 | const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type); | |
| 218 | switch (rel_type) { | |
| 219 | .X86_64_RELOC_BRANCH, | |
| 220 | .X86_64_RELOC_GOT, | |
| 221 | .X86_64_RELOC_GOT_LOAD, | |
| 222 | .X86_64_RELOC_TLV, | |
| 223 | => { | |
| 172 | switch (self.type) { | |
| 173 | .branch, .got, .tlv, .signed => { | |
| 224 | 174 | const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4); |
| 225 | 175 | mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement)); |
| 226 | 176 | }, |
| 227 | .X86_64_RELOC_SIGNED, | |
| 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 => { | |
| 177 | .tlv_initializer, .unsigned => { | |
| 243 | 178 | switch (self.length) { |
| 244 | 179 | 2 => { |
| 245 | 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 | 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 | } |
| 256 | 191 | |
| ... | ... | @@ -258,3 +193,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool { |
| 258 | 193 | const group_decode = @truncate(u5, inst[3]); |
| 259 | 194 | return ((group_decode >> 2) == 4); |
| 260 | 195 | } |
| 196 | ||
| 197 | const Relocation = @This(); | |
| 198 | ||
| 199 | const std = @import("std"); | |
| 200 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | |
| 201 | const assert = std.debug.assert; | |
| 202 | const log = std.log.scoped(.link); | |
| 203 | const macho = std.macho; | |
| 204 | const math = std.math; | |
| 205 | const mem = std.mem; | |
| 206 | const meta = std.meta; | |
| 207 | ||
| 208 | const Atom = @import("Atom.zig"); | |
| 209 | const MachO = @import("../MachO.zig"); | |
| 210 | const SymbolWithLoc = MachO.SymbolWithLoc; |