zld: refactor out logic for dylib LC creation

This commit is contained in:
Jakub Konka 2021-05-17 13:40:35 +02:00
parent 138cecc028
commit 17b2588598
3 changed files with 49 additions and 63 deletions

View File

@ -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;
}

View File

@ -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,
});
}

View File

@ -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());