Skip to content

Commit db6addf

Browse files
committed
macho: store open file descriptors in a global array
1 parent 7bd8b35 commit db6addf

File tree

5 files changed

+68
-36
lines changed

5 files changed

+68
-36
lines changed

src/link/MachO.zig

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ d_sym: ?DebugSymbols = null,
1010
/// Index of each input file also encodes the priority or precedence of one input file
1111
/// over another.
1212
files: std.MultiArrayList(File.Entry) = .{},
13+
/// Long-lived list of all file descriptors.
14+
/// We store them globally rather than per actual File so that we can re-use
15+
/// one file handle per every object file within an archive.
16+
file_handles: std.ArrayListUnmanaged(File.Handle) = .{},
1317
zig_object: ?File.Index = null,
1418
internal_object: ?File.Index = null,
1519
objects: std.ArrayListUnmanaged(File.Index) = .{},
@@ -315,6 +319,11 @@ pub fn deinit(self: *MachO) void {
315319
d_sym.deinit();
316320
}
317321

322+
for (self.file_handles.items) |handle| {
323+
handle.close();
324+
}
325+
self.file_handles.deinit(gpa);
326+
318327
for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
319328
.null => {},
320329
.zig_object => data.zig_object.deinit(gpa),
@@ -394,8 +403,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
394403
sub_prog_node.activate();
395404
defer sub_prog_node.end();
396405

397-
const target = comp.root_mod.resolved_target.result;
398-
_ = target;
399406
const directory = self.base.emit.directory;
400407
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
401408
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
@@ -985,14 +992,16 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
985992

986993
const gpa = self.base.comp.gpa;
987994
const file = try std.fs.cwd().openFile(path, .{});
995+
errdefer file.close();
996+
const handle = try self.addFileHandle(file);
988997
const mtime: u64 = mtime: {
989998
const stat = file.stat() catch break :mtime 0;
990999
break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
9911000
};
9921001
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
9931002
self.files.set(index, .{ .object = .{
9941003
.path = try gpa.dupe(u8, path),
995-
.file = file,
1004+
.file_handle = handle,
9961005
.mtime = mtime,
9971006
.index = index,
9981007
} });
@@ -1020,11 +1029,12 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
10201029
const gpa = self.base.comp.gpa;
10211030

10221031
const file = try std.fs.cwd().openFile(lib.path, .{});
1023-
defer file.close();
1032+
errdefer file.close();
1033+
const handle = try self.addFileHandle(file);
10241034

10251035
var archive = Archive{};
10261036
defer archive.deinit(gpa);
1027-
try archive.parse(self, lib.path, file, fat_arch);
1037+
try archive.parse(self, lib.path, handle, fat_arch);
10281038

10291039
var has_parse_error = false;
10301040
for (archive.objects.items) |extracted| {
@@ -3796,6 +3806,19 @@ pub fn getInternalObject(self: *MachO) ?*InternalObject {
37963806
return self.getFile(index).?.internal;
37973807
}
37983808

3809+
pub fn addFileHandle(self: *MachO, file: std.fs.File) !File.HandleIndex {
3810+
const gpa = self.base.comp.gpa;
3811+
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
3812+
const fh = try self.file_handles.addOne(gpa);
3813+
fh.* = file;
3814+
return index;
3815+
}
3816+
3817+
pub fn getFileHandle(self: MachO, index: File.HandleIndex) File.Handle {
3818+
assert(index < self.file_handles.items.len);
3819+
return self.file_handles.items[index];
3820+
}
3821+
37993822
pub fn addAtom(self: *MachO) error{OutOfMemory}!Atom.Index {
38003823
const index = @as(Atom.Index, @intCast(self.atoms.items.len));
38013824
const atom = try self.atoms.addOne(self.base.comp.gpa);
@@ -4616,7 +4639,6 @@ const Cache = std.Build.Cache;
46164639
const CodeSignature = @import("MachO/CodeSignature.zig");
46174640
const Compilation = @import("../Compilation.zig");
46184641
pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
4619-
const Dwarf = File.Dwarf;
46204642
const DwarfInfo = @import("MachO/DwarfInfo.zig");
46214643
const Dylib = @import("MachO/Dylib.zig");
46224644
const ExportTrieSection = synthetic.ExportTrieSection;

src/link/MachO/Archive.zig

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,25 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
7373
self.objects.deinit(allocator);
7474
}
7575

76-
pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.File, fat_arch: ?fat.Arch) !void {
76+
pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
7777
const gpa = macho_file.base.comp.gpa;
7878

7979
var arena = std.heap.ArenaAllocator.init(gpa);
8080
defer arena.deinit();
8181

82+
const handle = macho_file.getFileHandle(handle_index);
8283
const offset = if (fat_arch) |ar| ar.offset else 0;
83-
const size = if (fat_arch) |ar| ar.size else (try file.stat()).size;
84-
try file.seekTo(offset);
84+
const size = if (fat_arch) |ar| ar.size else (try handle.stat()).size;
85+
try handle.seekTo(offset);
8586

86-
const reader = file.reader();
87+
const reader = handle.reader();
8788
_ = try reader.readBytesNoEof(Archive.SARMAG);
8889

8990
var pos: usize = Archive.SARMAG;
9091
while (true) {
9192
if (pos >= size) break;
9293
if (!mem.isAligned(pos, 2)) {
93-
try file.seekBy(1);
94+
try handle.seekBy(1);
9495
pos += 1;
9596
}
9697

@@ -118,7 +119,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.
118119
unreachable;
119120
};
120121
defer {
121-
_ = file.seekBy(hdr_size) catch {};
122+
_ = handle.seekBy(hdr_size) catch {};
122123
pos += hdr_size;
123124
}
124125

@@ -130,7 +131,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.
130131
.offset = offset + pos,
131132
},
132133
.path = try gpa.dupe(u8, name),
133-
.file = try std.fs.cwd().openFile(path, .{}),
134+
.file_handle = handle_index,
134135
.index = undefined,
135136
.alive = false,
136137
.mtime = hdr.date() catch 0,
@@ -150,5 +151,6 @@ const std = @import("std");
150151

