macho: create scaffolding for parsing different input objects
This commit is contained in:
@@ -384,6 +384,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
|
||||
error.MalformedArchive,
|
||||
error.InvalidCpuArch,
|
||||
error.InvalidTarget,
|
||||
error.UnknownFileType,
|
||||
=> continue, // already reported
|
||||
else => |e| try self.reportParseError(
|
||||
obj.path,
|
||||
@@ -393,6 +394,81 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
|
||||
};
|
||||
}
|
||||
|
||||
var system_libs = std.ArrayList(SystemLib).init(gpa);
|
||||
defer system_libs.deinit();
|
||||
|
||||
// libs
|
||||
try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
|
||||
for (comp.system_libs.values()) |info| {
|
||||
system_libs.appendAssumeCapacity(.{
|
||||
.needed = info.needed,
|
||||
.weak = info.weak,
|
||||
.path = info.path.?,
|
||||
});
|
||||
}
|
||||
|
||||
// frameworks
|
||||
try system_libs.ensureUnusedCapacity(self.frameworks.len);
|
||||
for (self.frameworks) |info| {
|
||||
system_libs.appendAssumeCapacity(.{
|
||||
.needed = info.needed,
|
||||
.weak = info.weak,
|
||||
.path = info.path,
|
||||
});
|
||||
}
|
||||
|
||||
// libc++ dep
|
||||
if (comp.config.link_libcpp) {
|
||||
try system_libs.ensureUnusedCapacity(2);
|
||||
system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
|
||||
system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
|
||||
}
|
||||
|
||||
// libc/libSystem dep
|
||||
self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {
|
||||
error.MissingLibSystem => {}, // already reported
|
||||
else => |e| return e, // TODO: convert into an error
|
||||
};
|
||||
|
||||
for (system_libs.items) |lib| {
|
||||
self.parseLibrary(lib, false) catch |err| switch (err) {
|
||||
error.MalformedDylib,
|
||||
error.MalformedArchive,
|
||||
error.InvalidCpuArch,
|
||||
error.UnknownFileType,
|
||||
=> continue, // already reported
|
||||
else => |e| try self.reportParseError(
|
||||
lib.path,
|
||||
"unexpected error: parsing library failed with error {s}",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// Finally, link against compiler_rt.
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
|
||||
if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
|
||||
break :blk null;
|
||||
};
|
||||
if (compiler_rt_path) |path| {
|
||||
self.parsePositional(path, false) catch |err| switch (err) {
|
||||
error.MalformedObject,
|
||||
error.MalformedArchive,
|
||||
error.InvalidCpuArch,
|
||||
error.InvalidTarget,
|
||||
error.UnknownFileType,
|
||||
=> {}, // already reported
|
||||
else => |e| try self.reportParseError(
|
||||
path,
|
||||
"unexpected error: parsing input file failed with error {s}",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
if (comp.link_errors.items.len > 0) return error.FlushFailure;
|
||||
|
||||
state_log.debug("{}", .{self.dumpState()});
|
||||
|
||||
@panic("TODO");
|
||||
@@ -626,13 +702,12 @@ pub fn resolveLibSystem(
|
||||
};
|
||||
|
||||
try self.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
|
||||
return;
|
||||
return error.MissingLibSystem;
|
||||
}
|
||||
|
||||
const libsystem_path = try arena.dupe(u8, test_path.items);
|
||||
try out_libs.put(libsystem_path, .{
|
||||
try out_libs.append(.{
|
||||
.needed = true,
|
||||
.weak = false,
|
||||
.path = libsystem_path,
|
||||
});
|
||||
}
|
||||
@@ -685,6 +760,7 @@ fn accessLibPath(
|
||||
const ParseError = error{
|
||||
MalformedObject,
|
||||
MalformedArchive,
|
||||
MalformedDylib,
|
||||
NotLibStub,
|
||||
InvalidCpuArch,
|
||||
InvalidTarget,
|
||||
@@ -696,6 +772,8 @@ const ParseError = error{
|
||||
EndOfStream,
|
||||
FileSystem,
|
||||
NotSupported,
|
||||
Unhandled,
|
||||
UnknownFileType,
|
||||
} || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError || tapi.TapiError;
|
||||
|
||||
fn 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
|
||||
}
|
||||
|
||||
fn parseLibrary(self: *MachO, lib: SystemLib, must_link: bool) ParseError!void {
|
||||
_ = self;
|
||||
_ = lib;
|
||||
_ = must_link;
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
if (try fat.isFatLibrary(lib.path)) {
|
||||
const fat_arch = try self.parseFatLibrary(lib.path);
|
||||
if (try Archive.isArchive(lib.path, fat_arch)) {
|
||||
try self.parseArchive(lib, must_link, fat_arch);
|
||||
} else if (try Dylib.isDylib(lib.path, fat_arch)) {
|
||||
try self.parseDylib(lib, true, fat_arch);
|
||||
} else {
|
||||
try self.reportParseError(lib.path, "unknown file type for a library", .{});
|
||||
return error.UnknownFileType;
|
||||
}
|
||||
} else if (try Archive.isArchive(lib.path, null)) {
|
||||
try self.parseArchive(lib, must_link, null);
|
||||
} else if (try Dylib.isDylib(lib.path, null)) {
|
||||
try self.parseDylib(lib, true, null);
|
||||
} else {
|
||||
try self.parseTbd(lib, true);
|
||||
}
|
||||
}
|
||||
|
||||
fn parseObject(self: *MachO, path: []const u8) ParseError!void {
|
||||
@@ -739,6 +833,40 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
|
||||
try object.parse(self);
|
||||
}
|
||||
|
||||
fn parseFatLibrary(self: *MachO, path: []const u8) !fat.Arch {
|
||||
var buffer: [2]fat.Arch = undefined;
|
||||
const fat_archs = try fat.parseArchs(path, &buffer);
|
||||
const cpu_arch = self.getTarget().cpu.arch;
|
||||
for (fat_archs) |arch| {
|
||||
if (arch.tag == cpu_arch) return arch;
|
||||
}
|
||||
try self.reportParseError(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
|
||||
return error.InvalidCpuArch;
|
||||
}
|
||||
|
||||
fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Arch) ParseError!void {
|
||||
_ = self;
|
||||
_ = lib;
|
||||
_ = must_link;
|
||||
_ = fat_arch;
|
||||
return error.Unhandled;
|
||||
}
|
||||
|
||||
fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) ParseError!void {
|
||||
_ = self;
|
||||
_ = lib;
|
||||
_ = explicit;
|
||||
_ = fat_arch;
|
||||
return error.Unhandled;
|
||||
}
|
||||
|
||||
fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!void {
|
||||
_ = self;
|
||||
_ = lib;
|
||||
_ = explicit;
|
||||
return error.Unhandled;
|
||||
}
|
||||
|
||||
fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
|
||||
_ = self;
|
||||
_ = atom_index;
|
||||
|
||||
@@ -61,6 +61,17 @@ const ar_hdr = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
if (fat_arch) |arch| {
|
||||
try file.seekTo(arch.offset);
|
||||
}
|
||||
const magic = file.reader().readBytesNoEof(SARMAG) catch return false;
|
||||
if (!mem.eql(u8, &magic, ARMAG)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Archive, allocator: Allocator) void {
|
||||
self.objects.deinit(allocator);
|
||||
}
|
||||
@@ -117,6 +128,7 @@ pub fn parse(self: *Archive, arena: Allocator, macho_file: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
const fat = @import("fat.zig");
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
|
||||
@@ -23,6 +23,16 @@ referenced: bool = false,
|
||||
|
||||
output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
|
||||
pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
if (fat_arch) |arch| {
|
||||
try file.seekTo(arch.offset);
|
||||
}
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch return false;
|
||||
return header.filetype == macho.MH_DYLIB;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Dylib, allocator: Allocator) void {
|
||||
self.exports.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
|
||||
@@ -34,8 +34,7 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
pub fn isObject(path: []const u8) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const reader = file.reader();
|
||||
const header = reader.readStruct(macho.mach_header_64) catch return false;
|
||||
const header = file.reader().readStruct(macho.mach_header_64) catch return false;
|
||||
return header.filetype == macho.MH_OBJECT;
|
||||
}
|
||||
|
||||
@@ -175,8 +174,12 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
|
||||
});
|
||||
return error.InvalidTarget;
|
||||
}
|
||||
if (macho_file.platform.version.order(platform.version) != .lt) {
|
||||
try macho_file.reportParseError2(self.index, "object file built for newer platform: {}", .{platform});
|
||||
if (macho_file.platform.version.order(platform.version) == .lt) {
|
||||
try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
|
||||
macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
|
||||
macho_file.platform.version,
|
||||
platform.version,
|
||||
});
|
||||
return error.InvalidTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ const native_endian = builtin.target.cpu.arch.endian();
|
||||
|
||||
const MachO = @import("../MachO.zig");
|
||||
|
||||
pub fn isFatLibrary(file: std.fs.File) bool {
|
||||
const reader = file.reader();
|
||||
const hdr = reader.readStructEndian(macho.fat_header, .big) catch return false;
|
||||
defer file.seekTo(0) catch {};
|
||||
pub fn isFatLibrary(path: []const u8) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const hdr = file.reader().readStructEndian(macho.fat_header, .big) catch return false;
|
||||
return hdr.magic == macho.FAT_MAGIC;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ pub const Arch = struct {
|
||||
size: u32,
|
||||
};
|
||||
|
||||
pub fn parseArchs(file: std.fs.File, buffer: *[2]Arch) ![]const Arch {
|
||||
pub fn parseArchs(path: []const u8, buffer: *[2]Arch) ![]const Arch {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
defer file.close();
|
||||
const reader = file.reader();
|
||||
const fat_header = try reader.readStructEndian(macho.fat_header, .big);
|
||||
assert(fat_header.magic == macho.FAT_MAGIC);
|
||||
|
||||
Reference in New Issue
Block a user