diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-11 17:34:52 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-24 12:34:38 +0100 |
| commit | c5e509595a267ddec7d49a9d89ab2bc4f86a9d35 (patch) | |
| tree | e0af57085dd439d7642a9b6920e9dd32187c2517 /src | |
| parent | d05e9c379267e9a68522eca3fe8800803c6a5c70 (diff) | |
| download | zig-c5e509595a267ddec7d49a9d89ab2bc4f86a9d35.tar.gz zig-c5e509595a267ddec7d49a9d89ab2bc4f86a9d35.zip | |
macho: parse archives
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 47 | ||||
| -rw-r--r-- | src/link/MachO/Archive.zig | 26 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 1 |
3 files changed, 59 insertions, 15 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index b34d3324c6..0a64fbd624 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -845,11 +845,48 @@ fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch { } fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void { - _ = self; - _ = lib; - _ = must_link; - _ = fat_arch; - return error.Unhandled; + 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)); + + var archive = Archive{ .path = try gpa.dupe(u8, lib.path), .data = data }; + defer archive.deinit(gpa); + try archive.parse(self); + + var has_parse_error = false; + for (archive.objects.items) |extracted| { + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); + self.files.set(index, .{ .object = extracted }); + const object = &self.files.items(.data)[index].object; + object.index = index; + object.alive = must_link or lib.needed; // TODO: or self.options.all_load; + object.hidden = lib.hidden; + object.parse(self) catch |err| switch (err) { + error.MalformedObject, + error.InvalidCpuArch, + error.InvalidTarget, + => has_parse_error = true, + else => |e| return e, + }; + try self.objects.append(gpa, index); + + // Finally, we do a post-parse check for -ObjC to see if we need to force load this member + // anyhow. + // TODO: object.alive = object.alive or (self.options.force_load_objc and object.hasObjc()); + } + if (has_parse_error) return error.MalformedArchive; } fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void { diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 2451874eb0..7203d89b94 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -73,14 +73,20 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool { } pub fn deinit(self: *Archive, allocator: Allocator) void { + allocator.free(self.data); + allocator.free(self.path); self.objects.deinit(allocator); } -pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; +pub fn parse(self: *Archive, macho_file: *MachO) !void { + const gpa = macho_file.base.comp.gpa; + + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); var stream = std.io.fixedBufferStream(self.data); const reader = stream.reader(); + _ = try reader.readBytesNoEof(SARMAG); while (true) { if (stream.pos >= self.data.len) break; @@ -89,18 +95,18 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void { const hdr = try reader.readStruct(ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { - macho_file.base.fatal("{s}: invalid header delimiter: expected '{s}', found '{s}'", .{ - self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), + try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{ + std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), }); - return error.ParseFailed; + return error.MalformedArchive; } var size = try hdr.size(); const name = name: { - if (hdr.name()) |n| break :name try arena.dupe(u8, n); + if (hdr.name()) |n| break :name n; if (try hdr.nameLength()) |len| { size -= len; - const buf = try arena.alloc(u8, len); + const buf = try arena.allocator().alloc(u8, len); try reader.readNoEof(buf); const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; break :name buf[0..actual_len]; @@ -114,9 +120,9 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void { if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue; const object = Object{ - .archive = self.path, - .path = name, - .data = self.data[stream.pos..][0..size], + .archive = try gpa.dupe(u8, self.path), + .path = try gpa.dupe(u8, name), + .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), .index = undefined, .alive = false, .mtime = hdr.date() catch 0, diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 9b453fad49..e28c23d4ad 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -56,6 +56,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { sf.stabs.deinit(allocator); } self.stab_files.deinit(allocator); + allocator.free(self.data); } pub fn parse(self: *Object, macho_file: *MachO) !void { |
