diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 78ea58c509..5d95838f30 100644 --- a/src/link/MachO.zig +++ b/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"); diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index 4cac061d93..a366fea2b9 100644 --- a/src/link/MachO/synthetic.zig +++ b/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;