| author | |
| committer | |
| log | 06396ddd7d632704681bbd6278f18dcc2b6bf20c |
| tree | 068f069096fe341c19a63e0de66e52c19e22ad5b |
| parent | e73777333dd66570ddacdb7de56a390de01b33c5 |
instead, ownership is transferred to MachO. This makes Object
management align closer with data-oriented design.3 files changed, 46 insertions(+), 56 deletions(-)
src/link/MachO.zig+17-15| ... | @@ -61,7 +61,7 @@ header_pad: u16 = 0x1000, | ... | @@ -61,7 +61,7 @@ header_pad: u16 = 0x1000, |
| 61 | /// The absolute address of the entry point. | 61 | /// The absolute address of the entry point. |
| 62 | entry_addr: ?u64 = null, | 62 | entry_addr: ?u64 = null, |
| 63 | 63 | ||
| 64 | objects: std.ArrayListUnmanaged(*Object) = .{}, | 64 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 65 | archives: std.ArrayListUnmanaged(*Archive) = .{}, | 65 | archives: std.ArrayListUnmanaged(*Archive) = .{}, |
| 66 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, | 66 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, |
| 67 | 67 | ||
| ... | @@ -990,13 +990,19 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const | ... | @@ -990,13 +990,19 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 990 | const arch = self.base.options.target.cpu.arch; | 990 | const arch = self.base.options.target.cpu.arch; |
| 991 | for (files) |file_name| { | 991 | for (files) |file_name| { |
| 992 | const full_path = full_path: { | 992 | const full_path = full_path: { |
| 993 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 993 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; |
| 994 | const path = try std.fs.realpath(file_name, &buffer); | 994 | const path = try std.fs.realpath(file_name, &buffer); |
| 995 | break :full_path try self.base.allocator.dupe(u8, path); | 995 | break :full_path try self.base.allocator.dupe(u8, path); |
| 996 | }; | 996 | }; |
| 997 | const file = try fs.cwd().openFile(full_path, .{}); | ||
| 997 | 998 | ||
| 998 | if (try Object.createAndParseFromPath(self.base.allocator, arch, full_path)) |object| { | 999 | if (try Object.isObject(file)) { |
| 999 | try self.objects.append(self.base.allocator, object); | 1000 | const object = try self.objects.addOne(self.base.allocator); |
| 1001 | object.* = .{ | ||
| 1002 | .name = full_path, | ||
| 1003 | .file = file, | ||
| 1004 | }; | ||
| 1005 | try object.parse(self.base.allocator, arch); | ||
| 1000 | continue; | 1006 | continue; |
| 1001 | } | 1007 | } |
| 1002 | 1008 | ||
| ... | @@ -1993,7 +1999,7 @@ fn writeStubHelperCommon(self: *MachO) !void { | ... | @@ -1993,7 +1999,7 @@ fn writeStubHelperCommon(self: *MachO) !void { |
| 1993 | } | 1999 | } |
| 1994 | 2000 | ||
| 1995 | fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { | 2001 | fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 1996 | const object = self.objects.items[object_id]; | 2002 | const object = &self.objects.items[object_id]; |
| 1997 | 2003 | ||
| 1998 | log.debug("resolving symbols in '{s}'", .{object.name}); | 2004 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| 1999 | 2005 | ||
| ... | @@ -2228,13 +2234,10 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2228,13 +2234,10 @@ fn resolveSymbols(self: *MachO) !void { |
| 2228 | }; | 2234 | }; |
| 2229 | assert(offsets.items.len > 0); | 2235 | assert(offsets.items.len > 0); |
| 2230 | 2236 | ||
| 2231 | const object = try archive.parseObject( | ||
| 2232 | self.base.allocator, | ||
| 2233 | self.base.options.target.cpu.arch, | ||
| 2234 | offsets.items[0], | ||
| 2235 | ); | ||
| 2236 | const object_id = @intCast(u16, self.objects.items.len); | 2237 | const object_id = @intCast(u16, self.objects.items.len); |
| 2237 | try self.objects.append(self.base.allocator, object); | 2238 | const object = try self.objects.addOne(self.base.allocator); |
| 2239 | object.* = try archive.extractObject(self.base.allocator, offsets.items[0]); | ||
| 2240 | try object.parse(self.base.allocator, self.base.options.target.cpu.arch); | ||
| 2238 | try self.resolveSymbolsInObject(object_id); | 2241 | try self.resolveSymbolsInObject(object_id); |
| 2239 | 2242 | ||
| 2240 | continue :loop; | 2243 | continue :loop; |
| ... | @@ -2460,8 +2463,8 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2460,8 +2463,8 @@ fn resolveSymbols(self: *MachO) !void { |
| 2460 | } | 2463 | } |
| 2461 | 2464 | ||
| 2462 | fn parseTextBlocks(self: *MachO) !void { | 2465 | fn parseTextBlocks(self: *MachO) !void { |
| 2463 | for (self.objects.items) |object| { | 2466 | for (self.objects.items) |*object, object_id| { |
| 2464 | try object.parseTextBlocks(self.base.allocator, self); | 2467 | try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self); |
| 2465 | } | 2468 | } |
| 2466 | } | 2469 | } |
| 2467 | 2470 | ||
| ... | @@ -3337,9 +3340,8 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3337,9 +3340,8 @@ pub fn deinit(self: *MachO) void { |
| 3337 | self.locals_free_list.deinit(self.base.allocator); | 3340 | self.locals_free_list.deinit(self.base.allocator); |
| 3338 | self.symbol_resolver.deinit(self.base.allocator); | 3341 | self.symbol_resolver.deinit(self.base.allocator); |
| 3339 | 3342 | ||
| 3340 | for (self.objects.items) |object| { | 3343 | for (self.objects.items) |*object| { |
| 3341 | object.deinit(self.base.allocator); | 3344 | object.deinit(self.base.allocator); |
| 3342 | self.base.allocator.destroy(object); | ||
| 3343 | } | 3345 | } |
| 3344 | self.objects.deinit(self.base.allocator); | 3346 | self.objects.deinit(self.base.allocator); |
| 3345 | 3347 |
src/link/MachO/Archive.zig+3-7| ... | @@ -223,8 +223,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype) | ... | @@ -223,8 +223,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype) |
| 223 | } | 223 | } |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | /// Caller owns the Object instance. | 226 | pub fn extractObject(self: Archive, allocator: *Allocator, offset: u32) !Object { |
| 227 | pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32) !*Object { | ||
| 228 | var reader = self.file.reader(); | 227 | var reader = self.file.reader(); |
| 229 | try reader.context.seekTo(offset + self.library_offset); | 228 | try reader.context.seekTo(offset + self.library_offset); |
| 230 | 229 | ||
| ... | @@ -246,16 +245,13 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32 | ... | @@ -246,16 +245,13 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32 |
| 246 | break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name }); | 245 | break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name }); |
| 247 | }; | 246 | }; |
| 248 | 247 | ||
| 249 | var object = try allocator.create(Object); | 248 | var object = Object{ |
| 250 | errdefer allocator.destroy(object); | ||
| 251 | |||
| 252 | object.* = .{ | ||
| 253 | .file = try fs.cwd().openFile(self.name, .{}), | 249 | .file = try fs.cwd().openFile(self.name, .{}), |
| 254 | .name = name, | 250 | .name = name, |
| 255 | .file_offset = @intCast(u32, try reader.context.getPos()), | 251 | .file_offset = @intCast(u32, try reader.context.getPos()), |
| 256 | .mtime = try self.header.?.date(), | 252 | .mtime = try self.header.?.date(), |
| 257 | }; | 253 | }; |
| 258 | try object.parse(allocator, arch); | 254 | |
| 259 | try reader.context.seekTo(0); | 255 | try reader.context.seekTo(0); |
| 260 | 256 | ||
| 261 | return object; | 257 | return object; |
src/link/MachO/Object.zig+26-34| ... | @@ -127,36 +127,6 @@ const DebugInfo = struct { | ... | @@ -127,36 +127,6 @@ const DebugInfo = struct { |
| 127 | } | 127 | } |
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object { | ||
| 131 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | ||
| 132 | error.FileNotFound => return null, | ||
| 133 | else => |e| return e, | ||
| 134 | }; | ||
| 135 | errdefer file.close(); | ||
| 136 | |||
| 137 | const object = try allocator.create(Object); | ||
| 138 | errdefer allocator.destroy(object); | ||
| 139 | |||
| 140 | const name = try allocator.dupe(u8, path); | ||
| 141 | errdefer allocator.free(name); | ||
| 142 | |||
| 143 | object.* = .{ | ||
| 144 | .name = name, | ||
| 145 | .file = file, | ||
| 146 | }; | ||
| 147 | |||
| 148 | object.parse(allocator, arch) catch |err| switch (err) { | ||
| 149 | error.EndOfStream, error.NotObject => { | ||
| 150 | object.deinit(allocator); | ||
| 151 | allocator.destroy(object); | ||
| 152 | return null; | ||
| 153 | }, | ||
| 154 | else => |e| return e, | ||
| 155 | }; | ||
| 156 | |||
| 157 | return object; | ||
| 158 | } | ||
| 159 | |||
| 160 | pub fn deinit(self: *Object, allocator: *Allocator) void { | 130 | pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 161 | for (self.load_commands.items) |*lc| { | 131 | for (self.load_commands.items) |*lc| { |
| 162 | lc.deinit(allocator); | 132 | lc.deinit(allocator); |
| ... | @@ -184,6 +154,22 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { | ... | @@ -184,6 +154,22 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 184 | } | 154 | } |
| 185 | } | 155 | } |
| 186 | 156 | ||
| 157 | pub fn isObject(file: fs.File) !bool { | ||
| 158 | const reader = file.reader(); | ||
| 159 | const is_object = blk: { | ||
| 160 | if (reader.readStruct(macho.mach_header_64)) |header| { | ||
| 161 | break :blk header.filetype == macho.MH_OBJECT; | ||
| 162 | } else |err| { | ||
| 163 | switch (err) { | ||
| 164 | error.EndOfStream => break :blk false, | ||
| 165 | else => |e| return e, | ||
| 166 | } | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | try file.seekTo(0); | ||
| 170 | return is_object; | ||
| 171 | } | ||
| 172 | |||
| 187 | pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { | 173 | pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 188 | var reader = self.file.reader(); | 174 | var reader = self.file.reader(); |
| 189 | if (self.file_offset) |offset| { | 175 | if (self.file_offset) |offset| { |
| ... | @@ -481,7 +467,12 @@ const TextBlockParser = struct { | ... | @@ -481,7 +467,12 @@ const TextBlockParser = struct { |
| 481 | } | 467 | } |
| 482 | }; | 468 | }; |
| 483 | 469 | ||
| 484 | pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) !void { | 470 | pub fn parseTextBlocks( |
| 471 | self: *Object, | ||
| 472 | allocator: *Allocator, | ||
| 473 | object_id: u16, | ||
| 474 | macho_file: *MachO, | ||
| 475 | ) !void { | ||
| 485 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 476 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 486 | 477 | ||
| 487 | log.debug("analysing {s}", .{self.name}); | 478 | log.debug("analysing {s}", .{self.name}); |
| ... | @@ -668,13 +659,14 @@ pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) | ... | @@ -668,13 +659,14 @@ pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) |
| 668 | if (is_ext) { | 659 | if (is_ext) { |
| 669 | if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| { | 660 | if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| { |
| 670 | assert(resolv.where == .global); | 661 | assert(resolv.where == .global); |
| 671 | const global_object = macho_file.objects.items[resolv.file]; | 662 | if (resolv.file != object_id) { |
| 672 | if (global_object != self) { | ||
| 673 | log.debug("deduping definition of {s} in {s}", .{ | 663 | log.debug("deduping definition of {s} in {s}", .{ |
| 674 | macho_file.getString(sym.n_strx), | 664 | macho_file.getString(sym.n_strx), |
| 675 | self.name, | 665 | self.name, |
| 676 | }); | 666 | }); |
| 677 | log.debug(" already defined in {s}", .{global_object.name}); | 667 | log.debug(" already defined in {s}", .{ |
| 668 | macho_file.objects.items[resolv.file].name, | ||
| 669 | }); | ||
| 678 | continue; | 670 | continue; |
| 679 | } | 671 | } |
| 680 | } | 672 | } |