authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-11 10:19:18+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:38+01:00
logd05e9c379267e9a68522eca3fe8800803c6a5c70
treece5e437e4cd6e32e4c1f39dac465fc5aee7285ed
parent0c171afab003f7d7dfde8491141e00cac7e99c21

macho: create scaffolding for parsing different input objects


5 files changed, 170 insertions(+), 15 deletions(-)

src/link/MachO.zig+134-6
...@@ -384,6 +384,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -384,6 +384,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
384 error.MalformedArchive,384 error.MalformedArchive,
385 error.InvalidCpuArch,385 error.InvalidCpuArch,
386 error.InvalidTarget,386 error.InvalidTarget,
387 error.UnknownFileType,
387 => continue, // already reported388 => continue, // already reported
388 else => |e| try self.reportParseError(389 else => |e| try self.reportParseError(
389 obj.path,390 obj.path,
...@@ -393,6 +394,81 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -393,6 +394,81 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
393 };394 };
394 }395 }
395396
397 var system_libs = std.ArrayList(SystemLib).init(gpa);
398 defer system_libs.deinit();
399
400 // libs
401 try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
402 for (comp.system_libs.values()) |info| {
403 system_libs.appendAssumeCapacity(.{
404 .needed = info.needed,
405 .weak = info.weak,
406 .path = info.path.?,
407 });
408 }
409
410 // frameworks
411 try system_libs.ensureUnusedCapacity(self.frameworks.len);
412 for (self.frameworks) |info| {
413 system_libs.appendAssumeCapacity(.{
414 .needed = info.needed,
415 .weak = info.weak,
416 .path = info.path,
417 });
418 }
419
420 // libc++ dep
421 if (comp.config.link_libcpp) {
422 try system_libs.ensureUnusedCapacity(2);
423 system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
424 system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
425 }
426
427 // libc/libSystem dep
428 self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {
429 error.MissingLibSystem => {}, // already reported
430 else => |e| return e, // TODO: convert into an error
431 };
432
433 for (system_libs.items) |lib| {
434 self.parseLibrary(lib, false) catch |err| switch (err) {
435 error.MalformedDylib,
436 error.MalformedArchive,
437 error.InvalidCpuArch,
438 error.UnknownFileType,
439 => continue, // already reported
440 else => |e| try self.reportParseError(
441 lib.path,
442 "unexpected error: parsing library failed with error {s}",
443 .{@errorName(e)},
444 ),
445 };
446 }
447
448 // Finally, link against compiler_rt.
449 const compiler_rt_path: ?[]const u8 = blk: {
450 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
451 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
452 break :blk null;
453 };
454 if (compiler_rt_path) |path| {
455 self.parsePositional(path, false) catch |err| switch (err) {
456 error.MalformedObject,
457 error.MalformedArchive,
458 error.InvalidCpuArch,
459 error.InvalidTarget,
460 error.UnknownFileType,
461 => {}, // already reported
462 else => |e| try self.reportParseError(
463 path,
464 "unexpected error: parsing input file failed with error {s}",
465 .{@errorName(e)},
466 ),
467 };
468 }
469
470 if (comp.link_errors.items.len > 0) return error.FlushFailure;
471
396 state_log.debug("{}", .{self.dumpState()});472 state_log.debug("{}", .{self.dumpState()});
397473
398 @panic("TODO");474 @panic("TODO");
...@@ -626,13 +702,12 @@ pub fn resolveLibSystem(...@@ -626,13 +702,12 @@ pub fn resolveLibSystem(
626 };702 };
627703
628 try self.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});704 try self.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
629 return;705 return error.MissingLibSystem;
630 }706 }
631707
632 const libsystem_path = try arena.dupe(u8, test_path.items);708 const libsystem_path = try arena.dupe(u8, test_path.items);
633 try out_libs.put(libsystem_path, .{709 try out_libs.append(.{
634 .needed = true,710 .needed = true,
635 .weak = false,
636 .path = libsystem_path,711 .path = libsystem_path,
637 });712 });
638}713}
...@@ -685,6 +760,7 @@ fn accessLibPath(...@@ -685,6 +760,7 @@ fn accessLibPath(
685const ParseError = error{760const ParseError = error{
686 MalformedObject,761 MalformedObject,
687 MalformedArchive,762 MalformedArchive,
763 MalformedDylib,
688 NotLibStub,764 NotLibStub,
689 InvalidCpuArch,765 InvalidCpuArch,
690 InvalidTarget,766 InvalidTarget,
...@@ -696,6 +772,8 @@ const ParseError = error{...@@ -696,6 +772,8 @@ const ParseError = error{
696 EndOfStream,772 EndOfStream,
697 FileSystem,773 FileSystem,
698 NotSupported,774 NotSupported,
775 Unhandled,
776 UnknownFileType,
699} || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError || tapi.TapiError;777} || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError || tapi.TapiError;
700778
701fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {779fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {
...@@ -709,9 +787,25 @@ fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!v...@@ -709,9 +787,25 @@ fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!v
709}787}
710788
711fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void {789fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void {
712 _ = self;790 const tracy = trace(@src());
713 _ = lib;791 defer tracy.end();
714 _ = must_link;792 if (try fat.isFatLibrary(lib.path)) {
793 const fat_arch = try self.parseFatLibrary(lib.path);
794 if (try Archive.isArchive(lib.path, fat_arch)) {
795 try self.parseArchive(lib, must_link, fat_arch);
796 } else if (try Dylib.isDylib(lib.path, fat_arch)) {
797 try self.parseDylib(lib, true, fat_arch);
798 } else {
799 try self.reportParseError(lib.path, "unknown file type for a library", .{});
800 return error.UnknownFileType;
801 }
802 } else if (try Archive.isArchive(lib.path, null)) {
803 try self.parseArchive(lib, must_link, null);
804 } else if (try Dylib.isDylib(lib.path, null)) {
805 try self.parseDylib(lib, true, null);
806 } else {
807 try self.parseTbd(lib, true);
808 }
715}809}
716810
717fn parseObject(self: *MachO, path: []const u8) ParseError!void {811fn parseObject(self: *MachO, path: []const u8) ParseError!void {
...@@ -739,6 +833,40 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {...@@ -739,6 +833,40 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
739 try object.parse(self);833 try object.parse(self);
740}834}
741835
836fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
837 var buffer: [2]fat.Arch = undefined;
838 const fat_archs = try fat.parseArchs(path, &buffer);
839 const cpu_arch = self.getTarget().cpu.arch;
840 for (fat_archs) |arch| {
841 if (arch.tag == cpu_arch) return arch;
842 }
843 try self.reportParseError(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
844 return error.InvalidCpuArch;
845}
846
847fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {
848 _ = self;
849 _ = lib;
850 _ = must_link;
851 _ = fat_arch;
852 return error.Unhandled;
853}
854
855fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {
856 _ = self;
857 _ = lib;
858 _ = explicit;
859 _ = fat_arch;
860 return error.Unhandled;
861}
862
863fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!void {
864 _ = self;
865 _ = lib;
866 _ = explicit;
867 return error.Unhandled;
868}
869
742fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {870fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
743 _ = self;871 _ = self;
744 _ = atom_index;872 _ = atom_index;
src/link/MachO/Archive.zig+12
...@@ -61,6 +61,17 @@ const ar_hdr = extern struct {...@@ -61,6 +61,17 @@ const ar_hdr = extern struct {
61 }61 }
62};62};
6363
64pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
65 const file = try std.fs.cwd().openFile(path, .{});
66 defer file.close();
67 if (fat_arch) |arch| {
68 try file.seekTo(arch.offset);
69 }
70 const magic = file.reader().readBytesNoEof(SARMAG) catch return false;
71 if (!mem.eql(u8, &magic, ARMAG)) return false;
72 return true;
73}
74
64pub fn deinit(self: *Archive, allocator: Allocator) void {75pub fn deinit(self: *Archive, allocator: Allocator) void {
65 self.objects.deinit(allocator);76 self.objects.deinit(allocator);
66}77}
...@@ -117,6 +128,7 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {...@@ -117,6 +128,7 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
117 }128 }
118}129}
119130
131const fat = @import("fat.zig");
120const log = std.log.scoped(.link);132const log = std.log.scoped(.link);
121const macho = std.macho;133const macho = std.macho;
122const mem = std.mem;134const mem = std.mem;
src/link/MachO/Dylib.zig+10
...@@ -23,6 +23,16 @@ referenced: bool = false,...@@ -23,6 +23,16 @@ referenced: bool = false,
2323
24output_symtab_ctx: MachO.SymtabCtx = .{},24output_symtab_ctx: MachO.SymtabCtx = .{},
2525
26pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool {
27 const file = try std.fs.cwd().openFile(path, .{});
28 defer file.close();
29 if (fat_arch) |arch| {
30 try file.seekTo(arch.offset);
31 }
32 const header = file.reader().readStruct(macho.mach_header_64) catch return false;
33 return header.filetype == macho.MH_DYLIB;
34}
35
26pub fn deinit(self: *Dylib, allocator: Allocator) void {36pub fn deinit(self: *Dylib, allocator: Allocator) void {
27 self.exports.deinit(allocator);37 self.exports.deinit(allocator);
28 self.strtab.deinit(allocator);38 self.strtab.deinit(allocator);
src/link/MachO/Object.zig+7-4
...@@ -34,8 +34,7 @@ output_symtab_ctx: MachO.SymtabCtx = .{},...@@ -34,8 +34,7 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
34pub fn isObject(path: []const u8) !bool {34pub fn isObject(path: []const u8) !bool {
35 const file = try std.fs.cwd().openFile(path, .{});35 const file = try std.fs.cwd().openFile(path, .{});
36 defer file.close();36 defer file.close();
37 const reader = file.reader();37 const header = file.reader().readStruct(macho.mach_header_64) catch return false;
38 const header = reader.readStruct(macho.mach_header_64) catch return false;
39 return header.filetype == macho.MH_OBJECT;38 return header.filetype == macho.MH_OBJECT;
40}39}
4140
...@@ -175,8 +174,12 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -175,8 +174,12 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
175 });174 });
176 return error.InvalidTarget;175 return error.InvalidTarget;
177 }176 }
178 if (macho_file.platform.version.order(platform.version) != .lt) {177 if (macho_file.platform.version.order(platform.version) == .lt) {
179 try macho_file.reportParseError2(self.index, "object file built for newer platform: {}", .{platform});178 try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
179 macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
180 macho_file.platform.version,
181 platform.version,
182 });
180 return error.InvalidTarget;183 return error.InvalidTarget;
181 }184 }
182 }185 }
src/link/MachO/fat.zig+7-5
...@@ -8,10 +8,10 @@ const native_endian = builtin.target.cpu.arch.endian();...@@ -8,10 +8,10 @@ const native_endian = builtin.target.cpu.arch.endian();
88
9const MachO = @import("../MachO.zig");9const MachO = @import("../MachO.zig");
1010
11pub fn isFatLibrary(file: std.fs.File) bool {11pub fn isFatLibrary(path: []const u8) !bool {
12 const reader = file.reader();12 const file = try std.fs.cwd().openFile(path, .{});
13 const hdr = reader.readStructEndian(macho.fat_header, .big) catch return false;13 defer file.close();
14 defer file.seekTo(0) catch {};14 const hdr = file.reader().readStructEndian(macho.fat_header, .big) catch return false;
15 return hdr.magic == macho.FAT_MAGIC;15 return hdr.magic == macho.FAT_MAGIC;
16}16}
1717
...@@ -21,7 +21,9 @@ pub const Arch = struct {...@@ -21,7 +21,9 @@ pub const Arch = struct {
21 size: u32,21 size: u32,
22};22};
2323
24pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {24pub fn parseArchs(path: []const u8, buffer: *[2]Arch) ![]const Arch {
25 const file = try std.fs.cwd().openFile(path, .{});
26 defer file.close();
25 const reader = file.reader();27 const reader = file.reader();
26 const fat_header = try reader.readStructEndian(macho.fat_header, .big);28 const fat_header = try reader.readStructEndian(macho.fat_header, .big);
27 assert(fat_header.magic == macho.FAT_MAGIC);29 assert(fat_header.magic == macho.FAT_MAGIC);