Skip to content

Commit

Permalink
macho: close file descriptor in Object immediately after parsing
Browse files Browse the repository at this point in the history
The cost being here pre-parsing section's contents.
  • Loading branch information
kubkon committed Feb 5, 2024
1 parent c184cf0 commit ff3eb85
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 83 deletions.
8 changes: 4 additions & 4 deletions src/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ fn parseObject(self: *MachO, obj: LinkObject) !bool {

const gpa = self.base.allocator;
const file = try std.fs.cwd().openFile(obj.path, .{});
defer file.close();

const header = file.reader().readStruct(macho.mach_header_64) catch return false;
try file.seekTo(0);
Expand All @@ -681,12 +682,11 @@ fn parseObject(self: *MachO, obj: LinkObject) !bool {
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
self.files.set(index, .{ .object = .{
.path = try gpa.dupe(u8, obj.path),
.file = file,
.index = index,
.mtime = mtime,
} });
const object = &self.files.items(.data)[index].object;
try object.parse(self);
try object.parse(file, self);
try self.objects.append(gpa, index);
self.validateCpuArch(index, header.cputype);
self.validatePlatform(index);
Expand Down Expand Up @@ -727,7 +727,7 @@ fn parseArchive(self: *MachO, obj: LinkObject) !bool {
object.index = index;
object.alive = obj.must_link or obj.needed or self.options.all_load;
object.hidden = obj.hidden;
object.parse(self) catch |err| switch (err) {
object.parse(file, self) catch |err| switch (err) {
error.ParseFailed => {
has_parse_error = true;
// TODO see below
Expand Down Expand Up @@ -2088,7 +2088,7 @@ fn writeAtoms(self: *MachO) !void {
const atom = self.getAtom(atom_index).?;
assert(atom.flags.alive);
const off = atom.value;
try atom.getCode(self, buffer[off..][0..atom.size]);
try atom.getData(self, buffer[off..][0..atom.size]);
atom.resolveRelocs(self, buffer[off..][0..atom.size]) catch |err| switch (err) {
error.ResolveFailed => has_resolve_error = true,
else => |e| return e,
Expand Down
1 change: 0 additions & 1 deletion src/MachO/Archive.zig
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.
.offset = offset + pos,
},
.path = name,
.file = try std.fs.cwd().openFile(path, .{}),
.index = undefined,
.alive = false,
.mtime = hdr.date() catch 0,
Expand Down
19 changes: 4 additions & 15 deletions src/MachO/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,19 @@ pub fn getPriority(self: Atom, macho_file: *MachO) u64 {
return (@as(u64, @intCast(file.getIndex())) << 32) | @as(u64, @intCast(self.n_sect));
}

pub fn getCode(self: Atom, macho_file: *MachO, buffer: []u8) !void {
pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void {
assert(buffer.len == self.size);
switch (self.getFile(macho_file)) {
.dylib => unreachable,
.object => |x| {
const slice = x.sections.slice();
const offset = if (x.archive) |ar| ar.offset else 0;
const sect = slice.items(.header)[self.n_sect];
const amt = try x.file.preadAll(buffer, sect.offset + offset + self.off);
if (amt != buffer.len) return error.InputOutput;
},
.internal => |x| {
const code = x.getSectionData(self.n_sect);
@memcpy(buffer, code);
},
inline else => |x| try x.getAtomData(self, buffer),
}
}

pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
const relocs = switch (self.getFile(macho_file)) {
return switch (self.getFile(macho_file)) {
.dylib => unreachable,
inline else => |x| x.sections.items(.relocs)[self.n_sect],
inline else => |x| x.getAtomRelocs(self),
};
return relocs.items[self.relocs.pos..][0..self.relocs.len];
}

pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Record.Index {
Expand Down
28 changes: 19 additions & 9 deletions src/MachO/InternalObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,26 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,
return n_sect;
}

pub fn getSectionData(self: *const InternalObject, index: u32) []const u8 {
pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) !void {
assert(buffer.len == atom.size);
const slice = self.sections.slice();
assert(index < slice.items(.header).len);
const sect = slice.items(.header)[index];
const extra = slice.items(.extra)[index];
if (extra.is_objc_methname) {
return self.objc_methnames.items[sect.offset..][0..sect.size];
} else if (extra.is_objc_selref) {
return &self.objc_selrefs;
} else @panic("ref to non-existent section");
const sect = slice.items(.header)[atom.n_sect];
const extra = slice.items(.extra)[atom.n_sect];
const data = if (extra.is_objc_methname) blk: {
const size = std.math.cast(usize, sect.size) orelse return error.Overflow;
break :blk self.objc_methnames.items[sect.offset..][0..size];
} else if (extra.is_objc_selref)
&self.objc_selrefs
else
@panic("ref to non-existent section");
const off = std.math.cast(usize, atom.off) orelse return error.Overflow;
const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
@memcpy(buffer, data[off..][0..size]);
}

pub fn getAtomRelocs(self: *const InternalObject, atom: Atom) []const Relocation {
const relocs = self.sections.items(.relocs)[atom.n_sect];
return relocs.items[atom.relocs.pos..][0..atom.relocs.len];
}

fn addString(self: *InternalObject, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
Expand Down
Loading

0 comments on commit ff3eb85

Please sign in to comment.