| ... | @@ -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); |
| 3799 | | 3799 | |
| 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); |
| 3802 | | 3802 | |
| 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}); |
| 3804 | | 3805 | |
| 3805 | errdefer self.freeAtom(atom, match, true); | 3806 | errdefer self.freeAtom(atom, match, true); |
| 3806 | | 3807 | |
| ... | @@ -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 | } |
| 3905 | | 3906 | |
| 3906 | fn 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. |
| | 3909 | fn 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 | } |
| 3926 | | 3959 | |
| 3927 | fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection { | 3960 | fn 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]; |
| 4057 | | 4049 | |
| | 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); | | |
| 4065 | | 4058 | |
| 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); |
| 4072 | | 4065 | |
| 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}); |
| 4074 | | 4068 | |
| 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); |
| 4106 | | 4100 | |
| 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}); |
| 4108 | | 4103 | |
| 4109 | errdefer self.freeAtom(&decl.link.macho, match, false); | 4104 | errdefer self.freeAtom(&decl.link.macho, match, false); |
| 4110 | | 4105 | |