Commit f86a38564f

Jakub Konka <kubkon@jakubkonka.com>
2024-07-09 19:30:58
macho: migrate synthetic sections
1 parent 2e87883
Changed files (2)
src
src/link/MachO/synthetic.zig
@@ -18,15 +18,15 @@ pub const ZigGotSection = struct {
     }
 
     pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index {
-        const comp = macho_file.base.comp;
-        const gpa = comp.gpa;
+        const gpa = macho_file.base.comp.gpa;
+        const zo = macho_file.getZigObject().?;
         const index = try zig_got.allocateEntry(gpa);
         const entry = &zig_got.entries.items[index];
         entry.* = sym_index;
-        const symbol = macho_file.getSymbol(sym_index);
+        const symbol = zo.getSymbol(sym_index);
         assert(symbol.flags.needs_zig_got);
         symbol.flags.has_zig_got = true;
-        try symbol.addExtra(.{ .zig_got = index }, macho_file);
+        symbol.addExtra(.{ .zig_got = index }, macho_file);
         return index;
     }
 
@@ -53,9 +53,10 @@ pub const ZigGotSection = struct {
             try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size);
             zig_got.dirty = false;
         }
+        const zo = macho_file.getZigObject().?;
         const off = zig_got.entryOffset(index, macho_file);
         const entry = zig_got.entries.items[index];
-        const value = macho_file.getSymbol(entry).getAddress(.{ .stubs = false }, macho_file);
+        const value = zo.getSymbol(entry).getAddress(.{ .stubs = false }, macho_file);
 
         var buf: [8]u8 = undefined;
         std.mem.writeInt(u64, &buf, value, .little);
@@ -63,8 +64,9 @@ pub const ZigGotSection = struct {
     }
 
     pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void {
+        const zo = macho_file.getZigObject().?;
         for (zig_got.entries.items) |entry| {
-            const symbol = macho_file.getSymbol(entry);
+            const symbol = zo.getSymbol(entry);
             const value = symbol.address(.{ .stubs = false }, macho_file);
             try writer.writeInt(u64, value, .little);
         }
@@ -87,22 +89,25 @@ pub const ZigGotSection = struct {
     ) !void {
         _ = options;
         _ = unused_fmt_string;
+        const zig_got = ctx.zig_got;
+        const macho_file = ctx.macho_file;
+        const zo = macho_file.getZigObject().?;
         try writer.writeAll("__zig_got\n");
-        for (ctx.zig_got.entries.items, 0..) |entry, index| {
-            const symbol = ctx.macho_file.getSymbol(entry);
+        for (zig_got.entries.items, 0..) |entry, index| {
+            const symbol = zo.getSymbol(entry);
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 index,
-                ctx.zig_got.entryAddress(@intCast(index), ctx.macho_file),
+                zig_got.entryAddress(@intCast(index), macho_file),
                 entry,
-                symbol.getAddress(.{}, ctx.macho_file),
-                symbol.getName(ctx.macho_file),
+                symbol.getAddress(.{}, macho_file),
+                symbol.getName(macho_file),
             });
         }
     }
 };
 
 pub const GotSection = struct {
-    symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+    symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},
 
     pub const Index = u32;
 
@@ -110,14 +115,14 @@ pub const GotSection = struct {
         got.symbols.deinit(allocator);
     }
 
