authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-31 15:33:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-01 09:06:56+02:00
logf023cdad7ca676977d9b5abd3d38677779aab211
treee9f6005480147c3daa1766e37ce1715d31877bc9
parent06396ddd7d632704681bbd6278f18dcc2b6bf20c

macho: don't allocate Archives on the heap

instead, transfer ownership directly to MachO struct.

3 files changed, 56 insertions(+), 71 deletions(-)

src/link/MachO.zig+21-7
......@@ -62,7 +62,7 @@ header_pad: u16 = 0x1000,
6262entry_addr: ?u64 = null,
6363
6464objects: std.ArrayListUnmanaged(Object) = .{},
65archives: std.ArrayListUnmanaged(*Archive) = .{},
65archives: std.ArrayListUnmanaged(Archive) = .{},
6666dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
6767
6868next_dylib_ordinal: u16 = 1,
......@@ -1006,8 +1006,13 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
10061006 continue;
10071007 }
10081008
1009 if (try Archive.createAndParseFromPath(self.base.allocator, arch, full_path)) |archive| {
1010 try self.archives.append(self.base.allocator, archive);
1009 if (try Archive.isArchive(file, arch)) {
1010 const archive = try self.archives.addOne(self.base.allocator);
1011 archive.* = .{
1012 .name = full_path,
1013 .file = file,
1014 };
1015 try archive.parse(self.base.allocator, arch);
10111016 continue;
10121017 }
10131018
......@@ -1019,6 +1024,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
10191024 continue;
10201025 }
10211026
1027 self.base.allocator.free(full_path);
1028 file.close();
10221029 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
10231030 }
10241031}
......@@ -1026,6 +1033,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
10261033fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void {
10271034 const arch = self.base.options.target.cpu.arch;
10281035 for (libs) |lib| {
1036 const file = try fs.cwd().openFile(lib, .{});
1037
10291038 if (try Dylib.createAndParseFromPath(self.base.allocator, arch, lib, .{
10301039 .syslibroot = syslibroot,
10311040 })) |dylibs| {
......@@ -1034,11 +1043,17 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v
10341043 continue;
10351044 }
10361045
1037 if (try Archive.createAndParseFromPath(self.base.allocator, arch, lib)) |archive| {
1038 try self.archives.append(self.base.allocator, archive);
1046 if (try Archive.isArchive(file, arch)) {
1047 const archive = try self.archives.addOne(self.base.allocator);
1048 archive.* = .{
1049 .name = try self.base.allocator.dupe(u8, lib),
1050 .file = file,
1051 };
1052 try archive.parse(self.base.allocator, arch);
10391053 continue;
10401054 }
10411055
1056 file.close();
10421057 log.warn("unknown filetype for a library: '{s}'", .{lib});
10431058 }
10441059}
......@@ -3345,9 +3360,8 @@ pub fn deinit(self: *MachO) void {
33453360 }
33463361 self.objects.deinit(self.base.allocator);
33473362
3348 for (self.archives.items) |archive| {
3363 for (self.archives.items) |*archive| {
33493364 archive.deinit(self.base.allocator);
3350 self.base.allocator.destroy(archive);
33513365 }
33523366 self.archives.deinit(self.base.allocator);
33533367
src/link/MachO/Archive.zig+25-47
......@@ -93,36 +93,6 @@ const ar_hdr = extern struct {
9393 }
9494};
9595
96pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
97 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
98 error.FileNotFound => return null,
99 else => |e| return e,
100 };
101 errdefer file.close();
102
103 const archive = try allocator.create(Archive);
104 errdefer allocator.destroy(archive);
105
106 const name = try allocator.dupe(u8, path);
107 errdefer allocator.free(name);
108
109 archive.* = .{
110 .name = name,
111 .file = file,
112 };
113
114 archive.parse(allocator, arch) catch |err| switch (err) {
115 error.EndOfStream, error.NotArchive => {
116 archive.deinit(allocator);
117 allocator.destroy(archive);
118 return null;
119 },
120 else => |e| return e,
121 };
122
123 return archive;
124}
125
12696pub fn deinit(self: *Archive, allocator: *Allocator) void {
12797 for (self.toc.keys()) |*key| {
12898 allocator.free(key.*);
......@@ -134,32 +104,40 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void {
134104 allocator.free(self.name);
135105}
136106
107pub fn isArchive(file: fs.File, arch: Arch) !bool {
108 const Internal = struct {
109 fn isArchive(reader: anytype, a: Arch) !bool {
110 const offset = try fat.getLibraryOffset(reader, a);
111 try reader.context.seekTo(offset);
112 const magic = try reader.readBytesNoEof(SARMAG);
113 if (!mem.eql(u8, &magic, ARMAG)) return false;
114 const header = try reader.readStruct(ar_hdr);
115 return mem.eql(u8, &header.ar_fmag, ARFMAG);
116 }
117 };
118 const is_archive = if (Internal.isArchive(file.reader(), arch)) |res|
119 res
120 else |err| switch (err) {
121 error.EndOfStream => false,
122 error.MismatchedCpuArchitecture => true, // TODO maybe this check should be done differently?
123 else => |e| return e,
124 };
125 try file.seekTo(0);
126 return is_archive;
127}
128
137129pub fn parse(self: *Archive, allocator: *Allocator, arch: Arch) !void {
138130 self.library_offset = try fat.getLibraryOffset(self.file.reader(), arch);
139
140131 try self.file.seekTo(self.library_offset);
141
142 var reader = self.file.reader();
132 const reader = self.file.reader();
143133 const magic = try reader.readBytesNoEof(SARMAG);
144
145 if (!mem.eql(u8, &magic, ARMAG)) {
146 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
147 return error.NotArchive;
148 }
149
150134 self.header = try reader.readStruct(ar_hdr);
151
152 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
153 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
154 return error.NotArchive;
155 }
156
157135 var embedded_name = try parseName(allocator, self.header.?, reader);
158 log.debug("parsing archive '{s}' at '{s}'", .{ embedded_name, self.name });
159136 defer allocator.free(embedded_name);
160137
161 try self.parseTableOfContents(allocator, reader);
138 log.debug("parsing archive '{s}' at '{s}'", .{ embedded_name, self.name });
162139
140 try self.parseTableOfContents(allocator, reader);
163141 try reader.context.seekTo(0);
164142}
165143
src/link/MachO/Object.zig+10-17
......@@ -155,17 +155,18 @@ pub fn deinit(self: *Object, allocator: *Allocator) void {
155155}
156156
157157pub fn isObject(file: fs.File) !bool {
158 const reader = file.reader();
159 const is_object = blk: {
160 if (reader.readStruct(macho.mach_header_64)) |header| {
161 break :blk header.filetype == macho.MH_OBJECT;
162 } else |err| {
163 switch (err) {
164 error.EndOfStream => break :blk false,
165 else => |e| return e,
166 }
158 const Internal = struct {
159 fn isObject(reader: anytype) !bool {
160 const header = try reader.readStruct(macho.mach_header_64);
161 return header.filetype == macho.MH_OBJECT;
167162 }
168163 };
164 const is_object = if (Internal.isObject(file.reader())) |res|
165 res
166 else |err| switch (err) {
167 error.EndOfStream => false,
168 else => |e| return e,
169 };
169170 try file.seekTo(0);
170171 return is_object;
171172}
......@@ -175,14 +176,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
175176 if (self.file_offset) |offset| {
176177 try reader.context.seekTo(offset);
177178 }
178
179179 const header = try reader.readStruct(macho.mach_header_64);
180
181 if (header.filetype != macho.MH_OBJECT) {
182 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, header.filetype });
183 return error.NotObject;
184 }
185
186180 const this_arch: Arch = switch (header.cputype) {
187181 macho.CPU_TYPE_ARM64 => .aarch64,
188182 macho.CPU_TYPE_X86_64 => .x86_64,
......@@ -195,7 +189,6 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
195189 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });
196190 return error.MismatchedCpuArchitecture;
197191 }
198
199192 self.header = header;
200193
201194 try self.readLoadCommands(allocator, reader);