aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/InternalObject.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2024-05-23 14:21:31 +0200
committerGitHub <noreply@github.com>2024-05-23 14:21:31 +0200
commitfb88cfdf6aa3fabba700d8340f025e4a3e0d3fb2 (patch)
treef613ac6f06fe2cb46c58cd55eb1eaaee09990e07 /src/link/MachO/InternalObject.zig
parent9be8a9000faead40b1aec4877506ff10b066659c (diff)
parentd31eb744cec1d991def2d6d42a14ded82af1dbbe (diff)
downloadzig-fb88cfdf6aa3fabba700d8340f025e4a3e0d3fb2.tar.gz
zig-fb88cfdf6aa3fabba700d8340f025e4a3e0d3fb2.zip
Merge pull request #20032 from ziglang/macho-literals
link/macho: implement logic for merging literals
Diffstat (limited to 'src/link/MachO/InternalObject.zig')
-rw-r--r--src/link/MachO/InternalObject.zig148
1 files changed, 115 insertions, 33 deletions
diff --git a/src/link/MachO/InternalObject.zig b/src/link/MachO/InternalObject.zig
index 9f42eca114..cbc7f3025c 100644
--- a/src/link/MachO/InternalObject.zig
+++ b/src/link/MachO/InternalObject.zig
@@ -3,7 +3,6 @@ index: File.Index,
sections: std.MultiArrayList(Section) = .{},
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
-strtab: std.ArrayListUnmanaged(u8) = .{},
objc_methnames: std.ArrayListUnmanaged(u8) = .{},
objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64),
@@ -18,7 +17,6 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
self.sections.deinit(allocator);
self.atoms.deinit(allocator);
self.symbols.deinit(allocator);
- self.strtab.deinit(allocator);
self.objc_methnames.deinit(allocator);
}
@@ -38,9 +36,9 @@ pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO)
}
/// Creates a fake input sections __TEXT,__objc_methname and __DATA,__objc_selrefs.
-pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !u32 {
+pub fn addObjcMsgsendSections(self: *InternalObject, sym_name: []const u8, macho_file: *MachO) !Atom.Index {
const methname_atom_index = try self.addObjcMethnameSection(sym_name, macho_file);
- return try self.addObjcSelrefsSection(sym_name, methname_atom_index, macho_file);
+ return try self.addObjcSelrefsSection(methname_atom_index, macho_file);
}
fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_file: *MachO) !Atom.Index {
@@ -48,11 +46,8 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
const atom_index = try macho_file.addAtom();
try self.atoms.append(gpa, atom_index);
- const name = try std.fmt.allocPrintZ(gpa, "__TEXT$__objc_methname${s}", .{methname});
- defer gpa.free(name);
const atom = macho_file.getAtom(atom_index).?;
atom.atom_index = atom_index;
- atom.name = try self.addString(gpa, name);
atom.file = self.index;
atom.size = methname.len + 1;
atom.alignment = .@"1";
@@ -72,21 +67,13 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
return atom_index;
}
-fn addObjcSelrefsSection(
- self: *InternalObject,
- methname: []const u8,
- methname_atom_index: Atom.Index,
- macho_file: *MachO,
-) !Atom.Index {
+fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, macho_file: *MachO) !Atom.Index {
const gpa = macho_file.base.comp.gpa;
const atom_index = try macho_file.addAtom();
try self.atoms.append(gpa, atom_index);
- const name = try std.fmt.allocPrintZ(gpa, "__DATA$__objc_selrefs${s}", .{methname});
- defer gpa.free(name);
const atom = macho_file.getAtom(atom_index).?;
atom.atom_index = atom_index;
- atom.name = try self.addString(gpa, name);
atom.file = self.index;
atom.size = @sizeOf(u64);
atom.alignment = .@"8";
@@ -122,6 +109,102 @@ fn addObjcSelrefsSection(
return atom_index;
}
+pub fn resolveLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
+ const gpa = macho_file.base.comp.gpa;
+
+ var buffer = std.ArrayList(u8).init(gpa);
+ defer buffer.deinit();
+
+ const slice = self.sections.slice();
+ for (slice.items(.header), self.atoms.items, 0..) |header, atom_index, n_sect| {
+ if (Object.isCstringLiteral(header) or Object.isFixedSizeLiteral(header)) {
+ const data = try self.getSectionData(@intCast(n_sect));
+ const atom = macho_file.getAtom(atom_index).?;
+ const res = try lp.insert(gpa, header.type(), data);
+ if (!res.found_existing) {
+ res.atom.* = atom_index;
+ }
+ atom.flags.literal_pool = true;
+ try atom.addExtra(.{ .literal_index = res.index }, macho_file);
+ } else if (Object.isPtrLiteral(header)) {
+ const atom = macho_file.getAtom(atom_index).?;
+ const relocs = atom.getRelocs(macho_file);
+ assert(relocs.len == 1);
+ const rel = relocs[0];
+ assert(rel.tag == .local);
+ const target = macho_file.getAtom(rel.target).?;
+ const addend = std.math.cast(u32, rel.addend) orelse return error.Overflow;
+ const target_size = std.math.cast(usize, target.size) orelse return error.Overflow;
+ try buffer.ensureUnusedCapacity(target_size);
+ buffer.resize(target_size) catch unreachable;
+ try target.getData(macho_file, buffer.items);
+ const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);
+ buffer.clearRetainingCapacity();
+ if (!res.found_existing) {
+ res.atom.* = atom_index;
+ }
+ atom.flags.literal_pool = true;
+ try atom.addExtra(.{ .literal_index = res.index }, macho_file);
+ }
+ }
+}
+
+pub fn dedupLiterals(self: InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void {
+ for (self.atoms.items) |atom_index| {
+ const atom = macho_file.getAtom(atom_index) orelse continue;
+ if (!atom.flags.alive) continue;
+ if (!atom.flags.relocs) continue;
+
+ const relocs = blk: {
+ const extra = atom.getExtra(macho_file).?;
+ const relocs = self.sections.items(.relocs)[atom.n_sect].items;
+ break :blk relocs[extra.rel_index..][0..extra.rel_count];
+ };
+ for (relocs) |*rel| switch (rel.tag) {
+ .local => {
+ const target = macho_file.getAtom(rel.target).?;
+ if (target.getLiteralPoolIndex(macho_file)) |lp_index| {
+ const lp_atom = lp.getAtom(lp_index, macho_file);
+ if (target.atom_index != lp_atom.atom_index) {
+ lp_atom.alignment = lp_atom.alignment.max(target.alignment);
+ target.flags.alive = false;
+ rel.target = lp_atom.atom_index;
+ }
+ }
+ },
+ .@"extern" => {
+ const target_sym = rel.getTargetSymbol(macho_file);
+ if (target_sym.getAtom(macho_file)) |target_atom| {
+ if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| {
+ const lp_atom = lp.getAtom(lp_index, macho_file);
+ if (target_atom.atom_index != lp_atom.atom_index) {
+ lp_atom.alignment = lp_atom.alignment.max(target_atom.alignment);
+ target_atom.flags.alive = false;
+ target_sym.atom = lp_atom.atom_index;
+ }
+ }
+ }
+ },
+ };
+ }
+
+ for (self.symbols.items) |sym_index| {
+ const sym = macho_file.getSymbol(sym_index);
+ if (!sym.flags.objc_stubs) continue;
+ var extra = sym.getExtra(macho_file).?;
+ const atom = macho_file.getAtom(extra.objc_selrefs).?;
+ if (atom.getLiteralPoolIndex(macho_file)) |lp_index| {
+ const lp_atom = lp.getAtom(lp_index, macho_file);
+ if (atom.atom_index != lp_atom.atom_index) {
+ lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
+ atom.flags.alive = false;
+ extra.objc_selrefs = lp_atom.atom_index;
+ sym.setExtra(extra, macho_file);
+ }
+ }
+ }
+}
+
pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) !void {
for (self.symbols.items) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
@@ -167,18 +250,23 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,
return n_sect;
}
-pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) !void {
- assert(buffer.len == atom.size);
+fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]const u8 {
const slice = self.sections.slice();
- const sect = slice.items(.header)[atom.n_sect];
- const extra = slice.items(.extra)[atom.n_sect];
- const data = if (extra.is_objc_methname) blk: {
+ assert(index < slice.items(.header).len);
+ const sect = slice.items(.header)[index];
+ const extra = slice.items(.extra)[index];
+ if (extra.is_objc_methname) {
const size = std.math.cast(usize, sect.size) orelse return error.Overflow;
- break :blk self.objc_methnames.items[sect.offset..][0..size];
+ return self.objc_methnames.items[sect.offset..][0..size];
} else if (extra.is_objc_selref)
- &self.objc_selrefs
+ return &self.objc_selrefs
else
@panic("ref to non-existent section");
+}
+
+pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) error{Overflow}!void {
+ assert(buffer.len == atom.size);
+ const data = try self.getSectionData(atom.n_sect);
const off = std.math.cast(usize, atom.off) orelse return error.Overflow;
const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
@memcpy(buffer, data[off..][0..size]);
@@ -191,17 +279,11 @@ pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO
return relocs.items[extra.rel_index..][0..extra.rel_count];
}
-fn addString(self: *InternalObject, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
- const off: u32 = @intCast(self.strtab.items.len);
- try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
- self.strtab.appendSliceAssumeCapacity(name);
- self.strtab.appendAssumeCapacity(0);
- return off;
-}
-
pub fn getString(self: InternalObject, off: u32) [:0]const u8 {
- assert(off < self.strtab.items.len);
- return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
+ _ = self;
+ _ = off;
+ // We don't have any local strings for synthetic atoms.
+ return "";
}
pub fn asFile(self: *InternalObject) File {