mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
MachO: revert unfinished changes
This commit is contained in:
parent
c8fcd2ff2c
commit
49be02e6d7
@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },
|
||||
uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
|
||||
codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
|
||||
|
||||
pagezero_seg_index: ?u4 = null,
|
||||
text_seg_index: ?u4 = null,
|
||||
linkedit_seg_index: ?u4 = null,
|
||||
pagezero_seg_index: ?u8 = null,
|
||||
text_seg_index: ?u8 = null,
|
||||
linkedit_seg_index: ?u8 = null,
|
||||
text_sect_index: ?u8 = null,
|
||||
data_sect_index: ?u8 = null,
|
||||
got_sect_index: ?u8 = null,
|
||||
@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},
|
||||
data_in_code: DataInCode = .{},
|
||||
|
||||
/// Tracked loadable segments during incremental linking.
|
||||
zig_text_seg_index: ?u4 = null,
|
||||
zig_const_seg_index: ?u4 = null,
|
||||
zig_data_seg_index: ?u4 = null,
|
||||
zig_bss_seg_index: ?u4 = null,
|
||||
zig_text_seg_index: ?u8 = null,
|
||||
zig_const_seg_index: ?u8 = null,
|
||||
zig_data_seg_index: ?u8 = null,
|
||||
zig_bss_seg_index: ?u8 = null,
|
||||
|
||||
/// Tracked section headers with incremental updates to Zig object.
|
||||
zig_text_sect_index: ?u8 = null,
|
||||
@ -591,7 +591,6 @@ pub fn flush(
|
||||
error.NoSpaceLeft => unreachable,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.LinkFailure => return error.LinkFailure,
|
||||
else => unreachable,
|
||||
};
|
||||
try self.writeHeader(ncmds, sizeofcmds);
|
||||
self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
|
||||
@ -1075,7 +1074,7 @@ fn accessLibPath(
|
||||
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||
test_path.clearRetainingCapacity();
|
||||
try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
|
||||
try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
|
||||
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
||||
fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
@ -1098,7 +1097,7 @@ fn accessFrameworkPath(
|
||||
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||
test_path.clearRetainingCapacity();
|
||||
try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
|
||||
try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
|
||||
search_dir,
|
||||
name,
|
||||
name,
|
||||
@ -1179,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||
test_path.clearRetainingCapacity();
|
||||
if (self.base.comp.sysroot) |root| {
|
||||
try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
|
||||
try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
|
||||
} else {
|
||||
try test_path.print("{s}{s}", .{ path, ext });
|
||||
try test_path.writer().print("{s}{s}", .{ path, ext });
|
||||
}
|
||||
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
||||
fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
||||
@ -2132,7 +2131,7 @@ fn initSegments(self: *MachO) !void {
|
||||
|
||||
mem.sort(Entry, entries.items, self, Entry.lessThan);
|
||||
|
||||
const backlinks = try gpa.alloc(u4, entries.items.len);
|
||||
const backlinks = try gpa.alloc(u8, entries.items.len);
|
||||
defer gpa.free(backlinks);
|
||||
for (entries.items, 0..) |entry, i| {
|
||||
backlinks[entry.index] = @intCast(i);
|
||||
@ -2146,7 +2145,7 @@ fn initSegments(self: *MachO) !void {
|
||||
self.segments.appendAssumeCapacity(segments[sorted.index]);
|
||||
}
|
||||
|
||||
for (&[_]*?u4{
|
||||
for (&[_]*?u8{
|
||||
&self.pagezero_seg_index,
|
||||
&self.text_seg_index,
|
||||
&self.linkedit_seg_index,
|
||||
@ -2164,7 +2163,7 @@ fn initSegments(self: *MachO) !void {
|
||||
for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
|
||||
const segname = header.segName();
|
||||
const segment_id = self.getSegmentByName(segname) orelse blk: {
|
||||
const segment_id: u4 = @intCast(self.segments.items.len);
|
||||
const segment_id = @as(u8, @intCast(self.segments.items.len));
|
||||
const protection = getSegmentProt(segname);
|
||||
try self.segments.append(gpa, .{
|
||||
.cmdsize = @sizeOf(macho.segment_command_64),
|
||||
@ -2527,8 +2526,10 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
|
||||
|
||||
const doWork = struct {
|
||||
fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
|
||||
var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]);
|
||||
try th.write(macho_file, &bw);
|
||||
const off = try macho_file.cast(usize, th.value);
|
||||
const size = th.size();
|
||||
var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
|
||||
try th.write(macho_file, stream.writer());
|
||||
}
|
||||
}.doWork;
|
||||
const out = self.sections.items(.out)[thunk.out_n_sect].items;
|
||||
@ -2555,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
|
||||
|
||||
const doWork = struct {
|
||||
fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
|
||||
var bw: Writer = .fixed(buffer);
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
switch (tag) {
|
||||
.eh_frame => eh_frame.write(macho_file, buffer),
|
||||
.unwind_info => try macho_file.unwind_info.write(macho_file, &bw),
|
||||
.got => try macho_file.got.write(macho_file, &bw),
|
||||
.stubs => try macho_file.stubs.write(macho_file, &bw),
|
||||
.la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw),
|
||||
.tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw),
|
||||
.objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw),
|
||||
.unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
|
||||
.got => try macho_file.got.write(macho_file, stream.writer()),
|
||||
.stubs => try macho_file.stubs.write(macho_file, stream.writer()),
|
||||
.la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),
|
||||
.tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),
|
||||
.objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),
|
||||
}
|
||||
}
|
||||
}.doWork;
|
||||
@ -2604,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
|
||||
try macho_file.lazy_bind_section.updateSize(macho_file);
|
||||
const sect_id = macho_file.stubs_helper_sect_index.?;
|
||||
const out = &macho_file.sections.items(.out)[sect_id];
|
||||
var bw: Writer = .fixed(out.items);
|
||||
try macho_file.stubs_helper.write(macho_file, &bw);
|
||||
var stream = std.io.fixedBufferStream(out.items);
|
||||
try macho_file.stubs_helper.write(macho_file, stream.writer());
|
||||
}
|
||||
}.doWork;
|
||||
doWork(self) catch |err|
|
||||
@ -2664,49 +2665,46 @@ fn writeDyldInfo(self: *MachO) !void {
|
||||
needed_size += cmd.lazy_bind_size;
|
||||
needed_size += cmd.export_size;
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));
|
||||
defer gpa.free(bw.buffer);
|
||||
@memset(bw.buffer, 0);
|
||||
const buffer = try gpa.alloc(u8, needed_size);
|
||||
defer gpa.free(buffer);
|
||||
@memset(buffer, 0);
|
||||
|
||||
try self.rebase_section.write(&bw);
|
||||
bw.end = cmd.bind_off - base_off;
|
||||
try self.bind_section.write(&bw);
|
||||
bw.end = cmd.weak_bind_off - base_off;
|
||||
try self.weak_bind_section.write(&bw);
|
||||
bw.end = cmd.lazy_bind_off - base_off;
|
||||
try self.lazy_bind_section.write(&bw);
|
||||
bw.end = cmd.export_off - base_off;
|
||||
try self.export_trie.write(&bw);
|
||||
try self.pwriteAll(bw.buffer, cmd.rebase_off);
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const writer = stream.writer();
|
||||
|
||||
try self.rebase_section.write(writer);
|
||||
try stream.seekTo(cmd.bind_off - base_off);
|
||||
try self.bind_section.write(writer);
|
||||
try stream.seekTo(cmd.weak_bind_off - base_off);
|
||||
try self.weak_bind_section.write(writer);
|
||||
try stream.seekTo(cmd.lazy_bind_off - base_off);
|
||||
try self.lazy_bind_section.write(writer);
|
||||
try stream.seekTo(cmd.export_off - base_off);
|
||||
try self.export_trie.write(writer);
|
||||
try self.pwriteAll(buffer, cmd.rebase_off);
|
||||
}
|
||||
|
||||
pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {
|
||||
pub fn writeDataInCode(self: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
const gpa = self.base.comp.gpa;
|
||||
const cmd = self.data_in_code_cmd;
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size()));
|
||||
defer gpa.free(bw.buffer);
|
||||
|
||||
try self.data_in_code.write(self, &bw);
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try self.pwriteAll(bw.buffer, cmd.dataoff);
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());
|
||||
defer buffer.deinit();
|
||||
try self.data_in_code.write(self, buffer.writer());
|
||||
try self.pwriteAll(buffer.items, cmd.dataoff);
|
||||
}
|
||||
|
||||
fn writeIndsymtab(self: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const cmd = self.dysymtab_cmd;
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms));
|
||||
defer gpa.free(bw.buffer);
|
||||
|
||||
try self.indsymtab.write(self, &bw);
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try self.pwriteAll(bw.buffer, cmd.indirectsymoff);
|
||||
const needed_size = cmd.nindirectsyms * @sizeOf(u32);
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
|
||||
defer buffer.deinit();
|
||||
try self.indsymtab.write(self, buffer.writer());
|
||||
try self.pwriteAll(buffer.items, cmd.indirectsymoff);
|
||||
}
|
||||
|
||||
pub fn writeSymtabToFile(self: *MachO) !void {
|
||||
@ -2816,12 +2814,15 @@ fn calcSymtabSize(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
|
||||
fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
|
||||
const comp = self.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const needed_size = try load_commands.calcLoadCommandsSize(self, false);
|
||||
const buffer = try gpa.alloc(u8, needed_size);
|
||||
defer gpa.free(buffer);
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false)));
|
||||
defer gpa.free(bw.buffer);
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const writer = stream.writer();
|
||||
|
||||
var ncmds: usize = 0;
|
||||
|
||||
@ -2830,26 +2831,26 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
|
||||
const slice = self.sections.slice();
|
||||
var sect_id: usize = 0;
|
||||
for (self.segments.items) |seg| {
|
||||
try bw.writeStruct(seg);
|
||||
try writer.writeStruct(seg);
|
||||
for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
|
||||
try bw.writeStruct(header);
|
||||
try writer.writeStruct(header);
|
||||
}
|
||||
sect_id += seg.nsects;
|
||||
}
|
||||
ncmds += self.segments.items.len;
|
||||
}
|
||||
|
||||
try bw.writeStruct(self.dyld_info_cmd);
|
||||
try writer.writeStruct(self.dyld_info_cmd);
|
||||
ncmds += 1;
|
||||
try bw.writeStruct(self.function_starts_cmd);
|
||||
try writer.writeStruct(self.function_starts_cmd);
|
||||
ncmds += 1;
|
||||
try bw.writeStruct(self.data_in_code_cmd);
|
||||
try writer.writeStruct(self.data_in_code_cmd);
|
||||
ncmds += 1;
|
||||
try bw.writeStruct(self.symtab_cmd);
|
||||
try writer.writeStruct(self.symtab_cmd);
|
||||
ncmds += 1;
|
||||
try bw.writeStruct(self.dysymtab_cmd);
|
||||
try writer.writeStruct(self.dysymtab_cmd);
|
||||
ncmds += 1;
|
||||
try load_commands.writeDylinkerLC(&bw);
|
||||
try load_commands.writeDylinkerLC(writer);
|
||||
ncmds += 1;
|
||||
|
||||
if (self.getInternalObject()) |obj| {
|
||||
@ -2860,7 +2861,7 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
|
||||
0
|
||||
else
|
||||
@as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
|
||||
try bw.writeStruct(macho.entry_point_command{
|
||||
try writer.writeStruct(macho.entry_point_command{
|
||||
.entryoff = entryoff,
|
||||
.stacksize = self.base.stack_size,
|
||||
});
|
||||
@ -2869,35 +2870,35 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
|
||||
}
|
||||
|
||||
if (self.base.isDynLib()) {
|
||||
try load_commands.writeDylibIdLC(self, &bw);
|
||||
try load_commands.writeDylibIdLC(self, writer);
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
for (self.rpath_list) |rpath| {
|
||||
try load_commands.writeRpathLC(&bw, rpath);
|
||||
try load_commands.writeRpathLC(rpath, writer);
|
||||
ncmds += 1;
|
||||
}
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
|
||||
defer gpa.free(path);
|
||||
const rpath = std.fs.path.dirname(path) orelse ".";
|
||||
try load_commands.writeRpathLC(&bw, rpath);
|
||||
try load_commands.writeRpathLC(rpath, writer);
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
try bw.writeStruct(macho.source_version_command{ .version = 0 });
|
||||
try writer.writeStruct(macho.source_version_command{ .version = 0 });
|
||||
ncmds += 1;
|
||||
|
||||
if (self.platform.isBuildVersionCompatible()) {
|
||||
try load_commands.writeBuildVersionLC(&bw, self.platform, self.sdk_version);
|
||||
try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);
|
||||
ncmds += 1;
|
||||
} else {
|
||||
try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);
|
||||
try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;
|
||||
try bw.writeStruct(self.uuid_cmd);
|
||||
const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
|
||||
try writer.writeStruct(self.uuid_cmd);
|
||||
ncmds += 1;
|
||||
|
||||
for (self.dylibs.items) |index| {
|
||||
@ -2915,19 +2916,20 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
|
||||
.timestamp = dylib_id.timestamp,
|
||||
.current_version = dylib_id.current_version,
|
||||
.compatibility_version = dylib_id.compatibility_version,
|
||||
}, &bw);
|
||||
}, writer);
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
if (self.requiresCodeSig()) {
|
||||
try bw.writeStruct(self.codesig_cmd);
|
||||
try writer.writeStruct(self.codesig_cmd);
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
|
||||
assert(stream.pos == needed_size);
|
||||
|
||||
return .{ ncmds, bw.end, uuid_cmd_offset };
|
||||
try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
|
||||
|
||||
return .{ ncmds, buffer.len, uuid_cmd_offset };
|
||||
}
|
||||
|
||||
fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
|
||||
@ -3010,27 +3012,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
|
||||
}
|
||||
|
||||
pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
const seg = self.getTextSegment();
|
||||
const offset = self.codesig_cmd.dataoff;
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));
|
||||
defer gpa.free(bw.buffer);
|
||||
var buffer = std.ArrayList(u8).init(self.base.comp.gpa);
|
||||
defer buffer.deinit();
|
||||
try buffer.ensureTotalCapacityPrecise(code_sig.size());
|
||||
try code_sig.writeAdhocSignature(self, .{
|
||||
.file = self.base.file.?,
|
||||
.exec_seg_base = seg.fileoff,
|
||||
.exec_seg_limit = seg.filesize,
|
||||
.file_size = offset,
|
||||
.dylib = self.base.isDynLib(),
|
||||
}, &bw);
|
||||
}, buffer.writer());
|
||||
assert(buffer.items.len == code_sig.size());
|
||||
|
||||
log.debug("writing code signature from 0x{x} to 0x{x}", .{
|
||||
offset,
|
||||
offset + bw.end,
|
||||
offset + buffer.items.len,
|
||||
});
|
||||
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try self.pwriteAll(bw.buffer, offset);
|
||||
try self.pwriteAll(buffer.items, offset);
|
||||
}
|
||||
|
||||
pub fn updateFunc(
|
||||
@ -3339,7 +3341,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
|
||||
}
|
||||
|
||||
const appendSect = struct {
|
||||
fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u4) void {
|
||||
fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void {
|
||||
const sect = &macho_file.sections.items(.header)[sect_id];
|
||||
const seg = macho_file.segments.items[seg_id];
|
||||
sect.addr = seg.vmaddr;
|
||||
@ -3598,7 +3600,7 @@ inline fn requiresThunks(self: MachO) bool {
|
||||
}
|
||||
|
||||
pub fn isZigSegment(self: MachO, seg_id: u8) bool {
|
||||
inline for (&[_]?u4{
|
||||
inline for (&[_]?u8{
|
||||
self.zig_text_seg_index,
|
||||
self.zig_const_seg_index,
|
||||
self.zig_data_seg_index,
|
||||
@ -3646,9 +3648,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
|
||||
fileoff: u64 = 0,
|
||||
filesize: u64 = 0,
|
||||
prot: macho.vm_prot_t = macho.PROT.NONE,
|
||||
}) error{OutOfMemory}!u4 {
|
||||
}) error{OutOfMemory}!u8 {
|
||||
const gpa = self.base.comp.gpa;
|
||||
const index: u4 = @intCast(self.segments.items.len);
|
||||
const index = @as(u8, @intCast(self.segments.items.len));
|
||||
try self.segments.append(gpa, .{
|
||||
.segname = makeStaticString(name),
|
||||
.vmaddr = opts.vmaddr,
|
||||
@ -3698,9 +3700,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
|
||||
return buf;
|
||||
}
|
||||
|
||||
pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {
|
||||
pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
|
||||
for (self.segments.items, 0..) |seg, i| {
|
||||
if (mem.eql(u8, segname, seg.segName())) return @intCast(i);
|
||||
if (mem.eql(u8, segname, seg.segName())) return @as(u8, @intCast(i));
|
||||
} else return null;
|
||||
}
|
||||
|
||||
@ -4028,7 +4030,7 @@ const default_entry_symbol_name = "_main";
|
||||
|
||||
const Section = struct {
|
||||
header: macho.section_64,
|
||||
segment_id: u4,
|
||||
segment_id: u8,
|
||||
atoms: std.ArrayListUnmanaged(Ref) = .empty,
|
||||
free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
|
||||
last_atom_index: Atom.Index = 0,
|
||||
@ -4353,7 +4355,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
|
||||
// The file/property is also available with vendored libc.
|
||||
fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
|
||||
const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
|
||||
const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16)));
|
||||
const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
|
||||
const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
|
||||
if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
|
||||
return error.SdkVersionFailure;
|
||||
@ -4369,7 +4371,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
|
||||
};
|
||||
|
||||
const parseNext = struct {
|
||||
fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {
|
||||
fn parseNext(it: anytype) ?u16 {
|
||||
const nn = it.next() orelse return null;
|
||||
return std.fmt.parseInt(u16, nn, 10) catch null;
|
||||
}
|
||||
@ -5317,11 +5319,8 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
|
||||
pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
|
||||
const comp = macho_file.base.comp;
|
||||
const diags = &comp.link_diags;
|
||||
var fw = macho_file.base.file.?.writer();
|
||||
fw.pos = offset;
|
||||
var bw = fw.interface().unbuffered();
|
||||
bw.writeAll(bytes) catch |err| switch (err) {
|
||||
error.WriteFailed => return diags.fail("failed to write: {s}", .{@errorName(fw.err.?)}),
|
||||
macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
|
||||
return diags.fail("failed to write: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -71,29 +71,53 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
|
||||
.mtime = hdr.date() catch 0,
|
||||
};
|
||||
|
||||
log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
|
||||
log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
|
||||
|
||||
try self.objects.append(gpa, object);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeHeader(
|
||||
bw: *Writer,
|
||||
object_name: []const u8,
|
||||
object_size: usize,
|
||||
format: Format,
|
||||
) Writer.Error!void {
|
||||
var hdr: ar_hdr = undefined;
|
||||
@memset(mem.asBytes(&hdr), ' ');
|
||||
inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0';
|
||||
writer: anytype,
|
||||
) !void {
|
||||
var hdr: ar_hdr = .{
|
||||
.ar_name = undefined,
|
||||
.ar_date = undefined,
|
||||
.ar_uid = undefined,
|
||||
.ar_gid = undefined,
|
||||
.ar_mode = undefined,
|
||||
.ar_size = undefined,
|
||||
.ar_fmag = undefined,
|
||||
};
|
||||
@memset(mem.asBytes(&hdr), 0x20);
|
||||
inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
|
||||
var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
|
||||
stream.writer().print("0", .{}) catch unreachable;
|
||||
}
|
||||
@memcpy(&hdr.ar_fmag, ARFMAG);
|
||||
|
||||
const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
|
||||
_ = std.fmt.bufPrint(&hdr.ar_name, "#1/{d}", .{object_name_len}) catch unreachable;
|
||||
const total_object_size = object_size + object_name_len;
|
||||
_ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable;
|
||||
try bw.writeStruct(hdr);
|
||||
try bw.writeAll(object_name);
|
||||
try bw.splatByteAll(0, object_name_len - object_name.len);
|
||||
|
||||
{
|
||||
var stream = std.io.fixedBufferStream(&hdr.ar_name);
|
||||
stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;
|
||||
}
|
||||
{
|
||||
var stream = std.io.fixedBufferStream(&hdr.ar_size);
|
||||
stream.writer().print("{d}", .{total_object_size}) catch unreachable;
|
||||
}
|
||||
|
||||
try writer.writeAll(mem.asBytes(&hdr));
|
||||
try writer.print("{s}\x00", .{object_name});
|
||||
|
||||
const padding = object_name_len - object_name.len - 1;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
// Archive files start with the ARMAG identifying string. Then follows a
|
||||
@ -177,12 +201,12 @@ pub const ArSymtab = struct {
|
||||
return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
|
||||
}
|
||||
|
||||
pub fn write(ar: ArSymtab, bw: *Writer, format: Format, macho_file: *MachO) Writer.Error!void {
|
||||
pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {
|
||||
const ptr_width = ptrWidth(format);
|
||||
// Header
|
||||
try writeHeader(bw, SYMDEF, ar.size(format), format);
|
||||
try writeHeader(SYMDEF, ar.size(format), format, writer);
|
||||
// Symtab size
|
||||
try writeInt(bw, format, ar.entries.items.len * 2 * ptr_width);
|
||||
try writeInt(format, ar.entries.items.len * 2 * ptr_width, writer);
|
||||
// Symtab entries
|
||||
for (ar.entries.items) |entry| {
|
||||
const file_off = switch (macho_file.getFile(entry.file).?) {
|
||||
@ -191,16 +215,19 @@ pub const ArSymtab = struct {
|
||||
else => unreachable,
|
||||
};
|
||||
// Name offset
|
||||
try writeInt(bw, format, entry.off);
|
||||
try writeInt(format, entry.off, writer);
|
||||
// File offset
|
||||
try writeInt(bw, format, file_off);
|
||||
try writeInt(format, file_off, writer);
|
||||
}
|
||||
// Strtab size
|
||||
const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
|
||||
try writeInt(bw, format, strtab_size);
|
||||
const padding = strtab_size - ar.strtab.buffer.items.len;
|
||||
try writeInt(format, strtab_size, writer);
|
||||
// Strtab
|
||||
try bw.writeAll(ar.strtab.buffer.items);
|
||||
try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);
|
||||
try writer.writeAll(ar.strtab.buffer.items);
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
const PrintFormat = struct {
|
||||
@ -248,10 +275,10 @@ pub fn ptrWidth(format: Format) usize {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {
|
||||
pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
|
||||
switch (format) {
|
||||
.p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
|
||||
.p64 => try bw.writeInt(u64, value, .little),
|
||||
.p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
|
||||
.p64 => try writer.writeInt(u64, value, .little),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -580,9 +580,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
|
||||
|
||||
relocs_log.debug("{x}: {s}", .{ self.value, name });
|
||||
|
||||
var bw: Writer = .fixed(buffer);
|
||||
|
||||
var has_error = false;
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
var i: usize = 0;
|
||||
while (i < relocs.len) : (i += 1) {
|
||||
const rel = relocs[i];
|
||||
@ -593,28 +592,30 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
|
||||
if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
|
||||
}
|
||||
|
||||
bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow;
|
||||
self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) {
|
||||
error.RelaxFail => {
|
||||
const target = switch (rel.tag) {
|
||||
.@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
|
||||
.local => rel.getTargetAtom(self, macho_file).getName(macho_file),
|
||||
};
|
||||
try macho_file.reportParseError2(
|
||||
file.getIndex(),
|
||||
"{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",
|
||||
.{
|
||||
name,
|
||||
self.getAddress(macho_file),
|
||||
rel.offset,
|
||||
rel.fmtPretty(macho_file.getTarget().cpu.arch),
|
||||
target,
|
||||
},
|
||||
);
|
||||
has_error = true;
|
||||
},
|
||||
error.RelaxFailUnexpectedInstruction => has_error = true,
|
||||
else => |e| return e,
|
||||
try stream.seekTo(rel_offset);
|
||||
self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {
|
||||
switch (err) {
|
||||
error.RelaxFail => {
|
||||
const target = switch (rel.tag) {
|
||||
.@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
|
||||
.local => rel.getTargetAtom(self, macho_file).getName(macho_file),
|
||||
};
|
||||
try macho_file.reportParseError2(
|
||||
file.getIndex(),
|
||||
"{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",
|
||||
.{
|
||||
name,
|
||||
self.getAddress(macho_file),
|
||||
rel.offset,
|
||||
rel.fmtPretty(macho_file.getTarget().cpu.arch),
|
||||
target,
|
||||
},
|
||||
);
|
||||
has_error = true;
|
||||
},
|
||||
error.RelaxFailUnexpectedInstruction => has_error = true,
|
||||
else => |e| return e,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -637,8 +638,8 @@ fn resolveRelocInner(
|
||||
subtractor: ?Relocation,
|
||||
code: []u8,
|
||||
macho_file: *MachO,
|
||||
bw: *Writer,
|
||||
) Writer.Error!void {
|
||||
writer: anytype,
|
||||
) ResolveError!void {
|
||||
const t = &macho_file.base.comp.root_mod.resolved_target.result;
|
||||
const cpu_arch = t.cpu.arch;
|
||||
const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
|
||||
@ -652,7 +653,7 @@ fn resolveRelocInner(
|
||||
const divExact = struct {
|
||||
fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
|
||||
return math.divExact(u12, num, den) catch {
|
||||
try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{
|
||||
try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{
|
||||
atom.getName(ctx),
|
||||
r.fmtPretty(ctx.getTarget().cpu.arch),
|
||||
r.offset,
|
||||
@ -689,14 +690,14 @@ fn resolveRelocInner(
|
||||
if (rel.tag == .@"extern") {
|
||||
const sym = rel.getTargetSymbol(self, macho_file);
|
||||
if (sym.isTlvInit(macho_file)) {
|
||||
try bw.writeInt(u64, @intCast(S - TLS), .little);
|
||||
try writer.writeInt(u64, @intCast(S - TLS), .little);
|
||||
return;
|
||||
}
|
||||
if (sym.flags.import) return;
|
||||
}
|
||||
try bw.writeInt(u64, @bitCast(S + A - SUB), .little);
|
||||
try writer.writeInt(u64, @bitCast(S + A - SUB), .little);
|
||||
} else if (rel.meta.length == 2) {
|
||||
try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
|
||||
try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
|
||||
} else unreachable;
|
||||
},
|
||||
|
||||
@ -704,7 +705,7 @@ fn resolveRelocInner(
|
||||
assert(rel.tag == .@"extern");
|
||||
assert(rel.meta.length == 2);
|
||||
assert(rel.meta.pcrel);
|
||||
try bw.writeInt(i32, @intCast(G + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(G + A - P), .little);
|
||||
},
|
||||
|
||||
.branch => {
|
||||
@ -713,7 +714,7 @@ fn resolveRelocInner(
|
||||
assert(rel.tag == .@"extern");
|
||||
|
||||
switch (cpu_arch) {
|
||||
.x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little),
|
||||
.x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little),
|
||||
.aarch64 => {
|
||||
const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
|
||||
const thunk = self.getThunk(macho_file);
|
||||
@ -731,10 +732,10 @@ fn resolveRelocInner(
|
||||
assert(rel.meta.length == 2);
|
||||
assert(rel.meta.pcrel);
|
||||
if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {
|
||||
try bw.writeInt(i32, @intCast(G + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(G + A - P), .little);
|
||||
} else {
|
||||
try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
|
||||
try bw.writeInt(i32, @intCast(S + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(S + A - P), .little);
|
||||
}
|
||||
},
|
||||
|
||||
@ -745,17 +746,17 @@ fn resolveRelocInner(
|
||||
const sym = rel.getTargetSymbol(self, macho_file);
|
||||
if (sym.getSectionFlags().tlv_ptr) {
|
||||
const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
|
||||
try bw.writeInt(i32, @intCast(S_ + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(S_ + A - P), .little);
|
||||
} else {
|
||||
try x86_64.relaxTlv(code[rel_offset - 3 ..], t);
|
||||
try bw.writeInt(i32, @intCast(S + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(S + A - P), .little);
|
||||
}
|
||||
},
|
||||
|
||||
.signed, .signed1, .signed2, .signed4 => {
|
||||
assert(rel.meta.length == 2);
|
||||
assert(rel.meta.pcrel);
|
||||
try bw.writeInt(i32, @intCast(S + A - P), .little);
|
||||
try writer.writeInt(i32, @intCast(S + A - P), .little);
|
||||
},
|
||||
|
||||
.page,
|
||||
@ -807,7 +808,7 @@ fn resolveRelocInner(
|
||||
2 => try divExact(self, rel, @truncate(target), 4, macho_file),
|
||||
3 => try divExact(self, rel, @truncate(target), 8, macho_file),
|
||||
};
|
||||
try bw.writeInt(u32, inst.toU32(), .little);
|
||||
try writer.writeInt(u32, inst.toU32(), .little);
|
||||
}
|
||||
},
|
||||
|
||||
@ -885,7 +886,7 @@ fn resolveRelocInner(
|
||||
.sf = @as(u1, @truncate(reg_info.size)),
|
||||
},
|
||||
};
|
||||
try bw.writeInt(u32, inst.toU32(), .little);
|
||||
try writer.writeInt(u32, inst.toU32(), .little);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -937,8 +938,11 @@ const x86_64 = struct {
|
||||
}
|
||||
|
||||
fn encode(insts: []const Instruction, code: []u8) !void {
|
||||
var bw: Writer = .fixed(code);
|
||||
for (insts) |inst| try inst.encode(&bw, .{});
|
||||
var stream = std.io.fixedBufferStream(code);
|
||||
const writer = stream.writer();
|
||||
for (insts) |inst| {
|
||||
try inst.encode(writer, .{});
|
||||
}
|
||||
}
|
||||
|
||||
const bits = @import("../../arch/x86_64/bits.zig");
|
||||
|
||||
@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
|
||||
pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
|
||||
const file = try fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const inner = try file.readToEndAlloc(allocator, .unlimited);
|
||||
const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
|
||||
self.entitlements = .{ .inner = inner };
|
||||
}
|
||||
|
||||
@ -304,11 +304,10 @@ pub fn writeAdhocSignature(
|
||||
var hash: [hash_size]u8 = undefined;
|
||||
|
||||
if (self.requirements) |*req| {
|
||||
var aw: std.io.Writer.Allocating = .init(allocator);
|
||||
defer aw.deinit();
|
||||
|
||||
try req.write(&aw.writer);
|
||||
Sha256.hash(aw.getWritten(), &hash, .{});
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
defer buf.deinit();
|
||||
try req.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(req.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .requirements = req });
|
||||
@ -317,11 +316,10 @@ pub fn writeAdhocSignature(
|
||||
}
|
||||
|
||||
if (self.entitlements) |*ents| {
|
||||
var aw: std.io.Writer.Allocating = .init(allocator);
|
||||
defer aw.deinit();
|
||||
|
||||
try ents.write(&aw.writer);
|
||||
Sha256.hash(aw.getWritten(), &hash, .{});
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
defer buf.deinit();
|
||||
try ents.write(buf.writer());
|
||||
Sha256.hash(buf.items, &hash, .{});
|
||||
self.code_directory.addSpecialHash(ents.slotType(), hash);
|
||||
|
||||
try blobs.append(.{ .entitlements = ents });
|
||||
|
||||
@ -269,14 +269,18 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
|
||||
|
||||
fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
|
||||
const gpa = self.allocator;
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));
|
||||
defer gpa.free(bw.buffer);
|
||||
const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
|
||||
const buffer = try gpa.alloc(u8, needed_size);
|
||||
defer gpa.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const writer = stream.writer();
|
||||
|
||||
var ncmds: usize = 0;
|
||||
|
||||
// UUID comes first presumably to speed up lookup by the consumer like lldb.
|
||||
@memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
|
||||
try bw.writeStruct(self.uuid_cmd);
|
||||
try writer.writeStruct(self.uuid_cmd);
|
||||
ncmds += 1;
|
||||
|
||||
// Segment and section load commands
|
||||
@ -289,11 +293,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
|
||||
var out_seg = seg;
|
||||
out_seg.fileoff = 0;
|
||||
out_seg.filesize = 0;
|
||||
try bw.writeStruct(out_seg);
|
||||
try writer.writeStruct(out_seg);
|
||||
for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
|
||||
var out_header = header;
|
||||
out_header.offset = 0;
|
||||
try bw.writeStruct(out_header);
|
||||
try writer.writeStruct(out_header);
|
||||
}
|
||||
sect_id += seg.nsects;
|
||||
}
|
||||
@ -302,22 +306,23 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
|
||||
// Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
|
||||
sect_id = 0;
|
||||
for (self.segments.items) |seg| {
|
||||
try bw.writeStruct(seg);
|
||||
try writer.writeStruct(seg);
|
||||
for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
|
||||
try bw.writeStruct(header);
|
||||
try writer.writeStruct(header);
|
||||
}
|
||||
sect_id += seg.nsects;
|
||||
}
|
||||
ncmds += self.segments.items.len;
|
||||
}
|
||||
|
||||
try bw.writeStruct(self.symtab_cmd);
|
||||
try writer.writeStruct(self.symtab_cmd);
|
||||
ncmds += 1;
|
||||
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
|
||||
assert(stream.pos == needed_size);
|
||||
|
||||
return .{ ncmds, bw.end };
|
||||
try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
|
||||
|
||||
return .{ ncmds, buffer.len };
|
||||
}
|
||||
|
||||
fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
|
||||
|
||||
@ -81,7 +81,7 @@ pub const InfoReader = struct {
|
||||
.dwarf64 => 12,
|
||||
} + cuh_length;
|
||||
while (p.pos < end_pos) {
|
||||
const di_code = try p.readLeb128(u64);
|
||||
const di_code = try p.readUleb128(u64);
|
||||
if (di_code == 0) return error.UnexpectedEndOfFile;
|
||||
if (di_code == code) return;
|
||||
|
||||
@ -174,14 +174,14 @@ pub const InfoReader = struct {
|
||||
dw.FORM.block1 => try p.readByte(),
|
||||
dw.FORM.block2 => try p.readInt(u16),
|
||||
dw.FORM.block4 => try p.readInt(u32),
|
||||
dw.FORM.block => try p.readLeb128(u64),
|
||||
dw.FORM.block => try p.readUleb128(u64),
|
||||
else => unreachable,
|
||||
};
|
||||
return p.readNBytes(len);
|
||||
}
|
||||
|
||||
pub fn readExprLoc(p: *InfoReader) ![]const u8 {
|
||||
const len: u64 = try p.readLeb128(u64);
|
||||
const len: u64 = try p.readUleb128(u64);
|
||||
return p.readNBytes(len);
|
||||
}
|
||||
|
||||
@ -191,8 +191,8 @@ pub const InfoReader = struct {
|
||||
dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
|
||||
dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
|
||||
dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),
|
||||
dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64),
|
||||
dw.FORM.sdata => @bitCast(try p.readLeb128(i64)),
|
||||
dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),
|
||||
dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
|
||||
else => return error.UnhandledConstantForm,
|
||||
};
|
||||
}
|
||||
@ -203,7 +203,7 @@ pub const InfoReader = struct {
|
||||
dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
|
||||
dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,
|
||||
dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),
|
||||
dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64),
|
||||
dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64),
|
||||
else => return error.UnhandledIndexForm,
|
||||
};
|
||||
}
|
||||
@ -272,10 +272,20 @@ pub const InfoReader = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type {
|
||||
var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
|
||||
defer p.pos += r.seek;
|
||||
return r.takeLeb128(Type);
|
||||
pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {
|
||||
var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const value: Type = try leb.readUleb128(Type, creader.reader());
|
||||
p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn readIleb128(p: *InfoReader, comptime Type: type) !Type {
|
||||
var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const value: Type = try leb.readIleb128(Type, creader.reader());
|
||||
p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn seekTo(p: *InfoReader, off: u64) !void {
|
||||
@ -297,10 +307,10 @@ pub const AbbrevReader = struct {
|
||||
|
||||
pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
|
||||
const pos = p.pos;
|
||||
const code = try p.readLeb128(Code);
|
||||
const code = try p.readUleb128(Code);
|
||||
if (code == 0) return null;
|
||||
|
||||
const tag = try p.readLeb128(Tag);
|
||||
const tag = try p.readUleb128(Tag);
|
||||
const has_children = (try p.readByte()) > 0;
|
||||
return .{
|
||||
.code = code,
|
||||
@ -313,8 +323,8 @@ pub const AbbrevReader = struct {
|
||||
|
||||
pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
|
||||
const pos = p.pos;
|
||||
const at = try p.readLeb128(At);
|
||||
const form = try p.readLeb128(Form);
|
||||
const at = try p.readUleb128(At);
|
||||
const form = try p.readUleb128(Form);
|
||||
return if (at == 0 and form == 0) null else .{
|
||||
.at = at,
|
||||
.form = form,
|
||||
@ -329,10 +339,12 @@ pub const AbbrevReader = struct {
|
||||
return p.bytes()[p.pos];
|
||||
}
|
||||
|
||||
pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type {
|
||||
var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
|
||||
defer p.pos += r.seek;
|
||||
return r.takeLeb128(Type);
|
||||
pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {
|
||||
var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const value: Type = try leb.readUleb128(Type, creader.reader());
|
||||
p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn seekTo(p: *AbbrevReader, off: u64) !void {
|
||||
|
||||
@ -158,6 +158,46 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
const TrieIterator = struct {
|
||||
data: []const u8,
|
||||
pos: usize = 0,
|
||||
|
||||
fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {
|
||||
return std.io.fixedBufferStream(it.data[it.pos..]);
|
||||
}
|
||||
|
||||
fn readUleb128(it: *TrieIterator) !u64 {
|
||||
var stream = it.getStream();
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const reader = creader.reader();
|
||||
const value = try std.leb.readUleb128(u64, reader);
|
||||
it.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
|
||||
return value;
|
||||
}
|
||||
|
||||
fn readString(it: *TrieIterator) ![:0]const u8 {
|
||||
var stream = it.getStream();
|
||||
const reader = stream.reader();
|
||||
|
||||
var count: usize = 0;
|
||||
while (true) : (count += 1) {
|
||||
const byte = try reader.readByte();
|
||||
if (byte == 0) break;
|
||||
}
|
||||
|
||||
const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0];
|
||||
it.pos += count + 1;
|
||||
return str;
|
||||
}
|
||||
|
||||
fn readByte(it: *TrieIterator) !u8 {
|
||||
var stream = it.getStream();
|
||||
const value = try stream.reader().readByte();
|
||||
it.pos += 1;
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
|
||||
try self.exports.append(allocator, .{
|
||||
.name = try self.addString(allocator, name),
|
||||
@ -167,16 +207,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
|
||||
|
||||
fn parseTrieNode(
|
||||
self: *Dylib,
|
||||
br: *std.io.Reader,
|
||||
it: *TrieIterator,
|
||||
allocator: Allocator,
|
||||
arena: Allocator,
|
||||
prefix: []const u8,
|
||||
) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
const size = try br.takeLeb128(u64);
|
||||
const size = try it.readUleb128();
|
||||
if (size > 0) {
|
||||
const flags = try br.takeLeb128(u8);
|
||||
const flags = try it.readUleb128();
|
||||
const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
|
||||
const out_flags = Export.Flags{
|
||||
.abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
|
||||
@ -184,28 +224,29 @@ fn parseTrieNode(
|
||||
.weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
|
||||
};
|
||||
if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
|
||||
_ = try br.takeLeb128(u64); // dylib ordinal
|
||||
const name = try br.takeSentinel(0);
|
||||
_ = try it.readUleb128(); // dylib ordinal
|
||||
const name = try it.readString();
|
||||
try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
|
||||
} else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
|
||||
_ = try br.takeLeb128(u64); // stub offset
|
||||
_ = try br.takeLeb128(u64); // resolver offset
|
||||
_ = try it.readUleb128(); // stub offset
|
||||
_ = try it.readUleb128(); // resolver offset
|
||||
try self.addExport(allocator, prefix, out_flags);
|
||||
} else {
|
||||
_ = try br.takeLeb128(u64); // VM offset
|
||||
_ = try it.readUleb128(); // VM offset
|
||||
try self.addExport(allocator, prefix, out_flags);
|
||||
}
|
||||
}
|
||||
|
||||
const nedges = try br.takeByte();
|
||||
const nedges = try it.readByte();
|
||||
|
||||
for (0..nedges) |_| {
|
||||
const label = try br.takeSentinel(0);
|
||||
const off = try br.takeLeb128(usize);
|
||||
const label = try it.readString();
|
||||
const off = try it.readUleb128();
|
||||
const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
|
||||
const seek = br.seek;
|
||||
br.seek = off;
|
||||
try self.parseTrieNode(br, allocator, arena, prefix_label);
|
||||
br.seek = seek;
|
||||
const curr = it.pos;
|
||||
it.pos = math.cast(usize, off) orelse return error.Overflow;
|
||||
try self.parseTrieNode(it, allocator, arena, prefix_label);
|
||||
it.pos = curr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,8 +257,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena.deinit();
|
||||
|
||||
var r: std.io.Reader = .fixed(data);
|
||||
try self.parseTrieNode(&r, gpa, arena.allocator(), "");
|
||||
var it: TrieIterator = .{ .data = data };
|
||||
try self.parseTrieNode(&it, gpa, arena.allocator(), "");
|
||||
}
|
||||
|
||||
fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
|
||||
|
||||
@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
|
||||
|
||||
sect.offset = @intCast(self.objc_methnames.items.len);
|
||||
try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
|
||||
self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
|
||||
self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;
|
||||
|
||||
const name_str = try self.addString(gpa, "ltmp");
|
||||
const sym_index = try self.addSymbol(gpa);
|
||||
|
||||
@ -1069,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
|
||||
}
|
||||
}
|
||||
|
||||
var it: eh_frame.Iterator = .{ .br = .fixed(self.eh_frame_data.items) };
|
||||
var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };
|
||||
while (try it.next()) |rec| {
|
||||
switch (rec.tag) {
|
||||
.cie => try self.cies.append(allocator, .{
|
||||
@ -1698,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void {
|
||||
pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
|
||||
// Header
|
||||
const size = try macho_file.cast(usize, self.output_ar_state.size);
|
||||
const basename = std.fs.path.basename(self.path.sub_path);
|
||||
try Archive.writeHeader(bw, basename, size, ar_format);
|
||||
try Archive.writeHeader(basename, size, ar_format, writer);
|
||||
// Data
|
||||
const file = macho_file.getFileHandle(self.file_handle);
|
||||
// TODO try using copyRangeAll
|
||||
@ -1711,7 +1711,7 @@ pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file:
|
||||
defer gpa.free(data);
|
||||
const amt = try file.preadAll(data, self.offset);
|
||||
if (amt != size) return error.InputOutput;
|
||||
try bw.writeAll(data);
|
||||
try writer.writeAll(data);
|
||||
}
|
||||
|
||||
pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
|
||||
@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
|
||||
}
|
||||
gpa.free(sections_data);
|
||||
}
|
||||
@memset(sections_data, &.{});
|
||||
@memset(sections_data, &[0]u8{});
|
||||
const file = macho_file.getFileHandle(self.file_handle);
|
||||
|
||||
for (headers, 0..) |header, n_sect| {
|
||||
|
||||
@ -297,7 +297,7 @@ const Format = struct {
|
||||
symbol: Symbol,
|
||||
macho_file: *MachO,
|
||||
|
||||
fn format2(f: Format, w: *Writer) Writer.Error!void {
|
||||
fn default(f: Format, w: *Writer) Writer.Error!void {
|
||||
const symbol = f.symbol;
|
||||
try w.print("%{d} : {s} : @{x}", .{
|
||||
symbol.nlist_idx,
|
||||
|
||||
@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
|
||||
return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
|
||||
}
|
||||
|
||||
pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
|
||||
for (thunk.symbols.keys(), 0..) |ref, i| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
|
||||
const taddr = sym.getAddress(.{}, macho_file);
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
const off: u12 = @truncate(taddr);
|
||||
try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
|
||||
try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -289,10 +289,13 @@ pub fn calcSize(info: UnwindInfo) usize {
|
||||
return total_size;
|
||||
}
|
||||
|
||||
pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!void {
|
||||
pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
|
||||
const seg = macho_file.getTextSegment();
|
||||
const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const writer = stream.writer();
|
||||
|
||||
const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
|
||||
const common_encodings_count: u32 = info.common_encodings_count;
|
||||
const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32);
|
||||
@ -300,7 +303,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
|
||||
const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
|
||||
const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
|
||||
|
||||
try bw.writeStruct(macho.unwind_info_section_header{
|
||||
try writer.writeStruct(macho.unwind_info_section_header{
|
||||
.commonEncodingsArraySectionOffset = common_encodings_offset,
|
||||
.commonEncodingsArrayCount = common_encodings_count,
|
||||
.personalityArraySectionOffset = personalities_offset,
|
||||
@ -309,11 +312,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
|
||||
.indexCount = indexes_count,
|
||||
});
|
||||
|
||||
try bw.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
|
||||
try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
|
||||
|
||||
for (info.personalities[0..info.personalities_count]) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
try bw.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
|
||||
try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
|
||||
}
|
||||
|
||||
const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));
|
||||
@ -322,7 +325,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
|
||||
for (info.pages.items, 0..) |page, i| {
|
||||
assert(page.count > 0);
|
||||
const rec = info.records.items[page.start].getUnwindRecord(macho_file);
|
||||
try bw.writeStruct(macho.unwind_info_section_header_index_entry{
|
||||
try writer.writeStruct(macho.unwind_info_section_header_index_entry{
|
||||
.functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
|
||||
.secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
|
||||
.lsdaIndexArraySectionOffset = lsda_base_offset +
|
||||
@ -332,7 +335,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
|
||||
|
||||
const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
|
||||
const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
|
||||
try bw.writeStruct(macho.unwind_info_section_header_index_entry{
|
||||
try writer.writeStruct(macho.unwind_info_section_header_index_entry{
|
||||
.functionOffset = sentinel_address,
|
||||
.secondLevelPagesSectionOffset = 0,
|
||||
.lsdaIndexArraySectionOffset = lsda_base_offset +
|
||||
@ -341,20 +344,23 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
|
||||
|
||||
for (info.lsdas.items) |index| {
|
||||
const rec = info.records.items[index].getUnwindRecord(macho_file);
|
||||
try bw.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
|
||||
try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
|
||||
.functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
|
||||
.lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
|
||||
});
|
||||
}
|
||||
|
||||
for (info.pages.items) |page| {
|
||||
const start = bw.count;
|
||||
try page.write(info, macho_file, bw);
|
||||
const nwritten = bw.count - start;
|
||||
try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow);
|
||||
const start = stream.pos;
|
||||
try page.write(info, macho_file, writer);
|
||||
const nwritten = stream.pos - start;
|
||||
if (nwritten < second_level_page_bytes) {
|
||||
const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
@memset(bw.unusedCapacitySlice(), 0);
|
||||
@memset(buffer[stream.pos..], 0);
|
||||
}
|
||||
|
||||
fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
|
||||
|
||||
@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {
|
||||
self.output_ar_state.size = self.data.items.len;
|
||||
}
|
||||
|
||||
pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void {
|
||||
pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
|
||||
// Header
|
||||
const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
|
||||
try Archive.writeHeader(bw, self.basename, size, ar_format);
|
||||
try Archive.writeHeader(self.basename, size, ar_format, writer);
|
||||
// Data
|
||||
try bw.writeAll(self.data.items);
|
||||
try writer.writeAll(self.data.items);
|
||||
}
|
||||
|
||||
pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
|
||||
@ -884,6 +884,7 @@ pub fn updateNav(
|
||||
defer debug_wip_nav.deinit();
|
||||
dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.Overflow => return error.Overflow,
|
||||
else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
|
||||
};
|
||||
}
|
||||
@ -920,6 +921,7 @@ pub fn updateNav(
|
||||
|
||||
if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.Overflow => return error.Overflow,
|
||||
else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
|
||||
};
|
||||
} else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
|
||||
|
||||
@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
pub const Entry = struct {
|
||||
offset: u64,
|
||||
segment_id: u4,
|
||||
segment_id: u8,
|
||||
|
||||
pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
|
||||
_ = ctx;
|
||||
@ -110,35 +110,33 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
|
||||
fn finalize(rebase: *Rebase, gpa: Allocator) !void {
|
||||
if (rebase.entries.items.len == 0) return;
|
||||
|
||||
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
|
||||
const bw = &aw.writer;
|
||||
defer rebase.buffer = aw.toArrayList();
|
||||
const writer = rebase.buffer.writer(gpa);
|
||||
|
||||
log.debug("rebase opcodes", .{});
|
||||
|
||||
std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
|
||||
|
||||
try setTypePointer(bw);
|
||||
try setTypePointer(writer);
|
||||
|
||||
var start: usize = 0;
|
||||
var seg_id: ?u8 = null;
|
||||
for (rebase.entries.items, 0..) |entry, i| {
|
||||
if (seg_id != null and seg_id.? == entry.segment_id) continue;
|
||||
try finalizeSegment(rebase.entries.items[start..i], bw);
|
||||
try finalizeSegment(rebase.entries.items[start..i], writer);
|
||||
seg_id = entry.segment_id;
|
||||
start = i;
|
||||
}
|
||||
|
||||
try finalizeSegment(rebase.entries.items[start..], bw);
|
||||
try done(bw);
|
||||
try finalizeSegment(rebase.entries.items[start..], writer);
|
||||
try done(writer);
|
||||
}
|
||||
|
||||
fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
|
||||
if (entries.len == 0) return;
|
||||
|
||||
const segment_id = entries[0].segment_id;
|
||||
var offset = entries[0].offset;
|
||||
try setSegmentOffset(segment_id, offset, bw);
|
||||
try setSegmentOffset(segment_id, offset, writer);
|
||||
|
||||
var count: usize = 0;
|
||||
var skip: u64 = 0;
|
||||
@ -157,7 +155,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
.start => {
|
||||
if (offset < current_offset) {
|
||||
const delta = current_offset - offset;
|
||||
try addAddr(delta, bw);
|
||||
try addAddr(delta, writer);
|
||||
offset += delta;
|
||||
}
|
||||
state = .times;
|
||||
@ -177,7 +175,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
offset += skip;
|
||||
i -= 1;
|
||||
} else {
|
||||
try rebaseTimes(count, bw);
|
||||
try rebaseTimes(count, writer);
|
||||
state = .start;
|
||||
i -= 1;
|
||||
}
|
||||
@ -186,9 +184,9 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
if (current_offset < offset) {
|
||||
count -= 1;
|
||||
if (count == 1) {
|
||||
try rebaseAddAddr(skip, bw);
|
||||
try rebaseAddAddr(skip, writer);
|
||||
} else {
|
||||
try rebaseTimesSkip(count, skip, bw);
|
||||
try rebaseTimesSkip(count, skip, writer);
|
||||
}
|
||||
state = .start;
|
||||
offset = offset - (@sizeOf(u64) + skip);
|
||||
@ -201,7 +199,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
count += 1;
|
||||
offset += @sizeOf(u64) + skip;
|
||||
} else {
|
||||
try rebaseTimesSkip(count, skip, bw);
|
||||
try rebaseTimesSkip(count, skip, writer);
|
||||
state = .start;
|
||||
i -= 1;
|
||||
}
|
||||
@ -212,66 +210,68 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
|
||||
switch (state) {
|
||||
.start => unreachable,
|
||||
.times => {
|
||||
try rebaseTimes(count, bw);
|
||||
try rebaseTimes(count, writer);
|
||||
},
|
||||
.times_skip => {
|
||||
try rebaseTimesSkip(count, skip, bw);
|
||||
try rebaseTimesSkip(count, skip, writer);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn setTypePointer(bw: *Writer) Writer.Error!void {
|
||||
fn setTypePointer(writer: anytype) !void {
|
||||
log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});
|
||||
try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER)));
|
||||
try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.REBASE_TYPE_POINTER)));
|
||||
}
|
||||
|
||||
fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
|
||||
fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
|
||||
log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
|
||||
try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
|
||||
try bw.writeLeb128(offset);
|
||||
try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
|
||||
try std.leb.writeUleb128(writer, offset);
|
||||
}
|
||||
|
||||
fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
|
||||
fn rebaseAddAddr(addr: u64, writer: anytype) !void {
|
||||
log.debug(">>> rebase with add: {x}", .{addr});
|
||||
try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
|
||||
try bw.writeLeb128(addr);
|
||||
try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
|
||||
try std.leb.writeUleb128(writer, addr);
|
||||
}
|
||||
|
||||
fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {
|
||||
fn rebaseTimes(count: usize, writer: anytype) !void {
|
||||
log.debug(">>> rebase with count: {d}", .{count});
|
||||
if (count <= 0xf) {
|
||||
try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
|
||||
try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
|
||||
} else {
|
||||
try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
|
||||
try bw.writeLeb128(count);
|
||||
try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
|
||||
try std.leb.writeUleb128(writer, count);
|
||||
}
|
||||
}
|
||||
|
||||
fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
|
||||
fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
|
||||
log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
|
||||
try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
|
||||
try bw.writeLeb128(count);
|
||||
try bw.writeLeb128(skip);
|
||||
try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
|
||||
try std.leb.writeUleb128(writer, count);
|
||||
try std.leb.writeUleb128(writer, skip);
|
||||
}
|
||||
|
||||
fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
|
||||
fn addAddr(addr: u64, writer: anytype) !void {
|
||||
log.debug(">>> add: {x}", .{addr});
|
||||
if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
|
||||
if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
|
||||
macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled,
|
||||
);
|
||||
} else |_| {}
|
||||
try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
|
||||
try bw.writeLeb128(addr);
|
||||
if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
|
||||
const imm = @divExact(addr, @sizeOf(u64));
|
||||
if (imm <= 0xf) {
|
||||
try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
|
||||
try std.leb.writeUleb128(writer, addr);
|
||||
}
|
||||
|
||||
fn done(bw: *Writer) Writer.Error!void {
|
||||
fn done(writer: anytype) !void {
|
||||
log.debug(">>> done", .{});
|
||||
try bw.writeByte(macho.REBASE_OPCODE_DONE);
|
||||
try writer.writeByte(macho.REBASE_OPCODE_DONE);
|
||||
}
|
||||
|
||||
pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {
|
||||
try bw.writeAll(rebase.buffer.items);
|
||||
pub fn write(rebase: Rebase, writer: anytype) !void {
|
||||
try writer.writeAll(rebase.buffer.items);
|
||||
}
|
||||
|
||||
test "rebase - no entries" {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
/// The root node of the trie.
|
||||
root: ?Node.Index = null,
|
||||
buffer: []u8 = &.{},
|
||||
buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
nodes: std.MultiArrayList(Node) = .{},
|
||||
edges: std.ArrayListUnmanaged(Edge) = .empty,
|
||||
|
||||
@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
|
||||
|
||||
try self.finalize(gpa);
|
||||
|
||||
macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.len), @alignOf(u64));
|
||||
macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
|
||||
}
|
||||
|
||||
/// Finalizes this trie for writing to a byte stream.
|
||||
@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
|
||||
defer ordered_nodes.deinit();
|
||||
try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);
|
||||
|
||||
var fifo = DeprecatedLinearFifo(Node.Index).init(allocator);
|
||||
var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator);
|
||||
defer fifo.deinit();
|
||||
|
||||
try fifo.writeItem(self.root.?);
|
||||
@ -164,11 +164,9 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
|
||||
}
|
||||
}
|
||||
|
||||
assert(self.buffer.len == 0);
|
||||
self.buffer = try allocator.alloc(u8, size);
|
||||
var bw: Writer = .fixed(self.buffer);
|
||||
try self.buffer.ensureTotalCapacityPrecise(allocator, size);
|
||||
for (ordered_nodes.items) |node_index| {
|
||||
try self.writeNode(node_index, &bw);
|
||||
try self.writeNode(node_index, self.buffer.writer(allocator));
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,17 +181,17 @@ const FinalizeNodeResult = struct {
|
||||
|
||||
/// Updates offset of this node in the output byte stream.
|
||||
fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
|
||||
var buf: [1024]u8 = undefined;
|
||||
var bw: Writer = .discarding(&buf);
|
||||
var stream = std.io.countingWriter(std.io.null_writer);
|
||||
const writer = stream.writer();
|
||||
const slice = self.nodes.slice();
|
||||
|
||||
var node_size: u32 = 0;
|
||||
if (slice.items(.is_terminal)[node_index]) {
|
||||
const export_flags = slice.items(.export_flags)[node_index];
|
||||
const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
|
||||
try bw.writeLeb128(export_flags);
|
||||
try bw.writeLeb128(vmaddr_offset);
|
||||
try bw.writeLeb128(bw.count);
|
||||
try leb.writeULEB128(writer, export_flags);
|
||||
try leb.writeULEB128(writer, vmaddr_offset);
|
||||
try leb.writeULEB128(writer, stream.bytes_written);
|
||||
} else {
|
||||
node_size += 1; // 0x0 for non-terminal nodes
|
||||
}
|
||||
@ -203,13 +201,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
|
||||
const edge = &self.edges.items[edge_index];
|
||||
const next_node_offset = slice.items(.trie_offset)[edge.node];
|
||||
node_size += @intCast(edge.label.len + 1);
|
||||
try bw.writeLeb128(next_node_offset);
|
||||
try leb.writeULEB128(writer, next_node_offset);
|
||||
}
|
||||
|
||||
const trie_offset = slice.items(.trie_offset)[node_index];
|
||||
const updated = offset_in_trie != trie_offset;
|
||||
slice.items(.trie_offset)[node_index] = offset_in_trie;
|
||||
node_size += @intCast(bw.count);
|
||||
node_size += @intCast(stream.bytes_written);
|
||||
|
||||
return .{ .node_size = node_size, .updated = updated };
|
||||
}
|
||||
@ -225,11 +223,12 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
|
||||
}
|
||||
self.nodes.deinit(allocator);
|
||||
self.edges.deinit(allocator);
|
||||
allocator.free(self.buffer);
|
||||
self.buffer.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
|
||||
try bw.writeAll(self.buffer);
|
||||
pub fn write(self: Trie, writer: anytype) !void {
|
||||
if (self.buffer.items.len == 0) return;
|
||||
try writer.writeAll(self.buffer.items);
|
||||
}
|
||||
|
||||
/// Writes this node to a byte stream.
|
||||
@ -238,7 +237,7 @@ pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
|
||||
/// iterate over `Trie.ordered_nodes` and call this method on each node.
|
||||
/// This is one of the requirements of the MachO.
|
||||
/// Panics if `finalize` was not called before calling this method.
|
||||
fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
|
||||
fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
|
||||
const slice = self.nodes.slice();
|
||||
const edges = slice.items(.edges)[node_index];
|
||||
const is_terminal = slice.items(.is_terminal)[node_index];
|
||||
@ -246,28 +245,36 @@ fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
|
||||
const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
|
||||
|
||||
if (is_terminal) {
|
||||
const start = bw.count;
|
||||
// Terminal node info: encode export flags and vmaddr offset of this symbol.
|
||||
var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
|
||||
var info_stream = std.io.fixedBufferStream(&info_buf);
|
||||
// TODO Implement for special flags.
|
||||
assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
|
||||
export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
|
||||
// Terminal node info: encode export flags and vmaddr offset of this symbol.
|
||||
try bw.writeLeb128(export_flags);
|
||||
try bw.writeLeb128(vmaddr_offset);
|
||||
try leb.writeULEB128(info_stream.writer(), export_flags);
|
||||
try leb.writeULEB128(info_stream.writer(), vmaddr_offset);
|
||||
|
||||
// Encode the size of the terminal node info.
|
||||
try bw.writeLeb128(bw.count - start);
|
||||
var size_buf: [@sizeOf(u64)]u8 = undefined;
|
||||
var size_stream = std.io.fixedBufferStream(&size_buf);
|
||||
try leb.writeULEB128(size_stream.writer(), info_stream.pos);
|
||||
|
||||
// Now, write them to the output stream.
|
||||
try writer.writeAll(size_buf[0..size_stream.pos]);
|
||||
try writer.writeAll(info_buf[0..info_stream.pos]);
|
||||
} else {
|
||||
// Non-terminal node is delimited by 0 byte.
|
||||
try bw.writeByte(0);
|
||||
try writer.writeByte(0);
|
||||
}
|
||||
// Write number of edges (max legal number of edges is 255).
|
||||
try bw.writeByte(@intCast(edges.items.len));
|
||||
// Write number of edges (max legal number of edges is 256).
|
||||
try writer.writeByte(@as(u8, @intCast(edges.items.len)));
|
||||
|
||||
for (edges.items) |edge_index| {
|
||||
const edge = self.edges.items[edge_index];
|
||||
// Write edge label and offset to next node in trie.
|
||||
try bw.writeAll(edge.label);
|
||||
try bw.writeByte(0);
|
||||
try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);
|
||||
try writer.writeAll(edge.label);
|
||||
try writer.writeByte(0);
|
||||
try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,10 +414,8 @@ const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const Writer = std.io.Writer;
|
||||
|
||||
const trace = @import("../../../tracy.zig").trace;
|
||||
const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const MachO = @import("../../MachO.zig");
|
||||
const Trie = @This();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
pub const Entry = struct {
|
||||
target: MachO.Ref,
|
||||
offset: u64,
|
||||
segment_id: u4,
|
||||
segment_id: u8,
|
||||
addend: i64,
|
||||
|
||||
pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
|
||||
@ -20,12 +20,14 @@ pub const Bind = struct {
|
||||
entries: std.ArrayListUnmanaged(Entry) = .empty,
|
||||
buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
pub fn deinit(bind: *Bind, gpa: Allocator) void {
|
||||
bind.entries.deinit(gpa);
|
||||
bind.buffer.deinit(gpa);
|
||||
const Self = @This();
|
||||
|
||||
pub fn deinit(self: *Self, gpa: Allocator) void {
|
||||
self.entries.deinit(gpa);
|
||||
self.buffer.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {
|
||||
pub fn updateSize(self: *Self, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -54,12 +56,15 @@ 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;
|
||||
if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,12 +75,15 @@ 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);
|
||||
if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,12 +94,15 @@ 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);
|
||||
if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
|
||||
const bind_entry = Entry{
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,48 +113,49 @@ 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);
|
||||
if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.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 bind.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
|
||||
try self.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
|
||||
}
|
||||
|
||||
fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {
|
||||
if (bind.entries.items.len == 0) return;
|
||||
fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
|
||||
if (self.entries.items.len == 0) return;
|
||||
|
||||
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
|
||||
const bw = &aw.writer;
|
||||
defer bind.buffer = aw.toArrayList();
|
||||
const writer = self.buffer.writer(gpa);
|
||||
|
||||
log.debug("bind opcodes", .{});
|
||||
|
||||
std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
|
||||
std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
|
||||
|
||||
var start: usize = 0;
|
||||
var seg_id: ?u8 = null;
|
||||
for (bind.entries.items, 0..) |entry, i| {
|
||||
for (self.entries.items, 0..) |entry, i| {
|
||||
if (seg_id != null and seg_id.? == entry.segment_id) continue;
|
||||
try finalizeSegment(bind.entries.items[start..i], ctx, bw);
|
||||
try finalizeSegment(self.entries.items[start..i], ctx, writer);
|
||||
seg_id = entry.segment_id;
|
||||
start = i;
|
||||
}
|
||||
|
||||
try finalizeSegment(bind.entries.items[start..], ctx, bw);
|
||||
try done(bw);
|
||||
try finalizeSegment(self.entries.items[start..], ctx, writer);
|
||||
try done(writer);
|
||||
}
|
||||
|
||||
fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
|
||||
fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
|
||||
if (entries.len == 0) return;
|
||||
|
||||
const seg_id = entries[0].segment_id;
|
||||
try setSegmentOffset(seg_id, 0, bw);
|
||||
try setSegmentOffset(seg_id, 0, writer);
|
||||
|
||||
var offset: u64 = 0;
|
||||
var addend: i64 = 0;
|
||||
@ -163,15 +175,15 @@ pub const Bind = struct {
|
||||
if (target == null or !target.?.eql(current.target)) {
|
||||
switch (state) {
|
||||
.start => {},
|
||||
.bind_single => try doBind(bw),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, bw),
|
||||
.bind_single => try doBind(writer),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, writer),
|
||||
}
|
||||
state = .start;
|
||||
target = current.target;
|
||||
|
||||
const sym = current.target.getSymbol(ctx).?;
|
||||
const name = sym.getName(ctx);
|
||||
const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
|
||||
const flags: u8 = 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) {
|
||||
@ -183,13 +195,13 @@ pub const Bind = struct {
|
||||
break :ord macho.BIND_SPECIAL_DYLIB_SELF;
|
||||
};
|
||||
|
||||
try setSymbol(name, flags, bw);
|
||||
try setTypePointer(bw);
|
||||
try setDylibOrdinal(ordinal, bw);
|
||||
try setSymbol(name, flags, writer);
|
||||
try setTypePointer(writer);
|
||||
try setDylibOrdinal(ordinal, writer);
|
||||
|
||||
if (current.addend != addend) {
|
||||
addend = current.addend;
|
||||
try setAddend(addend, bw);
|
||||
try setAddend(addend, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,11 +210,11 @@ pub const Bind = struct {
|
||||
switch (state) {
|
||||
.start => {
|
||||
if (current.offset < offset) {
|
||||
try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw);
|
||||
try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer);
|
||||
offset = offset - (offset - current.offset);
|
||||
} else if (current.offset > offset) {
|
||||
const delta = current.offset - offset;
|
||||
try addAddr(delta, bw);
|
||||
try addAddr(delta, writer);
|
||||
offset += delta;
|
||||
}
|
||||
state = .bind_single;
|
||||
@ -211,7 +223,7 @@ pub const Bind = struct {
|
||||
},
|
||||
.bind_single => {
|
||||
if (current.offset == offset) {
|
||||
try doBind(bw);
|
||||
try doBind(writer);
|
||||
state = .start;
|
||||
} else if (current.offset > offset) {
|
||||
const delta = current.offset - offset;
|
||||
@ -225,9 +237,9 @@ pub const Bind = struct {
|
||||
if (current.offset < offset) {
|
||||
count -= 1;
|
||||
if (count == 1) {
|
||||
try doBindAddAddr(skip, bw);
|
||||
try doBindAddAddr(skip, writer);
|
||||
} else {
|
||||
try doBindTimesSkip(count, skip, bw);
|
||||
try doBindTimesSkip(count, skip, writer);
|
||||
}
|
||||
state = .start;
|
||||
offset = offset - (@sizeOf(u64) + skip);
|
||||
@ -236,7 +248,7 @@ pub const Bind = struct {
|
||||
count += 1;
|
||||
offset += @sizeOf(u64) + skip;
|
||||
} else {
|
||||
try doBindTimesSkip(count, skip, bw);
|
||||
try doBindTimesSkip(count, skip, writer);
|
||||
state = .start;
|
||||
i -= 1;
|
||||
}
|
||||
@ -246,13 +258,13 @@ pub const Bind = struct {
|
||||
|
||||
switch (state) {
|
||||
.start => unreachable,
|
||||
.bind_single => try doBind(bw),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, bw),
|
||||
.bind_single => try doBind(writer),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, writer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {
|
||||
try bw.writeAll(bind.buffer.items);
|
||||
pub fn write(self: Self, writer: anytype) !void {
|
||||
try writer.writeAll(self.buffer.items);
|
||||
}
|
||||
};
|
||||
|
||||
@ -260,12 +272,14 @@ pub const WeakBind = struct {
|
||||
entries: std.ArrayListUnmanaged(Entry) = .empty,
|
||||
buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
pub fn deinit(bind: *WeakBind, gpa: Allocator) void {
|
||||
bind.entries.deinit(gpa);
|
||||
bind.buffer.deinit(gpa);
|
||||
const Self = @This();
|
||||
|
||||
pub fn deinit(self: *Self, gpa: Allocator) void {
|
||||
self.entries.deinit(gpa);
|
||||
self.buffer.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {
|
||||
pub fn updateSize(self: *Self, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -294,12 +308,15 @@ 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;
|
||||
if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,12 +327,15 @@ 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);
|
||||
if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.target = ref,
|
||||
.offset = addr - seg.vmaddr,
|
||||
.segment_id = seg_id,
|
||||
.addend = 0,
|
||||
};
|
||||
if (sym.flags.weak) {
|
||||
try self.entries.append(gpa, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,12 +347,15 @@ 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);
|
||||
if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
|
||||
const bind_entry = Entry{
|
||||
.target = ref,
|
||||
.offset = addr - seg.vmaddr,
|
||||
.segment_id = seg_id,
|
||||
.addend = 0,
|
||||
};
|
||||
if (sym.flags.weak) {
|
||||
try self.entries.append(gpa, bind_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,48 +366,49 @@ 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);
|
||||
if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
|
||||
const entry = Entry{
|
||||
.target = ref,
|
||||
.offset = addr - seg.vmaddr,
|
||||
.segment_id = seg_id,
|
||||
.addend = 0,
|
||||
};
|
||||
if (sym.flags.weak) {
|
||||
try self.entries.append(gpa, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try bind.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
|
||||
try self.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
|
||||
}
|
||||
|
||||
fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {
|
||||
if (bind.entries.items.len == 0) return;
|
||||
fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
|
||||
if (self.entries.items.len == 0) return;
|
||||
|
||||
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
|
||||
const bw = &aw.writer;
|
||||
defer bind.buffer = aw.toArrayList();
|
||||
const writer = self.buffer.writer(gpa);
|
||||
|
||||
log.debug("weak bind opcodes", .{});
|
||||
|
||||
std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
|
||||
std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
|
||||
|
||||
var start: usize = 0;
|
||||
var seg_id: ?u8 = null;
|
||||
for (bind.entries.items, 0..) |entry, i| {
|
||||
for (self.entries.items, 0..) |entry, i| {
|
||||
if (seg_id != null and seg_id.? == entry.segment_id) continue;
|
||||
try finalizeSegment(bind.entries.items[start..i], ctx, bw);
|
||||
try finalizeSegment(self.entries.items[start..i], ctx, writer);
|
||||
seg_id = entry.segment_id;
|
||||
start = i;
|
||||
}
|
||||
|
||||
try finalizeSegment(bind.entries.items[start..], ctx, bw);
|
||||
try done(bw);
|
||||
try finalizeSegment(self.entries.items[start..], ctx, writer);
|
||||
try done(writer);
|
||||
}
|
||||
|
||||
fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
|
||||
fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
|
||||
if (entries.len == 0) return;
|
||||
|
||||
const seg_id = entries[0].segment_id;
|
||||
try setSegmentOffset(seg_id, 0, bw);
|
||||
try setSegmentOffset(seg_id, 0, writer);
|
||||
|
||||
var offset: u64 = 0;
|
||||
var addend: i64 = 0;
|
||||
@ -404,8 +428,8 @@ pub const WeakBind = struct {
|
||||
if (target == null or !target.?.eql(current.target)) {
|
||||
switch (state) {
|
||||
.start => {},
|
||||
.bind_single => try doBind(bw),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, bw),
|
||||
.bind_single => try doBind(writer),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, writer),
|
||||
}
|
||||
state = .start;
|
||||
target = current.target;
|
||||
@ -414,12 +438,12 @@ pub const WeakBind = struct {
|
||||
const name = sym.getName(ctx);
|
||||
const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
|
||||
|
||||
try setSymbol(name, flags, bw);
|
||||
try setTypePointer(bw);
|
||||
try setSymbol(name, flags, writer);
|
||||
try setTypePointer(writer);
|
||||
|
||||
if (current.addend != addend) {
|
||||
addend = current.addend;
|
||||
try setAddend(addend, bw);
|
||||
try setAddend(addend, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -428,11 +452,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)))), bw);
|
||||
try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer);
|
||||
offset = offset - (offset - current.offset);
|
||||
} else if (current.offset > offset) {
|
||||
const delta = current.offset - offset;
|
||||
try addAddr(delta, bw);
|
||||
try addAddr(delta, writer);
|
||||
offset += delta;
|
||||
}
|
||||
state = .bind_single;
|
||||
@ -441,7 +465,7 @@ pub const WeakBind = struct {
|
||||
},
|
||||
.bind_single => {
|
||||
if (current.offset == offset) {
|
||||
try doBind(bw);
|
||||
try doBind(writer);
|
||||
state = .start;
|
||||
} else if (current.offset > offset) {
|
||||
const delta = current.offset - offset;
|
||||
@ -455,9 +479,9 @@ pub const WeakBind = struct {
|
||||
if (current.offset < offset) {
|
||||
count -= 1;
|
||||
if (count == 1) {
|
||||
try doBindAddAddr(skip, bw);
|
||||
try doBindAddAddr(skip, writer);
|
||||
} else {
|
||||
try doBindTimesSkip(count, skip, bw);
|
||||
try doBindTimesSkip(count, skip, writer);
|
||||
}
|
||||
state = .start;
|
||||
offset = offset - (@sizeOf(u64) + skip);
|
||||
@ -466,7 +490,7 @@ pub const WeakBind = struct {
|
||||
count += 1;
|
||||
offset += @sizeOf(u64) + skip;
|
||||
} else {
|
||||
try doBindTimesSkip(count, skip, bw);
|
||||
try doBindTimesSkip(count, skip, writer);
|
||||
state = .start;
|
||||
i -= 1;
|
||||
}
|
||||
@ -476,13 +500,13 @@ pub const WeakBind = struct {
|
||||
|
||||
switch (state) {
|
||||
.start => unreachable,
|
||||
.bind_single => try doBind(bw),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, bw),
|
||||
.bind_single => try doBind(writer),
|
||||
.bind_times_skip => try doBindTimesSkip(count, skip, writer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {
|
||||
try bw.writeAll(bind.buffer.items);
|
||||
pub fn write(self: Self, writer: anytype) !void {
|
||||
try writer.writeAll(self.buffer.items);
|
||||
}
|
||||
};
|
||||
|
||||
@ -491,13 +515,15 @@ pub const LazyBind = struct {
|
||||
buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
offsets: std.ArrayListUnmanaged(u32) = .empty,
|
||||
|
||||
pub fn deinit(bind: *LazyBind, gpa: Allocator) void {
|
||||
bind.entries.deinit(gpa);
|
||||
bind.buffer.deinit(gpa);
|
||||
bind.offsets.deinit(gpa);
|
||||
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 updateSize(bind: *LazyBind, macho_file: *MachO) !void {
|
||||
pub fn updateSize(self: *Self, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -511,35 +537,36 @@ 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);
|
||||
if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
|
||||
const bind_entry = Entry{
|
||||
.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 bind.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
|
||||
try self.finalize(gpa, macho_file);
|
||||
macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
|
||||
}
|
||||
|
||||
fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {
|
||||
try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len);
|
||||
fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
|
||||
try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
|
||||
|
||||
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
|
||||
const bw = &aw.writer;
|
||||
defer bind.buffer = aw.toArrayList();
|
||||
const writer = self.buffer.writer(gpa);
|
||||
|
||||
log.debug("lazy bind opcodes", .{});
|
||||
|
||||
var addend: i64 = 0;
|
||||
|
||||
for (bind.entries.items) |entry| {
|
||||
bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));
|
||||
for (self.entries.items) |entry| {
|
||||
self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
|
||||
|
||||
const sym = entry.target.getSymbol(ctx).?;
|
||||
const name = sym.getName(ctx);
|
||||
const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
|
||||
const flags: u8 = 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) {
|
||||
@ -551,116 +578,121 @@ pub const LazyBind = struct {
|
||||
break :ord macho.BIND_SPECIAL_DYLIB_SELF;
|
||||
};
|
||||
|
||||
try setSegmentOffset(entry.segment_id, entry.offset, bw);
|
||||
try setSymbol(name, flags, bw);
|
||||
try setDylibOrdinal(ordinal, bw);
|
||||
try setSegmentOffset(entry.segment_id, entry.offset, writer);
|
||||
try setSymbol(name, flags, writer);
|
||||
try setDylibOrdinal(ordinal, writer);
|
||||
|
||||
if (entry.addend != addend) {
|
||||
try setAddend(entry.addend, bw);
|
||||
try setAddend(entry.addend, writer);
|
||||
addend = entry.addend;
|
||||
}
|
||||
|
||||
try doBind(bw);
|
||||
try done(bw);
|
||||
try doBind(writer);
|
||||
try done(writer);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {
|
||||
try bw.writeAll(bind.buffer.items);
|
||||
pub fn write(self: Self, writer: anytype) !void {
|
||||
try writer.writeAll(self.buffer.items);
|
||||
}
|
||||
};
|
||||
|
||||
fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
|
||||
fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
|
||||
log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
|
||||
try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id);
|
||||
try bw.writeLeb128(offset);
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
|
||||
try std.leb.writeUleb128(writer, offset);
|
||||
}
|
||||
|
||||
fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void {
|
||||
fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
|
||||
log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
|
||||
try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
|
||||
try bw.writeAll(name);
|
||||
try bw.writeByte(0);
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
|
||||
try writer.writeAll(name);
|
||||
try writer.writeByte(0);
|
||||
}
|
||||
|
||||
fn setTypePointer(bw: *Writer) Writer.Error!void {
|
||||
fn setTypePointer(writer: anytype) !void {
|
||||
log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
|
||||
try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER)));
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
|
||||
}
|
||||
|
||||
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 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 setAddend(addend: i64, bw: *Writer) Writer.Error!void {
|
||||
fn setAddend(addend: i64, writer: anytype) !void {
|
||||
log.debug(">>> set addend: {x}", .{addend});
|
||||
try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
|
||||
try bw.writeLeb128(addend);
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
|
||||
try std.leb.writeIleb128(writer, addend);
|
||||
}
|
||||
|
||||
fn doBind(bw: *Writer) Writer.Error!void {
|
||||
fn doBind(writer: anytype) !void {
|
||||
log.debug(">>> bind", .{});
|
||||
try bw.writeByte(macho.BIND_OPCODE_DO_BIND);
|
||||
try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
|
||||
}
|
||||
|
||||
fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
|
||||
fn doBindAddAddr(addr: u64, writer: anytype) !void {
|
||||
log.debug(">>> bind with add: {x}", .{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);
|
||||
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);
|
||||
}
|
||||
|
||||
fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
|
||||
fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
|
||||
log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
|
||||
try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
|
||||
try bw.writeLeb128(count);
|
||||
try bw.writeLeb128(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);
|
||||
}
|
||||
|
||||
fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
|
||||
fn addAddr(addr: u64, writer: anytype) !void {
|
||||
log.debug(">>> add: {x}", .{addr});
|
||||
try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
|
||||
try bw.writeLeb128(addr);
|
||||
try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
|
||||
try std.leb.writeUleb128(writer, addr);
|
||||
}
|
||||
|
||||
fn done(bw: *Writer) Writer.Error!void {
|
||||
fn done(writer: anytype) !void {
|
||||
log.debug(">>> done", .{});
|
||||
try bw.writeByte(macho.BIND_OPCODE_DONE);
|
||||
try writer.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 Allocator = std.mem.Allocator;
|
||||
const Writer = std.io.Writer;
|
||||
|
||||
const trace = @import("../../../tracy.zig").trace;
|
||||
const std = @import("std");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const File = @import("../file.zig").File;
|
||||
const MachO = @import("../../MachO.zig");
|
||||
const Symbol = @import("../Symbol.zig");
|
||||
|
||||
@ -12,33 +12,36 @@ pub const Cie = struct {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var r: std.io.Reader = .fixed(cie.getData(macho_file));
|
||||
const data = cie.getData(macho_file);
|
||||
const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0);
|
||||
|
||||
try r.discard(9);
|
||||
const aug = try r.takeSentinel(0);
|
||||
if (aug[0] != 'z') return; // TODO should we error out?
|
||||
|
||||
_ = try r.takeLeb128(u64); // code alignment factor
|
||||
_ = try r.takeLeb128(u64); // data alignment factor
|
||||
_ = try r.takeLeb128(u64); // return address register
|
||||
_ = try r.takeLeb128(u64); // augmentation data length
|
||||
var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]);
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const reader = creader.reader();
|
||||
|
||||
_ = try leb.readUleb128(u64, reader); // code alignment factor
|
||||
_ = try leb.readUleb128(u64, reader); // data alignment factor
|
||||
_ = try leb.readUleb128(u64, reader); // return address register
|
||||
_ = try leb.readUleb128(u64, reader); // augmentation data length
|
||||
|
||||
for (aug[1..]) |ch| switch (ch) {
|
||||
'R' => {
|
||||
const enc = try r.takeByte();
|
||||
const enc = try reader.readByte();
|
||||
if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
|
||||
@panic("unexpected pointer encoding"); // TODO error
|
||||
}
|
||||
},
|
||||
'P' => {
|
||||
const enc = try r.takeByte();
|
||||
const enc = try reader.readByte();
|
||||
if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
|
||||
@panic("unexpected personality pointer encoding"); // TODO error
|
||||
}
|
||||
_ = try r.takeInt(u32, .little); // personality pointer
|
||||
_ = try reader.readInt(u32, .little); // personality pointer
|
||||
},
|
||||
'L' => {
|
||||
const enc = try r.takeByte();
|
||||
const enc = try reader.readByte();
|
||||
switch (enc & DW_EH_PE.type_mask) {
|
||||
DW_EH_PE.sdata4 => cie.lsda_size = .p32,
|
||||
DW_EH_PE.absptr => cie.lsda_size = .p64,
|
||||
@ -125,16 +128,12 @@ pub const Fde = struct {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const data = fde.getData(macho_file);
|
||||
const object = fde.getObject(macho_file);
|
||||
const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
|
||||
|
||||
var br: std.io.Reader = .fixed(fde.getData(macho_file));
|
||||
|
||||
try br.discard(4);
|
||||
const cie_ptr = try br.takeInt(u32, .little);
|
||||
const pc_begin = try br.takeInt(i64, .little);
|
||||
|
||||
// Parse target atom index
|
||||
const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
|
||||
const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
|
||||
fde.atom = object.findAtom(taddr) orelse {
|
||||
try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
|
||||
@ -146,6 +145,7 @@ pub const Fde = struct {
|
||||
fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
|
||||
|
||||
// Associate with a CIE
|
||||
const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
|
||||
const cie_offset = fde.offset + 4 - cie_ptr;
|
||||
const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
|
||||
if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
|
||||
@ -163,12 +163,14 @@ pub const Fde = struct {
|
||||
|
||||
// Parse LSDA atom index if any
|
||||
if (cie.lsda_size) |lsda_size| {
|
||||
try br.discard(8);
|
||||
_ = try br.takeLeb128(u64); // augmentation length
|
||||
fde.lsda_ptr_offset = @intCast(br.seek);
|
||||
var stream = std.io.fixedBufferStream(data[24..]);
|
||||
var creader = std.io.countingReader(stream.reader());
|
||||
const reader = creader.reader();
|
||||
_ = try leb.readUleb128(u64, reader); // augmentation length
|
||||
fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
|
||||
const lsda_ptr = switch (lsda_size) {
|
||||
.p32 => try br.takeInt(i32, .little),
|
||||
.p64 => try br.takeInt(i64, .little),
|
||||
.p32 => try reader.readInt(i32, .little),
|
||||
.p64 => try reader.readInt(i64, .little),
|
||||
};
|
||||
const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
|
||||
fde.lsda = object.findAtom(lsda_addr) orelse {
|
||||
@ -209,35 +211,56 @@ pub const Fde = struct {
|
||||
return fde.getObject(macho_file).getAtom(fde.lsda);
|
||||
}
|
||||
|
||||
pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
|
||||
pub fn format(
|
||||
fde: Fde,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = fde;
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
_ = writer;
|
||||
@compileError("do not format FDEs directly");
|
||||
}
|
||||
|
||||
pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(format2) {
|
||||
return .{ .data = .{
|
||||
.fde = fde,
|
||||
.macho_file = macho_file,
|
||||
} };
|
||||
}
|
||||
|
||||
const Format = struct {
|
||||
const FormatContext = struct {
|
||||
fde: Fde,
|
||||
macho_file: *MachO,
|
||||
|
||||
fn default(f: Format, w: *Writer) Writer.Error!void {
|
||||
const fde = f.fde;
|
||||
const macho_file = f.macho_file;
|
||||
try w.print("@{x} : size({x}) : cie({d}) : {s}", .{
|
||||
fde.offset,
|
||||
fde.getSize(),
|
||||
fde.cie,
|
||||
fde.getAtom(macho_file).getName(macho_file),
|
||||
});
|
||||
if (!fde.alive) try w.writeAll(" : [*]");
|
||||
}
|
||||
};
|
||||
|
||||
fn format2(
|
||||
ctx: FormatContext,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
const fde = ctx.fde;
|
||||
const macho_file = ctx.macho_file;
|
||||
try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
|
||||
fde.offset,
|
||||
fde.getSize(),
|
||||
fde.cie,
|
||||
fde.getAtom(macho_file).getName(macho_file),
|
||||
});
|
||||
if (!fde.alive) try writer.writeAll(" : [*]");
|
||||
}
|
||||
|
||||
pub const Index = u32;
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
reader: *std.io.Reader,
|
||||
data: []const u8,
|
||||
pos: u32 = 0,
|
||||
|
||||
pub const Record = struct {
|
||||
tag: enum { fde, cie },
|
||||
@ -246,19 +269,21 @@ pub const Iterator = struct {
|
||||
};
|
||||
|
||||
pub fn next(it: *Iterator) !?Record {
|
||||
const r = it.reader;
|
||||
if (r.seek >= r.storageBuffer().len) return null;
|
||||
if (it.pos >= it.data.len) return null;
|
||||
|
||||
const size = try r.takeInt(u32, .little);
|
||||
var stream = std.io.fixedBufferStream(it.data[it.pos..]);
|
||||
const reader = stream.reader();
|
||||
|
||||
const size = try reader.readInt(u32, .little);
|
||||
if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
|
||||
|
||||
const id = try r.takeInt(u32, .little);
|
||||
const record: Record = .{
|
||||
const id = try reader.readInt(u32, .little);
|
||||
const record = Record{
|
||||
.tag = if (id == 0) .cie else .fde,
|
||||
.offset = @intCast(r.seek),
|
||||
.offset = it.pos,
|
||||
.size = size,
|
||||
};
|
||||
try r.discard(size);
|
||||
it.pos += size + 4;
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
@ -321,11 +321,11 @@ pub const File = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeAr(file: File, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) Writer.Error!void {
|
||||
pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
|
||||
return switch (file) {
|
||||
.dylib, .internal => unreachable,
|
||||
.zig_object => |x| x.writeAr(bw, ar_format),
|
||||
.object => |x| x.writeAr(bw, ar_format, macho_file),
|
||||
.zig_object => |x| x.writeAr(ar_format, writer),
|
||||
.object => |x| x.writeAr(ar_format, macho_file, writer),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -181,20 +181,23 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
|
||||
return offset;
|
||||
}
|
||||
|
||||
pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {
|
||||
pub fn writeDylinkerLC(writer: anytype) !void {
|
||||
const name_len = mem.sliceTo(default_dyld_path, 0).len;
|
||||
const cmdsize = @as(u32, @intCast(mem.alignForward(
|
||||
u64,
|
||||
@sizeOf(macho.dylinker_command) + name_len,
|
||||
@sizeOf(u64),
|
||||
)));
|
||||
try bw.writeStruct(macho.dylinker_command{
|
||||
try writer.writeStruct(macho.dylinker_command{
|
||||
.cmd = .LOAD_DYLINKER,
|
||||
.cmdsize = cmdsize,
|
||||
.name = @sizeOf(macho.dylinker_command),
|
||||
});
|
||||
try bw.writeAll(mem.sliceTo(default_dyld_path, 0));
|
||||
try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);
|
||||
try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
|
||||
const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
const WriteDylibLCCtx = struct {
|
||||
@ -205,14 +208,14 @@ const WriteDylibLCCtx = struct {
|
||||
compatibility_version: u32 = 0x10000,
|
||||
};
|
||||
|
||||
pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
|
||||
pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
|
||||
const name_len = ctx.name.len + 1;
|
||||
const cmdsize: u32 = @intCast(mem.alignForward(
|
||||
const cmdsize = @as(u32, @intCast(mem.alignForward(
|
||||
u64,
|
||||
@sizeOf(macho.dylib_command) + name_len,
|
||||
@sizeOf(u64),
|
||||
));
|
||||
try bw.writeStruct(macho.dylib_command{
|
||||
)));
|
||||
try writer.writeStruct(macho.dylib_command{
|
||||
.cmd = ctx.cmd,
|
||||
.cmdsize = cmdsize,
|
||||
.dylib = .{
|
||||
@ -222,9 +225,12 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
|
||||
.compatibility_version = ctx.compatibility_version,
|
||||
},
|
||||
});
|
||||
try bw.writeAll(ctx.name);
|
||||
try bw.writeByte(0);
|
||||
try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);
|
||||
try writer.writeAll(ctx.name);
|
||||
try writer.writeByte(0);
|
||||
const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
|
||||
@ -253,23 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
|
||||
}, writer);
|
||||
}
|
||||
|
||||
pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {
|
||||
pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
|
||||
const rpath_len = rpath.len + 1;
|
||||
const cmdsize = @as(u32, @intCast(mem.alignForward(
|
||||
u64,
|
||||
@sizeOf(macho.rpath_command) + rpath_len,
|
||||
@sizeOf(u64),
|
||||
)));
|
||||
try bw.writeStruct(macho.rpath_command{
|
||||
try writer.writeStruct(macho.rpath_command{
|
||||
.cmdsize = cmdsize,
|
||||
.path = @sizeOf(macho.rpath_command),
|
||||
});
|
||||
try bw.writeAll(rpath);
|
||||
try bw.writeByte(0);
|
||||
try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);
|
||||
try writer.writeAll(rpath);
|
||||
try writer.writeByte(0);
|
||||
const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
|
||||
pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
|
||||
const cmd: macho.LC = switch (platform.os_tag) {
|
||||
.macos => .VERSION_MIN_MACOSX,
|
||||
.ios => .VERSION_MIN_IPHONEOS,
|
||||
@ -277,7 +286,7 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
|
||||
.watchos => .VERSION_MIN_WATCHOS,
|
||||
else => unreachable,
|
||||
};
|
||||
try bw.writeAll(mem.asBytes(&macho.version_min_command{
|
||||
try writer.writeAll(mem.asBytes(&macho.version_min_command{
|
||||
.cmd = cmd,
|
||||
.version = platform.toAppleVersion(),
|
||||
.sdk = if (sdk_version) |ver|
|
||||
@ -287,9 +296,9 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
|
||||
pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
|
||||
const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
|
||||
try bw.writeStruct(macho.build_version_command{
|
||||
try writer.writeStruct(macho.build_version_command{
|
||||
.cmdsize = cmdsize,
|
||||
.platform = platform.toApplePlatform(),
|
||||
.minos = platform.toAppleVersion(),
|
||||
@ -299,7 +308,7 @@ pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?
|
||||
platform.toAppleVersion(),
|
||||
.ntools = 1,
|
||||
});
|
||||
try bw.writeAll(mem.asBytes(&macho.build_tool_version{
|
||||
try writer.writeAll(mem.asBytes(&macho.build_tool_version{
|
||||
.tool = .ZIG,
|
||||
.version = 0x0,
|
||||
}));
|
||||
|
||||
@ -202,30 +202,38 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
|
||||
};
|
||||
|
||||
if (build_options.enable_logging) {
|
||||
state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
|
||||
state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)});
|
||||
}
|
||||
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, total_size));
|
||||
defer gpa.free(bw.buffer);
|
||||
var buffer = std.ArrayList(u8).init(gpa);
|
||||
defer buffer.deinit();
|
||||
try buffer.ensureTotalCapacityPrecise(total_size);
|
||||
const writer = buffer.writer();
|
||||
|
||||
// Write magic
|
||||
bw.writeAll(Archive.ARMAG) catch unreachable;
|
||||
try writer.writeAll(Archive.ARMAG);
|
||||
|
||||
// Write symtab
|
||||
ar_symtab.write(&bw, format, macho_file) catch |err| {
|
||||
return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});
|
||||
ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
|
||||
};
|
||||
|
||||
// Write object files
|
||||
for (files.items) |index| {
|
||||
bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable;
|
||||
macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err|
|
||||
const aligned = mem.alignForward(usize, buffer.items.len, 2);
|
||||
const padding = aligned - buffer.items.len;
|
||||
if (padding > 0) {
|
||||
try writer.writeByteNTimes(0, padding);
|
||||
}
|
||||
macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
|
||||
return diags.fail("failed to write archive: {s}", .{@errorName(err)});
|
||||
}
|
||||
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try macho_file.setEndPos(bw.end);
|
||||
try macho_file.pwriteAll(bw.buffer, 0);
|
||||
assert(buffer.items.len == total_size);
|
||||
|
||||
try macho_file.setEndPos(total_size);
|
||||
try macho_file.pwriteAll(buffer.items, 0);
|
||||
|
||||
if (diags.hasErrors()) return error.LinkFailure;
|
||||
}
|
||||
@ -664,7 +672,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
|
||||
diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
|
||||
}
|
||||
|
||||
fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
|
||||
fn writeSectionsToFile(macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -681,8 +689,12 @@ fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
|
||||
|
||||
fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));
|
||||
defer gpa.free(bw.buffer);
|
||||
const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
|
||||
const buffer = try gpa.alloc(u8, needed_size);
|
||||
defer gpa.free(buffer);
|
||||
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
const writer = stream.writer();
|
||||
|
||||
var ncmds: usize = 0;
|
||||
|
||||
@ -690,31 +702,47 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
|
||||
{
|
||||
assert(macho_file.segments.items.len == 1);
|
||||
const seg = macho_file.segments.items[0];
|
||||
bw.writeStruct(seg) catch unreachable;
|
||||
writer.writeStruct(seg) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
for (macho_file.sections.items(.header)) |header| {
|
||||
bw.writeStruct(header) catch unreachable;
|
||||
writer.writeStruct(header) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
}
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable;
|
||||
writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
ncmds += 1;
|
||||
bw.writeStruct(macho_file.symtab_cmd) catch unreachable;
|
||||
writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
ncmds += 1;
|
||||
bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable;
|
||||
writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
ncmds += 1;
|
||||
|
||||
if (macho_file.platform.isBuildVersionCompatible()) {
|
||||
load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
|
||||
load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
ncmds += 1;
|
||||
} else {
|
||||
load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
|
||||
load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
};
|
||||
ncmds += 1;
|
||||
}
|
||||
|
||||
assert(bw.end == bw.buffer.len);
|
||||
try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
|
||||
return .{ ncmds, bw.end };
|
||||
assert(stream.pos == needed_size);
|
||||
|
||||
try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
|
||||
|
||||
return .{ ncmds, buffer.len };
|
||||
}
|
||||
|
||||
fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
|
||||
|
||||
@ -27,13 +27,13 @@ pub const GotSection = struct {
|
||||
return got.symbols.items.len * @sizeOf(u64);
|
||||
}
|
||||
|
||||
pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
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 bw.writeInt(u64, value, .little);
|
||||
try writer.writeInt(u64, value, .little);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ pub const StubsSection = struct {
|
||||
return stubs.symbols.items.len * header.reserved2;
|
||||
}
|
||||
|
||||
pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
const cpu_arch = macho_file.getTarget().cpu.arch;
|
||||
@ -101,20 +101,20 @@ pub const StubsSection = struct {
|
||||
const target = laptr_sect.addr + idx * @sizeOf(u64);
|
||||
switch (cpu_arch) {
|
||||
.x86_64 => {
|
||||
try bw.writeAll(&.{ 0xff, 0x25 });
|
||||
try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
|
||||
try writer.writeAll(&.{ 0xff, 0x25 });
|
||||
try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
|
||||
},
|
||||
.aarch64 => {
|
||||
// TODO relax if possible
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
const off = try math.divExact(u12, @truncate(target), 8);
|
||||
try bw.writeInt(
|
||||
try writer.writeInt(
|
||||
u32,
|
||||
aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
|
||||
.little,
|
||||
);
|
||||
try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -175,11 +175,11 @@ pub const StubsHelperSection = struct {
|
||||
return s;
|
||||
}
|
||||
|
||||
pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
try stubs_helper.writePreamble(macho_file, bw);
|
||||
try stubs_helper.writePreamble(macho_file, writer);
|
||||
|
||||
const cpu_arch = macho_file.getTarget().cpu.arch;
|
||||
const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
|
||||
@ -195,24 +195,24 @@ pub const StubsHelperSection = struct {
|
||||
const target: i64 = @intCast(sect.addr);
|
||||
switch (cpu_arch) {
|
||||
.x86_64 => {
|
||||
try bw.writeByte(0x68);
|
||||
try bw.writeInt(u32, offset, .little);
|
||||
try bw.writeByte(0xe9);
|
||||
try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little);
|
||||
try writer.writeByte(0x68);
|
||||
try writer.writeInt(u32, offset, .little);
|
||||
try writer.writeByte(0xe9);
|
||||
try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
|
||||
},
|
||||
.aarch64 => {
|
||||
const literal = blk: {
|
||||
const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
|
||||
break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
|
||||
};
|
||||
try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(
|
||||
try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
|
||||
.w16,
|
||||
literal,
|
||||
).toU32(), .little);
|
||||
const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
|
||||
return error.Overflow;
|
||||
try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
|
||||
try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
|
||||
try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
|
||||
try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -220,7 +220,7 @@ pub const StubsHelperSection = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
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;
|
||||
@ -235,21 +235,21 @@ pub const StubsHelperSection = struct {
|
||||
};
|
||||
switch (cpu_arch) {
|
||||
.x86_64 => {
|
||||
try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d });
|
||||
try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
|
||||
try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
|
||||
try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
|
||||
try bw.writeByte(0x90);
|
||||
try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
|
||||
try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
|
||||
try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
|
||||
try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
|
||||
try writer.writeByte(0x90);
|
||||
},
|
||||
.aarch64 => {
|
||||
{
|
||||
// TODO relax if possible
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
|
||||
const off: u12 = @truncate(dyld_private_addr);
|
||||
try bw.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
|
||||
}
|
||||
try bw.writeInt(u32, aarch64.Instruction.stp(
|
||||
try writer.writeInt(u32, aarch64.Instruction.stp(
|
||||
.x16,
|
||||
.x17,
|
||||
aarch64.Register.sp,
|
||||
@ -258,15 +258,15 @@ pub const StubsHelperSection = struct {
|
||||
{
|
||||
// TODO relax if possible
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
|
||||
try bw.writeInt(u32, aarch64.Instruction.ldr(
|
||||
try writer.writeInt(u32, aarch64.Instruction.ldr(
|
||||
.x16,
|
||||
.x16,
|
||||
aarch64.Instruction.LoadStoreOffset.imm(off),
|
||||
).toU32(), .little);
|
||||
}
|
||||
try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -279,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
|
||||
return macho_file.stubs.symbols.items.len * @sizeOf(u64);
|
||||
}
|
||||
|
||||
pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
_ = laptr;
|
||||
@ -290,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
if (sym.flags.weak) {
|
||||
const value = sym.getAddress(.{ .stubs = false }, macho_file);
|
||||
try bw.writeInt(u64, @intCast(value), .little);
|
||||
try writer.writeInt(u64, @intCast(value), .little);
|
||||
} else {
|
||||
const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
|
||||
StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
|
||||
stub_helper_idx += 1;
|
||||
try bw.writeInt(u64, @intCast(value), .little);
|
||||
try writer.writeInt(u64, @intCast(value), .little);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,16 +329,16 @@ pub const TlvPtrSection = struct {
|
||||
return tlv.symbols.items.len * @sizeOf(u64);
|
||||
}
|
||||
|
||||
pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
for (tlv.symbols.items) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
if (sym.flags.import) {
|
||||
try bw.writeInt(u64, 0, .little);
|
||||
try writer.writeInt(u64, 0, .little);
|
||||
} else {
|
||||
try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
|
||||
try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,7 +400,7 @@ pub const ObjcStubsSection = struct {
|
||||
return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
|
||||
}
|
||||
|
||||
pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -411,18 +411,18 @@ pub const ObjcStubsSection = struct {
|
||||
const addr = objc.getAddress(@intCast(idx), macho_file);
|
||||
switch (macho_file.getTarget().cpu.arch) {
|
||||
.x86_64 => {
|
||||
try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });
|
||||
try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
|
||||
{
|
||||
const target = sym.getObjcSelrefsAddress(macho_file);
|
||||
const source = addr;
|
||||
try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little);
|
||||
try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little);
|
||||
}
|
||||
try bw.writeAll(&.{ 0xff, 0x25 });
|
||||
try writer.writeAll(&.{ 0xff, 0x25 });
|
||||
{
|
||||
const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
|
||||
const target = target_sym.getGotAddress(macho_file);
|
||||
const source = addr + 7;
|
||||
try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
|
||||
try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
|
||||
}
|
||||
},
|
||||
.aarch64 => {
|
||||
@ -430,9 +430,9 @@ pub const ObjcStubsSection = struct {
|
||||
const target = sym.getObjcSelrefsAddress(macho_file);
|
||||
const source = addr;
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
|
||||
const off = try math.divExact(u12, @truncate(target), 8);
|
||||
try bw.writeInt(
|
||||
try writer.writeInt(
|
||||
u32,
|
||||
aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
|
||||
.little,
|
||||
@ -443,18 +443,18 @@ pub const ObjcStubsSection = struct {
|
||||
const target = target_sym.getGotAddress(macho_file);
|
||||
const source = addr + 2 * @sizeOf(u32);
|
||||
const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
|
||||
try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
|
||||
const off = try math.divExact(u12, @truncate(target), 8);
|
||||
try bw.writeInt(
|
||||
try writer.writeInt(
|
||||
u32,
|
||||
aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
|
||||
.little,
|
||||
);
|
||||
}
|
||||
try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -496,7 +496,7 @@ pub const Indsymtab = struct {
|
||||
macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
|
||||
}
|
||||
|
||||
pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -505,21 +505,21 @@ pub const Indsymtab = struct {
|
||||
for (macho_file.stubs.symbols.items) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
if (sym.getOutputSymtabIndex(macho_file)) |idx| {
|
||||
try bw.writeInt(u32, idx, .little);
|
||||
try writer.writeInt(u32, idx, .little);
|
||||
}
|
||||
}
|
||||
|
||||
for (macho_file.got.symbols.items) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
if (sym.getOutputSymtabIndex(macho_file)) |idx| {
|
||||
try bw.writeInt(u32, idx, .little);
|
||||
try writer.writeInt(u32, idx, .little);
|
||||
}
|
||||
}
|
||||
|
||||
for (macho_file.stubs.symbols.items) |ref| {
|
||||
const sym = ref.getSymbol(macho_file).?;
|
||||
if (sym.getOutputSymtabIndex(macho_file)) |idx| {
|
||||
try bw.writeInt(u32, idx, .little);
|
||||
try writer.writeInt(u32, idx, .little);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -573,7 +573,7 @@ pub const DataInCode = struct {
|
||||
macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
|
||||
}
|
||||
|
||||
pub fn write(dice: DataInCode, macho_file: *MachO, bw: *Writer) !void {
|
||||
pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {
|
||||
const base_address = if (!macho_file.base.isRelocatable())
|
||||
macho_file.getTextSegment().vmaddr
|
||||
else
|
||||
@ -581,7 +581,7 @@ pub const DataInCode = struct {
|
||||
for (dice.entries.items) |entry| {
|
||||
const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
|
||||
const offset = atom_address + entry.offset - base_address;
|
||||
try bw.writeStruct(macho.data_in_code_entry{
|
||||
try writer.writeStruct(macho.data_in_code_entry{
|
||||
.offset = @intCast(offset),
|
||||
.length = entry.length,
|
||||
.kind = entry.kind,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user