Commit c5e509595a
Changed files (3)
src
link
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,
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 {
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 {