aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-02-25 15:26:24 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-02-25 21:59:19 +0100
commit1b8ed7842cc09ff687aa7386bf3af8565055a8d1 (patch)
treec439e150d94ca8d9d4263094cb9473a24df0580b /src/link
parentbf6540ce50f8613386be09aac7dc03604af12e1e (diff)
downloadzig-1b8ed7842cc09ff687aa7386bf3af8565055a8d1.tar.gz
zig-1b8ed7842cc09ff687aa7386bf3af8565055a8d1.zip
macho: redo selection of segment/section for decls and consts
* fix alignment issues for consts with natural ABI alignment not matching that of the `ldr` instruction in `aarch64` - solved by preceeding the `ldr` with an additional `add` instruction to form the full address before dereferencing the pointer. * redo selection of segment/section for decls and consts based on combined type and value
Diffstat (limited to 'src/link')
-rw-r--r--src/link/MachO.zig169
-rw-r--r--src/link/MachO/Atom.zig10
2 files changed, 87 insertions, 92 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 00019879ad..351acaeb17 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -3797,10 +3797,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
atom.code.clearRetainingCapacity();
try atom.code.appendSlice(self.base.allocator, code);
- const match = try self.getMatchingSectionAtom(atom, typed_value.ty, typed_value.val);
+ const match = try self.getMatchingSectionAtom(atom, decl_name, typed_value.ty, typed_value.val);
const addr = try self.allocateAtom(atom, code.len, required_alignment, match);
log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });
+ log.debug(" (required alignment 0x{x})", .{required_alignment});
errdefer self.freeAtom(atom, match, true);
@@ -3903,28 +3904,60 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
try self.updateDeclExports(module, decl, decl_exports);
}
-fn isElemTyPointer(ty: Type) bool {
+/// Checks if the value, or any of its embedded values stores a pointer, and thus requires
+/// a rebase opcode for the dynamic linker.
+fn needsPointerRebase(ty: Type, val: Value) bool {
+ if (ty.zigTypeTag() == .Fn) {
+ return false;
+ }
+ if (val.pointerDecl()) |_| {
+ return true;
+ }
+
switch (ty.zigTypeTag()) {
- .Fn => return false,
+ .Fn => unreachable,
.Pointer => return true,
- .Array => {
- const elem_ty = ty.elemType();
- return isElemTyPointer(elem_ty);
+ .Array, .Vector => {
+ if (ty.arrayLen() == 0) return false;
+ const elem_ty = ty.childType();
+ var elem_value_buf: Value.ElemValueBuffer = undefined;
+ const elem_val = val.elemValueBuffer(0, &elem_value_buf);
+ return needsPointerRebase(elem_ty, elem_val);
},
- .Struct, .Union => {
- const len = ty.structFieldCount();
- var i: usize = 0;
- while (i < len) : (i += 1) {
- const field_ty = ty.structFieldType(i);
- if (isElemTyPointer(field_ty)) return true;
- }
- return false;
+ .Struct => {
+ const fields = ty.structFields().values();
+ if (fields.len == 0) return false;
+ if (val.castTag(.@"struct")) |payload| {
+ const field_values = payload.data;
+ for (field_values) |field_val, i| {
+ if (needsPointerRebase(fields[i].ty, field_val)) return true;
+ } else return false;
+ } else return false;
+ },
+ .Optional => {
+ if (val.castTag(.opt_payload)) |payload| {
+ const sub_val = payload.data;
+ var buffer: Type.Payload.ElemType = undefined;
+ const sub_ty = ty.optionalChild(&buffer);
+ return needsPointerRebase(sub_ty, sub_val);
+ } else return false;
+ },
+ .Union => {
+ const union_obj = val.cast(Value.Payload.Union).?.data;
+ const active_field_ty = ty.unionFieldType(union_obj.tag);
+ return needsPointerRebase(active_field_ty, union_obj.val);
+ },
+ .ErrorUnion => {
+ if (val.castTag(.eu_payload)) |payload| {
+ const payload_ty = ty.errorUnionPayload();
+ return needsPointerRebase(payload_ty, payload.data);
+ } else return false;
},
else => return false,
}
}
-fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection {
+fn getMatchingSectionAtom(self: *MachO, atom: *Atom, name: []const u8, ty: Type, val: Value) !MatchingSection {
const code = atom.code.items;
const alignment = ty.abiAlignment(self.base.options.target);
const align_log_2 = math.log2(alignment);
@@ -3938,10 +3971,25 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
.seg = self.data_segment_cmd_index.?,
.sect = self.bss_section_index.?,
};
+ } else {
+ break :blk MatchingSection{
+ .seg = self.data_segment_cmd_index.?,
+ .sect = self.data_section_index.?,
+ };
}
+ }
+
+ if (val.castTag(.variable)) |_| {
+ break :blk MatchingSection{
+ .seg = self.data_segment_cmd_index.?,
+ .sect = self.data_section_index.?,
+ };
+ }
+
+ if (needsPointerRebase(ty, val)) {
break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__DATA"),
- .sectname = makeStaticString("__data"),
+ .segname = makeStaticString("__DATA_CONST"),
+ .sectname = makeStaticString("__const"),
.size = code.len,
.@"align" = align_log_2,
})).?;
@@ -3954,8 +4002,8 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
.sect = self.text_section_index.?,
};
},
- .Array => switch (val.tag()) {
- .bytes => {
+ .Array => {
+ if (val.tag() == .bytes) {
switch (ty.tag()) {
.array_u8_sentinel_0,
.const_slice_u8_sentinel_0,
@@ -3969,79 +4017,23 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
.@"align" = align_log_2,
})).?;
},
- else => {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__TEXT"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
- },
- }
- },
- .array => {
- if (isElemTyPointer(ty)) {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__DATA_CONST"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
- } else {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__TEXT"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
+ else => {},
}
- },
- else => {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__TEXT"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
- },
- },
- .Pointer => {
- if (val.castTag(.variable)) |_| {
- break :blk MatchingSection{
- .seg = self.data_segment_cmd_index.?,
- .sect = self.data_section_index.?,
- };
- } else {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__DATA_CONST"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
- }
- },
- else => {
- if (val.castTag(.variable)) |_| {
- break :blk MatchingSection{
- .seg = self.data_segment_cmd_index.?,
- .sect = self.data_section_index.?,
- };
- } else {
- break :blk (try self.getMatchingSection(.{
- .segname = makeStaticString("__TEXT"),
- .sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
- })).?;
}
},
+ else => {},
}
+ break :blk (try self.getMatchingSection(.{
+ .segname = makeStaticString("__TEXT"),
+ .sectname = makeStaticString("__const"),
+ .size = code.len,
+ .@"align" = align_log_2,
+ })).?;
};
- const local = self.locals.items[atom.local_sym_index];
const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{
- self.getString(local.n_strx),
+ name,
sect.segName(),
sect.sectName(),
match.seg,
@@ -4055,13 +4047,14 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes()
const symbol = &self.locals.items[decl.link.macho.local_sym_index];
+ const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
+ defer self.base.allocator.free(sym_name);
+
const decl_ptr = self.decls.getPtr(decl).?;
if (decl_ptr.* == null) {
- decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, decl.ty, decl.val);
+ decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, sym_name, decl.ty, decl.val);
}
const match = decl_ptr.*.?;
- const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
- defer self.base.allocator.free(sym_name);
if (decl.link.macho.size != 0) {
const capacity = decl.link.macho.capacity(self.*);
@@ -4071,6 +4064,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, match);
log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr });
+ log.debug(" (required alignment 0x{x})", .{required_alignment});
if (vaddr != symbol.n_value) {
log.debug(" (writing new GOT entry)", .{});
@@ -4105,6 +4099,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, match);
log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, addr });
+ log.debug(" (required alignment 0x{x})", .{required_alignment});
errdefer self.freeAtom(&decl.link.macho, match, false);
diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig
index fae1ff4eba..d0d82a12af 100644
--- a/src/link/MachO/Atom.zig
+++ b/src/link/MachO/Atom.zig
@@ -691,11 +691,11 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
if (is_via_got) {
const got_index = macho_file.got_entries_table.get(rel.target) orelse {
- const n_strx = switch (rel.target) {
- .local => |sym_index| macho_file.locals.items[sym_index].n_strx,
- .global => |n_strx| n_strx,
- };
- log.err("expected GOT entry for symbol '{s}'", .{macho_file.getString(n_strx)});
+ log.err("expected GOT entry for symbol", .{});
+ switch (rel.target) {
+ .local => |sym_index| log.err(" local @{d}", .{sym_index}),
+ .global => |n_strx| log.err(" global @'{s}'", .{macho_file.getString(n_strx)}),
+ }
log.err(" this is an internal linker error", .{});
return error.FailedToResolveRelocationTarget;
};