authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-26 08:19:01+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-26 08:19:01+01:00
log0474943ddfb12552262e3e13f74ecb3842b18019
treec46515f91973faaf597ab9758743bd2190652a2e
parentbf6540ce50f8613386be09aac7dc03604af12e1e
parente0f5627d4a9cb1b3a1361d70d40043c8c170b2af
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10991 from ziglang/macho-pointer-rebase


10 files changed, 141 insertions(+), 117 deletions(-)

src/arch/aarch64/CodeGen.zig+15
...@@ -786,6 +786,11 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -786,6 +786,11 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
786/// Use a pointer instruction as the basis for allocating stack memory.786/// Use a pointer instruction as the basis for allocating stack memory.
787fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {787fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
788 const elem_ty = self.air.typeOfIndex(inst).elemType();788 const elem_ty = self.air.typeOfIndex(inst).elemType();
789
790 if (!elem_ty.hasRuntimeBits()) {
791 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
792 }
793
789 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {794 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
790 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});795 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
791 };796 };
...@@ -3545,6 +3550,15 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {...@@ -3545,6 +3550,15 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
3545fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {3550fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
3546 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3551 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3547 const ptr_bytes: u64 = @divExact(ptr_bits, 8);3552 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3553
3554 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
3555 if (tv.ty.zigTypeTag() == .Pointer) blk: {
3556 if (tv.ty.castPtrToFn()) |_| break :blk;
3557 if (!tv.ty.elemType2().hasRuntimeBits()) {
3558 return MCValue.none;
3559 }
3560 }
3561
3548 decl.alive = true;3562 decl.alive = true;
3549 if (self.bin_file.cast(link.File.Elf)) |elf_file| {3563 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3550 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];3564 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
...@@ -3553,6 +3567,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa...@@ -3553,6 +3567,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
3553 } else if (self.bin_file.cast(link.File.MachO)) |_| {3567 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3554 // Because MachO is PIE-always-on, we defer memory address resolution until3568 // Because MachO is PIE-always-on, we defer memory address resolution until
3555 // the linker has enough info to perform relocations.3569 // the linker has enough info to perform relocations.
3570 assert(decl.link.macho.local_sym_index != 0);
3556 return MCValue{ .got_load = decl.link.macho.local_sym_index };3571 return MCValue{ .got_load = decl.link.macho.local_sym_index };
3557 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {3572 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3558 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;3573 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
src/arch/aarch64/Emit.zig+21-5
...@@ -208,8 +208,8 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {...@@ -208,8 +208,8 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
208 }208 }
209209
210 switch (tag) {210 switch (tag) {
211 .load_memory_direct => return 3 * 4,
211 .load_memory_got,212 .load_memory_got,
212 .load_memory_direct,
213 .load_memory_ptr_got,213 .load_memory_ptr_got,
214 .load_memory_ptr_direct,214 .load_memory_ptr_direct,
215 => return 2 * 4,215 => return 2 * 4,
...@@ -654,15 +654,31 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -654,15 +654,31 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
654 const data = emit.mir.extraData(Mir.LoadMemoryPie, payload).data;654 const data = emit.mir.extraData(Mir.LoadMemoryPie, payload).data;
655 const reg = @intToEnum(Register, data.register);655 const reg = @intToEnum(Register, data.register);
656656
657 // PC-relative displacement to the entry in the GOT table.657 // PC-relative displacement to the entry in memory.
658 // adrp658 // adrp
659 const offset = @intCast(u32, emit.code.items.len);659 const offset = @intCast(u32, emit.code.items.len);
660 try emit.writeInstruction(Instruction.adrp(reg, 0));660 try emit.writeInstruction(Instruction.adrp(reg, 0));
661661
662 switch (tag) {662 switch (tag) {
663 .load_memory_got,663 .load_memory_got => {
664 .load_memory_direct,664 // ldr reg, reg, offset
665 => {665 try emit.writeInstruction(Instruction.ldr(
666 reg,
667 reg,
668 Instruction.LoadStoreOffset.imm(0),
669 ));
670 },
671 .load_memory_direct => {
672 // We cannot load the offset directly as it may not be aligned properly.
673 // For example, load for 64bit register will require the target address offset
674 // to be 8-byte aligned, while the value might have non-8-byte natural alignment,
675 // meaning the linker might have put it at a non-8-byte aligned address. To circumvent
676 // this, we use `adrp, add` to form the address value which we then dereference with
677 // `ldr`.
678 // Note that this can potentially be optimised out by the codegen/linker if the
679 // target address is appropriately aligned.
680 // add reg, reg, offset
681 try emit.writeInstruction(Instruction.add(reg, reg, 0, false));
666 // ldr reg, reg, offset682 // ldr reg, reg, offset
667 try emit.writeInstruction(Instruction.ldr(683 try emit.writeInstruction(Instruction.ldr(
668 reg,684 reg,
src/arch/x86_64/CodeGen.zig+10-1
...@@ -852,7 +852,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -852,7 +852,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
852 const elem_ty = ptr_ty.elemType();852 const elem_ty = ptr_ty.elemType();
853853
854 if (!elem_ty.hasRuntimeBits()) {854 if (!elem_ty.hasRuntimeBits()) {
855 return self.allocMem(inst, 8, 8);855 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
856 }856 }
857857
858 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {858 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
...@@ -5333,6 +5333,14 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa...@@ -5333,6 +5333,14 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
5333 const ptr_bits = self.target.cpu.arch.ptrBitWidth();5333 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
5334 const ptr_bytes: u64 = @divExact(ptr_bits, 8);5334 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
53355335
5336 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
5337 if (tv.ty.zigTypeTag() == .Pointer) blk: {
5338 if (tv.ty.castPtrToFn()) |_| break :blk;
5339 if (!tv.ty.elemType2().hasRuntimeBits()) {
5340 return MCValue.none;
5341 }
5342 }
5343
5336 decl.alive = true;5344 decl.alive = true;
5337 if (self.bin_file.cast(link.File.Elf)) |elf_file| {5345 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
5338 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];5346 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
...@@ -5341,6 +5349,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa...@@ -5341,6 +5349,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
5341 } else if (self.bin_file.cast(link.File.MachO)) |_| {5349 } else if (self.bin_file.cast(link.File.MachO)) |_| {
5342 // Because MachO is PIE-always-on, we defer memory address resolution until5350 // Because MachO is PIE-always-on, we defer memory address resolution until
5343 // the linker has enough info to perform relocations.5351 // the linker has enough info to perform relocations.
5352 assert(decl.link.macho.local_sym_index != 0);
5344 return MCValue{ .got_load = decl.link.macho.local_sym_index };5353 return MCValue{ .got_load = decl.link.macho.local_sym_index };
5345 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {5354 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5346 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;5355 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
src/arch/x86_64/Emit.zig+1
...@@ -857,6 +857,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -857,6 +857,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
857 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),857 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
858 };858 };
859 const atom = macho_file.atom_by_index_table.get(load_reloc.atom_index).?;859 const atom = macho_file.atom_by_index_table.get(load_reloc.atom_index).?;
860 log.debug("adding reloc of type {} to local @{d}", .{ reloc_type, load_reloc.sym_index });
860 try atom.relocs.append(emit.bin_file.allocator, .{861 try atom.relocs.append(emit.bin_file.allocator, .{
861 .offset = @intCast(u32, end_offset - 4),862 .offset = @intCast(u32, end_offset - 4),
862 .target = .{ .local = load_reloc.sym_index },863 .target = .{ .local = load_reloc.sym_index },
src/link/MachO.zig+89-87
...@@ -3797,10 +3797,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De...@@ -3797,10 +3797,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
3797 atom.code.clearRetainingCapacity();3797 atom.code.clearRetainingCapacity();
3798 try atom.code.appendSlice(self.base.allocator, code);3798 try atom.code.appendSlice(self.base.allocator, code);
37993799
3800 const match = try self.getMatchingSectionAtom(atom, typed_value.ty, typed_value.val);3800 const match = try self.getMatchingSectionAtom(atom, decl_name, typed_value.ty, typed_value.val);
3801 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);3801 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);
38023802
3803 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });3803 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });
3804 log.debug(" (required alignment 0x{x})", .{required_alignment});
38043805
3805 errdefer self.freeAtom(atom, match, true);3806 errdefer self.freeAtom(atom, match, true);
38063807
...@@ -3903,28 +3904,60 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3903,28 +3904,60 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3903 try self.updateDeclExports(module, decl, decl_exports);3904 try self.updateDeclExports(module, decl, decl_exports);
3904}3905}
39053906
3906fn isElemTyPointer(ty: Type) bool {3907/// Checks if the value, or any of its embedded values stores a pointer, and thus requires
3908/// a rebase opcode for the dynamic linker.
3909fn needsPointerRebase(ty: Type, val: Value) bool {
3910 if (ty.zigTypeTag() == .Fn) {
3911 return false;
3912 }
3913 if (val.pointerDecl()) |_| {
3914 return true;
3915 }
3916
3907 switch (ty.zigTypeTag()) {3917 switch (ty.zigTypeTag()) {
3908 .Fn => return false,3918 .Fn => unreachable,
3909 .Pointer => return true,3919 .Pointer => return true,
3910 .Array => {3920 .Array, .Vector => {
3911 const elem_ty = ty.elemType();3921 if (ty.arrayLen() == 0) return false;
3912 return isElemTyPointer(elem_ty);3922 const elem_ty = ty.childType();
3923 var elem_value_buf: Value.ElemValueBuffer = undefined;
3924 const elem_val = val.elemValueBuffer(0, &elem_value_buf);
3925 return needsPointerRebase(elem_ty, elem_val);
3913 },3926 },
3914 .Struct, .Union => {3927 .Struct => {
3915 const len = ty.structFieldCount();3928 const fields = ty.structFields().values();
3916 var i: usize = 0;3929 if (fields.len == 0) return false;
3917 while (i < len) : (i += 1) {3930 if (val.castTag(.@"struct")) |payload| {
3918 const field_ty = ty.structFieldType(i);3931 const field_values = payload.data;
3919 if (isElemTyPointer(field_ty)) return true;3932 for (field_values) |field_val, i| {
3920 }3933 if (needsPointerRebase(fields[i].ty, field_val)) return true;
3921 return false;3934 } else return false;
3935 } else return false;
3936 },
3937 .Optional => {
3938 if (val.castTag(.opt_payload)) |payload| {
3939 const sub_val = payload.data;
3940 var buffer: Type.Payload.ElemType = undefined;
3941 const sub_ty = ty.optionalChild(&buffer);
3942 return needsPointerRebase(sub_ty, sub_val);
3943 } else return false;
3944 },
3945 .Union => {
3946 const union_obj = val.cast(Value.Payload.Union).?.data;
3947 const active_field_ty = ty.unionFieldType(union_obj.tag);
3948 return needsPointerRebase(active_field_ty, union_obj.val);
3949 },
3950 .ErrorUnion => {
3951 if (val.castTag(.eu_payload)) |payload| {
3952 const payload_ty = ty.errorUnionPayload();
3953 return needsPointerRebase(payload_ty, payload.data);
3954 } else return false;
3922 },3955 },
3923 else => return false,3956 else => return false,
3924 }3957 }
3925}3958}
39263959
3927fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection {3960fn getMatchingSectionAtom(self: *MachO, atom: *Atom, name: []const u8, ty: Type, val: Value) !MatchingSection {
3928 const code = atom.code.items;3961 const code = atom.code.items;
3929 const alignment = ty.abiAlignment(self.base.options.target);3962 const alignment = ty.abiAlignment(self.base.options.target);
3930 const align_log_2 = math.log2(alignment);3963 const align_log_2 = math.log2(alignment);
...@@ -3938,10 +3971,25 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc...@@ -3938,10 +3971,25 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
3938 .seg = self.data_segment_cmd_index.?,3971 .seg = self.data_segment_cmd_index.?,
3939 .sect = self.bss_section_index.?,3972 .sect = self.bss_section_index.?,
3940 };3973 };
3974 } else {
3975 break :blk MatchingSection{
3976 .seg = self.data_segment_cmd_index.?,
3977 .sect = self.data_section_index.?,
3978 };
3941 }3979 }
3980 }
3981
3982 if (val.castTag(.variable)) |_| {
3983 break :blk MatchingSection{
3984 .seg = self.data_segment_cmd_index.?,
3985 .sect = self.data_section_index.?,
3986 };
3987 }
3988
3989 if (needsPointerRebase(ty, val)) {
3942 break :blk (try self.getMatchingSection(.{3990 break :blk (try self.getMatchingSection(.{
3943 .segname = makeStaticString("__DATA"),3991 .segname = makeStaticString("__DATA_CONST"),
3944 .sectname = makeStaticString("__data"),3992 .sectname = makeStaticString("__const"),
3945 .size = code.len,3993 .size = code.len,
3946 .@"align" = align_log_2,3994 .@"align" = align_log_2,
3947 })).?;3995 })).?;
...@@ -3954,8 +4002,8 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc...@@ -3954,8 +4002,8 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
3954 .sect = self.text_section_index.?,4002 .sect = self.text_section_index.?,
3955 };4003 };
3956 },4004 },
3957 .Array => switch (val.tag()) {4005 .Array => {
3958 .bytes => {4006 if (val.tag() == .bytes) {
3959 switch (ty.tag()) {4007 switch (ty.tag()) {
3960 .array_u8_sentinel_0,4008 .array_u8_sentinel_0,
3961 .const_slice_u8_sentinel_0,4009 .const_slice_u8_sentinel_0,
...@@ -3969,79 +4017,23 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc...@@ -3969,79 +4017,23 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
3969 .@"align" = align_log_2,4017 .@"align" = align_log_2,
3970 })).?;4018 })).?;
3971 },4019 },
3972 else => {4020 else => {},
3973 break :blk (try self.getMatchingSection(.{
3974 .segname = makeStaticString("__TEXT"),
3975 .sectname = makeStaticString("__const"),
3976 .size = code.len,
3977 .@"align" = align_log_2,
3978 })).?;
3979 },
3980 }
3981 },
3982 .array => {
3983 if (isElemTyPointer(ty)) {
3984 break :blk (try self.getMatchingSection(.{
3985 .segname = makeStaticString("__DATA_CONST"),
3986 .sectname = makeStaticString("__const"),
3987 .size = code.len,
3988 .@"align" = align_log_2,
3989 })).?;
3990 } else {
3991 break :blk (try self.getMatchingSection(.{
3992 .segname = makeStaticString("__TEXT"),
3993 .sectname = makeStaticString("__const"),
3994 .size = code.len,
3995 .@"align" = align_log_2,
3996 })).?;
3997 }4021 }
3998 },
3999 else => {
4000 break :blk (try self.getMatchingSection(.{
4001 .segname = makeStaticString("__TEXT"),
4002 .sectname = makeStaticString("__const"),
4003 .size = code.len,
4004 .@"align" = align_log_2,
4005 })).?;
4006 },
4007 },
4008 .Pointer => {
4009 if (val.castTag(.variable)) |_| {
4010 break :blk MatchingSection{
4011 .seg = self.data_segment_cmd_index.?,
4012 .sect = self.data_section_index.?,
4013 };
4014 } else {
4015 break :blk (try self.getMatchingSection(.{
4016 .segname = makeStaticString("__DATA_CONST"),
4017 .sectname = makeStaticString("__const"),
4018 .size = code.len,
4019 .@"align" = align_log_2,
4020 })).?;
4021 }
4022 },
4023 else => {
4024 if (val.castTag(.variable)) |_| {
4025 break :blk MatchingSection{
4026 .seg = self.data_segment_cmd_index.?,
4027 .sect = self.data_section_index.?,
4028 };
4029 } else {
4030 break :blk (try self.getMatchingSection(.{
4031 .segname = makeStaticString("__TEXT"),
4032 .sectname = makeStaticString("__const"),
4033 .size = code.len,
4034 .@"align" = align_log_2,
4035 })).?;
4036 }4022 }
4037 },4023 },
4024 else => {},
4038 }4025 }
4026 break :blk (try self.getMatchingSection(.{
4027 .segname = makeStaticString("__TEXT"),
4028 .sectname = makeStaticString("__const"),
4029 .size = code.len,
4030 .@"align" = align_log_2,
4031 })).?;
4039 };4032 };
4040 const local = self.locals.items[atom.local_sym_index];
4041 const seg = self.load_commands.items[match.seg].segment;4033 const seg = self.load_commands.items[match.seg].segment;
4042 const sect = seg.sections.items[match.sect];4034 const sect = seg.sections.items[match.sect];
4043 log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{4035 log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{
4044 self.getString(local.n_strx),4036 name,
4045 sect.segName(),4037 sect.segName(),
4046 sect.sectName(),4038 sect.sectName(),
4047 match.seg,4039 match.seg,
...@@ -4055,13 +4047,14 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -4055,13 +4047,14 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
4055 assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes()4047 assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes()
4056 const symbol = &self.locals.items[decl.link.macho.local_sym_index];4048 const symbol = &self.locals.items[decl.link.macho.local_sym_index];
40574049
4050 const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
4051 defer self.base.allocator.free(sym_name);
4052
4058 const decl_ptr = self.decls.getPtr(decl).?;4053 const decl_ptr = self.decls.getPtr(decl).?;
4059 if (decl_ptr.* == null) {4054 if (decl_ptr.* == null) {
4060 decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, decl.ty, decl.val);4055 decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, sym_name, decl.ty, decl.val);
4061 }4056 }
4062 const match = decl_ptr.*.?;4057 const match = decl_ptr.*.?;
4063 const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
4064 defer self.base.allocator.free(sym_name);
40654058
4066 if (decl.link.macho.size != 0) {4059 if (decl.link.macho.size != 0) {
4067 const capacity = decl.link.macho.capacity(self.*);4060 const capacity = decl.link.macho.capacity(self.*);
...@@ -4071,6 +4064,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -4071,6 +4064,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
4071 const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, match);4064 const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, match);
40724065
4073 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr });4066 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr });
4067 log.debug(" (required alignment 0x{x})", .{required_alignment});
40744068
4075 if (vaddr != symbol.n_value) {4069 if (vaddr != symbol.n_value) {
4076 log.debug(" (writing new GOT entry)", .{});4070 log.debug(" (writing new GOT entry)", .{});
...@@ -4105,6 +4099,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -4105,6 +4099,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
4105 const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, match);4099 const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, match);
41064100
4107 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, addr });4101 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, addr });
4102 log.debug(" (required alignment 0x{x})", .{required_alignment});
41084103
4109 errdefer self.freeAtom(&decl.link.macho, match, false);4104 errdefer self.freeAtom(&decl.link.macho, match, false);
41104105
...@@ -4291,6 +4286,7 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -4291,6 +4286,7 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
4291}4286}
42924287
4293fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {4288fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {
4289 log.debug("freeUnnamedConsts for decl {*}", .{decl});
4294 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl) orelse return;4290 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl) orelse return;
4295 for (unnamed_consts.items) |atom| {4291 for (unnamed_consts.items) |atom| {
4296 self.freeAtom(atom, .{4292 self.freeAtom(atom, .{
...@@ -4300,6 +4296,7 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {...@@ -4300,6 +4296,7 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {
4300 self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {};4296 self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
4301 self.locals.items[atom.local_sym_index].n_type = 0;4297 self.locals.items[atom.local_sym_index].n_type = 0;
4302 _ = self.atom_by_index_table.remove(atom.local_sym_index);4298 _ = self.atom_by_index_table.remove(atom.local_sym_index);
4299 log.debug(" adding local symbol index {d} to free list", .{atom.local_sym_index});
4303 atom.local_sym_index = 0;4300 atom.local_sym_index = 0;
4304 }4301 }
4305 unnamed_consts.clearAndFree(self.base.allocator);4302 unnamed_consts.clearAndFree(self.base.allocator);
...@@ -4324,10 +4321,15 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -4324,10 +4321,15 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
4324 self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};4321 self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};
4325 self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };4322 self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };
4326 _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });4323 _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });
4324 log.debug(" adding GOT index {d} to free list (target local@{d})", .{
4325 got_index,
4326 decl.link.macho.local_sym_index,
4327 });
4327 }4328 }
43284329
4329 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;4330 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
4330 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);4331 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);
4332 log.debug(" adding local symbol index {d} to free list", .{decl.link.macho.local_sym_index});
4331 decl.link.macho.local_sym_index = 0;4333 decl.link.macho.local_sym_index = 0;
4332 }4334 }
4333 if (self.d_sym) |*d_sym| {4335 if (self.d_sym) |*d_sym| {
src/link/MachO/Atom.zig+5-5
...@@ -691,11 +691,11 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -691,11 +691,11 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
691691
692 if (is_via_got) {692 if (is_via_got) {
693 const got_index = macho_file.got_entries_table.get(rel.target) orelse {693 const got_index = macho_file.got_entries_table.get(rel.target) orelse {
694 const n_strx = switch (rel.target) {694 log.err("expected GOT entry for symbol", .{});
695 .local => |sym_index| macho_file.locals.items[sym_index].n_strx,695 switch (rel.target) {
696 .global => |n_strx| n_strx,696 .local => |sym_index| log.err(" local @{d}", .{sym_index}),
697 };697 .global => |n_strx| log.err(" global @'{s}'", .{macho_file.getString(n_strx)}),
698 log.err("expected GOT entry for symbol '{s}'", .{macho_file.getString(n_strx)});698 }
699 log.err(" this is an internal linker error", .{});699 log.err(" this is an internal linker error", .{});
700 return error.FailedToResolveRelocationTarget;700 return error.FailedToResolveRelocationTarget;
701 };701 };
test/behavior/align.zig-1
...@@ -7,7 +7,6 @@ var foo: u8 align(4) = 100;...@@ -7,7 +7,6 @@ var foo: u8 align(4) = 100;
77
8test "global variable alignment" {8test "global variable alignment" {
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
1110
12 comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);11 comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
13 comptime try expect(@TypeOf(&foo) == *align(4) u8);12 comptime try expect(@TypeOf(&foo) == *align(4) u8);
test/behavior/basic.zig-5
...@@ -195,9 +195,6 @@ test "multiline string comments at multiple places" {...@@ -195,9 +195,6 @@ test "multiline string comments at multiple places" {
195}195}
196196
197test "string concatenation" {197test "string concatenation" {
198 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
199 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
200
201 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));198 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
202}199}
203200
...@@ -402,8 +399,6 @@ fn testTakeAddressOfParameter(f: f32) !void {...@@ -402,8 +399,6 @@ fn testTakeAddressOfParameter(f: f32) !void {
402399
403test "pointer to void return type" {400test "pointer to void return type" {
404 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO401 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
407402
408 try testPointerToVoidReturnType();403 try testPointerToVoidReturnType();
409}404}
test/behavior/struct.zig-2
...@@ -370,8 +370,6 @@ test "empty struct method call" {...@@ -370,8 +370,6 @@ test "empty struct method call" {
370 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO370 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO371 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
373 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
375373
376 const es = EmptyStruct{};374 const es = EmptyStruct{};
377 try expect(es.method() == 1234);375 try expect(es.method() == 1234);
test/behavior/union.zig-11
...@@ -44,7 +44,6 @@ fn setInt(foo: *Foo, x: i32) void {...@@ -44,7 +44,6 @@ fn setInt(foo: *Foo, x: i32) void {
4444
45test "comptime union field access" {45test "comptime union field access" {
46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4847
49 comptime {48 comptime {
50 var foo = Foo{ .int = 0 };49 var foo = Foo{ .int = 0 };
...@@ -77,14 +76,12 @@ const ExternPtrOrInt = extern union {...@@ -77,14 +76,12 @@ const ExternPtrOrInt = extern union {
77};76};
78test "extern union size" {77test "extern union size" {
79 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8179
82 comptime try expect(@sizeOf(ExternPtrOrInt) == 8);80 comptime try expect(@sizeOf(ExternPtrOrInt) == 8);
83}81}
8482
85test "0-sized extern union definition" {83test "0-sized extern union definition" {
86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8885
89 const U = extern union {86 const U = extern union {
90 a: void,87 a: void,
...@@ -115,9 +112,7 @@ const err = @as(anyerror!Agg, Agg{...@@ -115,9 +112,7 @@ const err = @as(anyerror!Agg, Agg{
115const array = [_]Value{ v1, v2, v1, v2 };112const array = [_]Value{ v1, v2, v1, v2 };
116113
117test "unions embedded in aggregate types" {114test "unions embedded in aggregate types" {
118 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
121116
122 switch (array[1]) {117 switch (array[1]) {
123 Value.Array => |arr| try expect(arr[4] == 3),118 Value.Array => |arr| try expect(arr[4] == 3),
...@@ -131,7 +126,6 @@ test "unions embedded in aggregate types" {...@@ -131,7 +126,6 @@ test "unions embedded in aggregate types" {
131126
132test "access a member of tagged union with conflicting enum tag name" {127test "access a member of tagged union with conflicting enum tag name" {
133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;128 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135129
136 const Bar = union(enum) {130 const Bar = union(enum) {
137 A: A,131 A: A,
...@@ -176,7 +170,6 @@ const TaggedUnionWithPayload = union(enum) {...@@ -176,7 +170,6 @@ const TaggedUnionWithPayload = union(enum) {
176170
177test "union alignment" {171test "union alignment" {
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180173
181 comptime {174 comptime {
182 try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf([9]u8));175 try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf([9]u8));
...@@ -276,7 +269,6 @@ fn testCastUnionToTag() !void {...@@ -276,7 +269,6 @@ fn testCastUnionToTag() !void {
276269
277test "union field access gives the enum values" {270test "union field access gives the enum values" {
278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
280272
281 try expect(TheUnion.A == TheTag.A);273 try expect(TheUnion.A == TheTag.A);
282 try expect(TheUnion.B == TheTag.B);274 try expect(TheUnion.B == TheTag.B);
...@@ -352,7 +344,6 @@ const PackedPtrOrInt = packed union {...@@ -352,7 +344,6 @@ const PackedPtrOrInt = packed union {
352};344};
353test "packed union size" {345test "packed union size" {
354 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
356347
357 comptime try expect(@sizeOf(PackedPtrOrInt) == 8);348 comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
358}349}
...@@ -362,7 +353,6 @@ const ZeroBits = union {...@@ -362,7 +353,6 @@ const ZeroBits = union {
362};353};
363test "union with only 1 field which is void should be zero bits" {354test "union with only 1 field which is void should be zero bits" {
364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;355 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
366356
367 comptime try expect(@sizeOf(ZeroBits) == 0);357 comptime try expect(@sizeOf(ZeroBits) == 0);
368}358}
...@@ -422,7 +412,6 @@ test "union with only 1 field casted to its enum type" {...@@ -422,7 +412,6 @@ test "union with only 1 field casted to its enum type" {
422412
423test "union with one member defaults to u0 tag type" {413test "union with one member defaults to u0 tag type" {
424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
425 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
426415
427 const U0 = union(enum) {416 const U0 = union(enum) {
428 X: u32,417 X: u32,