| author | |
| committer | |
| log | 1dac5f5214aa9e35ad0fbc2ba561a894bd193ae3 |
| tree | 5badfc9bca79b7f59780648cd504203e66097c0d |
| parent | ca772735c3d01c58551639d8bcfe355bc7ac9785 |
* add preliminary rpath support
* enable shared_library test on x86_64 macOS5 files changed, 119 insertions(+), 8 deletions(-)
lib/std/macho.zig+13| ... | ... | @@ -516,6 +516,19 @@ pub const dylib = extern struct { |
| 516 | 516 | compatibility_version: u32, |
| 517 | 517 | }; |
| 518 | 518 | |
| 519 | /// The rpath_command contains a path which at runtime should be added to the current | |
| 520 | /// run path used to find @rpath prefixed dylibs. | |
| 521 | pub const rpath_command = extern struct { | |
| 522 | /// LC_RPATH | |
| 523 | cmd: u32, | |
| 524 | ||
| 525 | /// includes string | |
| 526 | cmdsize: u32, | |
| 527 | ||
| 528 | /// path to add to run path | |
| 529 | path: u32, | |
| 530 | }; | |
| 531 | ||
| 519 | 532 | /// The segment load command indicates that a part of this file is to be |
| 520 | 533 | /// mapped into the task's address space. The size of this segment in memory, |
| 521 | 534 | /// vmsize, maybe equal to or larger than the amount to map from this file, |
src/link/MachO.zig+22-1| ... | ... | @@ -756,6 +756,19 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 756 | 756 | } |
| 757 | 757 | } |
| 758 | 758 | |
| 759 | // rpaths | |
| 760 | var rpath_table = std.StringArrayHashMap(void).init(arena); | |
| 761 | for (self.base.options.rpath_list) |rpath| { | |
| 762 | if (rpath_table.contains(rpath)) continue; | |
| 763 | try rpath_table.putNoClobber(rpath, {}); | |
| 764 | } | |
| 765 | ||
| 766 | var rpaths = std.ArrayList([]const u8) .init(arena); | |
| 767 | try rpaths.ensureCapacity(rpath_table.count()); | |
| 768 | for (rpath_table.items()) |entry| { | |
| 769 | rpaths.appendAssumeCapacity(entry.key); | |
| 770 | } | |
| 771 | ||
| 759 | 772 | if (self.base.options.verbose_link) { |
| 760 | 773 | var argv = std.ArrayList([]const u8).init(arena); |
| 761 | 774 | |
| ... | ... | @@ -767,6 +780,11 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 767 | 780 | try argv.append(syslibroot); |
| 768 | 781 | } |
| 769 | 782 | |
| 783 | for (rpaths.items) |rpath| { | |
| 784 | try argv.append("-rpath"); | |
| 785 | try argv.append(rpath); | |
| 786 | } | |
| 787 | ||
| 770 | 788 | try argv.appendSlice(positionals.items); |
| 771 | 789 | |
| 772 | 790 | try argv.append("-o"); |
| ... | ... | @@ -783,7 +801,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 783 | 801 | Compilation.dump_argv(argv.items); |
| 784 | 802 | } |
| 785 | 803 | |
| 786 | try zld.link(positionals.items, shared_libs.items, full_out_path); | |
| 804 | try zld.link(positionals.items, full_out_path, .{ | |
| 805 | .shared_libs = shared_libs.items, | |
| 806 | .rpaths = rpaths.items, | |
| 807 | }); | |
| 787 | 808 | |
| 788 | 809 | break :outer; |
| 789 | 810 | } |
src/link/MachO/Zld.zig+74-3| ... | ... | @@ -186,7 +186,12 @@ pub fn closeFiles(self: Zld) void { |
| 186 | 186 | if (self.file) |f| f.close(); |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | pub fn link(self: *Zld, files: []const []const u8, shared_libs: []const []const u8, out_path: []const u8) !void { | |
| 189 | const LinkArgs = struct { | |
| 190 | shared_libs: []const []const u8, | |
| 191 | rpaths: []const []const u8, | |
| 192 | }; | |
| 193 | ||
| 194 | pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { | |
| 190 | 195 | if (files.len == 0) return error.NoInputFiles; |
| 191 | 196 | if (out_path.len == 0) return error.EmptyOutputPath; |
| 192 | 197 | |
| ... | ... | @@ -222,8 +227,9 @@ pub fn link(self: *Zld, files: []const []const u8, shared_libs: []const []const |
| 222 | 227 | }); |
| 223 | 228 | |
| 224 | 229 | try self.populateMetadata(); |
| 230 | try self.addRpaths(args.rpaths); | |
| 225 | 231 | try self.parseInputFiles(files); |
| 226 | try self.parseDylibs(shared_libs); | |
| 232 | try self.parseDylibs(args.shared_libs); | |
| 227 | 233 | try self.resolveSymbols(); |
| 228 | 234 | try self.resolveStubsAndGotEntries(); |
| 229 | 235 | try self.updateMetadata(); |
| ... | ... | @@ -241,6 +247,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 241 | 247 | kind: enum { |
| 242 | 248 | object, |
| 243 | 249 | archive, |
| 250 | dylib, | |
| 244 | 251 | }, |
| 245 | 252 | file: fs.File, |
| 246 | 253 | name: []const u8, |
| ... | ... | @@ -248,7 +255,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 248 | 255 | var classified = std.ArrayList(Input).init(self.allocator); |
| 249 | 256 | defer classified.deinit(); |
| 250 | 257 | |
| 251 | // First, classify input files as either object or archive. | |
| 258 | // First, classify input files: object, archive or dylib. | |
| 252 | 259 | for (files) |file_name| { |
| 253 | 260 | const file = try fs.cwd().openFile(file_name, .{}); |
| 254 | 261 | const full_path = full_path: { |
| ... | ... | @@ -289,6 +296,22 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 289 | 296 | continue; |
| 290 | 297 | } |
| 291 | 298 | |
| 299 | try_dylib: { | |
| 300 | const header = try file.reader().readStruct(macho.mach_header_64); | |
| 301 | if (header.filetype != macho.MH_DYLIB) { | |
| 302 | try file.seekTo(0); | |
| 303 | break :try_dylib; | |
| 304 | } | |
| 305 | ||
| 306 | try file.seekTo(0); | |
| 307 | try classified.append(.{ | |
| 308 | .kind = .dylib, | |
| 309 | .file = file, | |
| 310 | .name = full_path, | |
| 311 | }); | |
| 312 | continue; | |
| 313 | } | |
| 314 | ||
| 292 | 315 | log.debug("unexpected input file of unknown type '{s}'", .{file_name}); |
| 293 | 316 | } |
| 294 | 317 | |
| ... | ... | @@ -317,6 +340,35 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 317 | 340 | try archive.parse(); |
| 318 | 341 | try self.archives.append(self.allocator, archive); |
| 319 | 342 | }, |
| 343 | .dylib => { | |
| 344 | const dylib = try self.allocator.create(Dylib); | |
| 345 | errdefer self.allocator.destroy(dylib); | |
| 346 | ||
| 347 | dylib.* = Dylib.init(self.allocator); | |
| 348 | dylib.arch = self.arch.?; | |
| 349 | dylib.name = input.name; | |
| 350 | dylib.file = input.file; | |
| 351 | ||
| 352 | const ordinal = @intCast(u16, self.dylibs.items.len); | |
| 353 | dylib.ordinal = ordinal + 2; // TODO +2 since 1 is reserved for libSystem | |
| 354 | ||
| 355 | // TODO Defer parsing of the dylibs until they are actually needed | |
| 356 | try dylib.parse(); | |
| 357 | try self.dylibs.append(self.allocator, dylib); | |
| 358 | ||
| 359 | // Add LC_LOAD_DYLIB command | |
| 360 | const dylib_id = dylib.id orelse unreachable; | |
| 361 | var dylib_cmd = try createLoadDylibCommand( | |
| 362 | self.allocator, | |
| 363 | dylib_id.name, | |
| 364 | dylib_id.timestamp, | |
| 365 | dylib_id.current_version, | |
| 366 | dylib_id.compatibility_version, | |
| 367 | ); | |
| 368 | errdefer dylib_cmd.deinit(self.allocator); | |
| 369 | ||
| 370 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); | |
| 371 | }, | |
| 320 | 372 | } |
| 321 | 373 | } |
| 322 | 374 | } |
| ... | ... | @@ -2117,6 +2169,25 @@ fn populateMetadata(self: *Zld) !void { |
| 2117 | 2169 | } |
| 2118 | 2170 | } |
| 2119 | 2171 | |
| 2172 | fn addRpaths(self: *Zld, rpaths: []const []const u8) !void { | |
| 2173 | for (rpaths) |rpath| { | |
| 2174 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | |
| 2175 | u64, | |
| 2176 | @sizeOf(macho.rpath_command) + rpath.len, | |
| 2177 | @sizeOf(u64), | |
| 2178 | )); | |
| 2179 | var rpath_cmd = emptyGenericCommandWithData(macho.rpath_command{ | |
| 2180 | .cmd = macho.LC_RPATH, | |
| 2181 | .cmdsize = cmdsize, | |
| 2182 | .path = @sizeOf(macho.rpath_command), | |
| 2183 | }); | |
| 2184 | rpath_cmd.data = try self.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path); | |
| 2185 | mem.set(u8, rpath_cmd.data, 0); | |
| 2186 | mem.copy(u8, rpath_cmd.data, rpath); | |
| 2187 | try self.load_commands.append(self.allocator, .{ .Rpath = rpath_cmd }); | |
| 2188 | } | |
| 2189 | } | |
| 2190 | ||
| 2120 | 2191 | fn flush(self: *Zld) !void { |
| 2121 | 2192 | try self.writeStubHelperCommon(); |
| 2122 | 2193 | try self.resolveRelocsAndWriteSections(); |
src/link/MachO/commands.zig+9| ... | ... | @@ -24,6 +24,7 @@ pub const LoadCommand = union(enum) { |
| 24 | 24 | SourceVersion: macho.source_version_command, |
| 25 | 25 | Uuid: macho.uuid_command, |
| 26 | 26 | LinkeditData: macho.linkedit_data_command, |
| 27 | Rpath: GenericCommandWithData(macho.rpath_command), | |
| 27 | 28 | Unknown: GenericCommandWithData(macho.load_command), |
| 28 | 29 | |
| 29 | 30 | pub fn read(allocator: *Allocator, reader: anytype) !LoadCommand { |
| ... | ... | @@ -84,6 +85,9 @@ pub const LoadCommand = union(enum) { |
| 84 | 85 | => LoadCommand{ |
| 85 | 86 | .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command), |
| 86 | 87 | }, |
| 88 | macho.LC_RPATH => LoadCommand{ | |
| 89 | .Rpath = try GenericCommandWithData(macho.rpath_command).read(allocator, stream.reader()), | |
| 90 | }, | |
| 87 | 91 | else => LoadCommand{ |
| 88 | 92 | .Unknown = try GenericCommandWithData(macho.load_command).read(allocator, stream.reader()), |
| 89 | 93 | }, |
| ... | ... | @@ -103,6 +107,7 @@ pub const LoadCommand = union(enum) { |
| 103 | 107 | .Segment => |x| x.write(writer), |
| 104 | 108 | .Dylinker => |x| x.write(writer), |
| 105 | 109 | .Dylib => |x| x.write(writer), |
| 110 | .Rpath => |x| x.write(writer), | |
| 106 | 111 | .Unknown => |x| x.write(writer), |
| 107 | 112 | }; |
| 108 | 113 | } |
| ... | ... | @@ -120,6 +125,7 @@ pub const LoadCommand = union(enum) { |
| 120 | 125 | .Segment => |x| x.inner.cmd, |
| 121 | 126 | .Dylinker => |x| x.inner.cmd, |
| 122 | 127 | .Dylib => |x| x.inner.cmd, |
| 128 | .Rpath => |x| x.inner.cmd, | |
| 123 | 129 | .Unknown => |x| x.inner.cmd, |
| 124 | 130 | }; |
| 125 | 131 | } |
| ... | ... | @@ -137,6 +143,7 @@ pub const LoadCommand = union(enum) { |
| 137 | 143 | .Segment => |x| x.inner.cmdsize, |
| 138 | 144 | .Dylinker => |x| x.inner.cmdsize, |
| 139 | 145 | .Dylib => |x| x.inner.cmdsize, |
| 146 | .Rpath => |x| x.inner.cmdsize, | |
| 140 | 147 | .Unknown => |x| x.inner.cmdsize, |
| 141 | 148 | }; |
| 142 | 149 | } |
| ... | ... | @@ -146,6 +153,7 @@ pub const LoadCommand = union(enum) { |
| 146 | 153 | .Segment => |*x| x.deinit(allocator), |
| 147 | 154 | .Dylinker => |*x| x.deinit(allocator), |
| 148 | 155 | .Dylib => |*x| x.deinit(allocator), |
| 156 | .Rpath => |*x| x.deinit(allocator), | |
| 149 | 157 | .Unknown => |*x| x.deinit(allocator), |
| 150 | 158 | else => {}, |
| 151 | 159 | }; |
| ... | ... | @@ -169,6 +177,7 @@ pub const LoadCommand = union(enum) { |
| 169 | 177 | .Segment => |x| x.eql(other.Segment), |
| 170 | 178 | .Dylinker => |x| x.eql(other.Dylinker), |
| 171 | 179 | .Dylib => |x| x.eql(other.Dylib), |
| 180 | .Rpath => |x| x.eql(other.Rpath), | |
| 172 | 181 | .Unknown => |x| x.eql(other.Unknown), |
| 173 | 182 | }; |
| 174 | 183 | } |
test/standalone.zig+1-4| ... | ... | @@ -9,10 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 9 | 9 | cases.add("test/standalone/main_return_error/error_u8.zig"); |
| 10 | 10 | cases.add("test/standalone/main_return_error/error_u8_non_zero.zig"); |
| 11 | 11 | cases.addBuildFile("test/standalone/main_pkg_path/build.zig"); |
| 12 | if (std.Target.current.os.tag != .macos) { | |
| 13 | // TODO zld cannot link shared libraries yet. | |
| 14 | cases.addBuildFile("test/standalone/shared_library/build.zig"); | |
| 15 | } | |
| 12 | cases.addBuildFile("test/standalone/shared_library/build.zig"); | |
| 16 | 13 | cases.addBuildFile("test/standalone/mix_o_files/build.zig"); |
| 17 | 14 | cases.addBuildFile("test/standalone/global_linkage/build.zig"); |
| 18 | 15 | cases.addBuildFile("test/standalone/static_c_lib/build.zig"); |