authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-17 13:40:35+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-18 09:28:00+02:00
log17b25885989d5f4f0e87de69f5eb3173553de4bc
tree87e1378ce887b74715ed5d24925d1e9313faae63
parent138cecc0283fdc3ec1b4343c15001e2802ed29de

zld: refactor out logic for dylib LC creation


3 files changed, 49 insertions(+), 63 deletions(-)

src/link/MachO.zig+5-21
...@@ -2096,28 +2096,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2096,28 +2096,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
2096 }2096 }
2097 if (self.libsystem_cmd_index == null) {2097 if (self.libsystem_cmd_index == null) {
2098 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);2098 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
2099 const cmdsize = @intCast(u32, mem.alignForwardGeneric(2099
2100 u64,2100 var dylib_cmd = try createLoadDylibCommand(self.base.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0);
2101 @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH),2101 errdefer dylib_cmd.deinit(self.base.allocator);
2102 @sizeOf(u64),2102
2103 ));
2104 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
2105 // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0.
2106 const min_version = 0x0;
2107 var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
2108 .cmd = macho.LC_LOAD_DYLIB,
2109 .cmdsize = cmdsize,
2110 .dylib = .{
2111 .name = @sizeOf(macho.dylib_command),
2112 .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
2113 .current_version = min_version,
2114 .compatibility_version = min_version,
2115 },
2116 });
2117 dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
2118 mem.set(u8, dylib_cmd.data, 0);
2119 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
2120 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });2103 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
2104
2121 self.header_dirty = true;2105 self.header_dirty = true;
2122 self.load_commands_dirty = true;2106 self.load_commands_dirty = true;
2123 }2107 }
src/link/MachO/Zld.zig+13-42
...@@ -339,26 +339,10 @@ fn parseDylibs(self: *Zld, shared_libs: []const []const u8) !void {...@@ -339,26 +339,10 @@ fn parseDylibs(self: *Zld, shared_libs: []const []const u8) !void {
339 try self.dylibs.append(self.allocator, dylib);339 try self.dylibs.append(self.allocator, dylib);
340340
341 // Add LC_LOAD_DYLIB command341 // Add LC_LOAD_DYLIB command
342 const cmdsize = @intCast(u32, mem.alignForwardGeneric(342 // TODO Read the timestamp and versions from the dylib itself.
343 u64,343 var dylib_cmd = try createLoadDylibCommand(self.allocator, dylib.name.?, 2, 0, 0);
344 @sizeOf(macho.dylib_command) + dylib.name.?.len,344 errdefer dylib_cmd.deinit(self.allocator);
345 @sizeOf(u64),345
346 ));
347 // TODO Read the min version from the dylib itself.
348 const min_version = 0x0;
349 var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
350 .cmd = macho.LC_LOAD_DYLIB,
351 .cmdsize = cmdsize,
352 .dylib = .{
353 .name = @sizeOf(macho.dylib_command),
354 .timestamp = 2, // TODO parse from the dylib.
355 .current_version = min_version,
356 .compatibility_version = min_version,
357 },
358 });
359 dylib_cmd.data = try self.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
360 mem.set(u8, dylib_cmd.data, 0);
361 mem.copy(u8, dylib_cmd.data, dylib.name.?);
362 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });346 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
363 }347 }
364}348}
...@@ -2061,27 +2045,10 @@ fn populateMetadata(self: *Zld) !void {...@@ -2061,27 +2045,10 @@ fn populateMetadata(self: *Zld) !void {
20612045
2062 if (self.libsystem_cmd_index == null) {2046 if (self.libsystem_cmd_index == null) {
2063 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);2047 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
2064 const cmdsize = @intCast(u32, mem.alignForwardGeneric(2048
2065 u64,2049 var dylib_cmd = try createLoadDylibCommand(self.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0);
2066 @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH),2050 errdefer dylib_cmd.deinit(self.allocator);
2067 @sizeOf(u64),2051
2068 ));
2069 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
2070 // In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0.
2071 const min_version = 0x0;
2072 var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
2073 .cmd = macho.LC_LOAD_DYLIB,
2074 .cmdsize = cmdsize,
2075 .dylib = .{
2076 .name = @sizeOf(macho.dylib_command),
2077 .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
2078 .current_version = min_version,
2079 .compatibility_version = min_version,
2080 },
2081 });
2082 dylib_cmd.data = try self.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
2083 mem.set(u8, dylib_cmd.data, 0);
2084 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
2085 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });2052 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
2086 }2053 }
20872054
...@@ -2738,11 +2705,15 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2738,11 +2705,15 @@ fn writeSymbolTable(self: *Zld) !void {
27382705
2739 for (self.imports.items()) |entry| {2706 for (self.imports.items()) |entry| {
2740 const sym = entry.value;2707 const sym = entry.value;
2708 const ordinal = ordinal: {
2709 const dylib = sym.cast(Symbol.Proxy).?.dylib orelse break :ordinal 1; // TODO handle libSystem
2710 break :ordinal dylib.ordinal.?;
2711 };
2741 try undefs.append(.{2712 try undefs.append(.{
2742 .n_strx = try self.makeString(sym.name),2713 .n_strx = try self.makeString(sym.name),
2743 .n_type = macho.N_UNDF | macho.N_EXT,2714 .n_type = macho.N_UNDF | macho.N_EXT,
2744 .n_sect = 0,2715 .n_sect = 0,
2745 .n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,2716 .n_desc = (ordinal * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
2746 .n_value = 0,2717 .n_value = 0,
2747 });2718 });
2748 }2719 }
src/link/MachO/commands.zig+31
...@@ -298,6 +298,37 @@ pub fn GenericCommandWithData(comptime Cmd: type) type {...@@ -298,6 +298,37 @@ pub fn GenericCommandWithData(comptime Cmd: type) type {
298 };298 };
299}299}
300300
301pub fn createLoadDylibCommand(
302 allocator: *Allocator,
303 name: []const u8,
304 timestamp: u32,
305 current_version: u32,
306 compatibility_version: u32,
307) !GenericCommandWithData(macho.dylib_command) {
308 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
309 u64,
310 @sizeOf(macho.dylib_command) + name.len,
311 @sizeOf(u64),
312 ));
313
314 var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
315 .cmd = macho.LC_LOAD_DYLIB,
316 .cmdsize = cmdsize,
317 .dylib = .{
318 .name = @sizeOf(macho.dylib_command),
319 .timestamp = timestamp,
320 .current_version = current_version,
321 .compatibility_version = compatibility_version,
322 },
323 });
324 dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
325
326 mem.set(u8, dylib_cmd.data, 0);
327 mem.copy(u8, dylib_cmd.data, name);
328
329 return dylib_cmd;
330}
331
301fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {332fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {
302 var stream = io.fixedBufferStream(buffer);333 var stream = io.fixedBufferStream(buffer);
303 var given = try LoadCommand.read(allocator, stream.reader());334 var given = try LoadCommand.read(allocator, stream.reader());