authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-11 17:53:58+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:38+01:00
logd153bc2f0c01af7027f09dd6d42786c4b4d076ed
tree5cc115407b6456f07e6f8e09929d11a05e63fc5f
parentc5e509595a267ddec7d49a9d89ab2bc4f86a9d35

macho: parse dylibs


2 files changed, 76 insertions(+), 16 deletions(-)

src/link/MachO.zig+37-9
......@@ -382,6 +382,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
382382 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
383383 error.MalformedObject,
384384 error.MalformedArchive,
385 error.MalformedDylib,
385386 error.InvalidCpuArch,
386387 error.InvalidTarget,
387388 error.UnknownFileType,
......@@ -432,8 +433,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
432433
433434 for (system_libs.items) |lib| {
434435 self.parseLibrary(lib, false) catch |err| switch (err) {
435 error.MalformedDylib,
436436 error.MalformedArchive,
437 error.MalformedDylib,
437438 error.InvalidCpuArch,
438439 error.UnknownFileType,
439440 => continue, // already reported
......@@ -794,7 +795,7 @@ fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void {
794795 if (try Archive.isArchive(lib.path, fat_arch)) {
795796 try self.parseArchive(lib, must_link, fat_arch);
796797 } else if (try Dylib.isDylib(lib.path, fat_arch)) {
797 try self.parseDylib(lib, true, fat_arch);
798 _ = try self.parseDylib(lib, true, fat_arch);
798799 } else {
799800 try self.reportParseError(lib.path, "unknown file type for a library", .{});
800801 return error.UnknownFileType;
......@@ -802,7 +803,7 @@ fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void {
802803 } else if (try Archive.isArchive(lib.path, null)) {
803804 try self.parseArchive(lib, must_link, null);
804805 } else if (try Dylib.isDylib(lib.path, null)) {
805 try self.parseDylib(lib, true, null);
806 _ = try self.parseDylib(lib, true, null);
806807 } else {
807808 try self.parseTbd(lib, true);
808809 }
......@@ -889,12 +890,39 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
889890 if (has_parse_error) return error.MalformedArchive;
890891}
891892
892fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {
893 _ = self;
894 _ = lib;
895 _ = explicit;
896 _ = fat_arch;
897 return error.Unhandled;
893fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!File.Index {
894 const tracy = trace(@src());
895 defer tracy.end();
896
897 const gpa = self.base.comp.gpa;
898
899 const file = try std.fs.cwd().openFile(lib.path, .{});
900 defer file.close();
901
902 const data = if (fat_arch) |arch| blk: {
903 try file.seekTo(arch.offset);
904 const data = try gpa.alloc(u8, arch.size);
905 const nread = try file.readAll(data);
906 if (nread != arch.size) return error.InputOutput;
907 break :blk data;
908 } else try file.readToEndAlloc(gpa, std.math.maxInt(u32));
909
910 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
911 self.files.set(index, .{ .dylib = .{
912 .path = try gpa.dupe(u8, lib.path),
913 .data = data,
914 .index = index,
915 .needed = lib.needed,
916 .weak = lib.weak,
917 .reexport = lib.reexport,
918 .explicit = explicit,
919 } });
920 const dylib = &self.files.items(.data)[index].dylib;
921 try dylib.parse(self);
922
923 try self.dylibs.append(gpa, index);
924
925 return index;
898926}
899927
900928fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!void {
src/link/MachO/Dylib.zig+39-7
......@@ -34,6 +34,8 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool {
3434}
3535
3636pub fn deinit(self: *Dylib, allocator: Allocator) void {
37 allocator.free(self.data);
38 allocator.free(self.path);
3739 self.exports.deinit(allocator);
3840 self.strtab.deinit(allocator);
3941 if (self.id) |*id| id.deinit(allocator);
......@@ -49,7 +51,7 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void {
4951 const tracy = trace(@src());
5052 defer tracy.end();
5153
52 const gpa = macho_file.base.allocator;
54 const gpa = macho_file.base.comp.gpa;
5355 var stream = std.io.fixedBufferStream(self.data);
5456 const reader = stream.reader();
5557
......@@ -57,9 +59,22 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void {
5759
5860 self.header = try reader.readStruct(macho.mach_header_64);
5961
62 const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
63 macho.CPU_TYPE_ARM64 => .aarch64,
64 macho.CPU_TYPE_X86_64 => .x86_64,
65 else => |x| {
66 try macho_file.reportParseError2(self.index, "unknown cpu architecture: {d}", .{x});
67 return error.InvalidCpuArch;
68 },
69 };
70 if (macho_file.getTarget().cpu.arch != this_cpu_arch) {
71 try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)});
72 return error.InvalidCpuArch;
73 }
74
6075 const lc_id = self.getLoadCommand(.ID_DYLIB) orelse {
61 macho_file.base.fatal("{s}: missing LC_ID_DYLIB load command", .{self.path});
62 return error.ParseFailed;
76 try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{});
77 return error.MalformedDylib;
6378 };
6479 self.id = try Id.fromLoadCommand(gpa, lc_id.cast(macho.dylib_command).?, lc_id.getDylibPathName());
6580
......@@ -90,6 +105,23 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void {
90105 };
91106
92107 self.initPlatform();
108
109 if (self.platform) |platform| {
110 if (!macho_file.platform.eqlTarget(platform)) {
111 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
112 platform.fmtTarget(macho_file.getTarget().cpu.arch),
113 });
114 return error.InvalidTarget;
115 }
116 if (macho_file.platform.version.order(platform.version) == .lt) {
117 try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
118 macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
119 macho_file.platform.version,
120 platform.version,
121 });
122 return error.InvalidTarget;
123 }
124 }
93125}
94126
95127const TrieIterator = struct {
......@@ -187,7 +219,7 @@ fn parseTrieNode(
187219fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
188220 const tracy = trace(@src());
189221 defer tracy.end();
190 const gpa = macho_file.base.allocator;
222 const gpa = macho_file.base.comp.gpa;
191223 var arena = std.heap.ArenaAllocator.init(gpa);
192224 defer arena.deinit();
193225
......@@ -204,7 +236,7 @@ pub fn parseTbd(
204236) !void {
205237 const tracy = trace(@src());
206238 defer tracy.end();
207 const gpa = macho_file.base.allocator;
239 const gpa = macho_file.base.comp.gpa;
208240
209241 log.debug("parsing dylib from stub", .{});
210242
......@@ -435,7 +467,7 @@ fn addObjCExport(
435467}
436468
437469pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {
438 const gpa = macho_file.base.allocator;
470 const gpa = macho_file.base.comp.gpa;
439471
440472 try self.symbols.ensureTotalCapacityPrecise(gpa, self.exports.items(.name).len);
441473
......@@ -459,7 +491,7 @@ fn initPlatform(self: *Dylib) void {
459491 .VERSION_MIN_IPHONEOS,
460492 .VERSION_MIN_TVOS,
461493 .VERSION_MIN_WATCHOS,
462 => break MachO.Options.Platform.fromLoadCommand(cmd),
494 => break MachO.Platform.fromLoadCommand(cmd),
463495 else => {},
464496 }
465497 } else null;