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