diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-11 17:53:58 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-24 12:34:38 +0100 |
| commit | d153bc2f0c01af7027f09dd6d42786c4b4d076ed (patch) | |
| tree | 5cc115407b6456f07e6f8e09929d11a05e63fc5f /src | |
| parent | c5e509595a267ddec7d49a9d89ab2bc4f86a9d35 (diff) | |
| download | zig-d153bc2f0c01af7027f09dd6d42786c4b4d076ed.tar.gz zig-d153bc2f0c01af7027f09dd6d42786c4b4d076ed.zip | |
macho: parse dylibs
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 46 | ||||
| -rw-r--r-- | src/link/MachO/Dylib.zig | 46 |
2 files changed, 76 insertions, 16 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 0a64fbd624..6a5e26d24c 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -382,6 +382,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { error.MalformedObject, error.MalformedArchive, + error.MalformedDylib, error.InvalidCpuArch, error.InvalidTarget, error.UnknownFileType, @@ -432,8 +433,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node for (system_libs.items) |lib| { self.parseLibrary(lib, false) catch |err| switch (err) { - error.MalformedDylib, error.MalformedArchive, + error.MalformedDylib, error.InvalidCpuArch, error.UnknownFileType, => continue, // already reported @@ -794,7 +795,7 @@ fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void { if (try Archive.isArchive(lib.path, fat_arch)) { try self.parseArchive(lib, must_link, fat_arch); } else if (try Dylib.isDylib(lib.path, fat_arch)) { - try self.parseDylib(lib, true, fat_arch); + _ = try self.parseDylib(lib, true, fat_arch); } else { try self.reportParseError(lib.path, "unknown file type for a library", .{}); return error.UnknownFileType; @@ -802,7 +803,7 @@ fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void { } else if (try Archive.isArchive(lib.path, null)) { try self.parseArchive(lib, must_link, null); } else if (try Dylib.isDylib(lib.path, null)) { - try self.parseDylib(lib, true, null); + _ = try self.parseDylib(lib, true, null); } else { try self.parseTbd(lib, true); } @@ -889,12 +890,39 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar if (has_parse_error) return error.MalformedArchive; } -fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void { - _ = self; - _ = lib; - _ = explicit; - _ = fat_arch; - return error.Unhandled; +fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!File.Index { + const tracy = trace(@src()); + defer tracy.end(); + + const gpa = self.base.comp.gpa; + + const file = try std.fs.cwd().openFile(lib.path, .{}); + defer file.close(); + + const data = if (fat_arch) |arch| blk: { + try file.seekTo(arch.offset); + const data = try gpa.alloc(u8, arch.size); + const nread = try file.readAll(data); + if (nread != arch.size) return error.InputOutput; + break :blk data; + } else try file.readToEndAlloc(gpa, std.math.maxInt(u32)); + + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); + self.files.set(index, .{ .dylib = .{ + .path = try gpa.dupe(u8, lib.path), + .data = data, + .index = index, + .needed = lib.needed, + .weak = lib.weak, + .reexport = lib.reexport, + .explicit = explicit, + } }); + const dylib = &self.files.items(.data)[index].dylib; + try dylib.parse(self); + + try self.dylibs.append(gpa, index); + + return index; } fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!void { diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index f0454d91c3..50eb8971c3 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -34,6 +34,8 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool { } pub fn deinit(self: *Dylib, allocator: Allocator) void { + allocator.free(self.data); + allocator.free(self.path); self.exports.deinit(allocator); self.strtab.deinit(allocator); if (self.id) |*id| id.deinit(allocator); @@ -49,7 +51,7 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); - const gpa = macho_file.base.allocator; + const gpa = macho_file.base.comp.gpa; var stream = std.io.fixedBufferStream(self.data); const reader = stream.reader(); @@ -57,9 +59,22 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void { self.header = try reader.readStruct(macho.mach_header_64); + const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { + macho.CPU_TYPE_ARM64 => .aarch64, + macho.CPU_TYPE_X86_64 => .x86_64, + else => |x| { + try macho_file.reportParseError2(self.index, "unknown cpu architecture: {d}", .{x}); + return error.InvalidCpuArch; + }, + }; + if (macho_file.getTarget().cpu.arch != this_cpu_arch) { + try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)}); + return error.InvalidCpuArch; + } + const lc_id = self.getLoadCommand(.ID_DYLIB) orelse { - macho_file.base.fatal("{s}: missing LC_ID_DYLIB load command", .{self.path}); - return error.ParseFailed; + try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{}); + return error.MalformedDylib; }; self.id = try Id.fromLoadCommand(gpa, lc_id.cast(macho.dylib_command).?, lc_id.getDylibPathName()); @@ -90,6 +105,23 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void { }; self.initPlatform(); + + if (self.platform) |platform| { + if (!macho_file.platform.eqlTarget(platform)) { + try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ + platform.fmtTarget(macho_file.getTarget().cpu.arch), + }); + return error.InvalidTarget; + } + if (macho_file.platform.version.order(platform.version) == .lt) { + try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{ + macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch), + macho_file.platform.version, + platform.version, + }); + return error.InvalidTarget; + } + } } const TrieIterator = struct { @@ -187,7 +219,7 @@ fn parseTrieNode( fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); - const gpa = macho_file.base.allocator; + const gpa = macho_file.base.comp.gpa; var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -204,7 +236,7 @@ pub fn parseTbd( ) !void { const tracy = trace(@src()); defer tracy.end(); - const gpa = macho_file.base.allocator; + const gpa = macho_file.base.comp.gpa; log.debug("parsing dylib from stub", .{}); @@ -435,7 +467,7 @@ fn addObjCExport( } pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const gpa = macho_file.base.comp.gpa; try self.symbols.ensureTotalCapacityPrecise(gpa, self.exports.items(.name).len); @@ -459,7 +491,7 @@ fn initPlatform(self: *Dylib) void { .VERSION_MIN_IPHONEOS, .VERSION_MIN_TVOS, .VERSION_MIN_WATCHOS, - => break MachO.Options.Platform.fromLoadCommand(cmd), + => break MachO.Platform.fromLoadCommand(cmd), else => {}, } } else null; |
