| author | |
| committer | |
| log | eca12b74b8f2ff9510de67907df2bc272614c8c8 |
| tree | 9fa91b35ec449e2190dbbe9ba1168c179be84d2c |
| parent | 5aff1d5d6fde5f95576cd639e6fa80281524e2d6 |
4 files changed, 116 insertions(+), 139 deletions(-)
src/link/MachO.zig+14-9| ... | @@ -871,17 +871,19 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -871,17 +871,19 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 871 | 871 | ||
| 872 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, | 872 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, |
| 873 | // we link against that instead of embedded libSystem.B.tbd file. | 873 | // we link against that instead of embedded libSystem.B.tbd file. |
| 874 | const libc_stub_path = blk: { | 874 | var link_native_libsystem = false; |
| 875 | if (self.base.options.is_native_os) { | 875 | if (self.base.options.is_native_os) { |
| 876 | if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| { | 876 | if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| { |
| 877 | break :blk full_path; | 877 | try libs.append(full_path); |
| 878 | } | 878 | link_native_libsystem = true; |
| 879 | } | 879 | } |
| 880 | 880 | } | |
| 881 | break :blk try comp.zig_lib_directory.join(arena, &[_][]const u8{ | 881 | if (!link_native_libsystem) { |
| 882 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | ||
| 882 | "libc", "darwin", "libSystem.B.tbd", | 883 | "libc", "darwin", "libSystem.B.tbd", |
| 883 | }); | 884 | }); |
| 884 | }; | 885 | try positionals.append(full_path); |
| 886 | } | ||
| 885 | 887 | ||
| 886 | // frameworks | 888 | // frameworks |
| 887 | var framework_dirs = std.ArrayList([]const u8).init(arena); | 889 | var framework_dirs = std.ArrayList([]const u8).init(arena); |
| ... | @@ -935,6 +937,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -935,6 +937,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 935 | try argv.append("-o"); | 937 | try argv.append("-o"); |
| 936 | try argv.append(full_out_path); | 938 | try argv.append(full_out_path); |
| 937 | 939 | ||
| 940 | if (link_native_libsystem) { | ||
| 941 | try argv.append("-lSystem"); | ||
| 942 | } | ||
| 943 | |||
| 938 | for (search_lib_names.items) |l_name| { | 944 | for (search_lib_names.items) |l_name| { |
| 939 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); | 945 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); |
| 940 | } | 946 | } |
| ... | @@ -950,7 +956,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -950,7 +956,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 950 | .syslibroot = self.base.options.sysroot, | 956 | .syslibroot = self.base.options.sysroot, |
| 951 | .libs = libs.items, | 957 | .libs = libs.items, |
| 952 | .rpaths = rpaths.items, | 958 | .rpaths = rpaths.items, |
| 953 | .libc_stub_path = libc_stub_path, | ||
| 954 | }); | 959 | }); |
| 955 | 960 | ||
| 956 | break :outer; | 961 | break :outer; |
src/link/MachO/Dylib.zig+79-49| ... | @@ -45,8 +45,8 @@ id: ?Id = null, | ... | @@ -45,8 +45,8 @@ id: ?Id = null, |
| 45 | /// a symbol is referenced by an object file. | 45 | /// a symbol is referenced by an object file. |
| 46 | symbols: std.StringArrayHashMapUnmanaged(void) = .{}, | 46 | symbols: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 47 | 47 | ||
| 48 | // TODO add parsing re-exported libs from binary dylibs | 48 | /// Array list of all dependent libs of this dylib. |
| 49 | dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{}, | 49 | dependent_libs: std.ArrayListUnmanaged(Id) = .{}, |
| 50 | 50 | ||
| 51 | pub const Id = struct { | 51 | pub const Id = struct { |
| 52 | name: []const u8, | 52 | name: []const u8, |
| ... | @@ -54,15 +54,28 @@ pub const Id = struct { | ... | @@ -54,15 +54,28 @@ pub const Id = struct { |
| 54 | current_version: u32, | 54 | current_version: u32, |
| 55 | compatibility_version: u32, | 55 | compatibility_version: u32, |
| 56 | 56 | ||
| 57 | pub fn default(name: []const u8) Id { | 57 | pub fn default(allocator: *Allocator, name: []const u8) !Id { |
| 58 | return .{ | 58 | return Id{ |
| 59 | .name = name, | 59 | .name = try allocator.dupe(u8, name), |
| 60 | .timestamp = 2, | 60 | .timestamp = 2, |
| 61 | .current_version = 0x10000, | 61 | .current_version = 0x10000, |
| 62 | .compatibility_version = 0x10000, | 62 | .compatibility_version = 0x10000, |
| 63 | }; | 63 | }; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | pub fn fromLoadCommand(allocator: *Allocator, lc: GenericCommandWithData(macho.dylib_command)) !Id { | ||
| 67 | const dylib = lc.inner.dylib; | ||
| 68 | const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]); | ||
| 69 | const name = try allocator.dupe(u8, mem.spanZ(dylib_name)); | ||
| 70 | |||
| 71 | return Id{ | ||
| 72 | .name = name, | ||
| 73 | .timestamp = dylib.timestamp, | ||
| 74 | .current_version = dylib.current_version, | ||
| 75 | .compatibility_version = dylib.compatibility_version, | ||
| 76 | }; | ||
| 77 | } | ||
| 78 | |||
| 66 | pub fn deinit(id: *Id, allocator: *Allocator) void { | 79 | pub fn deinit(id: *Id, allocator: *Allocator) void { |
| 67 | allocator.free(id.name); | 80 | allocator.free(id.name); |
| 68 | } | 81 | } |
| ... | @@ -129,12 +142,12 @@ pub const Error = error{ | ... | @@ -129,12 +142,12 @@ pub const Error = error{ |
| 129 | UnsupportedCpuArchitecture, | 142 | UnsupportedCpuArchitecture, |
| 130 | } || fs.File.OpenError || std.os.PReadError || Id.ParseError; | 143 | } || fs.File.OpenError || std.os.PReadError || Id.ParseError; |
| 131 | 144 | ||
| 132 | pub fn createAndParseFromPath( | 145 | pub const CreateOpts = struct { |
| 133 | allocator: *Allocator, | 146 | syslibroot: ?[]const u8 = null, |
| 134 | arch: Arch, | 147 | id: ?Id = null, |
| 135 | path: []const u8, | 148 | }; |
| 136 | syslibroot: ?[]const u8, | 149 | |
| 137 | ) Error!?[]*Dylib { | 150 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8, opts: CreateOpts) Error!?[]*Dylib { |
| 138 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | 151 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 139 | error.FileNotFound => return null, | 152 | error.FileNotFound => return null, |
| 140 | else => |e| return e, | 153 | else => |e| return e, |
| ... | @@ -152,7 +165,7 @@ pub fn createAndParseFromPath( | ... | @@ -152,7 +165,7 @@ pub fn createAndParseFromPath( |
| 152 | .arch = arch, | 165 | .arch = arch, |
| 153 | .name = name, | 166 | .name = name, |
| 154 | .file = file, | 167 | .file = file, |
| 155 | .syslibroot = syslibroot, | 168 | .syslibroot = opts.syslibroot, |
| 156 | }; | 169 | }; |
| 157 | 170 | ||
| 158 | dylib.parse() catch |err| switch (err) { | 171 | dylib.parse() catch |err| switch (err) { |
| ... | @@ -171,6 +184,20 @@ pub fn createAndParseFromPath( | ... | @@ -171,6 +184,20 @@ pub fn createAndParseFromPath( |
| 171 | else => |e| return e, | 184 | else => |e| return e, |
| 172 | }; | 185 | }; |
| 173 | 186 | ||
| 187 | if (opts.id) |id| { | ||
| 188 | if (dylib.id.?.current_version < id.compatibility_version) { | ||
| 189 | log.warn("found dylib is incompatible with the required minimum version", .{}); | ||
| 190 | log.warn(" | dylib: {s}", .{id.name}); | ||
| 191 | log.warn(" | required minimum version: {}", .{id.compatibility_version}); | ||
| 192 | log.warn(" | dylib version: {}", .{dylib.id.?.current_version}); | ||
| 193 | |||
| 194 | // TODO maybe this should be an error and facilitate auto-cleanup? | ||
| 195 | dylib.deinit(); | ||
| 196 | allocator.destroy(dylib); | ||
| 197 | return null; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 174 | var dylibs = std.ArrayList(*Dylib).init(allocator); | 201 | var dylibs = std.ArrayList(*Dylib).init(allocator); |
| 175 | defer dylibs.deinit(); | 202 | defer dylibs.deinit(); |
| 176 | 203 | ||
| ... | @@ -191,8 +218,8 @@ pub fn deinit(self: *Dylib) void { | ... | @@ -191,8 +218,8 @@ pub fn deinit(self: *Dylib) void { |
| 191 | } | 218 | } |
| 192 | self.symbols.deinit(self.allocator); | 219 | self.symbols.deinit(self.allocator); |
| 193 | 220 | ||
| 194 | for (self.dependent_libs.keys()) |key| { | 221 | for (self.dependent_libs.items) |*id| { |
| 195 | self.allocator.free(key); | 222 | id.deinit(self.allocator); |
| 196 | } | 223 | } |
| 197 | self.dependent_libs.deinit(self.allocator); | 224 | self.dependent_libs.deinit(self.allocator); |
| 198 | 225 | ||
| ... | @@ -287,6 +314,8 @@ fn readFatStruct(reader: anytype, comptime T: type) !T { | ... | @@ -287,6 +314,8 @@ fn readFatStruct(reader: anytype, comptime T: type) !T { |
| 287 | } | 314 | } |
| 288 | 315 | ||
| 289 | fn readLoadCommands(self: *Dylib, reader: anytype) !void { | 316 | fn readLoadCommands(self: *Dylib, reader: anytype) !void { |
| 317 | const should_lookup_reexports = self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0; | ||
| 318 | |||
| 290 | try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds); | 319 | try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds); |
| 291 | 320 | ||
| 292 | var i: u16 = 0; | 321 | var i: u16 = 0; |
| ... | @@ -302,6 +331,13 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void { | ... | @@ -302,6 +331,13 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void { |
| 302 | macho.LC_ID_DYLIB => { | 331 | macho.LC_ID_DYLIB => { |
| 303 | self.id_cmd_index = i; | 332 | self.id_cmd_index = i; |
| 304 | }, | 333 | }, |
| 334 | macho.LC_REEXPORT_DYLIB => { | ||
| 335 | if (should_lookup_reexports) { | ||
| 336 | // Parse install_name to dependent dylib. | ||
| 337 | const id = try Id.fromLoadCommand(self.allocator, cmd.Dylib); | ||
| 338 | try self.dependent_libs.append(self.allocator, id); | ||
| 339 | } | ||
| 340 | }, | ||
| 305 | else => { | 341 | else => { |
| 306 | log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()}); | 342 | log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()}); |
| 307 | }, | 343 | }, |
| ... | @@ -313,22 +349,10 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void { | ... | @@ -313,22 +349,10 @@ fn readLoadCommands(self: *Dylib, reader: anytype) !void { |
| 313 | fn parseId(self: *Dylib) !void { | 349 | fn parseId(self: *Dylib) !void { |
| 314 | const index = self.id_cmd_index orelse { | 350 | const index = self.id_cmd_index orelse { |
| 315 | log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{}); | 351 | log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{}); |
| 316 | self.id = Id.default(try self.allocator.dupe(u8, self.name.?)); | 352 | self.id = try Id.default(self.allocator, self.name.?); |
| 317 | return; | 353 | return; |
| 318 | }; | 354 | }; |
| 319 | const id_cmd = self.load_commands.items[index].Dylib; | 355 | self.id = try Id.fromLoadCommand(self.allocator, self.load_commands.items[index].Dylib); |
| 320 | const dylib = id_cmd.inner.dylib; | ||
| 321 | |||
| 322 | // TODO should we compare the name from the dylib's id with the user-specified one? | ||
| 323 | const dylib_name = @ptrCast([*:0]const u8, id_cmd.data[dylib.name - @sizeOf(macho.dylib_command) ..]); | ||
| 324 | const name = try self.allocator.dupe(u8, mem.spanZ(dylib_name)); | ||
| 325 | |||
| 326 | self.id = .{ | ||
| 327 | .name = name, | ||
| 328 | .timestamp = dylib.timestamp, | ||
| 329 | .current_version = dylib.current_version, | ||
| 330 | .compatibility_version = dylib.compatibility_version, | ||
| 331 | }; | ||
| 332 | } | 356 | } |
| 333 | 357 | ||
| 334 | fn parseSymbols(self: *Dylib) !void { | 358 | fn parseSymbols(self: *Dylib) !void { |
| ... | @@ -380,7 +404,7 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { | ... | @@ -380,7 +404,7 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { |
| 380 | 404 | ||
| 381 | const umbrella_lib = lib_stub.inner[0]; | 405 | const umbrella_lib = lib_stub.inner[0]; |
| 382 | 406 | ||
| 383 | var id = Id.default(try self.allocator.dupe(u8, umbrella_lib.install_name)); | 407 | var id = try Id.default(self.allocator, umbrella_lib.install_name); |
| 384 | if (umbrella_lib.current_version) |version| { | 408 | if (umbrella_lib.current_version) |version| { |
| 385 | try id.parseCurrentVersion(version); | 409 | try id.parseCurrentVersion(version); |
| 386 | } | 410 | } |
| ... | @@ -470,7 +494,9 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { | ... | @@ -470,7 +494,9 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { |
| 470 | } | 494 | } |
| 471 | 495 | ||
| 472 | log.debug(" | {s}", .{lib}); | 496 | log.debug(" | {s}", .{lib}); |
| 473 | try self.dependent_libs.put(self.allocator, try self.allocator.dupe(u8, lib), {}); | 497 | |
| 498 | const dep_id = try Id.default(self.allocator, lib); | ||
| 499 | try self.dependent_libs.append(self.allocator, dep_id); | ||
| 474 | } | 500 | } |
| 475 | } | 501 | } |
| 476 | } | 502 | } |
| ... | @@ -478,36 +504,40 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { | ... | @@ -478,36 +504,40 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { |
| 478 | } | 504 | } |
| 479 | 505 | ||
| 480 | pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void { | 506 | pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void { |
| 481 | outer: for (self.dependent_libs.keys()) |lib| { | 507 | outer: for (self.dependent_libs.items) |id| { |
| 482 | const dirname = fs.path.dirname(lib) orelse { | 508 | const has_ext = blk: { |
| 483 | log.warn("unable to resolve dependency {s}", .{lib}); | 509 | const basename = fs.path.basename(id.name); |
| 484 | continue; | 510 | break :blk mem.lastIndexOfScalar(u8, basename, '.') != null; |
| 485 | }; | 511 | }; |
| 486 | const filename = fs.path.basename(lib); | 512 | const extension = if (has_ext) fs.path.extension(id.name) else ""; |
| 487 | const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index| | 513 | const without_ext = if (has_ext) blk: { |
| 488 | filename[0..index] | 514 | const index = mem.lastIndexOfScalar(u8, id.name, '.') orelse unreachable; |
| 489 | else | 515 | break :blk id.name[0..index]; |
| 490 | filename; | 516 | } else id.name; |
| 491 | 517 | ||
| 492 | for (&[_][]const u8{ "dylib", "tbd" }) |ext| { | 518 | for (&[_][]const u8{ extension, ".tbd" }) |ext| { |
| 493 | const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ | 519 | const with_ext = try std.fmt.allocPrint(self.allocator, "{s}{s}", .{ |
| 494 | without_ext, | 520 | without_ext, |
| 495 | ext, | 521 | ext, |
| 496 | }); | 522 | }); |
| 497 | defer self.allocator.free(with_ext); | 523 | defer self.allocator.free(with_ext); |
| 498 | 524 | ||
| 499 | const lib_path = if (self.syslibroot) |syslibroot| | 525 | const full_path = if (self.syslibroot) |syslibroot| |
| 500 | try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext }) | 526 | try fs.path.join(self.allocator, &.{ syslibroot, with_ext }) |
| 501 | else | 527 | else |
| 502 | try fs.path.join(self.allocator, &.{ dirname, with_ext }); | 528 | with_ext; |
| 529 | defer if (self.syslibroot) |_| self.allocator.free(full_path); | ||
| 503 | 530 | ||
| 504 | log.debug("trying dependency at fully resolved path {s}", .{lib_path}); | 531 | log.debug("trying dependency at fully resolved path {s}", .{full_path}); |
| 505 | 532 | ||
| 506 | const dylibs = (try createAndParseFromPath( | 533 | const dylibs = (try createAndParseFromPath( |
| 507 | self.allocator, | 534 | self.allocator, |
| 508 | self.arch.?, | 535 | self.arch.?, |
| 509 | lib_path, | 536 | full_path, |
| 510 | self.syslibroot, | 537 | .{ |
| 538 | .id = id, | ||
| 539 | .syslibroot = self.syslibroot, | ||
| 540 | }, | ||
| 511 | )) orelse { | 541 | )) orelse { |
| 512 | continue; | 542 | continue; |
| 513 | }; | 543 | }; |
| ... | @@ -516,7 +546,7 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void { | ... | @@ -516,7 +546,7 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void { |
| 516 | 546 | ||
| 517 | continue :outer; | 547 | continue :outer; |
| 518 | } else { | 548 | } else { |
| 519 | log.warn("unable to resolve dependency {s}", .{lib}); | 549 | log.warn("unable to resolve dependency {s}", .{id.name}); |
| 520 | } | 550 | } |
| 521 | } | 551 | } |
| 522 | } | 552 | } |
src/link/MachO/Symbol.zig+2-1| ... | @@ -111,7 +111,8 @@ pub const Unresolved = struct { | ... | @@ -111,7 +111,8 @@ pub const Unresolved = struct { |
| 111 | base: Symbol, | 111 | base: Symbol, |
| 112 | 112 | ||
| 113 | /// File where this symbol was referenced. | 113 | /// File where this symbol was referenced. |
| 114 | file: *Object, | 114 | /// null means synthetic, e.g., dyld_stub_binder. |
| 115 | file: ?*Object = null, | ||
| 115 | 116 | ||
| 116 | pub const base_type: Symbol.Type = .unresolved; | 117 | pub const base_type: Symbol.Type = .unresolved; |
| 117 | }; | 118 | }; |
src/link/MachO/Zld.zig+21-80| ... | @@ -38,7 +38,6 @@ objects: std.ArrayListUnmanaged(*Object) = .{}, | ... | @@ -38,7 +38,6 @@ objects: std.ArrayListUnmanaged(*Object) = .{}, |
| 38 | archives: std.ArrayListUnmanaged(*Archive) = .{}, | 38 | archives: std.ArrayListUnmanaged(*Archive) = .{}, |
| 39 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, | 39 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, |
| 40 | 40 | ||
| 41 | libsystem_dylib_index: ?u16 = null, | ||
| 42 | next_dylib_ordinal: u16 = 1, | 41 | next_dylib_ordinal: u16 = 1, |
| 43 | 42 | ||
| 44 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 43 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| ... | @@ -199,7 +198,6 @@ const LinkArgs = struct { | ... | @@ -199,7 +198,6 @@ const LinkArgs = struct { |
| 199 | syslibroot: ?[]const u8, | 198 | syslibroot: ?[]const u8, |
| 200 | libs: []const []const u8, | 199 | libs: []const []const u8, |
| 201 | rpaths: []const []const u8, | 200 | rpaths: []const []const u8, |
| 202 | libc_stub_path: []const u8, | ||
| 203 | }; | 201 | }; |
| 204 | 202 | ||
| 205 | pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { | 203 | pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { |
| ... | @@ -240,7 +238,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L | ... | @@ -240,7 +238,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L |
| 240 | try self.populateMetadata(); | 238 | try self.populateMetadata(); |
| 241 | try self.parseInputFiles(files, args.syslibroot); | 239 | try self.parseInputFiles(files, args.syslibroot); |
| 242 | try self.parseLibs(args.libs, args.syslibroot); | 240 | try self.parseLibs(args.libs, args.syslibroot); |
| 243 | try self.parseLibSystem(args.libc_stub_path, args.syslibroot); | ||
| 244 | try self.resolveSymbols(); | 241 | try self.resolveSymbols(); |
| 245 | try self.resolveStubsAndGotEntries(); | 242 | try self.resolveStubsAndGotEntries(); |
| 246 | try self.updateMetadata(); | 243 | try self.updateMetadata(); |
| ... | @@ -280,7 +277,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u | ... | @@ -280,7 +277,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u |
| 280 | self.allocator, | 277 | self.allocator, |
| 281 | self.arch.?, | 278 | self.arch.?, |
| 282 | full_path, | 279 | full_path, |
| 283 | syslibroot, | 280 | .{ .syslibroot = syslibroot }, |
| 284 | )) |dylibs| { | 281 | )) |dylibs| { |
| 285 | defer self.allocator.free(dylibs); | 282 | defer self.allocator.free(dylibs); |
| 286 | try self.dylibs.appendSlice(self.allocator, dylibs); | 283 | try self.dylibs.appendSlice(self.allocator, dylibs); |
| ... | @@ -297,7 +294,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi | ... | @@ -297,7 +294,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi |
| 297 | self.allocator, | 294 | self.allocator, |
| 298 | self.arch.?, | 295 | self.arch.?, |
| 299 | lib, | 296 | lib, |
| 300 | syslibroot, | 297 | .{ .syslibroot = syslibroot }, |
| 301 | )) |dylibs| { | 298 | )) |dylibs| { |
| 302 | defer self.allocator.free(dylibs); | 299 | defer self.allocator.free(dylibs); |
| 303 | try self.dylibs.appendSlice(self.allocator, dylibs); | 300 | try self.dylibs.appendSlice(self.allocator, dylibs); |
| ... | @@ -313,36 +310,6 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi | ... | @@ -313,36 +310,6 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi |
| 313 | } | 310 | } |
| 314 | } | 311 | } |
| 315 | 312 | ||
| 316 | fn parseLibSystem(self: *Zld, libc_stub_path: []const u8, syslibroot: ?[]const u8) !void { | ||
| 317 | const dylibs = (try Dylib.createAndParseFromPath( | ||
| 318 | self.allocator, | ||
| 319 | self.arch.?, | ||
| 320 | libc_stub_path, | ||
| 321 | syslibroot, | ||
| 322 | )) orelse return error.FailedToParseLibSystem; | ||
| 323 | defer self.allocator.free(dylibs); | ||
| 324 | |||
| 325 | assert(dylibs.len == 1); // More than one dylib output from parsing libSystem! | ||
| 326 | const dylib = dylibs[0]; | ||
| 327 | |||
| 328 | self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len); | ||
| 329 | try self.dylibs.append(self.allocator, dylib); | ||
| 330 | |||
| 331 | // Add LC_LOAD_DYLIB load command. | ||
| 332 | dylib.ordinal = self.next_dylib_ordinal; | ||
| 333 | const dylib_id = dylib.id orelse unreachable; | ||
| 334 | var dylib_cmd = try createLoadDylibCommand( | ||
| 335 | self.allocator, | ||
| 336 | dylib_id.name, | ||
| 337 | dylib_id.timestamp, | ||
| 338 | dylib_id.current_version, | ||
| 339 | dylib_id.compatibility_version, | ||
| 340 | ); | ||
| 341 | errdefer dylib_cmd.deinit(self.allocator); | ||
| 342 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); | ||
| 343 | self.next_dylib_ordinal += 1; | ||
| 344 | } | ||
| 345 | |||
| 346 | fn mapAndUpdateSections( | 313 | fn mapAndUpdateSections( |
| 347 | self: *Zld, | 314 | self: *Zld, |
| 348 | object: *Object, | 315 | object: *Object, |
| ... | @@ -1656,6 +1623,21 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1656,6 +1623,21 @@ fn resolveSymbols(self: *Zld) !void { |
| 1656 | } | 1623 | } |
| 1657 | self.unresolved.clearRetainingCapacity(); | 1624 | self.unresolved.clearRetainingCapacity(); |
| 1658 | 1625 | ||
| 1626 | // Put dyld_stub_binder as an unresolved special symbol. | ||
| 1627 | { | ||
| 1628 | const name = try self.allocator.dupe(u8, "dyld_stub_binder"); | ||
| 1629 | errdefer self.allocator.free(name); | ||
| 1630 | const undef = try self.allocator.create(Symbol.Unresolved); | ||
| 1631 | errdefer self.allocator.destroy(undef); | ||
| 1632 | undef.* = .{ | ||
| 1633 | .base = .{ | ||
| 1634 | .@"type" = .unresolved, | ||
| 1635 | .name = name, | ||
| 1636 | }, | ||
| 1637 | }; | ||
| 1638 | try unresolved.append(&undef.base); | ||
| 1639 | } | ||
| 1640 | |||
| 1659 | var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); | 1641 | var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); |
| 1660 | defer referenced.deinit(); | 1642 | defer referenced.deinit(); |
| 1661 | 1643 | ||
| ... | @@ -1664,9 +1646,7 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1664,9 +1646,7 @@ fn resolveSymbols(self: *Zld) !void { |
| 1664 | const proxy = inner: { | 1646 | const proxy = inner: { |
| 1665 | for (self.dylibs.items) |dylib, i| { | 1647 | for (self.dylibs.items) |dylib, i| { |
| 1666 | const proxy = (try dylib.createProxy(undef.name)) orelse continue; | 1648 | const proxy = (try dylib.createProxy(undef.name)) orelse continue; |
| 1667 | if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately. | 1649 | try referenced.put(dylib, {}); |
| 1668 | try referenced.put(dylib, {}); | ||
| 1669 | } | ||
| 1670 | break :inner proxy; | 1650 | break :inner proxy; |
| 1671 | } | 1651 | } |
| 1672 | if (mem.eql(u8, undef.name, "___dso_handle")) { | 1652 | if (mem.eql(u8, undef.name, "___dso_handle")) { |
| ... | @@ -1681,7 +1661,6 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1681,7 +1661,6 @@ fn resolveSymbols(self: *Zld) !void { |
| 1681 | .@"type" = .proxy, | 1661 | .@"type" = .proxy, |
| 1682 | .name = name, | 1662 | .name = name, |
| 1683 | }, | 1663 | }, |
| 1684 | .file = null, | ||
| 1685 | }; | 1664 | }; |
| 1686 | break :inner &proxy.base; | 1665 | break :inner &proxy.base; |
| 1687 | } | 1666 | } |
| ... | @@ -1717,21 +1696,13 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1717,21 +1696,13 @@ fn resolveSymbols(self: *Zld) !void { |
| 1717 | if (self.unresolved.count() > 0) { | 1696 | if (self.unresolved.count() > 0) { |
| 1718 | for (self.unresolved.values()) |undef| { | 1697 | for (self.unresolved.values()) |undef| { |
| 1719 | log.err("undefined reference to symbol '{s}'", .{undef.name}); | 1698 | log.err("undefined reference to symbol '{s}'", .{undef.name}); |
| 1720 | log.err(" | referenced in {s}", .{ | 1699 | if (undef.cast(Symbol.Unresolved).?.file) |file| { |
| 1721 | undef.cast(Symbol.Unresolved).?.file.name.?, | 1700 | log.err(" | referenced in {s}", .{file.name.?}); |
| 1722 | }); | 1701 | } |
| 1723 | } | 1702 | } |
| 1724 | 1703 | ||
| 1725 | return error.UndefinedSymbolReference; | 1704 | return error.UndefinedSymbolReference; |
| 1726 | } | 1705 | } |
| 1727 | |||
| 1728 | // Finally put dyld_stub_binder as an Import | ||
| 1729 | const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?]; | ||
| 1730 | const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse { | ||
| 1731 | log.err("undefined reference to symbol 'dyld_stub_binder'", .{}); | ||
| 1732 | return error.UndefinedSymbolReference; | ||
| 1733 | }; | ||
| 1734 | try self.imports.putNoClobber(self.allocator, proxy.name, proxy); | ||
| 1735 | } | 1706 | } |
| 1736 | 1707 | ||
| 1737 | fn resolveStubsAndGotEntries(self: *Zld) !void { | 1708 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| ... | @@ -3173,33 +3144,3 @@ pub fn parseName(name: *const [16]u8) []const u8 { | ... | @@ -3173,33 +3144,3 @@ pub fn parseName(name: *const [16]u8) []const u8 { |
| 3173 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | 3144 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; |
| 3174 | return name[0..len]; | 3145 | return name[0..len]; |
| 3175 | } | 3146 | } |
| 3176 | |||
| 3177 | fn printSymbols(self: *Zld) void { | ||
| 3178 | log.debug("globals", .{}); | ||
| 3179 | for (self.globals.values()) |value| { | ||
| 3180 | const sym = value.cast(Symbol.Regular) orelse unreachable; | ||
| 3181 | log.debug(" | {s} @ {*}", .{ sym.base.name, value }); | ||
| 3182 | log.debug(" => alias of {*}", .{sym.base.alias}); | ||
| 3183 | log.debug(" => linkage {s}", .{sym.linkage}); | ||
| 3184 | log.debug(" => defined in {s}", .{sym.file.name.?}); | ||
| 3185 | } | ||
| 3186 | for (self.objects.items) |object| { | ||
| 3187 | log.debug("locals in {s}", .{object.name.?}); | ||
| 3188 | for (object.symbols.items) |sym| { | ||
| 3189 | log.debug(" | {s} @ {*}", .{ sym.name, sym }); | ||
| 3190 | log.debug(" => alias of {*}", .{sym.alias}); | ||
| 3191 | if (sym.cast(Symbol.Regular)) |reg| { | ||
| 3192 | log.debug(" => linkage {s}", .{reg.linkage}); | ||
| 3193 | } else { | ||
| 3194 | log.debug(" => unresolved", .{}); | ||
| 3195 | } | ||
| 3196 | } | ||
| 3197 | } | ||
| 3198 | log.debug("proxies", .{}); | ||
| 3199 | for (self.imports.values()) |value| { | ||
| 3200 | const sym = value.cast(Symbol.Proxy) orelse unreachable; | ||
| 3201 | log.debug(" | {s} @ {*}", .{ sym.base.name, value }); | ||
| 3202 | log.debug(" => alias of {*}", .{sym.base.alias}); | ||
| 3203 | log.debug(" => defined in libSystem.B.dylib", .{}); | ||
| 3204 | } | ||
| 3205 | } |