| ... | @@ -44,11 +44,13 @@ pub const Options = struct { | ... | @@ -44,11 +44,13 @@ pub const Options = struct { |
| 44 | pub const File = struct { | 44 | pub const File = struct { |
| 45 | pub const LinkBlock = union { | 45 | pub const LinkBlock = union { |
| 46 | elf: Elf.TextBlock, | 46 | elf: Elf.TextBlock, |
| | 47 | macho: MachO.TextBlock, |
| 47 | c: void, | 48 | c: void, |
| 48 | }; | 49 | }; |
| 49 | | 50 | |
| 50 | pub const LinkFn = union { | 51 | pub const LinkFn = union { |
| 51 | elf: Elf.SrcFn, | 52 | elf: Elf.SrcFn, |
| | 53 | macho: MachO.SrcFn, |
| 52 | c: void, | 54 | c: void, |
| 53 | }; | 55 | }; |
| 54 | | 56 | |
| ... | @@ -66,7 +68,7 @@ pub const File = struct { | ... | @@ -66,7 +68,7 @@ pub const File = struct { |
| 66 | .unknown => unreachable, | 68 | .unknown => unreachable, |
| 67 | .coff => return error.TODOImplementCoff, | 69 | .coff => return error.TODOImplementCoff, |
| 68 | .elf => return Elf.openPath(allocator, dir, sub_path, options), | 70 | .elf => return Elf.openPath(allocator, dir, sub_path, options), |
| 69 | .macho => return error.TODOImplementMacho, | 71 | .macho => return MachO.openPath(allocator, dir, sub_path, options), |
| 70 | .wasm => return error.TODOImplementWasm, | 72 | .wasm => return error.TODOImplementWasm, |
| 71 | .c => return C.openPath(allocator, dir, sub_path, options), | 73 | .c => return C.openPath(allocator, dir, sub_path, options), |
| 72 | .hex => return error.TODOImplementHex, | 74 | .hex => return error.TODOImplementHex, |
| ... | @@ -83,7 +85,7 @@ pub const File = struct { | ... | @@ -83,7 +85,7 @@ pub const File = struct { |
| 83 | | 85 | |
| 84 | pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { | 86 | pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { |
| 85 | switch (base.tag) { | 87 | switch (base.tag) { |
| 86 | .elf => { | 88 | .elf, .macho => { |
| 87 | if (base.file != null) return; | 89 | if (base.file != null) return; |
| 88 | base.file = try dir.createFile(sub_path, .{ | 90 | base.file = try dir.createFile(sub_path, .{ |
| 89 | .truncate = false, | 91 | .truncate = false, |
| ... | @@ -106,6 +108,7 @@ pub const File = struct { | ... | @@ -106,6 +108,7 @@ pub const File = struct { |
| 106 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { | 108 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 107 | switch (base.tag) { | 109 | switch (base.tag) { |
| 108 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), | 110 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), |
| | 111 | .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), |
| 109 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), | 112 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), |
| 110 | } | 113 | } |
| 111 | } | 114 | } |
| ... | @@ -113,6 +116,7 @@ pub const File = struct { | ... | @@ -113,6 +116,7 @@ pub const File = struct { |
| 113 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { | 116 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 114 | switch (base.tag) { | 117 | switch (base.tag) { |
| 115 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), | 118 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), |
| | 119 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), |
| 116 | .c => {}, | 120 | .c => {}, |
| 117 | } | 121 | } |
| 118 | } | 122 | } |
| ... | @@ -120,6 +124,7 @@ pub const File = struct { | ... | @@ -120,6 +124,7 @@ pub const File = struct { |
| 120 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { | 124 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { |
| 121 | switch (base.tag) { | 125 | switch (base.tag) { |
| 122 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), | 126 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), |
| | 127 | .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), |
| 123 | .c => {}, | 128 | .c => {}, |
| 124 | } | 129 | } |
| 125 | } | 130 | } |
| ... | @@ -128,6 +133,7 @@ pub const File = struct { | ... | @@ -128,6 +133,7 @@ pub const File = struct { |
| 128 | if (base.file) |f| f.close(); | 133 | if (base.file) |f| f.close(); |
| 129 | switch (base.tag) { | 134 | switch (base.tag) { |
| 130 | .elf => @fieldParentPtr(Elf, "base", base).deinit(), | 135 | .elf => @fieldParentPtr(Elf, "base", base).deinit(), |
| | 136 | .macho => @fieldParentPtr(MachO, "base", base).deinit(), |
| 131 | .c => @fieldParentPtr(C, "base", base).deinit(), | 137 | .c => @fieldParentPtr(C, "base", base).deinit(), |
| 132 | } | 138 | } |
| 133 | } | 139 | } |
| ... | @@ -139,6 +145,11 @@ pub const File = struct { | ... | @@ -139,6 +145,11 @@ pub const File = struct { |
| 139 | parent.deinit(); | 145 | parent.deinit(); |
| 140 | base.allocator.destroy(parent); | 146 | base.allocator.destroy(parent); |
| 141 | }, | 147 | }, |
| | 148 | .macho => { |
| | 149 | const parent = @fieldParentPtr(MachO, "base", base); |
| | 150 | parent.deinit(); |
| | 151 | base.allocator.destroy(parent); |
| | 152 | }, |
| 142 | .c => { | 153 | .c => { |
| 143 | const parent = @fieldParentPtr(C, "base", base); | 154 | const parent = @fieldParentPtr(C, "base", base); |
| 144 | parent.deinit(); | 155 | parent.deinit(); |
| ... | @@ -153,6 +164,7 @@ pub const File = struct { | ... | @@ -153,6 +164,7 @@ pub const File = struct { |
| 153 | | 164 | |
| 154 | try switch (base.tag) { | 165 | try switch (base.tag) { |
| 155 | .elf => @fieldParentPtr(Elf, "base", base).flush(), | 166 | .elf => @fieldParentPtr(Elf, "base", base).flush(), |
| | 167 | .macho => @fieldParentPtr(MachO, "base", base).flush(), |
| 156 | .c => @fieldParentPtr(C, "base", base).flush(), | 168 | .c => @fieldParentPtr(C, "base", base).flush(), |
| 157 | }; | 169 | }; |
| 158 | } | 170 | } |
| ... | @@ -160,6 +172,7 @@ pub const File = struct { | ... | @@ -160,6 +172,7 @@ pub const File = struct { |
| 160 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { | 172 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { |
| 161 | switch (base.tag) { | 173 | switch (base.tag) { |
| 162 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), | 174 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), |
| | 175 | .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl), |
| 163 | .c => unreachable, | 176 | .c => unreachable, |
| 164 | } | 177 | } |
| 165 | } | 178 | } |
| ... | @@ -167,6 +180,7 @@ pub const File = struct { | ... | @@ -167,6 +180,7 @@ pub const File = struct { |
| 167 | pub fn errorFlags(base: *File) ErrorFlags { | 180 | pub fn errorFlags(base: *File) ErrorFlags { |
| 168 | return switch (base.tag) { | 181 | return switch (base.tag) { |
| 169 | .elf => @fieldParentPtr(Elf, "base", base).error_flags, | 182 | .elf => @fieldParentPtr(Elf, "base", base).error_flags, |
| | 183 | .macho => @fieldParentPtr(MachO, "base", base).error_flags, |
| 170 | .c => return .{ .no_entry_point_found = false }, | 184 | .c => return .{ .no_entry_point_found = false }, |
| 171 | }; | 185 | }; |
| 172 | } | 186 | } |
| ... | @@ -180,12 +194,14 @@ pub const File = struct { | ... | @@ -180,12 +194,14 @@ pub const File = struct { |
| 180 | ) !void { | 194 | ) !void { |
| 181 | switch (base.tag) { | 195 | switch (base.tag) { |
| 182 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), | 196 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), |
| | 197 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl, exports), |
| 183 | .c => return {}, | 198 | .c => return {}, |
| 184 | } | 199 | } |
| 185 | } | 200 | } |
| 186 | | 201 | |
| 187 | pub const Tag = enum { | 202 | pub const Tag = enum { |
| 188 | elf, | 203 | elf, |
| | 204 | macho, |
| 189 | c, | 205 | c, |
| 190 | }; | 206 | }; |
| 191 | | 207 | |
| ... | @@ -2815,6 +2831,100 @@ pub const File = struct { | ... | @@ -2815,6 +2831,100 @@ pub const File = struct { |
| 2815 | } | 2831 | } |
| 2816 | | 2832 | |
| 2817 | }; | 2833 | }; |
| | 2834 | |
| | 2835 | pub const MachO = struct { |
| | 2836 | pub const base_tag: Tag = .macho; |
| | 2837 | |
| | 2838 | base: File, |
| | 2839 | |
| | 2840 | ptr_width: enum { p32, p64 }, |
| | 2841 | |
| | 2842 | error_flags: ErrorFlags = ErrorFlags{}, |
| | 2843 | |
| | 2844 | pub const TextBlock = struct { |
| | 2845 | pub const empty = TextBlock{}; |
| | 2846 | }; |
| | 2847 | |
| | 2848 | pub const SrcFn = struct { |
| | 2849 | pub const empty = SrcFn{}; |
| | 2850 | }; |
| | 2851 | |
| | 2852 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { |
| | 2853 | assert(options.object_format == .macho); |
| | 2854 | |
| | 2855 | const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) }); |
| | 2856 | errdefer file.close(); |
| | 2857 | |
| | 2858 | var macho_file = try allocator.create(MachO); |
| | 2859 | errdefer allocator.destroy(macho_file); |
| | 2860 | |
| | 2861 | macho_file.* = openFile(allocator, file, options) catch |err| switch (err) { |
| | 2862 | error.IncrFailed => try createFile(allocator, file, options), |
| | 2863 | else => |e| return e, |
| | 2864 | }; |
| | 2865 | |
| | 2866 | return &macho_file.base; |
| | 2867 | } |
| | 2868 | |
| | 2869 | /// Returns error.IncrFailed if incremental update could not be performed. |
| | 2870 | fn openFile(allocator: *Allocator, file: fs.File, options: Options) !MachO { |
| | 2871 | switch (options.output_mode) { |
| | 2872 | .Exe => {}, |
| | 2873 | .Obj => {}, |
| | 2874 | .Lib => return error.IncrFailed, |
| | 2875 | } |
| | 2876 | var self: MachO = .{ |
| | 2877 | .base = .{ |
| | 2878 | .file = file, |
| | 2879 | .tag = .macho, |
| | 2880 | .options = options, |
| | 2881 | .allocator = allocator, |
| | 2882 | }, |
| | 2883 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { |
| | 2884 | 32 => .p32, |
| | 2885 | 64 => .p64, |
| | 2886 | else => return error.UnsupportedELFArchitecture, |
| | 2887 | }, |
| | 2888 | }; |
| | 2889 | errdefer self.deinit(); |
| | 2890 | |
| | 2891 | // TODO implement reading the macho file |
| | 2892 | return error.IncrFailed; |
| | 2893 | //try self.populateMissingMetadata(); |
| | 2894 | //return self; |
| | 2895 | } |
| | 2896 | |
| | 2897 | /// Truncates the existing file contents and overwrites the contents. |
| | 2898 | /// Returns an error if `file` is not already open with +read +write +seek abilities. |
| | 2899 | fn createFile(allocator: *Allocator, file: fs.File, options: Options) !MachO { |
| | 2900 | switch (options.output_mode) { |
| | 2901 | .Exe => return error.TODOImplementWritingMachOExeFiles, |
| | 2902 | .Obj => return error.TODOImplementWritingMachOObjFiles, |
| | 2903 | .Lib => return error.TODOImplementWritingLibFiles, |
| | 2904 | } |
| | 2905 | } |
| | 2906 | |
| | 2907 | /// Commit pending changes and write headers. |
| | 2908 | pub fn flush(self: *MachO) !void {} |
| | 2909 | |
| | 2910 | pub fn deinit(self: *MachO) void {} |
| | 2911 | |
| | 2912 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {} |
| | 2913 | |
| | 2914 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {} |
| | 2915 | |
| | 2916 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} |
| | 2917 | |
| | 2918 | /// Must be called only after a successful call to `updateDecl`. |
| | 2919 | pub fn updateDeclExports( |
| | 2920 | self: *MachO, |
| | 2921 | module: *Module, |
| | 2922 | decl: *const Module.Decl, |
| | 2923 | exports: []const *Module.Export, |
| | 2924 | ) !void {} |
| | 2925 | |
| | 2926 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| | 2927 | }; |
| 2818 | }; | 2928 | }; |
| 2819 | | 2929 | |
| 2820 | /// Saturating multiplication | 2930 | /// Saturating multiplication |