Commit 73c015b956
lib/std/macho.zig
@@ -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
src/link/MachO/Dylib.zig
@@ -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;
src/link/MachO/Zld.zig
@@ -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 });