zld: parse dylib id

This commit is contained in:
Jakub Konka
2021-05-17 14:28:49 +02:00
parent 17b2588598
commit 73c015b956
3 changed files with 88 additions and 2 deletions

View File

@@ -71,6 +71,38 @@ pub const source_version_command = extern struct {
version: u64,
};
/// The build_version_command contains the min OS version on which this
/// binary was built to run for its platform. The list of known platforms and
/// tool values following it.
pub const build_version_command = extern struct {
/// LC_BUILD_VERSION
cmd: u32,
/// sizeof(struct build_version_command) plus
/// ntools * sizeof(struct build_version_command)
cmdsize: u32,
/// platform
platform: u32,
/// X.Y.Z is encoded in nibbles xxxx.yy.zz
minos: u32,
/// X.Y.Z is encoded in nibbles xxxx.yy.zz
sdk: u32,
/// number of tool entries following this
ntools: u32,
};
pub const build_tool_version = extern struct {
/// enum for the tool
tool: u32,
/// version number of the tool
version: u32,
};
/// The entry_point_command is a replacement for thread_command.
/// It is used for main executables to specify the location (file offset)
/// of main(). If -stack_size was used at link time, the stacksize

View File

@@ -23,9 +23,23 @@ load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
symtab_cmd_index: ?u16 = null,
dysymtab_cmd_index: ?u16 = null,
id_cmd_index: ?u16 = null,
id: ?Id = null,
symbols: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
pub const Id = struct {
name: []const u8,
timestamp: u32,
current_version: u32,
compatibility_version: u32,
pub fn deinit(id: *Id, allocator: *Allocator) void {
allocator.free(id.name);
}
};
pub fn init(allocator: *Allocator) Dylib {
return .{ .allocator = allocator };
}
@@ -45,6 +59,10 @@ pub fn deinit(self: *Dylib) void {
if (self.name) |name| {
self.allocator.free(name);
}
if (self.id) |*id| {
id.deinit(self.allocator);
}
}
pub fn closeFile(self: Dylib) void {
@@ -78,6 +96,7 @@ pub fn parse(self: *Dylib) !void {
}
try self.readLoadCommands(reader);
try self.parseId();
try self.parseSymbols();
}
@@ -94,6 +113,9 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
macho.LC_DYSYMTAB => {
self.dysymtab_cmd_index = i;
},
macho.LC_ID_DYLIB => {
self.id_cmd_index = i;
},
else => {
log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
},
@@ -102,6 +124,32 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
}
}
pub fn parseId(self: *Dylib) !void {
const index = self.id_cmd_index orelse {
log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
self.id = .{
.name = try self.allocator.dupe(u8, self.name.?),
.timestamp = 2,
.current_version = 0,
.compatibility_version = 0,
};
return;
};
const id_cmd = self.load_commands.items[index].Dylib;
const dylib = id_cmd.inner.dylib;
// TODO should we compare the name from the dylib's id with the user-specified one?
const dylib_name = @ptrCast([*:0]const u8, id_cmd.data[dylib.name - @sizeOf(macho.dylib_command) ..]);
const name = try self.allocator.dupe(u8, mem.spanZ(dylib_name));
self.id = .{
.name = name,
.timestamp = dylib.timestamp,
.current_version = dylib.current_version,
.compatibility_version = dylib.compatibility_version,
};
}
pub fn parseSymbols(self: *Dylib) !void {
const index = self.symtab_cmd_index orelse return;
const symtab_cmd = self.load_commands.items[index].Symtab;

View File

@@ -339,8 +339,14 @@ fn parseDylibs(self: *Zld, shared_libs: []const []const u8) !void {
try self.dylibs.append(self.allocator, dylib);
// Add LC_LOAD_DYLIB command
// TODO Read the timestamp and versions from the dylib itself.
var dylib_cmd = try createLoadDylibCommand(self.allocator, dylib.name.?, 2, 0, 0);
const dylib_id = dylib.id orelse unreachable;
var dylib_cmd = try createLoadDylibCommand(
self.allocator,
dylib_id.name,
dylib_id.timestamp,
dylib_id.current_version,
dylib_id.compatibility_version,
);
errdefer dylib_cmd.deinit(self.allocator);
try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });