authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-07 19:08:15+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-07 19:27:26+01:00
logf9eb14ddcfdc508fd03f35e9d89a8f55baf7d11b
tree38319996d8e4f0657253a1177ac40144b3f91ded
parent82144a9073aa06f037e248f332608f94caed59b9

macho: parse input object files specifically for incl in archive


3 files changed, 162 insertions(+), 4 deletions(-)

src/link/MachO.zig+2-2
...@@ -926,7 +926,7 @@ pub fn resolveLibSystem(...@@ -926,7 +926,7 @@ pub fn resolveLibSystem(
926 });926 });
927}927}
928928
929const ParseError = error{929pub const ParseError = error{
930 MalformedObject,930 MalformedObject,
931 MalformedArchive,931 MalformedArchive,
932 MalformedDylib,932 MalformedDylib,
...@@ -1003,7 +1003,7 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {...@@ -1003,7 +1003,7 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
1003 try object.parse(self);1003 try object.parse(self);
1004}1004}
10051005
1006fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {1006pub fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
1007 var buffer: [2]fat.Arch = undefined;1007 var buffer: [2]fat.Arch = undefined;
1008 const fat_archs = try fat.parseArchs(path, &buffer);1008 const fat_archs = try fat.parseArchs(path, &buffer);
1009 const cpu_arch = self.getTarget().cpu.arch;1009 const cpu_arch = self.getTarget().cpu.arch;
src/link/MachO/Object.zig+76
...@@ -1233,6 +1233,82 @@ fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname...@@ -1233,6 +1233,82 @@ fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname
1233 return n_sect;1233 return n_sect;
1234}1234}
12351235
1236pub fn parseAr(self: *Object, macho_file: *MachO) !void {
1237 const tracy = trace(@src());
1238 defer tracy.end();
1239
1240 const gpa = macho_file.base.comp.gpa;
1241 const offset = if (self.archive) |ar| ar.offset else 0;
1242 const handle = macho_file.getFileHandle(self.file_handle);
1243
1244 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
1245 {
1246 const amt = try handle.preadAll(&header_buffer, offset);
1247 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
1248 }
1249 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
1250
1251 const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
1252 macho.CPU_TYPE_ARM64 => .aarch64,
1253 macho.CPU_TYPE_X86_64 => .x86_64,
1254 else => |x| {
1255 try macho_file.reportParseError2(self.index, "unknown cpu architecture: {d}", .{x});
1256 return error.InvalidCpuArch;
1257 },
1258 };
1259 if (macho_file.getTarget().cpu.arch != this_cpu_arch) {
1260 try macho_file.reportParseError2(self.index, "invalid cpu architecture: {s}", .{@tagName(this_cpu_arch)});
1261 return error.InvalidCpuArch;
1262 }
1263
1264 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
1265 defer gpa.free(lc_buffer);
1266 {
1267 const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
1268 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
1269 }
1270
1271 var it = LoadCommandIterator{
1272 .ncmds = self.header.?.ncmds,
1273 .buffer = lc_buffer,
1274 };
1275 while (it.next()) |lc| switch (lc.cmd()) {
1276 .SYMTAB => {
1277 const cmd = lc.cast(macho.symtab_command).?;
1278 try self.strtab.resize(gpa, cmd.strsize);
1279 {
1280 const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset);
1281 if (amt != self.strtab.items.len) return error.InputOutput;
1282 }
1283
1284 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
1285 defer gpa.free(symtab_buffer);
1286 {
1287 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);
1288 if (amt != symtab_buffer.len) return error.InputOutput;
1289 }
1290 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];
1291 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
1292 for (symtab) |nlist| {
1293 self.symtab.appendAssumeCapacity(.{
1294 .nlist = nlist,
1295 .atom = 0,
1296 .size = 0,
1297 });
1298 }
1299 },
1300 .BUILD_VERSION,
1301 .VERSION_MIN_MACOSX,
1302 .VERSION_MIN_IPHONEOS,
1303 .VERSION_MIN_TVOS,
1304 .VERSION_MIN_WATCHOS,
1305 => if (self.platform == null) {
1306 self.platform = MachO.Platform.fromLoadCommand(lc);
1307 },
1308 else => {},
1309 };
1310}
1311
1236pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void {1312pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void {
1237 const gpa = macho_file.base.comp.gpa;1313 const gpa = macho_file.base.comp.gpa;
1238 for (self.symtab.items(.nlist)) |nlist| {1314 for (self.symtab.items(.nlist)) |nlist| {
src/link/MachO/relocatable.zig+84-2
...@@ -104,8 +104,19 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -104,8 +104,19 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
104 if (module_obj_path) |path| try positionals.append(.{ .path = path });104 if (module_obj_path) |path| try positionals.append(.{ .path = path });
105105
106 for (positionals.items) |obj| {106 for (positionals.items) |obj| {
107 // TODO: parse for archive meaning don't unpack objects107 parsePositional(macho_file, obj.path) catch |err| switch (err) {
108 _ = obj;108 error.MalformedObject,
109 error.MalformedArchive,
110 error.InvalidCpuArch,
111 error.InvalidTarget,
112 => continue, // already reported
113 error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}),
114 else => |e| try macho_file.reportParseError(
115 obj.path,
116 "unexpected error: parsing input file failed with error {s}",
117 .{@errorName(e)},
118 ),
119 };
109 }120 }
110121
111 if (comp.link_errors.items.len > 0) return error.FlushFailure;122 if (comp.link_errors.items.len > 0) return error.FlushFailure;
...@@ -241,6 +252,75 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -241,6 +252,75 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
241 if (comp.link_errors.items.len > 0) return error.FlushFailure;252 if (comp.link_errors.items.len > 0) return error.FlushFailure;
242}253}
243254
255fn parsePositional(macho_file: *MachO, path: []const u8) MachO.ParseError!void {
256 const tracy = trace(@src());
257 defer tracy.end();
258 if (try Object.isObject(path)) {
259 try parseObject(macho_file, path);
260 } else if (try fat.isFatLibrary(path)) {
261 const fat_arch = try macho_file.parseFatLibrary(path);
262 if (try Archive.isArchive(path, fat_arch)) {
263 try parseArchive(macho_file, path, fat_arch);
264 } else return error.UnknownFileType;
265 } else if (try Archive.isArchive(path, null)) {
266 try parseArchive(macho_file, path, null);
267 } else return error.UnknownFileType;
268}
269
270fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void {
271 const tracy = trace(@src());
272 defer tracy.end();
273
274 const gpa = macho_file.base.comp.gpa;
275 const file = try std.fs.cwd().openFile(path, .{});
276 errdefer file.close();
277 const handle = try macho_file.addFileHandle(file);
278 const mtime: u64 = mtime: {
279 const stat = file.stat() catch break :mtime 0;
280 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
281 };
282 const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa)));
283 macho_file.files.set(index, .{ .object = .{
284 .path = try gpa.dupe(u8, path),
285 .file_handle = handle,
286 .mtime = mtime,
287 .index = index,
288 } });
289 try macho_file.objects.append(gpa, index);
290
291 const object = macho_file.getFile(index).?.object;
292 try object.parseAr(macho_file);
293}
294
295fn parseArchive(macho_file: *MachO, path: []const u8, fat_arch: ?fat.Arch) MachO.ParseError!void {
296 const tracy = trace(@src());
297 defer tracy.end();
298
299 const gpa = macho_file.base.comp.gpa;
300
301 const file = try std.fs.cwd().openFile(path, .{});
302 errdefer file.close();
303 const handle = try macho_file.addFileHandle(file);
304
305 var archive = Archive{};
306 defer archive.deinit(gpa);
307 try archive.parse(macho_file, path, handle, fat_arch);
308
309 var has_parse_error = false;
310 for (archive.objects.items) |extracted| {
311 const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa)));
312 macho_file.files.set(index, .{ .object = extracted });
313 const object = &macho_file.files.items(.data)[index].object;
314 object.index = index;
315 object.parseAr(macho_file) catch |err| switch (err) {
316 error.InvalidCpuArch => has_parse_error = true,
317 else => |e| return e,
318 };
319 try macho_file.objects.append(gpa, index);
320 }
321 if (has_parse_error) return error.MalformedArchive;
322}
323
244fn markExports(macho_file: *MachO) void {324fn markExports(macho_file: *MachO) void {
245 if (macho_file.getZigObject()) |zo| {325 if (macho_file.getZigObject()) |zo| {
246 zo.asFile().markExportsRelocatable(macho_file);326 zo.asFile().markExportsRelocatable(macho_file);
...@@ -733,6 +813,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {...@@ -733,6 +813,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
733const assert = std.debug.assert;813const assert = std.debug.assert;
734const build_options = @import("build_options");814const build_options = @import("build_options");
735const eh_frame = @import("eh_frame.zig");815const eh_frame = @import("eh_frame.zig");
816const fat = @import("fat.zig");
736const link = @import("../../link.zig");817const link = @import("../../link.zig");
737const load_commands = @import("load_commands.zig");818const load_commands = @import("load_commands.zig");
738const log = std.log.scoped(.link);819const log = std.log.scoped(.link);
...@@ -748,4 +829,5 @@ const Atom = @import("Atom.zig");...@@ -748,4 +829,5 @@ const Atom = @import("Atom.zig");
748const Compilation = @import("../../Compilation.zig");829const Compilation = @import("../../Compilation.zig");
749const File = @import("file.zig").File;830const File = @import("file.zig").File;
750const MachO = @import("../MachO.zig");831const MachO = @import("../MachO.zig");
832const Object = @import("Object.zig");
751const Symbol = @import("Symbol.zig");833const Symbol = @import("Symbol.zig");