diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-05-23 14:21:31 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-23 14:21:31 +0200 |
| commit | fb88cfdf6aa3fabba700d8340f025e4a3e0d3fb2 (patch) | |
| tree | f613ac6f06fe2cb46c58cd55eb1eaaee09990e07 /src/link/MachO/InternalObject.zig | |
| parent | 9be8a9000faead40b1aec4877506ff10b066659c (diff) | |
| parent | d31eb744cec1d991def2d6d42a14ded82af1dbbe (diff) | |
| download | zig-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.zig | 148 |
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 { |
