aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-06-24 22:19:44 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-06-24 22:19:44 +0200
commitad0be7857745613f53d3902c86d54401bb72696c (patch)
treebee04eee57f4156e01f60fb02fe39788ff19be56 /src
parent5e0e7b2cb4b568e244a4b0b4eb51d8faeb3fb226 (diff)
downloadzig-ad0be7857745613f53d3902c86d54401bb72696c.tar.gz
zig-ad0be7857745613f53d3902c86d54401bb72696c.zip
zld: parse dylib's id from tbd
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO/Dylib.zig91
-rw-r--r--src/link/tapi.zig5
2 files changed, 82 insertions, 14 deletions
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index 56ad7107d5..737c83f2f9 100644
--- a/src/link/MachO/Dylib.zig
+++ b/src/link/MachO/Dylib.zig
@@ -3,8 +3,10 @@ const Dylib = @This();
const std = @import("std");
const assert = std.debug.assert;
const fs = std.fs;
+const fmt = std.fmt;
const log = std.log.scoped(.dylib);
const macho = std.macho;
+const math = std.math;
const mem = std.mem;
const Allocator = mem.Allocator;
@@ -37,6 +39,7 @@ id: ?Id = null,
/// a symbol is referenced by an object file.
symbols: std.StringArrayHashMapUnmanaged(void) = .{},
+// TODO add parsing re-exported libs from binary dylibs
dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
pub const Id = struct {
@@ -45,9 +48,72 @@ pub const Id = struct {
current_version: u32,
compatibility_version: u32,
+ pub fn default(name: []const u8) Id {
+ return .{
+ .name = name,
+ .timestamp = 2,
+ .current_version = 0x10000,
+ .compatibility_version = 0x10000,
+ };
+ }
+
pub fn deinit(id: *Id, allocator: *Allocator) void {
allocator.free(id.name);
}
+
+ const ParseError = fmt.ParseIntError || fmt.BufPrintError;
+
+ pub fn parseCurrentVersion(id: *Id, version: anytype) ParseError!void {
+ id.current_version = try parseVersion(version);
+ }
+
+ pub fn parseCompatibilityVersion(id: *Id, version: anytype) ParseError!void {
+ id.compatibility_version = try parseVersion(version);
+ }
+
+ fn parseVersion(version: anytype) ParseError!u32 {
+ const string = blk: {
+ switch (version) {
+ .int => |int| {
+ var out: u32 = 0;
+ const major = try math.cast(u16, int);
+ out += @intCast(u32, major) << 16;
+ return out;
+ },
+ .float => |float| {
+ var buf: [256]u8 = undefined;
+ break :blk try fmt.bufPrint(&buf, "{d:.2}", .{float});
+ },
+ .string => |string| {
+ break :blk string;
+ },
+ }
+ };
+
+ var out: u32 = 0;
+ var values: [3][]const u8 = undefined;
+
+ var split = mem.split(string, ".");
+ var i: u4 = 0;
+ while (split.next()) |value| {
+ if (i > 2) {
+ log.warn("malformed version field: {s}", .{string});
+ return 0x10000;
+ }
+ values[i] = value;
+ i += 1;
+ }
+
+ if (values.len > 2) {
+ out += try fmt.parseInt(u8, values[2], 10);
+ }
+ if (values.len > 1) {
+ out += @intCast(u32, try fmt.parseInt(u8, values[1], 10)) << 8;
+ }
+ out += @intCast(u32, try fmt.parseInt(u16, values[0], 10)) << 16;
+
+ return out;
+ }
};
pub const Error = error{
@@ -55,7 +121,7 @@ pub const Error = error{
EmptyStubFile,
MismatchedCpuArchitecture,
UnsupportedCpuArchitecture,
-} || fs.File.OpenError || std.os.PReadError;
+} || fs.File.OpenError || std.os.PReadError || Id.ParseError;
pub fn createAndParseFromPath(
allocator: *Allocator,
@@ -195,12 +261,7 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void {
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,
- };
+ self.id = Id.default(try self.allocator.dupe(u8, self.name.?));
return;
};
const id_cmd = self.load_commands.items[index].Dylib;
@@ -266,13 +327,15 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
log.debug("parsing shared library from stub '{s}'", .{self.name.?});
const umbrella_lib = lib_stub.inner[0];
- self.id = .{
- .name = try self.allocator.dupe(u8, umbrella_lib.install_name),
- // TODO parse from the stub
- .timestamp = 2,
- .current_version = 0,
- .compatibility_version = 0,
- };
+
+ var id = Id.default(try self.allocator.dupe(u8, umbrella_lib.install_name));
+ if (umbrella_lib.current_version) |version| {
+ try id.parseCurrentVersion(version);
+ }
+ if (umbrella_lib.compatibility_version) |version| {
+ try id.parseCompatibilityVersion(version);
+ }
+ self.id = id;
const target_string: []const u8 = switch (self.arch.?) {
.aarch64 => "arm64-macos",
diff --git a/src/link/tapi.zig b/src/link/tapi.zig
index dc696577e8..35193b0eec 100644
--- a/src/link/tapi.zig
+++ b/src/link/tapi.zig
@@ -26,6 +26,11 @@ pub const LibStub = struct {
float: f64,
int: u64,
},
+ compatibility_version: ?union(enum) {
+ string: []const u8,
+ float: f64,
+ int: u64,
+ },
reexported_libraries: ?[]const struct {
targets: []const []const u8,
libraries: []const []const u8,