From 17b25885989d5f4f0e87de69f5eb3173553de4bc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 17 May 2021 13:40:35 +0200 Subject: [PATCH] zld: refactor out logic for dylib LC creation --- src/link/MachO.zig | 26 ++++-------------- src/link/MachO/Zld.zig | 55 +++++++++---------------------------- src/link/MachO/commands.zig | 31 +++++++++++++++++++++ 3 files changed, 49 insertions(+), 63 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 759b193acf..6d7f461084 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2096,28 +2096,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { } if (self.libsystem_cmd_index == null) { self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); - const cmdsize = @intCast(u32, mem.alignForwardGeneric( - u64, - @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), - @sizeOf(u64), - )); - // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. - // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. - const min_version = 0x0; - var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ - .cmd = macho.LC_LOAD_DYLIB, - .cmdsize = cmdsize, - .dylib = .{ - .name = @sizeOf(macho.dylib_command), - .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files - .current_version = min_version, - .compatibility_version = min_version, - }, - }); - dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); - mem.set(u8, dylib_cmd.data, 0); - mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); + + var dylib_cmd = try createLoadDylibCommand(self.base.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0); + errdefer dylib_cmd.deinit(self.base.allocator); + try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); + self.header_dirty = true; self.load_commands_dirty = true; } diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 0b1eed8a73..12f3968d53 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -339,26 +339,10 @@ fn parseDylibs(self: *Zld, shared_libs: []const []const u8) !void { try self.dylibs.append(self.allocator, dylib); // Add LC_LOAD_DYLIB command - const cmdsize = @intCast(u32, mem.alignForwardGeneric( - u64, - @sizeOf(macho.dylib_command) + dylib.name.?.len, - @sizeOf(u64), - )); - // TODO Read the min version from the dylib itself. - const min_version = 0x0; - var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ - .cmd = macho.LC_LOAD_DYLIB, - .cmdsize = cmdsize, - .dylib = .{ - .name = @sizeOf(macho.dylib_command), - .timestamp = 2, // TODO parse from the dylib. - .current_version = min_version, - .compatibility_version = min_version, - }, - }); - dylib_cmd.data = try self.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); - mem.set(u8, dylib_cmd.data, 0); - mem.copy(u8, dylib_cmd.data, dylib.name.?); + // TODO Read the timestamp and versions from the dylib itself. + var dylib_cmd = try createLoadDylibCommand(self.allocator, dylib.name.?, 2, 0, 0); + errdefer dylib_cmd.deinit(self.allocator); + try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); } } @@ -2061,27 +2045,10 @@ fn populateMetadata(self: *Zld) !void { if (self.libsystem_cmd_index == null) { self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); - const cmdsize = @intCast(u32, mem.alignForwardGeneric( - u64, - @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), - @sizeOf(u64), - )); - // TODO Find a way to work out runtime version from the OS version triple stored in std.Target. - // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0. - const min_version = 0x0; - var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ - .cmd = macho.LC_LOAD_DYLIB, - .cmdsize = cmdsize, - .dylib = .{ - .name = @sizeOf(macho.dylib_command), - .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files - .current_version = min_version, - .compatibility_version = min_version, - }, - }); - dylib_cmd.data = try self.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); - mem.set(u8, dylib_cmd.data, 0); - mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); + + var dylib_cmd = try createLoadDylibCommand(self.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0); + errdefer dylib_cmd.deinit(self.allocator); + try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); } @@ -2738,11 +2705,15 @@ fn writeSymbolTable(self: *Zld) !void { for (self.imports.items()) |entry| { const sym = entry.value; + const ordinal = ordinal: { + const dylib = sym.cast(Symbol.Proxy).?.dylib orelse break :ordinal 1; // TODO handle libSystem + break :ordinal dylib.ordinal.?; + }; try undefs.append(.{ .n_strx = try self.makeString(sym.name), .n_type = macho.N_UNDF | macho.N_EXT, .n_sect = 0, - .n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, + .n_desc = (ordinal * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY, .n_value = 0, }); } diff --git a/src/link/MachO/commands.zig b/src/link/MachO/commands.zig index a7bd3aa893..6370d89770 100644 --- a/src/link/MachO/commands.zig +++ b/src/link/MachO/commands.zig @@ -298,6 +298,37 @@ pub fn GenericCommandWithData(comptime Cmd: type) type { }; } +pub fn createLoadDylibCommand( + allocator: *Allocator, + name: []const u8, + timestamp: u32, + current_version: u32, + compatibility_version: u32, +) !GenericCommandWithData(macho.dylib_command) { + const cmdsize = @intCast(u32, mem.alignForwardGeneric( + u64, + @sizeOf(macho.dylib_command) + name.len, + @sizeOf(u64), + )); + + var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ + .cmd = macho.LC_LOAD_DYLIB, + .cmdsize = cmdsize, + .dylib = .{ + .name = @sizeOf(macho.dylib_command), + .timestamp = timestamp, + .current_version = current_version, + .compatibility_version = compatibility_version, + }, + }); + dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); + + mem.set(u8, dylib_cmd.data, 0); + mem.copy(u8, dylib_cmd.data, name); + + return dylib_cmd; +} + fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void { var stream = io.fixedBufferStream(buffer); var given = try LoadCommand.read(allocator, stream.reader());