diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-07-01 18:14:45 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-07-07 22:43:52 -0700 |
| commit | c8fcd2ff2c032b2de8cc1a57e075552d1cab35df (patch) | |
| tree | 7155f58049ecd0e948533f6b64cba1553dd33ae2 /src/link/MachO/dyld_info/bind.zig | |
| parent | f71d97e4cbb0e56213cb76657ad6c9edf6134868 (diff) | |
| download | zig-c8fcd2ff2c032b2de8cc1a57e075552d1cab35df.tar.gz zig-c8fcd2ff2c032b2de8cc1a57e075552d1cab35df.zip | |
MachO: update to new std.io APIs
Diffstat (limited to 'src/link/MachO/dyld_info/bind.zig')
| -rw-r--r-- | src/link/MachO/dyld_info/bind.zig | 342 |
1 files changed, 155 insertions, 187 deletions
diff --git a/src/link/MachO/dyld_info/bind.zig b/src/link/MachO/dyld_info/bind.zig index 328d6a402c..f6697b6275 100644 --- a/src/link/MachO/dyld_info/bind.zig +++ b/src/link/MachO/dyld_info/bind.zig @@ -1,7 +1,7 @@ pub const Entry = struct { target: MachO.Ref, offset: u64, - segment_id: u8, + segment_id: u4, addend: i64, pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool { @@ -20,14 +20,12 @@ pub const Bind = struct { entries: std.ArrayListUnmanaged(Entry) = .empty, buffer: std.ArrayListUnmanaged(u8) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); + pub fn deinit(bind: *Bind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *Bind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -56,15 +54,12 @@ pub const Bind = struct { const addend = rel.addend + rel.getRelocAddend(cpu_arch); const sym = rel.getTargetSymbol(atom.*, macho_file); if (sym.isTlvInit(macho_file)) continue; - const entry = Entry{ + if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{ .target = rel.getTargetSymbolRef(atom.*, macho_file), .offset = atom_addr + rel_offset - seg.vmaddr, .segment_id = seg_id, .addend = addend, }; - if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) { - try self.entries.append(gpa, entry); - } } } } @@ -75,15 +70,12 @@ pub const Bind = struct { for (macho_file.got.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.got.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, entry); - } } } @@ -94,15 +86,12 @@ pub const Bind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import and sym.flags.weak) { - try self.entries.append(gpa, bind_entry); - } } } @@ -113,49 +102,48 @@ pub const Bind = struct { for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, entry); - } } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - if (self.entries.items.len == 0) return; + fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void { + if (bind.entries.items.len == 0) return; - const writer = self.buffer.writer(gpa); + var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer); + const bw = &aw.writer; + defer bind.buffer = aw.toArrayList(); log.debug("bind opcodes", .{}); - std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); + std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); var start: usize = 0; var seg_id: ?u8 = null; - for (self.entries.items, 0..) |entry, i| { + for (bind.entries.items, 0..) |entry, i| { if (seg_id != null and seg_id.? == entry.segment_id) continue; - try finalizeSegment(self.entries.items[start..i], ctx, writer); + try finalizeSegment(bind.entries.items[start..i], ctx, bw); seg_id = entry.segment_id; start = i; } - try finalizeSegment(self.entries.items[start..], ctx, writer); - try done(writer); + try finalizeSegment(bind.entries.items[start..], ctx, bw); + try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; - try setSegmentOffset(seg_id, 0, writer); + try setSegmentOffset(seg_id, 0, bw); var offset: u64 = 0; var addend: i64 = 0; @@ -175,15 +163,15 @@ pub const Bind = struct { if (target == null or !target.?.eql(current.target)) { switch (state) { .start => {}, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } state = .start; target = current.target; const sym = current.target.getSymbol(ctx).?; const name = sym.getName(ctx); - const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; + const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; const ordinal: i16 = ord: { if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP; if (sym.flags.import) { @@ -195,13 +183,13 @@ pub const Bind = struct { break :ord macho.BIND_SPECIAL_DYLIB_SELF; }; - try setSymbol(name, flags, writer); - try setTypePointer(writer); - try setDylibOrdinal(ordinal, writer); + try setSymbol(name, flags, bw); + try setTypePointer(bw); + try setDylibOrdinal(ordinal, bw); if (current.addend != addend) { addend = current.addend; - try setAddend(addend, writer); + try setAddend(addend, bw); } } @@ -210,11 +198,11 @@ pub const Bind = struct { switch (state) { .start => { if (current.offset < offset) { - try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer); + try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw); offset = offset - (offset - current.offset); } else if (current.offset > offset) { const delta = current.offset - offset; - try addAddr(delta, writer); + try addAddr(delta, bw); offset += delta; } state = .bind_single; @@ -223,7 +211,7 @@ pub const Bind = struct { }, .bind_single => { if (current.offset == offset) { - try doBind(writer); + try doBind(bw); state = .start; } else if (current.offset > offset) { const delta = current.offset - offset; @@ -237,9 +225,9 @@ pub const Bind = struct { if (current.offset < offset) { count -= 1; if (count == 1) { - try doBindAddAddr(skip, writer); + try doBindAddAddr(skip, bw); } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); } state = .start; offset = offset - (@sizeOf(u64) + skip); @@ -248,7 +236,7 @@ pub const Bind = struct { count += 1; offset += @sizeOf(u64) + skip; } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); state = .start; i -= 1; } @@ -258,13 +246,13 @@ pub const Bind = struct { switch (state) { .start => unreachable, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: Bind, bw: *Writer) Writer.Error!void { + try bw.writeAll(bind.buffer.items); } }; @@ -272,14 +260,12 @@ pub const WeakBind = struct { entries: std.ArrayListUnmanaged(Entry) = .empty, buffer: std.ArrayListUnmanaged(u8) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); + pub fn deinit(bind: *WeakBind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -308,15 +294,12 @@ pub const WeakBind = struct { const addend = rel.addend + rel.getRelocAddend(cpu_arch); const sym = rel.getTargetSymbol(atom.*, macho_file); if (sym.isTlvInit(macho_file)) continue; - const entry = Entry{ + if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = rel.getTargetSymbolRef(atom.*, macho_file), .offset = atom_addr + rel_offset - seg.vmaddr, .segment_id = seg_id, .addend = addend, }; - if (!sym.isLocal() and sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } } @@ -327,15 +310,12 @@ pub const WeakBind = struct { for (macho_file.got.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.got.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } @@ -347,15 +327,12 @@ pub const WeakBind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, bind_entry); - } } } @@ -366,49 +343,48 @@ pub const WeakBind = struct { for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - if (self.entries.items.len == 0) return; + fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void { + if (bind.entries.items.len == 0) return; - const writer = self.buffer.writer(gpa); + var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer); + const bw = &aw.writer; + defer bind.buffer = aw.toArrayList(); log.debug("weak bind opcodes", .{}); - std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); + std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); var start: usize = 0; var seg_id: ?u8 = null; - for (self.entries.items, 0..) |entry, i| { + for (bind.entries.items, 0..) |entry, i| { if (seg_id != null and seg_id.? == entry.segment_id) continue; - try finalizeSegment(self.entries.items[start..i], ctx, writer); + try finalizeSegment(bind.entries.items[start..i], ctx, bw); seg_id = entry.segment_id; start = i; } - try finalizeSegment(self.entries.items[start..], ctx, writer); - try done(writer); + try finalizeSegment(bind.entries.items[start..], ctx, bw); + try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; - try setSegmentOffset(seg_id, 0, writer); + try setSegmentOffset(seg_id, 0, bw); var offset: u64 = 0; var addend: i64 = 0; @@ -428,8 +404,8 @@ pub const WeakBind = struct { if (target == null or !target.?.eql(current.target)) { switch (state) { .start => {}, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } state = .start; target = current.target; @@ -438,12 +414,12 @@ pub const WeakBind = struct { const name = sym.getName(ctx); const flags: u8 = 0; // TODO NON_WEAK_DEFINITION - try setSymbol(name, flags, writer); - try setTypePointer(writer); + try setSymbol(name, flags, bw); + try setTypePointer(bw); if (current.addend != addend) { addend = current.addend; - try setAddend(addend, writer); + try setAddend(addend, bw); } } @@ -452,11 +428,11 @@ pub const WeakBind = struct { switch (state) { .start => { if (current.offset < offset) { - try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer); + try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), bw); offset = offset - (offset - current.offset); } else if (current.offset > offset) { const delta = current.offset - offset; - try addAddr(delta, writer); + try addAddr(delta, bw); offset += delta; } state = .bind_single; @@ -465,7 +441,7 @@ pub const WeakBind = struct { }, .bind_single => { if (current.offset == offset) { - try doBind(writer); + try doBind(bw); state = .start; } else if (current.offset > offset) { const delta = current.offset - offset; @@ -479,9 +455,9 @@ pub const WeakBind = struct { if (current.offset < offset) { count -= 1; if (count == 1) { - try doBindAddAddr(skip, writer); + try doBindAddAddr(skip, bw); } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); } state = .start; offset = offset - (@sizeOf(u64) + skip); @@ -490,7 +466,7 @@ pub const WeakBind = struct { count += 1; offset += @sizeOf(u64) + skip; } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); state = .start; i -= 1; } @@ -500,13 +476,13 @@ pub const WeakBind = struct { switch (state) { .start => unreachable, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void { + try bw.writeAll(bind.buffer.items); } }; @@ -515,15 +491,13 @@ pub const LazyBind = struct { buffer: std.ArrayListUnmanaged(u8) = .empty, offsets: std.ArrayListUnmanaged(u32) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); - self.offsets.deinit(gpa); + pub fn deinit(bind: *LazyBind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); + bind.offsets.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -537,36 +511,35 @@ pub const LazyBind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, bind_entry); - } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len); + fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void { + try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len); - const writer = self.buffer.writer(gpa); + var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer); + const bw = &aw.writer; + defer bind.buffer = aw.toArrayList(); log.debug("lazy bind opcodes", .{}); var addend: i64 = 0; - for (self.entries.items) |entry| { - self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len)); + for (bind.entries.items) |entry| { + bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len)); const sym = entry.target.getSymbol(ctx).?; const name = sym.getName(ctx); - const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; + const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; const ordinal: i16 = ord: { if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP; if (sym.flags.import) { @@ -578,121 +551,116 @@ pub const LazyBind = struct { break :ord macho.BIND_SPECIAL_DYLIB_SELF; }; - try setSegmentOffset(entry.segment_id, entry.offset, writer); - try setSymbol(name, flags, writer); - try setDylibOrdinal(ordinal, writer); + try setSegmentOffset(entry.segment_id, entry.offset, bw); + try setSymbol(name, flags, bw); + try setDylibOrdinal(ordinal, bw); if (entry.addend != addend) { - try setAddend(entry.addend, writer); + try setAddend(entry.addend, bw); addend = entry.addend; } - try doBind(writer); - try done(writer); + try doBind(bw); + try done(bw); } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void { + try bw.writeAll(bind.buffer.items); } }; -fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void { +fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void { log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset }); - try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id))); - try std.leb.writeUleb128(writer, offset); + try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id); + try bw.writeLeb128(offset); } -fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void { +fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void { log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags }); - try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags))); - try writer.writeAll(name); - try writer.writeByte(0); + try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags); + try bw.writeAll(name); + try bw.writeByte(0); } -fn setTypePointer(writer: anytype) !void { +fn setTypePointer(bw: *Writer) Writer.Error!void { log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER}); - try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER))); + try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER))); } -fn setDylibOrdinal(ordinal: i16, writer: anytype) !void { - if (ordinal <= 0) { - switch (ordinal) { - macho.BIND_SPECIAL_DYLIB_SELF, - macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE, - macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP, - => {}, - else => unreachable, // Invalid dylib special binding - } - log.debug(">>> set dylib special: {d}", .{ordinal}); - const cast = @as(u16, @bitCast(ordinal)); - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast))); - } else { - const cast = @as(u16, @bitCast(ordinal)); - log.debug(">>> set dylib ordinal: {d}", .{ordinal}); - if (cast <= 0xf) { - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast))); - } else { - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); - try std.leb.writeUleb128(writer, cast); - } +fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void { + switch (ordinal) { + else => unreachable, // Invalid dylib special binding + macho.BIND_SPECIAL_DYLIB_SELF, + macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE, + macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP, + => { + log.debug(">>> set dylib special: {d}", .{ordinal}); + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal))))); + }, + 1...std.math.maxInt(i16) => { + log.debug(">>> set dylib ordinal: {d}", .{ordinal}); + if (std.math.cast(u4, ordinal)) |imm| { + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm); + } else { + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); + try bw.writeUleb128(ordinal); + } + }, } } -fn setAddend(addend: i64, writer: anytype) !void { +fn setAddend(addend: i64, bw: *Writer) Writer.Error!void { log.debug(">>> set addend: {x}", .{addend}); - try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB); - try std.leb.writeIleb128(writer, addend); + try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB); + try bw.writeLeb128(addend); } -fn doBind(writer: anytype) !void { +fn doBind(bw: *Writer) Writer.Error!void { log.debug(">>> bind", .{}); - try writer.writeByte(macho.BIND_OPCODE_DO_BIND); + try bw.writeByte(macho.BIND_OPCODE_DO_BIND); } -fn doBindAddAddr(addr: u64, writer: anytype) !void { +fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> bind with add: {x}", .{addr}); - if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) { - const imm = @divExact(addr, @sizeOf(u64)); - if (imm <= 0xf) { - try writer.writeByte( - macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)), - ); - return; - } - } - try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| { + if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte( + macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled, + ); + } else |_| {} + try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void { +fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void { log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip }); - try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB); - try std.leb.writeUleb128(writer, count); - try std.leb.writeUleb128(writer, skip); + try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB); + try bw.writeLeb128(count); + try bw.writeLeb128(skip); } -fn addAddr(addr: u64, writer: anytype) !void { +fn addAddr(addr: u64, bw: *Writer) Writer.Error!void { log.debug(">>> add: {x}", .{addr}); - try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn done(writer: anytype) !void { +fn done(bw: *Writer) Writer.Error!void { log.debug(">>> done", .{}); - try writer.writeByte(macho.BIND_OPCODE_DONE); + try bw.writeByte(macho.BIND_OPCODE_DONE); } +const std = @import("std"); const assert = std.debug.assert; const leb = std.leb; const log = std.log.scoped(.link_dyld_info); const macho = std.macho; const mem = std.mem; const testing = std.testing; -const trace = @import("../../../tracy.zig").trace; -const std = @import("std"); +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; -const Allocator = mem.Allocator; +const trace = @import("../../../tracy.zig").trace; const File = @import("../file.zig").File; const MachO = @import("../../MachO.zig"); const Symbol = @import("../Symbol.zig"); |
