aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-07-31 15:01:37 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-08-01 09:06:56 +0200
commit06396ddd7d632704681bbd6278f18dcc2b6bf20c (patch)
tree068f069096fe341c19a63e0de66e52c19e22ad5b /src/link
parente73777333dd66570ddacdb7de56a390de01b33c5 (diff)
downloadzig-06396ddd7d632704681bbd6278f18dcc2b6bf20c.tar.gz
zig-06396ddd7d632704681bbd6278f18dcc2b6bf20c.zip
macho: don't allocate Objects on the heap
instead, ownership is transferred to MachO. This makes Object management align closer with data-oriented design.
Diffstat (limited to 'src/link')
-rw-r--r--src/link/MachO.zig32
-rw-r--r--src/link/MachO/Archive.zig10
-rw-r--r--src/link/MachO/Object.zig60
3 files changed, 46 insertions, 56 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index aba45b6bd4..e13fc9b91c 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -61,7 +61,7 @@ header_pad: u16 = 0x1000,
/// The absolute address of the entry point.
entry_addr: ?u64 = null,
-objects: std.ArrayListUnmanaged(*Object) = .{},
+objects: std.ArrayListUnmanaged(Object) = .{},
archives: std.ArrayListUnmanaged(*Archive) = .{},
dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
@@ -990,13 +990,19 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
const arch = self.base.options.target.cpu.arch;
for (files) |file_name| {
const full_path = full_path: {
- var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
const path = try std.fs.realpath(file_name, &buffer);
break :full_path try self.base.allocator.dupe(u8, path);
};
+ const file = try fs.cwd().openFile(full_path, .{});
- if (try Object.createAndParseFromPath(self.base.allocator, arch, full_path)) |object| {
- try self.objects.append(self.base.allocator, object);
+ if (try Object.isObject(file)) {
+ const object = try self.objects.addOne(self.base.allocator);
+ object.* = .{
+ .name = full_path,
+ .file = file,
+ };
+ try object.parse(self.base.allocator, arch);
continue;
}
@@ -1993,7 +1999,7 @@ fn writeStubHelperCommon(self: *MachO) !void {
}
fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
- const object = self.objects.items[object_id];
+ const object = &self.objects.items[object_id];
log.debug("resolving symbols in '{s}'", .{object.name});
@@ -2228,13 +2234,10 @@ fn resolveSymbols(self: *MachO) !void {
};
assert(offsets.items.len > 0);
- const object = try archive.parseObject(
- self.base.allocator,
- self.base.options.target.cpu.arch,
- offsets.items[0],
- );
const object_id = @intCast(u16, self.objects.items.len);
- try self.objects.append(self.base.allocator, object);
+ const object = try self.objects.addOne(self.base.allocator);
+ object.* = try archive.extractObject(self.base.allocator, offsets.items[0]);
+ try object.parse(self.base.allocator, self.base.options.target.cpu.arch);
try self.resolveSymbolsInObject(object_id);
continue :loop;
@@ -2460,8 +2463,8 @@ fn resolveSymbols(self: *MachO) !void {
}
fn parseTextBlocks(self: *MachO) !void {
- for (self.objects.items) |object| {
- try object.parseTextBlocks(self.base.allocator, self);
+ for (self.objects.items) |*object, object_id| {
+ try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);
}
}
@@ -3337,9 +3340,8 @@ pub fn deinit(self: *MachO) void {
self.locals_free_list.deinit(self.base.allocator);
self.symbol_resolver.deinit(self.base.allocator);
- for (self.objects.items) |object| {
+ for (self.objects.items) |*object| {
object.deinit(self.base.allocator);
- self.base.allocator.destroy(object);
}
self.objects.deinit(self.base.allocator);
diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig
index 228e8f74b9..23d5d259ef 100644
--- a/src/link/MachO/Archive.zig
+++ b/src/link/MachO/Archive.zig
@@ -223,8 +223,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype)
}
}
-/// Caller owns the Object instance.
-pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32) !*Object {
+pub fn extractObject(self: Archive, allocator: *Allocator, offset: u32) !Object {
var reader = self.file.reader();
try reader.context.seekTo(offset + self.library_offset);
@@ -246,16 +245,13 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32
break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
};
- var object = try allocator.create(Object);
- errdefer allocator.destroy(object);
-
- object.* = .{
+ var object = Object{
.file = try fs.cwd().openFile(self.name, .{}),
.name = name,
.file_offset = @intCast(u32, try reader.context.getPos()),
.mtime = try self.header.?.date(),
};
- try object.parse(allocator, arch);
+
try reader.context.seekTo(0);
return object;
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 1250f015ed..6a1bf8fd57 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -127,36 +127,6 @@ const DebugInfo = struct {
}
};
-pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
- const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
- error.FileNotFound => return null,
- else => |e| return e,
- };
- errdefer file.close();
-
- const object = try allocator.create(Object);
- errdefer allocator.destroy(object);
-
- const name = try allocator.dupe(u8, path);
- errdefer allocator.free(name);
-
- object.* = .{
- .name = name,
- .file = file,
- };
-
- object.parse(allocator, arch) catch |err| switch (err) {
- error.EndOfStream, error.NotObject => {
- object.deinit(allocator);
- allocator.destroy(object);
- return null;
- },
- else => |e| return e,
- };
-
- return object;
-}
-
pub fn deinit(self: *Object, allocator: *Allocator) void {
for (self.load_commands.items) |*lc| {
lc.deinit(allocator);
@@ -184,6 +154,22 @@ pub fn deinit(self: *Object, allocator: *Allocator) void {
}
}
+pub fn isObject(file: fs.File) !bool {
+ const reader = file.reader();
+ const is_object = blk: {
+ if (reader.readStruct(macho.mach_header_64)) |header| {
+ break :blk header.filetype == macho.MH_OBJECT;
+ } else |err| {
+ switch (err) {
+ error.EndOfStream => break :blk false,
+ else => |e| return e,
+ }
+ }
+ };
+ try file.seekTo(0);
+ return is_object;
+}
+
pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
var reader = self.file.reader();
if (self.file_offset) |offset| {
@@ -481,7 +467,12 @@ const TextBlockParser = struct {
}
};
-pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO) !void {
+pub fn parseTextBlocks(
+ self: *Object,
+ allocator: *Allocator,
+ object_id: u16,
+ macho_file: *MachO,
+) !void {
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
log.debug("analysing {s}", .{self.name});
@@ -668,13 +659,14 @@ pub fn parseTextBlocks(self: *Object, allocator: *Allocator, macho_file: *MachO)
if (is_ext) {
if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| {
assert(resolv.where == .global);
- const global_object = macho_file.objects.items[resolv.file];
- if (global_object != self) {
+ if (resolv.file != object_id) {
log.debug("deduping definition of {s} in {s}", .{
macho_file.getString(sym.n_strx),
self.name,
});
- log.debug(" already defined in {s}", .{global_object.name});
+ log.debug(" already defined in {s}", .{
+ macho_file.objects.items[resolv.file].name,
+ });
continue;
}
}