authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 22:19:44+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 22:19:44+02:00
logad0be7857745613f53d3902c86d54401bb72696c
treebee04eee57f4156e01f60fb02fe39788ff19be56
parent5e0e7b2cb4b568e244a4b0b4eb51d8faeb3fb226

zld: parse dylib's id from tbd


2 files changed, 82 insertions(+), 14 deletions(-)

src/link/MachO/Dylib.zig+77-14
...@@ -3,8 +3,10 @@ const Dylib = @This();...@@ -3,8 +3,10 @@ const Dylib = @This();
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const fs = std.fs;5const fs = std.fs;
6const fmt = std.fmt;
6const log = std.log.scoped(.dylib);7const log = std.log.scoped(.dylib);
7const macho = std.macho;8const macho = std.macho;
9const math = std.math;
8const mem = std.mem;10const mem = std.mem;
911
10const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
...@@ -37,6 +39,7 @@ id: ?Id = null,...@@ -37,6 +39,7 @@ id: ?Id = null,
37/// a symbol is referenced by an object file.39/// a symbol is referenced by an object file.
38symbols: std.StringArrayHashMapUnmanaged(void) = .{},40symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3941
42// TODO add parsing re-exported libs from binary dylibs
40dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},43dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
4144
42pub const Id = struct {45pub const Id = struct {
...@@ -45,9 +48,72 @@ pub const Id = struct {...@@ -45,9 +48,72 @@ pub const Id = struct {
45 current_version: u32,48 current_version: u32,
46 compatibility_version: u32,49 compatibility_version: u32,
4750
51 pub fn default(name: []const u8) Id {
52 return .{
53 .name = name,
54 .timestamp = 2,
55 .current_version = 0x10000,
56 .compatibility_version = 0x10000,
57 };
58 }
59
48 pub fn deinit(id: *Id, allocator: *Allocator) void {60 pub fn deinit(id: *Id, allocator: *Allocator) void {
49 allocator.free(id.name);61 allocator.free(id.name);
50 }62 }
63
64 const ParseError = fmt.ParseIntError || fmt.BufPrintError;
65
66 pub fn parseCurrentVersion(id: *Id, version: anytype) ParseError!void {
67 id.current_version = try parseVersion(version);
68 }
69
70 pub fn parseCompatibilityVersion(id: *Id, version: anytype) ParseError!void {
71 id.compatibility_version = try parseVersion(version);
72 }
73
74 fn parseVersion(version: anytype) ParseError!u32 {
75 const string = blk: {
76 switch (version) {
77 .int => |int| {
78 var out: u32 = 0;
79 const major = try math.cast(u16, int);
80 out += @intCast(u32, major) << 16;
81 return out;
82 },
83 .float => |float| {
84 var buf: [256]u8 = undefined;
85 break :blk try fmt.bufPrint(&buf, "{d:.2}", .{float});
86 },
87 .string => |string| {
88 break :blk string;
89 },
90 }
91 };
92
93 var out: u32 = 0;
94 var values: [3][]const u8 = undefined;
95
96 var split = mem.split(string, ".");
97 var i: u4 = 0;
98 while (split.next()) |value| {
99 if (i > 2) {
100 log.warn("malformed version field: {s}", .{string});
101 return 0x10000;
102 }
103 values[i] = value;
104 i += 1;
105 }
106
107 if (values.len > 2) {
108 out += try fmt.parseInt(u8, values[2], 10);
109 }
110 if (values.len > 1) {
111 out += @intCast(u32, try fmt.parseInt(u8, values[1], 10)) << 8;
112 }
113 out += @intCast(u32, try fmt.parseInt(u16, values[0], 10)) << 16;
114
115 return out;
116 }
51};117};
52118
53pub const Error = error{119pub const Error = error{
...@@ -55,7 +121,7 @@ pub const Error = error{...@@ -55,7 +121,7 @@ pub const Error = error{
55 EmptyStubFile,121 EmptyStubFile,
56 MismatchedCpuArchitecture,122 MismatchedCpuArchitecture,
57 UnsupportedCpuArchitecture,123 UnsupportedCpuArchitecture,
58} || fs.File.OpenError || std.os.PReadError;124} || fs.File.OpenError || std.os.PReadError || Id.ParseError;
59125
60pub fn createAndParseFromPath(126pub fn createAndParseFromPath(
61 allocator: *Allocator,127 allocator: *Allocator,
...@@ -195,12 +261,7 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void {...@@ -195,12 +261,7 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void {
195fn parseId(self: *Dylib) !void {261fn parseId(self: *Dylib) !void {
196 const index = self.id_cmd_index orelse {262 const index = self.id_cmd_index orelse {
197 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});263 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
198 self.id = .{264 self.id = Id.default(try self.allocator.dupe(u8, self.name.?));
199 .name = try self.allocator.dupe(u8, self.name.?),
200 .timestamp = 2,
201 .current_version = 0,
202 .compatibility_version = 0,
203 };
204 return;265 return;
205 };266 };
206 const id_cmd = self.load_commands.items[index].Dylib;267 const id_cmd = self.load_commands.items[index].Dylib;
...@@ -266,13 +327,15 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {...@@ -266,13 +327,15 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
266 log.debug("parsing shared library from stub '{s}'", .{self.name.?});327 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
267328
268 const umbrella_lib = lib_stub.inner[0];329 const umbrella_lib = lib_stub.inner[0];
269 self.id = .{330
270 .name = try self.allocator.dupe(u8, umbrella_lib.install_name),331 var id = Id.default(try self.allocator.dupe(u8, umbrella_lib.install_name));
271 // TODO parse from the stub332 if (umbrella_lib.current_version) |version| {
272 .timestamp = 2,333 try id.parseCurrentVersion(version);
273 .current_version = 0,334 }
274 .compatibility_version = 0,335 if (umbrella_lib.compatibility_version) |version| {
275 };336 try id.parseCompatibilityVersion(version);
337 }
338 self.id = id;
276339
277 const target_string: []const u8 = switch (self.arch.?) {340 const target_string: []const u8 = switch (self.arch.?) {
278 .aarch64 => "arm64-macos",341 .aarch64 => "arm64-macos",
src/link/tapi.zig+5
...@@ -26,6 +26,11 @@ pub const LibStub = struct {...@@ -26,6 +26,11 @@ pub const LibStub = struct {
26 float: f64,26 float: f64,
27 int: u64,27 int: u64,
28 },28 },
29 compatibility_version: ?union(enum) {
30 string: []const u8,
31 float: f64,
32 int: u64,
33 },
29 reexported_libraries: ?[]const struct {34 reexported_libraries: ?[]const struct {
30 targets: []const []const u8,35 targets: []const []const u8,
31 libraries: []const []const u8,36 libraries: []const []const u8,