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,...@@ -62,7 +62,7 @@ header_pad: u16 = 0x1000,
62entry_addr: ?u64 = null,62entry_addr: ?u64 = null,
6363
64objects: std.ArrayListUnmanaged(Object) = .{},64objects: std.ArrayListUnmanaged(Object) = .{},
65archives: std.ArrayListUnmanaged(*Archive) = .{},65archives: std.ArrayListUnmanaged(Archive) = .{},
66dylibs: std.ArrayListUnmanaged(*Dylib) = .{},66dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
6767
68next_dylib_ordinal: u16 = 1,68next_dylib_ordinal: u16 = 1,
...@@ -1006,8 +1006,13 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1006,8 +1006,13 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1006 continue;1006 continue;
1007 }1007 }
10081008
1009 if (try Archive.createAndParseFromPath(self.base.allocator, arch, full_path)) |archive| {1009 if (try Archive.isArchive(file, arch)) {
1010 try self.archives.append(self.base.allocator, archive);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);
1011 continue;1016 continue;
1012 }1017 }
10131018
...@@ -1019,6 +1024,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1019,6 +1024,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1019 continue;1024 continue;
1020 }1025 }
10211026
1027 self.base.allocator.free(full_path);
1028 file.close();
1022 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});1029 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
1023 }1030 }
1024}1031}
...@@ -1026,6 +1033,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1026,6 +1033,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1026fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void {1033fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void {
1027 const arch = self.base.options.target.cpu.arch;1034 const arch = self.base.options.target.cpu.arch;
1028 for (libs) |lib| {1035 for (libs) |lib| {
1036 const file = try fs.cwd().openFile(lib, .{});
1037
1029 if (try Dylib.createAndParseFromPath(self.base.allocator, arch, lib, .{1038 if (try Dylib.createAndParseFromPath(self.base.allocator, arch, lib, .{
1030 .syslibroot = syslibroot,1039 .syslibroot = syslibroot,
1031 })) |dylibs| {1040 })) |dylibs| {
...@@ -1034,11 +1043,17 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v...@@ -1034,11 +1043,17 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v
1034 continue;1043 continue;
1035 }1044 }
10361045
1037 if (try Archive.createAndParseFromPath(self.base.allocator, arch, lib)) |archive| {1046 if (try Archive.isArchive(file, arch)) {
1038 try self.archives.append(self.base.allocator, archive);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);
1039 continue;1053 continue;
1040 }1054 }
10411055
1056 file.close();
1042 log.warn("unknown filetype for a library: '{s}'", .{lib});1057 log.warn("unknown filetype for a library: '{s}'", .{lib});
1043 }1058 }
1044}1059}
...@@ -3345,9 +3360,8 @@ pub fn deinit(self: *MachO) void {...@@ -3345,9 +3360,8 @@ pub fn deinit(self: *MachO) void {
3345 }3360 }
3346 self.objects.deinit(self.base.allocator);3361 self.objects.deinit(self.base.allocator);
33473362
3348 for (self.archives.items) |archive| {3363 for (self.archives.items) |*archive| {
3349 archive.deinit(self.base.allocator);3364 archive.deinit(self.base.allocator);
3350 self.base.allocator.destroy(archive);
3351 }3365 }
3352 self.archives.deinit(self.base.allocator);3366 self.archives.deinit(self.base.allocator);
33533367
src/link/MachO/Archive.zig+25-47
...@@ -93,36 +93,6 @@ const ar_hdr = extern struct {...@@ -93,36 +93,6 @@ const ar_hdr = extern struct {
93 }93 }
94};94};
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
126pub fn deinit(self: *Archive, allocator: *Allocator) void {96pub fn deinit(self: *Archive, allocator: *Allocator) void {
127 for (self.toc.keys()) |*key| {97 for (self.toc.keys()) |*key| {
128 allocator.free(key.*);98 allocator.free(key.*);
...@@ -134,32 +104,40 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void {...@@ -134,32 +104,40 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void {
134 allocator.free(self.name);104 allocator.free(self.name);
135}105}
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
137pub fn parse(self: *Archive, allocator: *Allocator, arch: Arch) !void {129pub fn parse(self: *Archive, allocator: *Allocator, arch: Arch) !void {
138 self.library_offset = try fat.getLibraryOffset(self.file.reader(), arch);130 self.library_offset = try fat.getLibraryOffset(self.file.reader(), arch);
139
140 try self.file.seekTo(self.library_offset);131 try self.file.seekTo(self.library_offset);
141132 const reader = self.file.reader();
142 var reader = self.file.reader();
143 const magic = try reader.readBytesNoEof(SARMAG);133 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
150 self.header = try reader.readStruct(ar_hdr);134 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
157 var embedded_name = try parseName(allocator, self.header.?, reader);135 var embedded_name = try parseName(allocator, self.header.?, reader);
158 log.debug("parsing archive '{s}' at '{s}'", .{ embedded_name, self.name });
159 defer allocator.free(embedded_name);136 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);
163 try reader.context.seekTo(0);141 try reader.context.seekTo(0);
164}142}
165143
src/link/MachO/Object.zig+10-17
...@@ -155,17 +155,18 @@ pub fn deinit(self: *Object, allocator: *Allocator) void {...@@ -155,17 +155,18 @@ pub fn deinit(self: *Object, allocator: *Allocator) void {
155}155}
156156
157pub fn isObject(file: fs.File) !bool {157pub fn isObject(file: fs.File) !bool {
158 const reader = file.reader();158 const Internal = struct {
159 const is_object = blk: {159 fn isObject(reader: anytype) !bool {
160 if (reader.readStruct(macho.mach_header_64)) |header| {160 const header = try reader.readStruct(macho.mach_header_64);
161 break :blk header.filetype == macho.MH_OBJECT;161 return header.filetype == macho.MH_OBJECT;
162 } else |err| {
163 switch (err) {
164 error.EndOfStream => break :blk false,
165 else => |e| return e,
166 }
167 }162 }
168 };163 };
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 };
169 try file.seekTo(0);170 try file.seekTo(0);
170 return is_object;171 return is_object;
171}172}
...@@ -175,14 +176,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {...@@ -175,14 +176,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
175 if (self.file_offset) |offset| {176 if (self.file_offset) |offset| {
176 try reader.context.seekTo(offset);177 try reader.context.seekTo(offset);
177 }178 }
178
179 const header = try reader.readStruct(macho.mach_header_64);179 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
186 const this_arch: Arch = switch (header.cputype) {180 const this_arch: Arch = switch (header.cputype) {
187 macho.CPU_TYPE_ARM64 => .aarch64,181 macho.CPU_TYPE_ARM64 => .aarch64,
188 macho.CPU_TYPE_X86_64 => .x86_64,182 macho.CPU_TYPE_X86_64 => .x86_64,
...@@ -195,7 +189,6 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {...@@ -195,7 +189,6 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
195 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });189 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });
196 return error.MismatchedCpuArchitecture;190 return error.MismatchedCpuArchitecture;
197 }191 }
198
199 self.header = header;192 self.header = header;
200193
201 try self.readLoadCommands(allocator, reader);194 try self.readLoadCommands(allocator, reader);