151152
const Allocator = mem.Allocator;
152153
const Archive = @This();
154+
const File = @import("file.zig").File;
153155
const MachO = @import("../MachO.zig");
154156
const Object = @import("Object.zig");

src/link/MachO/Atom.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void {
5858
assert(buffer.len == self.size);
5959
switch (self.getFile(macho_file)) {
6060
.internal => |x| try x.getAtomData(self, buffer),
61-
.object => |x| try x.getAtomData(self, buffer),
61+
.object => |x| try x.getAtomData(macho_file, self, buffer),
6262
.zig_object => |x| try x.getAtomData(macho_file, self, buffer),
6363
else => unreachable,
6464
}

src/link/MachO/Object.zig

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
archive: ?Archive = null,
22
path: []const u8,
3-
file: std.fs.File,
3+
file_handle: File.HandleIndex,
44
mtime: u64,
55
index: File.Index,
66

@@ -43,7 +43,6 @@ pub fn isObject(path: []const u8) !bool {
4343
}
4444

4545
pub fn deinit(self: *Object, allocator: Allocator) void {
46-
self.file.close();
4746
if (self.archive) |*ar| allocator.free(ar.path);
4847
allocator.free(self.path);
4948
for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
@@ -73,10 +72,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
7372

7473
const gpa = macho_file.base.comp.gpa;
7574
const offset = if (self.archive) |ar| ar.offset else 0;
75+
const handle = macho_file.getFileHandle(self.file_handle);
7676

7777
var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
7878
{
79-
const amt = try self.file.preadAll(&header_buffer, offset);
79+
const amt = try handle.preadAll(&header_buffer, offset);
8080
if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
8181
}
8282
self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
@@ -97,7 +97,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
9797
const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
9898
defer gpa.free(lc_buffer);
9999
{
100-
const amt = try self.file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
100+
const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
101101
if (amt != self.header.?.sizeofcmds) return error.InputOutput;
102102
}
103103

@@ -124,14 +124,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
124124
const cmd = lc.cast(macho.symtab_command).?;
125125
try self.strtab.resize(gpa, cmd.strsize);
126126
{
127-
const amt = try self.file.preadAll(self.strtab.items, cmd.stroff + offset);
127+
const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset);
128128
if (amt != self.strtab.items.len) return error.InputOutput;
129129
}
130130

131131
const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
132132
defer gpa.free(symtab_buffer);
133133
{
134-
const amt = try self.file.preadAll(symtab_buffer, cmd.symoff + offset);
134+
const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);
135135
if (amt != symtab_buffer.len) return error.InputOutput;
136136
}
137137
const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];
@@ -149,7 +149,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
149149
const buffer = try gpa.alloc(u8, cmd.datasize);
150150
defer gpa.free(buffer);
151151
{
152-
const amt = try self.file.preadAll(buffer, offset + cmd.dataoff);
152+
const amt = try handle.preadAll(buffer, offset + cmd.dataoff);
153153
if (amt != buffer.len) return error.InputOutput;
154154
}
155155
const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
@@ -697,7 +697,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
697697
const relocs = slice.items(.relocs)[sect_id];
698698

699699
// TODO: read into buffer directly
700-
const data = try self.getSectionData(gpa, sect_id);
700+
const data = try self.getSectionData(sect_id, macho_file);
701701
defer gpa.free(data);
702702

703703
try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len);
@@ -800,7 +800,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
800800
};
801801

