zld: parse dylib id
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 });
|
||||
|
||||
Reference in New Issue
Block a user