-    pub fn addSymbol(got: *GotSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
+    pub fn addSymbol(got: *GotSection, ref: MachO.Ref, macho_file: *MachO) !void {
         const gpa = macho_file.base.comp.gpa;
         const index = @as(Index, @intCast(got.symbols.items.len));
         const entry = try got.symbols.addOne(gpa);
-        entry.* = sym_index;
-        const symbol = macho_file.getSymbol(sym_index);
+        entry.* = ref;
+        const symbol = ref.getSymbol(macho_file).?;
         symbol.flags.has_got = true;
-        try symbol.addExtra(.{ .got = index }, macho_file);
+        symbol.addExtra(.{ .got = index }, macho_file);
     }
 
     pub fn getAddress(got: GotSection, index: Index, macho_file: *MachO) u64 {
@@ -133,8 +138,8 @@ pub const GotSection = struct {
     pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
-        for (got.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (got.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);
             try writer.writeInt(u64, value, .little);
         }
@@ -157,12 +162,12 @@ pub const GotSection = struct {
     ) !void {
         _ = options;
         _ = unused_fmt_string;
-        for (ctx.got.symbols.items, 0..) |entry, i| {
-            const symbol = ctx.macho_file.getSymbol(entry);
+        for (ctx.got.symbols.items, 0..) |ref, i| {
+            const symbol = ref.getSymbol(ctx.macho_file).?;
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 i,
                 symbol.getGotAddress(ctx.macho_file),
-                entry,
+                ref,
                 symbol.getAddress(.{}, ctx.macho_file),
                 symbol.getName(ctx.macho_file),
             });
@@ -171,7 +176,7 @@ pub const GotSection = struct {
 };
 
 pub const StubsSection = struct {
-    symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+    symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},
 
     pub const Index = u32;
 
@@ -179,13 +184,13 @@ pub const StubsSection = struct {
         stubs.symbols.deinit(allocator);
     }
 
-    pub fn addSymbol(stubs: *StubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
+    pub fn addSymbol(stubs: *StubsSection, ref: MachO.Ref, macho_file: *MachO) !void {
         const gpa = macho_file.base.comp.gpa;
         const index = @as(Index, @intCast(stubs.symbols.items.len));
         const entry = try stubs.symbols.addOne(gpa);
-        entry.* = sym_index;
-        const symbol = macho_file.getSymbol(sym_index);
-        try symbol.addExtra(.{ .stubs = index }, macho_file);
+        entry.* = ref;
+        const symbol = ref.getSymbol(macho_file).?;
+        symbol.addExtra(.{ .stubs = index }, macho_file);
     }
 
     pub fn getAddress(stubs: StubsSection, index: Index, macho_file: *MachO) u64 {
@@ -205,8 +210,8 @@ pub const StubsSection = struct {
         const cpu_arch = macho_file.getTarget().cpu.arch;
         const laptr_sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?];
 
-        for (stubs.symbols.items, 0..) |sym_index, idx| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (stubs.symbols.items, 0..) |ref, idx| {
+            const sym = ref.getSymbol(macho_file).?;
             const source = sym.getAddress(.{ .stubs = true }, macho_file);
             const target = laptr_sect.addr + idx * @sizeOf(u64);
             switch (cpu_arch) {
@@ -248,12 +253,12 @@ pub const StubsSection = struct {
     ) !void {
         _ = options;
         _ = unused_fmt_string;
-        for (ctx.stubs.symbols.items, 0..) |entry, i| {
-            const symbol = ctx.macho_file.getSymbol(entry);
+        for (ctx.stubs.symbols.items, 0..) |ref, i| {
+            const symbol = ref.getSymbol(ctx.macho_file).?;
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 i,
                 symbol.getStubsAddress(ctx.macho_file),
-                entry,
+                ref,
                 symbol.getAddress(.{}, ctx.macho_file),
                 symbol.getName(ctx.macho_file),
             });
@@ -284,8 +289,8 @@ pub const StubsHelperSection = struct {
         _ = stubs_helper;
         const cpu_arch = macho_file.getTarget().cpu.arch;
         var s: usize = preambleSize(cpu_arch);
-        for (macho_file.stubs.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.stubs.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.weak) continue;
             s += entrySize(cpu_arch);
         }
@@ -304,8 +309,8 @@ pub const StubsHelperSection = struct {
         const entry_size = entrySize(cpu_arch);
 
         var idx: usize = 0;
-        for (macho_file.stubs.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.stubs.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.weak) continue;
             const offset = macho_file.lazy_bind.offsets.items[idx];
             const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx);
@@ -339,14 +344,15 @@ pub const StubsHelperSection = struct {
 
     fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
         _ = stubs_helper;
+        const obj = macho_file.getInternalObject().?;
         const cpu_arch = macho_file.getTarget().cpu.arch;
         const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
         const dyld_private_addr = target: {
-            const sym = macho_file.getSymbol(macho_file.dyld_private_index.?);
+            const sym = obj.getDyldPrivateRef(macho_file).?.getSymbol(macho_file).?;
             break :target sym.getAddress(.{}, macho_file);
         };
         const dyld_stub_binder_addr = target: {
-            const sym = macho_file.getSymbol(macho_file.dyld_stub_binder_index.?);
+            const sym = obj.getDyldStubBinderRef(macho_file).?.getSymbol(macho_file).?;
             break :target sym.getGotAddress(macho_file);
         };
         switch (cpu_arch) {
@@ -402,8 +408,8 @@ pub const LaSymbolPtrSection = struct {
         const cpu_arch = macho_file.getTarget().cpu.arch;
         const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
         var stub_helper_idx: u32 = 0;
-        for (macho_file.stubs.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.stubs.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.weak) {
                 const value = sym.getAddress(.{ .stubs = false }, macho_file);
                 try writer.writeInt(u64, @intCast(value), .little);
@@ -418,7 +424,7 @@ pub const LaSymbolPtrSection = struct {
 };
 
 pub const TlvPtrSection = struct {
-    symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+    symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},
 
     pub const Index = u32;
 
@@ -426,13 +432,13 @@ pub const TlvPtrSection = struct {
         tlv.symbols.deinit(allocator);
     }
 
-    pub fn addSymbol(tlv: *TlvPtrSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
+    pub fn addSymbol(tlv: *TlvPtrSection, ref: MachO.Ref, macho_file: *MachO) !void {
         const gpa = macho_file.base.comp.gpa;
         const index = @as(Index, @intCast(tlv.symbols.items.len));
         const entry = try tlv.symbols.addOne(gpa);
-        entry.* = sym_index;
-        const symbol = macho_file.getSymbol(sym_index);
-        try symbol.addExtra(.{ .tlv_ptr = index }, macho_file);
+        entry.* = ref;
+        const symbol = ref.getSymbol(macho_file).?;
+        symbol.addExtra(.{ .tlv_ptr = index }, macho_file);
     }
 
     pub fn getAddress(tlv: TlvPtrSection, index: Index, macho_file: *MachO) u64 {
@@ -449,8 +455,8 @@ pub const TlvPtrSection = struct {
         const tracy = trace(@src());
         defer tracy.end();
 
-        for (tlv.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (tlv.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.import) {
                 try writer.writeInt(u64, 0, .little);
             } else {
@@ -476,12 +482,12 @@ pub const TlvPtrSection = struct {
     ) !void {
         _ = options;
         _ = unused_fmt_string;
-        for (ctx.tlv.symbols.items, 0..) |entry, i| {
-            const symbol = ctx.macho_file.getSymbol(entry);
+        for (ctx.tlv.symbols.items, 0..) |ref, i| {
+            const symbol = ref.getSymbol(ctx.macho_file).?;
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 i,
                 symbol.getTlvPtrAddress(ctx.macho_file),
-                entry,
+                ref,
                 symbol.getAddress(.{}, ctx.macho_file),
                 symbol.getName(ctx.macho_file),
             });
@@ -490,7 +496,7 @@ pub const TlvPtrSection = struct {
 };
 
 pub const ObjcStubsSection = struct {
-    symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+    symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},
 
     pub fn deinit(objc: *ObjcStubsSection, allocator: Allocator) void {
         objc.symbols.deinit(allocator);
@@ -504,13 +510,13 @@ pub const ObjcStubsSection = struct {
         };
     }
 
-    pub fn addSymbol(objc: *ObjcStubsSection, sym_index: Symbol.Index, macho_file: *MachO) !void {
+    pub fn addSymbol(objc: *ObjcStubsSection, ref: MachO.Ref, macho_file: *MachO) !void {
         const gpa = macho_file.base.comp.gpa;
         const index = @as(Index, @intCast(objc.symbols.items.len));
         const entry = try objc.symbols.addOne(gpa);
-        entry.* = sym_index;
-        const symbol = macho_file.getSymbol(sym_index);
-        try symbol.addExtra(.{ .objc_stubs = index }, macho_file);
+        entry.* = ref;
+        const symbol = ref.getSymbol(macho_file).?;
+        symbol.addExtra(.{ .objc_stubs = index }, macho_file);
     }
 
     pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 {
@@ -527,8 +533,10 @@ pub const ObjcStubsSection = struct {
         const tracy = trace(@src());
         defer tracy.end();
 
-        for (objc.symbols.items, 0..) |sym_index, idx| {
-            const sym = macho_file.getSymbol(sym_index);
+        const obj = macho_file.getInternalObject().?;
+
+        for (objc.symbols.items, 0..) |ref, idx| {
+            const sym = ref.getSymbol(macho_file).?;
             const addr = objc.getAddress(@intCast(idx), macho_file);
             switch (macho_file.getTarget().cpu.arch) {
                 .x86_64 => {
@@ -540,7 +548,7 @@ pub const ObjcStubsSection = struct {
                     }
                     try writer.writeAll(&.{ 0xff, 0x25 });
                     {
-                        const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);
+                        const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
                         const target = target_sym.getGotAddress(macho_file);
                         const source = addr + 7;
                         try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
@@ -560,7 +568,7 @@ pub const ObjcStubsSection = struct {
                         );
                     }
                     {
-                        const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);
+                        const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
                         const target = target_sym.getGotAddress(macho_file);
                         const source = addr + 2 * @sizeOf(u32);
                         const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
@@ -599,12 +607,12 @@ pub const ObjcStubsSection = struct {
     ) !void {
         _ = options;
         _ = unused_fmt_string;
-        for (ctx.objc.symbols.items, 0..) |entry, i| {
-            const symbol = ctx.macho_file.getSymbol(entry);
+        for (ctx.objc.symbols.items, 0..) |ref, i| {
+            const symbol = ref.getSymbol(ctx.macho_file).?;
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 i,
                 symbol.getObjcStubsAddress(ctx.macho_file),
-                entry,
+                ref,
                 symbol.getAddress(.{}, ctx.macho_file),
                 symbol.getName(ctx.macho_file),
             });
@@ -620,31 +628,89 @@ pub const Indsymtab = struct {
         return @intCast(macho_file.stubs.symbols.items.len * 2 + macho_file.got.symbols.items.len);
     }
 
+    pub fn updateSize(ind: *Indsymtab, macho_file: *MachO) !void {
+        macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
+    }
+
     pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
         _ = ind;
 
-        for (macho_file.stubs.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.stubs.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little);
         }
 
-        for (macho_file.got.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.got.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little);
         }
 
-        for (macho_file.stubs.symbols.items) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
+        for (macho_file.stubs.symbols.items) |ref| {
+            const sym = ref.getSymbol(macho_file).?;
             try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little);
         }
     }
 };
 
+pub const DataInCode = struct {
+    entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
+
+    pub fn deinit(dice: *DataInCode, allocator: Allocator) void {
+        dice.entries.deinit(allocator);
+    }
+
+    pub fn size(dice: DataInCode) usize {
+        return dice.entries.items.len * @sizeOf(macho.data_in_code_entry);
+    }
+
+    pub fn updateSize(dice: *DataInCode, macho_file: *MachO) !void {
+        const gpa = macho_file.base.comp.gpa;
+        const base_address = if (!macho_file.base.isRelocatable())
+            macho_file.getTextSegment().vmaddr
+        else
+            0;
+
+        for (macho_file.objects.items) |index| {
+            const object = macho_file.getFile(index).?.object;
+            const dices = object.getDataInCode();
+
+            try dice.entries.ensureUnusedCapacity(gpa, dices.len);
+
+            var next_dice: usize = 0;
+            for (object.getAtoms()) |atom_index| {
+                if (next_dice >= dices.len) break;
+                const atom = object.getAtom(atom_index) orelse continue;
+                if (!atom.flags.alive) continue;
+                const start_off = atom.getInputAddress(macho_file);
+                const end_off = start_off + atom.size;
+                const start_dice = next_dice;
+
+                if (end_off < dices[next_dice].offset) continue;
+
+                while (next_dice < dices.len and
+                    dices[next_dice].offset < end_off) : (next_dice += 1)
+                {}
+
+                if (atom.alive.load(.seq_cst)) for (dices[start_dice..next_dice]) |d| {
+                    dice.entries.appendAssumeCapacity(.{
+                        .offset = @intCast(atom.getAddress(macho_file) + d.offset - start_off - base_address),
+                        .length = d.length,
+                        .kind = d.kind,
+                    });
+                };
+            }
+        }
+
+        macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
+    }
+};
+
 const aarch64 = @import("../aarch64.zig");
 const assert = std.debug.assert;
+const macho = std.macho;
 const math = std.math;
 const std = @import("std");
 const trace = @import("../../tracy.zig").trace;
src/link/MachO.zig
@@ -68,6 +68,7 @@ weak_bind: WeakBind = .{},
 lazy_bind: LazyBind = .{},
 export_trie: ExportTrie = .{},
 unwind_info: UnwindInfo = .{},
+data_in_code: DataInCode = .{},
 
 /// Tracked loadable segments during incremental linking.
 zig_text_seg_index: ?u8 = null,
@@ -316,6 +317,7 @@ pub fn deinit(self: *MachO) void {
     self.lazy_bind.deinit(gpa);
     self.export_trie.deinit(gpa);
     self.unwind_info.deinit(gpa);
+    self.data_in_code.deinit(gpa);
 
     self.thunks.deinit(gpa);
 }
@@ -4524,6 +4526,7 @@ const Bind = bind.Bind;
 const Cache = std.Build.Cache;
 const CodeSignature = @import("MachO/CodeSignature.zig");
 const Compilation = @import("../Compilation.zig");
+const DataInCode = synthetic.DataInCode;
 pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
 const Dylib = @import("MachO/Dylib.zig");
 const ExportTrie = @import("MachO/dyld_info/Trie.zig");