802802
const gpa = macho_file.base.comp.gpa;
803-
const data = try self.getSectionData(gpa, sect_id);
803+
const data = try self.getSectionData(sect_id, macho_file);
804804
defer gpa.free(data);
805805
const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
806806
const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];
@@ -1019,11 +1019,11 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void {
10191019

10201020
if (debug_info_index == null or debug_abbrev_index == null) return;
10211021

1022-
const debug_info = try self.getSectionData(gpa, @intCast(debug_info_index.?));
1022+
const debug_info = try self.getSectionData(@intCast(debug_info_index.?), macho_file);
10231023
defer gpa.free(debug_info);
1024-
const debug_abbrev = try self.getSectionData(gpa, @intCast(debug_abbrev_index.?));
1024+
const debug_abbrev = try self.getSectionData(@intCast(debug_abbrev_index.?), macho_file);
10251025
defer gpa.free(debug_abbrev);
1026-
const debug_str = if (debug_str_index) |index| try self.getSectionData(gpa, @intCast(index)) else &[0]u8{};
1026+
const debug_str = if (debug_str_index) |index| try self.getSectionData(@intCast(index), macho_file) else &[0]u8{};
10271027
defer gpa.free(debug_str);
10281028

10291029
var dwarf_info = DwarfInfo{};
@@ -1589,25 +1589,28 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
15891589
}
15901590
}
15911591

1592-
fn getSectionData(self: *const Object, allocator: Allocator, index: u32) ![]u8 {
1592+
fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 {
1593+
const gpa = macho_file.base.comp.gpa;
15931594
const slice = self.sections.slice();
15941595
assert(index < slice.items(.header).len);
15951596
const sect = slice.items(.header)[index];
1597+
const handle = macho_file.getFileHandle(self.file_handle);
15961598
const offset = if (self.archive) |ar| ar.offset else 0;
15971599
const size = math.cast(usize, sect.size) orelse return error.Overflow;
1598-
const buffer = try allocator.alloc(u8, size);
1599-
errdefer allocator.free(buffer);
1600-
const amt = try self.file.preadAll(buffer, sect.offset + offset);
1600+
const buffer = try gpa.alloc(u8, size);
1601+
errdefer gpa.free(buffer);
1602+
const amt = try handle.preadAll(buffer, sect.offset + offset);
16011603
if (amt != buffer.len) return error.InputOutput;
16021604
return buffer;
16031605
}
16041606

1605-
pub fn getAtomData(self: *const Object, atom: Atom, buffer: []u8) !void {
1607+
pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: []u8) !void {
16061608
assert(buffer.len == atom.size);
16071609
const slice = self.sections.slice();
1610+
const handle = macho_file.getFileHandle(self.file_handle);
16081611
const offset = if (self.archive) |ar| ar.offset else 0;
16091612
const sect = slice.items(.header)[atom.n_sect];
1610-
const amt = try self.file.preadAll(buffer, sect.offset + offset + atom.off);
1613+
const amt = try handle.preadAll(buffer, sect.offset + offset + atom.off);
16111614
if (amt != buffer.len) return error.InputOutput;
16121615
}
16131616

@@ -1885,16 +1888,17 @@ const x86_64 = struct {
18851888
) !void {
18861889
const gpa = macho_file.base.comp.gpa;
18871890

1891+
const handle = macho_file.getFileHandle(self.file_handle);
18881892
const offset = if (self.archive) |ar| ar.offset else 0;
18891893
const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
18901894
defer gpa.free(relocs_buffer);
18911895
{
1892-
const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset);
1896+
const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);
18931897
if (amt != relocs_buffer.len) return error.InputOutput;
18941898
}
18951899
const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
18961900

1897-
const code = try self.getSectionData(gpa, @intCast(n_sect));
1901+
const code = try self.getSectionData(@intCast(n_sect), macho_file);
18981902
defer gpa.free(code);
18991903

19001904
try out.ensureTotalCapacityPrecise(gpa, relocs.len);
@@ -2047,16 +2051,17 @@ const aarch64 = struct {
20472051
) !void {
20482052
const gpa = macho_file.base.comp.gpa;
20492053

2054+
const handle = macho_file.getFileHandle(self.file_handle);
20502055
const offset = if (self.archive) |ar| ar.offset else 0;
20512056
const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
20522057
defer gpa.free(relocs_buffer);
20532058
{
2054-
const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset);
2059+
const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);
20552060
if (amt != relocs_buffer.len) return error.InputOutput;
20562061
}
20572062
const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
20582063

2059-
const code = try self.getSectionData(gpa, @intCast(n_sect));
2064+
const code = try self.getSectionData(@intCast(n_sect), macho_file);
20602065
defer gpa.free(code);
20612066

20622067
try out.ensureTotalCapacityPrecise(gpa, relocs.len);

src/link/MachO/file.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ pub const File = union(enum) {
105105
object: Object,
106106
dylib: Dylib,
107107
};
108+
109+
pub const Handle = std.fs.File;
110+
pub const HandleIndex = Index;
108111
};
109112

110113
const macho = std.macho;

0 commit comments

Comments
 (0)