diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 6272ef6d98..b23d446925 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1568,6 +1568,9 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { // in `Decl` to notice that the line number did not change. self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); }, + .macho => { + // TODO Implement for MachO + }, .c => {}, } } @@ -1776,10 +1779,12 @@ fn allocateNewDecl( .contents_hash = contents_hash, .link = switch (self.bin_file.tag) { .elf => .{ .elf = link.File.Elf.TextBlock.empty }, + .macho => .{ .macho = link.File.MachO.TextBlock.empty }, .c => .{ .c = {} }, }, .fn_link = switch (self.bin_file.tag) { .elf => .{ .elf = link.File.Elf.SrcFn.empty }, + .macho => .{ .macho = link.File.MachO.SrcFn.empty }, .c => .{ .c = {} }, }, .generation = 0, diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 76d889c581..fcdf556065 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -44,11 +44,13 @@ pub const Options = struct { pub const File = struct { pub const LinkBlock = union { elf: Elf.TextBlock, + macho: MachO.TextBlock, c: void, }; pub const LinkFn = union { elf: Elf.SrcFn, + macho: MachO.SrcFn, c: void, }; @@ -66,7 +68,7 @@ pub const File = struct { .unknown => unreachable, .coff => return error.TODOImplementCoff, .elf => return Elf.openPath(allocator, dir, sub_path, options), - .macho => return error.TODOImplementMacho, + .macho => return MachO.openPath(allocator, dir, sub_path, options), .wasm => return error.TODOImplementWasm, .c => return C.openPath(allocator, dir, sub_path, options), .hex => return error.TODOImplementHex, @@ -83,7 +85,7 @@ pub const File = struct { pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { switch (base.tag) { - .elf => { + .elf, .macho => { if (base.file != null) return; base.file = try dir.createFile(sub_path, .{ .truncate = false, @@ -106,6 +108,7 @@ pub const File = struct { pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), + .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), } } @@ -113,6 +116,7 @@ pub const File = struct { pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), + .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), .c => {}, } } @@ -120,6 +124,7 @@ pub const File = struct { pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), + .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), .c => {}, } } @@ -128,6 +133,7 @@ pub const File = struct { if (base.file) |f| f.close(); switch (base.tag) { .elf => @fieldParentPtr(Elf, "base", base).deinit(), + .macho => @fieldParentPtr(MachO, "base", base).deinit(), .c => @fieldParentPtr(C, "base", base).deinit(), } } @@ -139,6 +145,11 @@ pub const File = struct { parent.deinit(); base.allocator.destroy(parent); }, + .macho => { + const parent = @fieldParentPtr(MachO, "base", base); + parent.deinit(); + base.allocator.destroy(parent); + }, .c => { const parent = @fieldParentPtr(C, "base", base); parent.deinit(); @@ -153,6 +164,7 @@ pub const File = struct { try switch (base.tag) { .elf => @fieldParentPtr(Elf, "base", base).flush(), + .macho => @fieldParentPtr(MachO, "base", base).flush(), .c => @fieldParentPtr(C, "base", base).flush(), }; } @@ -160,6 +172,7 @@ pub const File = struct { pub fn freeDecl(base: *File, decl: *Module.Decl) void { switch (base.tag) { .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), + .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl), .c => unreachable, } } @@ -167,6 +180,7 @@ pub const File = struct { pub fn errorFlags(base: *File) ErrorFlags { return switch (base.tag) { .elf => @fieldParentPtr(Elf, "base", base).error_flags, + .macho => @fieldParentPtr(MachO, "base", base).error_flags, .c => return .{ .no_entry_point_found = false }, }; } @@ -180,12 +194,14 @@ pub const File = struct { ) !void { switch (base.tag) { .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), + .macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl, exports), .c => return {}, } } pub const Tag = enum { elf, + macho, c, }; @@ -2815,6 +2831,100 @@ pub const File = struct { } }; + + pub const MachO = struct { + pub const base_tag: Tag = .macho; + + base: File, + + ptr_width: enum { p32, p64 }, + + error_flags: ErrorFlags = ErrorFlags{}, + + pub const TextBlock = struct { + pub const empty = TextBlock{}; + }; + + pub const SrcFn = struct { + pub const empty = SrcFn{}; + }; + + pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { + assert(options.object_format == .macho); + + const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) }); + errdefer file.close(); + + var macho_file = try allocator.create(MachO); + errdefer allocator.destroy(macho_file); + + macho_file.* = openFile(allocator, file, options) catch |err| switch (err) { + error.IncrFailed => try createFile(allocator, file, options), + else => |e| return e, + }; + + return &macho_file.base; + } + + /// Returns error.IncrFailed if incremental update could not be performed. + fn openFile(allocator: *Allocator, file: fs.File, options: Options) !MachO { + switch (options.output_mode) { + .Exe => {}, + .Obj => {}, + .Lib => return error.IncrFailed, + } + var self: MachO = .{ + .base = .{ + .file = file, + .tag = .macho, + .options = options, + .allocator = allocator, + }, + .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { + 32 => .p32, + 64 => .p64, + else => return error.UnsupportedELFArchitecture, + }, + }; + errdefer self.deinit(); + + // TODO implement reading the macho file + return error.IncrFailed; + //try self.populateMissingMetadata(); + //return self; + } + + /// Truncates the existing file contents and overwrites the contents. + /// Returns an error if `file` is not already open with +read +write +seek abilities. + fn createFile(allocator: *Allocator, file: fs.File, options: Options) !MachO { + switch (options.output_mode) { + .Exe => return error.TODOImplementWritingMachOExeFiles, + .Obj => return error.TODOImplementWritingMachOObjFiles, + .Lib => return error.TODOImplementWritingLibFiles, + } + } + + /// Commit pending changes and write headers. + pub fn flush(self: *MachO) !void {} + + pub fn deinit(self: *MachO) void {} + + pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} + + pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {} + + pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} + + /// Must be called only after a successful call to `updateDecl`. + pub fn updateDeclExports( + self: *MachO, + module: *Module, + decl: *const Module.Decl, + exports: []const *Module.Export, + ) !void {} + + pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} + }; }; /// Saturating multiplication