| author | |
| committer | |
| log | 81bf05bf6c1249c39273b494d3e337d300b4ddd5 |
| tree | 9b53744d1d3a31ac82e153173bb9abe7bb52c999 |
| parent | 37fbf5b0d3b0be131903e4895ee3703393b32d8f |
| parent | 0e15205521b9a8c95db3c1714dffe3be1df5cda1 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
zig ld can create dylibs now; remove system linker hack and any mention of ld64.lld from the codebase10 files changed, 303 insertions(+), 535 deletions(-)
cmake/Findlld.cmake-1| ... | @@ -42,7 +42,6 @@ else() | ... | @@ -42,7 +42,6 @@ else() |
| 42 | FIND_AND_ADD_LLD_LIB(lldMinGW) | 42 | FIND_AND_ADD_LLD_LIB(lldMinGW) |
| 43 | FIND_AND_ADD_LLD_LIB(lldELF) | 43 | FIND_AND_ADD_LLD_LIB(lldELF) |
| 44 | FIND_AND_ADD_LLD_LIB(lldCOFF) | 44 | FIND_AND_ADD_LLD_LIB(lldCOFF) |
| 45 | FIND_AND_ADD_LLD_LIB(lldMachO) | ||
| 46 | FIND_AND_ADD_LLD_LIB(lldWasm) | 45 | FIND_AND_ADD_LLD_LIB(lldWasm) |
| 47 | FIND_AND_ADD_LLD_LIB(lldReaderWriter) | 46 | FIND_AND_ADD_LLD_LIB(lldReaderWriter) |
| 48 | FIND_AND_ADD_LLD_LIB(lldCore) | 47 | FIND_AND_ADD_LLD_LIB(lldCore) |
src/Compilation.zig+2-13| ... | @@ -879,24 +879,16 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -879,24 +879,16 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 879 | break :blk false; | 879 | break :blk false; |
| 880 | }; | 880 | }; |
| 881 | 881 | ||
| 882 | const darwin_can_use_system_linker_and_sdk = | 882 | const darwin_can_use_system_sdk = |
| 883 | // comptime conditions | 883 | // comptime conditions |
| 884 | ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and | 884 | ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and |
| 885 | // runtime conditions | 885 | // runtime conditions |
| 886 | (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); | 886 | (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); |
| 887 | 887 | ||
| 888 | const darwin_system_linker_hack = blk: { | ||
| 889 | if (darwin_can_use_system_linker_and_sdk) { | ||
| 890 | break :blk std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; | ||
| 891 | } else { | ||
| 892 | break :blk false; | ||
| 893 | } | ||
| 894 | }; | ||
| 895 | |||
| 896 | const sysroot = blk: { | 888 | const sysroot = blk: { |
| 897 | if (options.sysroot) |sysroot| { | 889 | if (options.sysroot) |sysroot| { |
| 898 | break :blk sysroot; | 890 | break :blk sysroot; |
| 899 | } else if (darwin_can_use_system_linker_and_sdk) { | 891 | } else if (darwin_can_use_system_sdk) { |
| 900 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. | 892 | // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. |
| 901 | // See https://github.com/ziglang/zig/issues/6996 | 893 | // See https://github.com/ziglang/zig/issues/6996 |
| 902 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; | 894 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; |
| ... | @@ -915,8 +907,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -915,8 +907,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 915 | break :blk false; | 907 | break :blk false; |
| 916 | } else if (options.c_source_files.len == 0) { | 908 | } else if (options.c_source_files.len == 0) { |
| 917 | break :blk false; | 909 | break :blk false; |
| 918 | } else if (darwin_system_linker_hack) { | ||
| 919 | break :blk false; | ||
| 920 | } else switch (options.output_mode) { | 910 | } else switch (options.output_mode) { |
| 921 | .Lib, .Obj => break :blk false, | 911 | .Lib, .Obj => break :blk false, |
| 922 | .Exe => switch (options.optimize_mode) { | 912 | .Exe => switch (options.optimize_mode) { |
| ... | @@ -1295,7 +1285,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1295,7 +1285,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1295 | .optimize_mode = options.optimize_mode, | 1285 | .optimize_mode = options.optimize_mode, |
| 1296 | .use_lld = use_lld, | 1286 | .use_lld = use_lld, |
| 1297 | .use_llvm = use_llvm, | 1287 | .use_llvm = use_llvm, |
| 1298 | .system_linker_hack = darwin_system_linker_hack, | ||
| 1299 | .link_libc = link_libc, | 1288 | .link_libc = link_libc, |
| 1300 | .link_libcpp = link_libcpp, | 1289 | .link_libcpp = link_libcpp, |
| 1301 | .link_libunwind = link_libunwind, | 1290 | .link_libunwind = link_libunwind, |
src/codegen/llvm/bindings.zig-2| ... | @@ -496,12 +496,10 @@ fn LLVMInitializeAllAsmParsers() callconv(.C) void { | ... | @@ -496,12 +496,10 @@ fn LLVMInitializeAllAsmParsers() callconv(.C) void { |
| 496 | 496 | ||
| 497 | extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; | 497 | extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; |
| 498 | extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; | 498 | extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; |
| 499 | extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; | ||
| 500 | extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; | 499 | extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; |
| 501 | 500 | ||
| 502 | pub const LinkCOFF = ZigLLDLinkCOFF; | 501 | pub const LinkCOFF = ZigLLDLinkCOFF; |
| 503 | pub const LinkELF = ZigLLDLinkELF; | 502 | pub const LinkELF = ZigLLDLinkELF; |
| 504 | pub const LinkMachO = ZigLLDLinkMachO; | ||
| 505 | pub const LinkWasm = ZigLLDLinkWasm; | 503 | pub const LinkWasm = ZigLLDLinkWasm; |
| 506 | 504 | ||
| 507 | pub const ObjectFormatType = enum(c_int) { | 505 | pub const ObjectFormatType = enum(c_int) { |
src/link.zig-3| ... | @@ -61,9 +61,6 @@ pub const Options = struct { | ... | @@ -61,9 +61,6 @@ pub const Options = struct { |
| 61 | /// other objects. | 61 | /// other objects. |
| 62 | /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary. | 62 | /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary. |
| 63 | use_llvm: bool, | 63 | use_llvm: bool, |
| 64 | /// Darwin-only. If this is true, `use_llvm` is true, and `is_native_os` is true, this link code will | ||
| 65 | /// use system linker `ld` instead of the LLD. | ||
| 66 | system_linker_hack: bool, | ||
| 67 | link_libc: bool, | 64 | link_libc: bool, |
| 68 | link_libcpp: bool, | 65 | link_libcpp: bool, |
| 69 | link_libunwind: bool, | 66 | link_libunwind: bool, |
src/link/MachO.zig+171-440| ... | @@ -430,7 +430,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO { | ... | @@ -430,7 +430,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO { |
| 430 | 430 | ||
| 431 | pub fn flush(self: *MachO, comp: *Compilation) !void { | 431 | pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 432 | if (build_options.have_llvm and self.base.options.use_lld) { | 432 | if (build_options.have_llvm and self.base.options.use_lld) { |
| 433 | return self.linkWithLLD(comp); | 433 | return self.linkWithZld(comp); |
| 434 | } else { | 434 | } else { |
| 435 | switch (self.base.options.effectiveOutputMode()) { | 435 | switch (self.base.options.effectiveOutputMode()) { |
| 436 | .Exe, .Obj => {}, | 436 | .Exe, .Obj => {}, |
| ... | @@ -593,7 +593,7 @@ fn resolveFramework( | ... | @@ -593,7 +593,7 @@ fn resolveFramework( |
| 593 | return null; | 593 | return null; |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | 596 | fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 597 | const tracy = trace(@src()); | 597 | const tracy = trace(@src()); |
| 598 | defer tracy.end(); | 598 | defer tracy.end(); |
| 599 | 599 | ||
| ... | @@ -631,7 +631,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -631,7 +631,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 631 | const stack_size = self.base.options.stack_size_override orelse 0; | 631 | const stack_size = self.base.options.stack_size_override orelse 0; |
| 632 | const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; | 632 | const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; |
| 633 | 633 | ||
| 634 | const id_symlink_basename = "lld.id"; | 634 | const id_symlink_basename = "zld.id"; |
| 635 | 635 | ||
| 636 | var man: Cache.Manifest = undefined; | 636 | var man: Cache.Manifest = undefined; |
| 637 | defer if (!self.base.options.disable_lld_caching) man.deinit(); | 637 | defer if (!self.base.options.disable_lld_caching) man.deinit(); |
| ... | @@ -669,7 +669,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -669,7 +669,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 669 | man.hash.addStringSet(self.base.options.system_libs); | 669 | man.hash.addStringSet(self.base.options.system_libs); |
| 670 | man.hash.add(allow_shlib_undefined); | 670 | man.hash.add(allow_shlib_undefined); |
| 671 | man.hash.add(self.base.options.bind_global_refs_locally); | 671 | man.hash.add(self.base.options.bind_global_refs_locally); |
| 672 | man.hash.add(self.base.options.system_linker_hack); | ||
| 673 | man.hash.addOptionalBytes(self.base.options.sysroot); | 672 | man.hash.addOptionalBytes(self.base.options.sysroot); |
| 674 | 673 | ||
| 675 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. | 674 | // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. |
| ... | @@ -682,17 +681,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -682,17 +681,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 682 | id_symlink_basename, | 681 | id_symlink_basename, |
| 683 | &prev_digest_buf, | 682 | &prev_digest_buf, |
| 684 | ) catch |err| blk: { | 683 | ) catch |err| blk: { |
| 685 | log.debug("MachO LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); | 684 | log.debug("MachO Zld new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); |
| 686 | // Handle this as a cache miss. | 685 | // Handle this as a cache miss. |
| 687 | break :blk prev_digest_buf[0..0]; | 686 | break :blk prev_digest_buf[0..0]; |
| 688 | }; | 687 | }; |
| 689 | if (mem.eql(u8, prev_digest, &digest)) { | 688 | if (mem.eql(u8, prev_digest, &digest)) { |
| 690 | log.debug("MachO LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); | 689 | log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); |
| 691 | // Hot diggity dog! The output binary is already there. | 690 | // Hot diggity dog! The output binary is already there. |
| 692 | self.base.lock = man.toOwnedLock(); | 691 | self.base.lock = man.toOwnedLock(); |
| 693 | return; | 692 | return; |
| 694 | } | 693 | } |
| 695 | log.debug("MachO LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); | 694 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); |
| 696 | 695 | ||
| 697 | // We are about to change the output file to be different, so we invalidate the build hash now. | 696 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| 698 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { | 697 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| ... | @@ -726,495 +725,227 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -726,495 +725,227 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 726 | if (!mem.eql(u8, the_object_path, full_out_path)) { | 725 | if (!mem.eql(u8, the_object_path, full_out_path)) { |
| 727 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); | 726 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); |
| 728 | } | 727 | } |
| 729 | } else outer: { | 728 | } else { |
| 730 | const use_zld = blk: { | 729 | var zld = Zld.init(self.base.allocator); |
| 731 | if (self.base.options.is_native_os and self.base.options.system_linker_hack) { | 730 | defer { |
| 732 | // If the user forces the use of ld64, make sure we are running native! | 731 | zld.closeFiles(); |
| 733 | break :blk false; | 732 | zld.deinit(); |
| 734 | } | 733 | } |
| 735 | 734 | zld.target = target; | |
| 736 | if (self.base.options.target.cpu.arch == .aarch64) { | 735 | zld.stack_size = stack_size; |
| 737 | // On aarch64, always use zld. | ||
| 738 | break :blk true; | ||
| 739 | } | ||
| 740 | |||
| 741 | if (self.base.options.output_mode == .Lib or | ||
| 742 | self.base.options.linker_script != null) | ||
| 743 | { | ||
| 744 | // Fallback to LLD in this handful of cases on x86_64 only. | ||
| 745 | break :blk false; | ||
| 746 | } | ||
| 747 | 736 | ||
| 748 | break :blk true; | 737 | // Positional arguments to the linker such as object files and static archives. |
| 749 | }; | 738 | var positionals = std.ArrayList([]const u8).init(arena); |
| 750 | 739 | ||
| 751 | if (use_zld) { | 740 | try positionals.appendSlice(self.base.options.objects); |
| 752 | var zld = Zld.init(self.base.allocator); | ||
| 753 | defer { | ||
| 754 | zld.closeFiles(); | ||
| 755 | zld.deinit(); | ||
| 756 | } | ||
| 757 | zld.arch = target.cpu.arch; | ||
| 758 | zld.stack_size = stack_size; | ||
| 759 | 741 | ||
| 760 | // Positional arguments to the linker such as object files and static archives. | 742 | for (comp.c_object_table.keys()) |key| { |
| 761 | var positionals = std.ArrayList([]const u8).init(arena); | 743 | try positionals.append(key.status.success.object_path); |
| 744 | } | ||
| 762 | 745 | ||
| 763 | try positionals.appendSlice(self.base.options.objects); | 746 | if (module_obj_path) |p| { |
| 747 | try positionals.append(p); | ||
| 748 | } | ||
| 764 | 749 | ||
| 765 | for (comp.c_object_table.keys()) |key| { | 750 | try positionals.append(comp.compiler_rt_static_lib.?.full_object_path); |
| 766 | try positionals.append(key.status.success.object_path); | ||
| 767 | } | ||
| 768 | 751 | ||
| 769 | if (module_obj_path) |p| { | 752 | // libc++ dep |
| 770 | try positionals.append(p); | 753 | if (self.base.options.link_libcpp) { |
| 771 | } | 754 | try positionals.append(comp.libcxxabi_static_lib.?.full_object_path); |
| 755 | try positionals.append(comp.libcxx_static_lib.?.full_object_path); | ||
| 756 | } | ||
| 772 | 757 | ||
| 773 | try positionals.append(comp.compiler_rt_static_lib.?.full_object_path); | 758 | // Shared and static libraries passed via `-l` flag. |
| 759 | var search_lib_names = std.ArrayList([]const u8).init(arena); | ||
| 774 | 760 | ||
| 775 | // libc++ dep | 761 | const system_libs = self.base.options.system_libs.keys(); |
| 776 | if (self.base.options.link_libcpp) { | 762 | for (system_libs) |link_lib| { |
| 777 | try positionals.append(comp.libcxxabi_static_lib.?.full_object_path); | 763 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries |
| 778 | try positionals.append(comp.libcxx_static_lib.?.full_object_path); | 764 | // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which |
| 765 | // case we want to avoid prepending "-l". | ||
| 766 | if (Compilation.classifyFileExt(link_lib) == .shared_library) { | ||
| 767 | try positionals.append(link_lib); | ||
| 768 | continue; | ||
| 779 | } | 769 | } |
| 780 | 770 | ||
| 781 | // Shared and static libraries passed via `-l` flag. | 771 | try search_lib_names.append(link_lib); |
| 782 | var search_lib_names = std.ArrayList([]const u8).init(arena); | 772 | } |
| 783 | |||
| 784 | const system_libs = self.base.options.system_libs.keys(); | ||
| 785 | for (system_libs) |link_lib| { | ||
| 786 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries | ||
| 787 | // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which | ||
| 788 | // case we want to avoid prepending "-l". | ||
| 789 | if (Compilation.classifyFileExt(link_lib) == .shared_library) { | ||
| 790 | try positionals.append(link_lib); | ||
| 791 | continue; | ||
| 792 | } | ||
| 793 | 773 | ||
| 794 | try search_lib_names.append(link_lib); | 774 | var lib_dirs = std.ArrayList([]const u8).init(arena); |
| 775 | for (self.base.options.lib_dirs) |dir| { | ||
| 776 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { | ||
| 777 | try lib_dirs.append(search_dir); | ||
| 778 | } else { | ||
| 779 | log.warn("directory not found for '-L{s}'", .{dir}); | ||
| 795 | } | 780 | } |
| 781 | } | ||
| 796 | 782 | ||
| 797 | var lib_dirs = std.ArrayList([]const u8).init(arena); | 783 | var libs = std.ArrayList([]const u8).init(arena); |
| 798 | for (self.base.options.lib_dirs) |dir| { | 784 | var lib_not_found = false; |
| 799 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { | 785 | for (search_lib_names.items) |lib_name| { |
| 800 | try lib_dirs.append(search_dir); | 786 | // Assume ld64 default: -search_paths_first |
| 801 | } else { | 787 | // Look in each directory for a dylib (stub first), and then for archive |
| 802 | log.warn("directory not found for '-L{s}'", .{dir}); | 788 | // TODO implement alternative: -search_dylibs_first |
| 789 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { | ||
| 790 | if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { | ||
| 791 | try libs.append(full_path); | ||
| 792 | break; | ||
| 803 | } | 793 | } |
| 794 | } else { | ||
| 795 | log.warn("library not found for '-l{s}'", .{lib_name}); | ||
| 796 | lib_not_found = true; | ||
| 804 | } | 797 | } |
| 798 | } | ||
| 805 | 799 | ||
| 806 | var libs = std.ArrayList([]const u8).init(arena); | 800 | if (lib_not_found) { |
| 807 | var lib_not_found = false; | 801 | log.warn("Library search paths:", .{}); |
| 808 | for (search_lib_names.items) |lib_name| { | 802 | for (lib_dirs.items) |dir| { |
| 809 | // Assume ld64 default: -search_paths_first | 803 | log.warn(" {s}", .{dir}); |
| 810 | // Look in each directory for a dylib (stub first), and then for archive | ||
| 811 | // TODO implement alternative: -search_dylibs_first | ||
| 812 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { | ||
| 813 | if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { | ||
| 814 | try libs.append(full_path); | ||
| 815 | break; | ||
| 816 | } | ||
| 817 | } else { | ||
| 818 | log.warn("library not found for '-l{s}'", .{lib_name}); | ||
| 819 | lib_not_found = true; | ||
| 820 | } | ||
| 821 | } | 804 | } |
| 805 | } | ||
| 822 | 806 | ||
| 823 | if (lib_not_found) { | 807 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, |
| 824 | log.warn("Library search paths:", .{}); | 808 | // we link against that instead of embedded libSystem.B.tbd file. |
| 825 | for (lib_dirs.items) |dir| { | 809 | var native_libsystem_available = false; |
| 826 | log.warn(" {s}", .{dir}); | 810 | if (self.base.options.is_native_os) blk: { |
| 827 | } | 811 | // Try stub file first. If we hit it, then we're done as the stub file |
| 812 | // re-exports every single symbol definition. | ||
| 813 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { | ||
| 814 | try libs.append(full_path); | ||
| 815 | native_libsystem_available = true; | ||
| 816 | break :blk; | ||
| 828 | } | 817 | } |
| 829 | 818 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib | |
| 830 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, | 819 | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| 831 | // we link against that instead of embedded libSystem.B.tbd file. | 820 | if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { |
| 832 | var native_libsystem_available = false; | 821 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { |
| 833 | if (self.base.options.is_native_os) blk: { | 822 | try libs.append(libsystem_path); |
| 834 | // Try stub file first. If we hit it, then we're done as the stub file | 823 | try libs.append(libc_path); |
| 835 | // re-exports every single symbol definition. | ||
| 836 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { | ||
| 837 | try libs.append(full_path); | ||
| 838 | native_libsystem_available = true; | 824 | native_libsystem_available = true; |
| 839 | break :blk; | 825 | break :blk; |
| 840 | } | 826 | } |
| 841 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib | ||
| 842 | // doesn't export libc.dylib which we'll need to resolve subsequently also. | ||
| 843 | if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { | ||
| 844 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { | ||
| 845 | try libs.append(libsystem_path); | ||
| 846 | try libs.append(libc_path); | ||
| 847 | native_libsystem_available = true; | ||
| 848 | break :blk; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | } | 827 | } |
| 852 | if (!native_libsystem_available) { | 828 | } |
| 853 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | 829 | if (!native_libsystem_available) { |
| 854 | "libc", "darwin", "libSystem.B.tbd", | 830 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 855 | }); | 831 | "libc", "darwin", "libSystem.B.tbd", |
| 856 | try libs.append(full_path); | ||
| 857 | } | ||
| 858 | |||
| 859 | // frameworks | ||
| 860 | var framework_dirs = std.ArrayList([]const u8).init(arena); | ||
| 861 | for (self.base.options.framework_dirs) |dir| { | ||
| 862 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { | ||
| 863 | try framework_dirs.append(search_dir); | ||
| 864 | } else { | ||
| 865 | log.warn("directory not found for '-F{s}'", .{dir}); | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | var framework_not_found = false; | ||
| 870 | for (self.base.options.frameworks) |framework| { | ||
| 871 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { | ||
| 872 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { | ||
| 873 | try libs.append(full_path); | ||
| 874 | break; | ||
| 875 | } | ||
| 876 | } else { | ||
| 877 | log.warn("framework not found for '-f{s}'", .{framework}); | ||
| 878 | framework_not_found = true; | ||
| 879 | } | ||
| 880 | } | ||
| 881 | |||
| 882 | if (framework_not_found) { | ||
| 883 | log.warn("Framework search paths:", .{}); | ||
| 884 | for (framework_dirs.items) |dir| { | ||
| 885 | log.warn(" {s}", .{dir}); | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | // rpaths | ||
| 890 | var rpath_table = std.StringArrayHashMap(void).init(arena); | ||
| 891 | for (self.base.options.rpath_list) |rpath| { | ||
| 892 | if (rpath_table.contains(rpath)) continue; | ||
| 893 | try rpath_table.putNoClobber(rpath, {}); | ||
| 894 | } | ||
| 895 | |||
| 896 | var rpaths = std.ArrayList([]const u8).init(arena); | ||
| 897 | try rpaths.ensureCapacity(rpath_table.count()); | ||
| 898 | for (rpath_table.keys()) |*key| { | ||
| 899 | rpaths.appendAssumeCapacity(key.*); | ||
| 900 | } | ||
| 901 | |||
| 902 | if (self.base.options.verbose_link) { | ||
| 903 | var argv = std.ArrayList([]const u8).init(arena); | ||
| 904 | |||
| 905 | try argv.append("zig"); | ||
| 906 | try argv.append("ld"); | ||
| 907 | |||
| 908 | if (self.base.options.sysroot) |syslibroot| { | ||
| 909 | try argv.append("-syslibroot"); | ||
| 910 | try argv.append(syslibroot); | ||
| 911 | } | ||
| 912 | |||
| 913 | for (rpaths.items) |rpath| { | ||
| 914 | try argv.append("-rpath"); | ||
| 915 | try argv.append(rpath); | ||
| 916 | } | ||
| 917 | |||
| 918 | try argv.appendSlice(positionals.items); | ||
| 919 | |||
| 920 | try argv.append("-o"); | ||
| 921 | try argv.append(full_out_path); | ||
| 922 | |||
| 923 | if (native_libsystem_available) { | ||
| 924 | try argv.append("-lSystem"); | ||
| 925 | try argv.append("-lc"); | ||
| 926 | } | ||
| 927 | |||
| 928 | for (search_lib_names.items) |l_name| { | ||
| 929 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); | ||
| 930 | } | ||
| 931 | |||
| 932 | for (self.base.options.lib_dirs) |lib_dir| { | ||
| 933 | try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); | ||
| 934 | } | ||
| 935 | |||
| 936 | Compilation.dump_argv(argv.items); | ||
| 937 | } | ||
| 938 | |||
| 939 | try zld.link(positionals.items, full_out_path, .{ | ||
| 940 | .syslibroot = self.base.options.sysroot, | ||
| 941 | .libs = libs.items, | ||
| 942 | .rpaths = rpaths.items, | ||
| 943 | }); | 832 | }); |
| 944 | 833 | try libs.append(full_path); | |
| 945 | break :outer; | ||
| 946 | } | 834 | } |
| 947 | 835 | ||
| 948 | // Create an LLD command line and invoke it. | 836 | // frameworks |
| 949 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | 837 | var framework_dirs = std.ArrayList([]const u8).init(arena); |
| 950 | defer argv.deinit(); | 838 | for (self.base.options.framework_dirs) |dir| { |
| 951 | 839 | if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { | |
| 952 | // TODO https://github.com/ziglang/zig/issues/6971 | 840 | try framework_dirs.append(search_dir); |
| 953 | // Note that there is no need to check if running natively since we do that already | 841 | } else { |
| 954 | // when setting `system_linker_hack` in Compilation struct. | 842 | log.warn("directory not found for '-F{s}'", .{dir}); |
| 955 | if (self.base.options.system_linker_hack) { | 843 | } |
| 956 | try argv.append("ld"); | ||
| 957 | } else { | ||
| 958 | // We will invoke ourselves as a child process to gain access to LLD. | ||
| 959 | // This is necessary because LLD does not behave properly as a library - | ||
| 960 | // it calls exit() and does not reset all global data between invocations. | ||
| 961 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld64.lld" }); | ||
| 962 | |||
| 963 | try argv.append("-error-limit"); | ||
| 964 | try argv.append("0"); | ||
| 965 | } | 844 | } |
| 966 | 845 | ||
| 967 | if (self.base.options.lto) { | 846 | var framework_not_found = false; |
| 968 | switch (self.base.options.optimize_mode) { | 847 | for (self.base.options.frameworks) |framework| { |
| 969 | .Debug => {}, | 848 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { |
| 970 | .ReleaseSmall => try argv.append("-O2"), | 849 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { |
| 971 | .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), | 850 | try libs.append(full_path); |
| 851 | break; | ||
| 852 | } | ||
| 853 | } else { | ||
| 854 | log.warn("framework not found for '-f{s}'", .{framework}); | ||
| 855 | framework_not_found = true; | ||
| 972 | } | 856 | } |
| 973 | } | 857 | } |
| 974 | try argv.append("-demangle"); | ||
| 975 | 858 | ||
| 976 | if (self.base.options.rdynamic and !self.base.options.system_linker_hack) { | 859 | if (framework_not_found) { |
| 977 | try argv.append("--export-dynamic"); | 860 | log.warn("Framework search paths:", .{}); |
| 861 | for (framework_dirs.items) |dir| { | ||
| 862 | log.warn(" {s}", .{dir}); | ||
| 863 | } | ||
| 978 | } | 864 | } |
| 979 | 865 | ||
| 980 | try argv.appendSlice(self.base.options.extra_lld_args); | 866 | // rpaths |
| 981 | 867 | var rpath_table = std.StringArrayHashMap(void).init(arena); | |
| 982 | if (self.base.options.z_nodelete) { | 868 | for (self.base.options.rpath_list) |rpath| { |
| 983 | try argv.append("-z"); | 869 | if (rpath_table.contains(rpath)) continue; |
| 984 | try argv.append("nodelete"); | 870 | try rpath_table.putNoClobber(rpath, {}); |
| 985 | } | ||
| 986 | if (self.base.options.z_defs) { | ||
| 987 | try argv.append("-z"); | ||
| 988 | try argv.append("defs"); | ||
| 989 | } | 871 | } |
| 990 | 872 | ||
| 991 | if (is_exe_or_dyn_lib) { | 873 | var rpaths = std.ArrayList([]const u8).init(arena); |
| 992 | try argv.append("-dynamic"); | 874 | try rpaths.ensureCapacity(rpath_table.count()); |
| 875 | for (rpath_table.keys()) |*key| { | ||
| 876 | rpaths.appendAssumeCapacity(key.*); | ||
| 993 | } | 877 | } |
| 994 | 878 | ||
| 995 | if (is_dyn_lib) { | 879 | const output: Zld.Output = output: { |
| 996 | try argv.append("-dylib"); | 880 | if (is_dyn_lib) { |
| 997 | 881 | const install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{ | |
| 998 | if (self.base.options.version) |ver| { | 882 | self.base.options.emit.?.sub_path, |
| 999 | const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major}); | 883 | }); |
| 1000 | try argv.append("-compatibility_version"); | 884 | break :output .{ |
| 1001 | try argv.append(compat_vers); | 885 | .tag = .dylib, |
| 1002 | 886 | .path = full_out_path, | |
| 1003 | const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); | 887 | .install_name = install_name, |
| 1004 | try argv.append("-current_version"); | 888 | }; |
| 1005 | try argv.append(cur_vers); | ||
| 1006 | } | 889 | } |
| 890 | break :output .{ | ||
| 891 | .tag = .exe, | ||
| 892 | .path = full_out_path, | ||
| 893 | }; | ||
| 894 | }; | ||
| 1007 | 895 | ||
| 1008 | const dylib_install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{self.base.options.emit.?.sub_path}); | 896 | if (self.base.options.verbose_link) { |
| 1009 | try argv.append("-install_name"); | 897 | var argv = std.ArrayList([]const u8).init(arena); |
| 1010 | try argv.append(dylib_install_name); | ||
| 1011 | } | ||
| 1012 | 898 | ||
| 1013 | try argv.append("-arch"); | 899 | try argv.append("zig"); |
| 1014 | try argv.append(darwinArchString(target.cpu.arch)); | 900 | try argv.append("ld"); |
| 1015 | 901 | ||
| 1016 | switch (target.os.tag) { | 902 | if (is_exe_or_dyn_lib) { |
| 1017 | .macos => { | 903 | try argv.append("-dynamic"); |
| 1018 | try argv.append("-macosx_version_min"); | 904 | } |
| 1019 | }, | ||
| 1020 | .ios, .tvos, .watchos => switch (target.cpu.arch) { | ||
| 1021 | .i386, .x86_64 => { | ||
| 1022 | try argv.append("-ios_simulator_version_min"); | ||
| 1023 | }, | ||
| 1024 | else => { | ||
| 1025 | try argv.append("-iphoneos_version_min"); | ||
| 1026 | }, | ||
| 1027 | }, | ||
| 1028 | else => unreachable, | ||
| 1029 | } | ||
| 1030 | const ver = target.os.version_range.semver.min; | ||
| 1031 | const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); | ||
| 1032 | try argv.append(version_string); | ||
| 1033 | 905 | ||
| 1034 | try argv.append("-sdk_version"); | 906 | if (is_dyn_lib) { |
| 1035 | try argv.append(version_string); | 907 | try argv.append("-dylib"); |
| 1036 | 908 | ||
| 1037 | if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) { | 909 | try argv.append("-install_name"); |
| 1038 | try argv.append("-pie"); | 910 | try argv.append(output.install_name.?); |
| 1039 | } | 911 | } |
| 1040 | 912 | ||
| 1041 | try argv.append("-o"); | 913 | if (self.base.options.sysroot) |syslibroot| { |
| 1042 | try argv.append(full_out_path); | 914 | try argv.append("-syslibroot"); |
| 915 | try argv.append(syslibroot); | ||
| 916 | } | ||
| 1043 | 917 | ||
| 1044 | // rpaths | 918 | for (rpaths.items) |rpath| { |
| 1045 | var rpath_table = std.StringHashMap(void).init(self.base.allocator); | ||
| 1046 | defer rpath_table.deinit(); | ||
| 1047 | for (self.base.options.rpath_list) |rpath| { | ||
| 1048 | if ((try rpath_table.fetchPut(rpath, {})) == null) { | ||
| 1049 | try argv.append("-rpath"); | 919 | try argv.append("-rpath"); |
| 1050 | try argv.append(rpath); | 920 | try argv.append(rpath); |
| 1051 | } | 921 | } |
| 1052 | } | ||
| 1053 | if (is_dyn_lib) { | ||
| 1054 | if ((try rpath_table.fetchPut(full_out_path, {})) == null) { | ||
| 1055 | try argv.append("-rpath"); | ||
| 1056 | try argv.append(full_out_path); | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | if (self.base.options.sysroot) |dir| { | ||
| 1061 | try argv.append("-syslibroot"); | ||
| 1062 | try argv.append(dir); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | for (self.base.options.lib_dirs) |lib_dir| { | ||
| 1066 | try argv.append("-L"); | ||
| 1067 | try argv.append(lib_dir); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | // Positional arguments to the linker such as object files. | ||
| 1071 | try argv.appendSlice(self.base.options.objects); | ||
| 1072 | |||
| 1073 | for (comp.c_object_table.keys()) |key| { | ||
| 1074 | try argv.append(key.status.success.object_path); | ||
| 1075 | } | ||
| 1076 | if (module_obj_path) |p| { | ||
| 1077 | try argv.append(p); | ||
| 1078 | } | ||
| 1079 | 922 | ||
| 1080 | // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce | 923 | try argv.appendSlice(positionals.items); |
| 1081 | if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) { | ||
| 1082 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); | ||
| 1083 | } | ||
| 1084 | 924 | ||
| 1085 | // Shared libraries. | 925 | try argv.append("-o"); |
| 1086 | const system_libs = self.base.options.system_libs.keys(); | 926 | try argv.append(output.path); |
| 1087 | try argv.ensureCapacity(argv.items.len + system_libs.len); | ||
| 1088 | for (system_libs) |link_lib| { | ||
| 1089 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries | ||
| 1090 | // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which | ||
| 1091 | // case we want to avoid prepending "-l". | ||
| 1092 | const ext = Compilation.classifyFileExt(link_lib); | ||
| 1093 | const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib}); | ||
| 1094 | argv.appendAssumeCapacity(arg); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | // libc++ dep | ||
| 1098 | if (self.base.options.link_libcpp) { | ||
| 1099 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); | ||
| 1100 | try argv.append(comp.libcxx_static_lib.?.full_object_path); | ||
| 1101 | } | ||
| 1102 | 927 | ||
| 1103 | // On Darwin, libSystem has libc in it, but also you have to use it | 928 | if (native_libsystem_available) { |
| 1104 | // to make syscalls because the syscall numbers are not documented | 929 | try argv.append("-lSystem"); |
| 1105 | // and change between versions. So we always link against libSystem. | 930 | try argv.append("-lc"); |
| 1106 | // LLD craps out if you do -lSystem cross compiling, so until that | ||
| 1107 | // codebase gets some love from the new maintainers we're left with | ||
| 1108 | // this dirty hack. | ||
| 1109 | if (self.base.options.is_native_os) { | ||
| 1110 | try argv.append("-lSystem"); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | for (self.base.options.framework_dirs) |framework_dir| { | ||
| 1114 | try argv.append("-F"); | ||
| 1115 | try argv.append(framework_dir); | ||
| 1116 | } | ||
| 1117 | for (self.base.options.frameworks) |framework| { | ||
| 1118 | try argv.append("-framework"); | ||
| 1119 | try argv.append(framework); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | if (allow_shlib_undefined) { | ||
| 1123 | try argv.append("-undefined"); | ||
| 1124 | try argv.append("dynamic_lookup"); | ||
| 1125 | } | ||
| 1126 | if (self.base.options.bind_global_refs_locally) { | ||
| 1127 | try argv.append("-Bsymbolic"); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | if (self.base.options.verbose_link) { | ||
| 1131 | // Potentially skip over our own name so that the LLD linker name is the first argv item. | ||
| 1132 | const adjusted_argv = if (self.base.options.system_linker_hack) argv.items else argv.items[1..]; | ||
| 1133 | Compilation.dump_argv(adjusted_argv); | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | // TODO https://github.com/ziglang/zig/issues/6971 | ||
| 1137 | // Note that there is no need to check if running natively since we do that already | ||
| 1138 | // when setting `system_linker_hack` in Compilation struct. | ||
| 1139 | if (self.base.options.system_linker_hack) { | ||
| 1140 | const result = try std.ChildProcess.exec(.{ .allocator = self.base.allocator, .argv = argv.items }); | ||
| 1141 | defer { | ||
| 1142 | self.base.allocator.free(result.stdout); | ||
| 1143 | self.base.allocator.free(result.stderr); | ||
| 1144 | } | 931 | } |
| 1145 | if (result.stdout.len != 0) { | ||
| 1146 | log.warn("unexpected LD stdout: {s}", .{result.stdout}); | ||
| 1147 | } | ||
| 1148 | if (result.stderr.len != 0) { | ||
| 1149 | log.warn("unexpected LD stderr: {s}", .{result.stderr}); | ||
| 1150 | } | ||
| 1151 | if (result.term != .Exited or result.term.Exited != 0) { | ||
| 1152 | // TODO parse this output and surface with the Compilation API rather than | ||
| 1153 | // directly outputting to stderr here. | ||
| 1154 | log.err("{s}", .{result.stderr}); | ||
| 1155 | return error.LDReportedFailure; | ||
| 1156 | } | ||
| 1157 | } else { | ||
| 1158 | // Sadly, we must run LLD as a child process because it does not behave | ||
| 1159 | // properly as a library. | ||
| 1160 | const child = try std.ChildProcess.init(argv.items, arena); | ||
| 1161 | defer child.deinit(); | ||
| 1162 | |||
| 1163 | if (comp.clang_passthrough_mode) { | ||
| 1164 | child.stdin_behavior = .Inherit; | ||
| 1165 | child.stdout_behavior = .Inherit; | ||
| 1166 | child.stderr_behavior = .Inherit; | ||
| 1167 | |||
| 1168 | const term = child.spawnAndWait() catch |err| { | ||
| 1169 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | ||
| 1170 | return error.UnableToSpawnSelf; | ||
| 1171 | }; | ||
| 1172 | switch (term) { | ||
| 1173 | .Exited => |code| { | ||
| 1174 | if (code != 0) { | ||
| 1175 | // TODO https://github.com/ziglang/zig/issues/6342 | ||
| 1176 | std.process.exit(1); | ||
| 1177 | } | ||
| 1178 | }, | ||
| 1179 | else => { | ||
| 1180 | log.err("{s} terminated", .{argv.items[0]}); | ||
| 1181 | return error.LLDCrashed; | ||
| 1182 | }, | ||
| 1183 | } | ||
| 1184 | } else { | ||
| 1185 | child.stdin_behavior = .Ignore; | ||
| 1186 | child.stdout_behavior = .Ignore; | ||
| 1187 | child.stderr_behavior = .Pipe; | ||
| 1188 | |||
| 1189 | try child.spawn(); | ||
| 1190 | |||
| 1191 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | ||
| 1192 | 932 | ||
| 1193 | const term = child.wait() catch |err| { | 933 | for (search_lib_names.items) |l_name| { |
| 1194 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | 934 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); |
| 1195 | return error.UnableToSpawnSelf; | 935 | } |
| 1196 | }; | ||
| 1197 | |||
| 1198 | switch (term) { | ||
| 1199 | .Exited => |code| { | ||
| 1200 | if (code != 0) { | ||
| 1201 | // TODO parse this output and surface with the Compilation API rather than | ||
| 1202 | // directly outputting to stderr here. | ||
| 1203 | std.debug.print("{s}", .{stderr}); | ||
| 1204 | return error.LLDReportedFailure; | ||
| 1205 | } | ||
| 1206 | }, | ||
| 1207 | else => { | ||
| 1208 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | ||
| 1209 | return error.LLDCrashed; | ||
| 1210 | }, | ||
| 1211 | } | ||
| 1212 | 936 | ||
| 1213 | if (stderr.len != 0) { | 937 | for (self.base.options.lib_dirs) |lib_dir| { |
| 1214 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | 938 | try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); |
| 1215 | } | ||
| 1216 | } | 939 | } |
| 940 | |||
| 941 | Compilation.dump_argv(argv.items); | ||
| 1217 | } | 942 | } |
| 943 | |||
| 944 | try zld.link(positionals.items, output, .{ | ||
| 945 | .syslibroot = self.base.options.sysroot, | ||
| 946 | .libs = libs.items, | ||
| 947 | .rpaths = rpaths.items, | ||
| 948 | }); | ||
| 1218 | } | 949 | } |
| 1219 | 950 | ||
| 1220 | if (!self.base.options.disable_lld_caching) { | 951 | if (!self.base.options.disable_lld_caching) { |
src/link/MachO/Trie.zig+3-2| ... | @@ -334,8 +334,9 @@ pub fn finalize(self: *Trie) !void { | ... | @@ -334,8 +334,9 @@ pub fn finalize(self: *Trie) !void { |
| 334 | self.ordered_nodes.shrinkRetainingCapacity(0); | 334 | self.ordered_nodes.shrinkRetainingCapacity(0); |
| 335 | try self.ordered_nodes.ensureCapacity(self.allocator, self.node_count); | 335 | try self.ordered_nodes.ensureCapacity(self.allocator, self.node_count); |
| 336 | 336 | ||
| 337 | const Fifo = std.fifo.LinearFifo(*Node, .{ .Static = std.math.maxInt(u8) }); | 337 | var fifo = std.fifo.LinearFifo(*Node, .Dynamic).init(self.allocator); |
| 338 | var fifo = Fifo.init(); | 338 | defer fifo.deinit(); |
| 339 | |||
| 339 | try fifo.writeItem(self.root.?); | 340 | try fifo.writeItem(self.root.?); |
| 340 | 341 | ||
| 341 | while (fifo.readItem()) |next| { | 342 | while (fifo.readItem()) |next| { |
src/link/MachO/Zld.zig+127-64| ... | @@ -25,10 +25,10 @@ usingnamespace @import("bind.zig"); | ... | @@ -25,10 +25,10 @@ usingnamespace @import("bind.zig"); |
| 25 | 25 | ||
| 26 | allocator: *Allocator, | 26 | allocator: *Allocator, |
| 27 | 27 | ||
| 28 | arch: ?std.Target.Cpu.Arch = null, | 28 | target: ?std.Target = null, |
| 29 | page_size: ?u16 = null, | 29 | page_size: ?u16 = null, |
| 30 | file: ?fs.File = null, | 30 | file: ?fs.File = null, |
| 31 | out_path: ?[]const u8 = null, | 31 | output: ?Output = null, |
| 32 | 32 | ||
| 33 | // TODO these args will become obselete once Zld is coalesced with incremental | 33 | // TODO these args will become obselete once Zld is coalesced with incremental |
| 34 | // linker. | 34 | // linker. |
| ... | @@ -54,6 +54,7 @@ dylinker_cmd_index: ?u16 = null, | ... | @@ -54,6 +54,7 @@ dylinker_cmd_index: ?u16 = null, |
| 54 | data_in_code_cmd_index: ?u16 = null, | 54 | data_in_code_cmd_index: ?u16 = null, |
| 55 | function_starts_cmd_index: ?u16 = null, | 55 | function_starts_cmd_index: ?u16 = null, |
| 56 | main_cmd_index: ?u16 = null, | 56 | main_cmd_index: ?u16 = null, |
| 57 | dylib_id_cmd_index: ?u16 = null, | ||
| 57 | version_min_cmd_index: ?u16 = null, | 58 | version_min_cmd_index: ?u16 = null, |
| 58 | source_version_cmd_index: ?u16 = null, | 59 | source_version_cmd_index: ?u16 = null, |
| 59 | uuid_cmd_index: ?u16 = null, | 60 | uuid_cmd_index: ?u16 = null, |
| ... | @@ -118,6 +119,12 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, | ... | @@ -118,6 +119,12 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 118 | 119 | ||
| 119 | stub_helper_stubs_start_off: ?u64 = null, | 120 | stub_helper_stubs_start_off: ?u64 = null, |
| 120 | 121 | ||
| 122 | pub const Output = struct { | ||
| 123 | tag: enum { exe, dylib }, | ||
| 124 | path: []const u8, | ||
| 125 | install_name: ?[]const u8 = null, | ||
| 126 | }; | ||
| 127 | |||
| 121 | const TlvOffset = struct { | 128 | const TlvOffset = struct { |
| 122 | source_addr: u64, | 129 | source_addr: u64, |
| 123 | offset: u64, | 130 | offset: u64, |
| ... | @@ -200,36 +207,17 @@ const LinkArgs = struct { | ... | @@ -200,36 +207,17 @@ const LinkArgs = struct { |
| 200 | rpaths: []const []const u8, | 207 | rpaths: []const []const u8, |
| 201 | }; | 208 | }; |
| 202 | 209 | ||
| 203 | pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { | 210 | pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArgs) !void { |
| 204 | if (files.len == 0) return error.NoInputFiles; | 211 | if (files.len == 0) return error.NoInputFiles; |
| 205 | if (out_path.len == 0) return error.EmptyOutputPath; | 212 | if (output.path.len == 0) return error.EmptyOutputPath; |
| 206 | |||
| 207 | if (self.arch == null) { | ||
| 208 | // Try inferring the arch from the object files. | ||
| 209 | self.arch = blk: { | ||
| 210 | const file = try fs.cwd().openFile(files[0], .{}); | ||
| 211 | defer file.close(); | ||
| 212 | var reader = file.reader(); | ||
| 213 | const header = try reader.readStruct(macho.mach_header_64); | ||
| 214 | const arch: std.Target.Cpu.Arch = switch (header.cputype) { | ||
| 215 | macho.CPU_TYPE_X86_64 => .x86_64, | ||
| 216 | macho.CPU_TYPE_ARM64 => .aarch64, | ||
| 217 | else => |value| { | ||
| 218 | log.err("unsupported cpu architecture 0x{x}", .{value}); | ||
| 219 | return error.UnsupportedCpuArchitecture; | ||
| 220 | }, | ||
| 221 | }; | ||
| 222 | break :blk arch; | ||
| 223 | }; | ||
| 224 | } | ||
| 225 | 213 | ||
| 226 | self.page_size = switch (self.arch.?) { | 214 | self.page_size = switch (self.target.?.cpu.arch) { |
| 227 | .aarch64 => 0x4000, | 215 | .aarch64 => 0x4000, |
| 228 | .x86_64 => 0x1000, | 216 | .x86_64 => 0x1000, |
| 229 | else => unreachable, | 217 | else => unreachable, |
| 230 | }; | 218 | }; |
| 231 | self.out_path = out_path; | 219 | self.output = output; |
| 232 | self.file = try fs.cwd().createFile(out_path, .{ | 220 | self.file = try fs.cwd().createFile(self.output.?.path, .{ |
| 233 | .truncate = true, | 221 | .truncate = true, |
| 234 | .read = true, | 222 | .read = true, |
| 235 | .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777, | 223 | .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777, |
| ... | @@ -263,19 +251,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u | ... | @@ -263,19 +251,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u |
| 263 | break :full_path try self.allocator.dupe(u8, path); | 251 | break :full_path try self.allocator.dupe(u8, path); |
| 264 | }; | 252 | }; |
| 265 | 253 | ||
| 266 | if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| { | 254 | if (try Object.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |object| { |
| 267 | try self.objects.append(self.allocator, object); | 255 | try self.objects.append(self.allocator, object); |
| 268 | continue; | 256 | continue; |
| 269 | } | 257 | } |
| 270 | 258 | ||
| 271 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| { | 259 | if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |archive| { |
| 272 | try self.archives.append(self.allocator, archive); | 260 | try self.archives.append(self.allocator, archive); |
| 273 | continue; | 261 | continue; |
| 274 | } | 262 | } |
| 275 | 263 | ||
| 276 | if (try Dylib.createAndParseFromPath( | 264 | if (try Dylib.createAndParseFromPath( |
| 277 | self.allocator, | 265 | self.allocator, |
| 278 | self.arch.?, | 266 | self.target.?.cpu.arch, |
| 279 | full_path, | 267 | full_path, |
| 280 | .{ .syslibroot = syslibroot }, | 268 | .{ .syslibroot = syslibroot }, |
| 281 | )) |dylibs| { | 269 | )) |dylibs| { |
| ... | @@ -292,7 +280,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi | ... | @@ -292,7 +280,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi |
| 292 | for (libs) |lib| { | 280 | for (libs) |lib| { |
| 293 | if (try Dylib.createAndParseFromPath( | 281 | if (try Dylib.createAndParseFromPath( |
| 294 | self.allocator, | 282 | self.allocator, |
| 295 | self.arch.?, | 283 | self.target.?.cpu.arch, |
| 296 | lib, | 284 | lib, |
| 297 | .{ .syslibroot = syslibroot }, | 285 | .{ .syslibroot = syslibroot }, |
| 298 | )) |dylibs| { | 286 | )) |dylibs| { |
| ... | @@ -301,7 +289,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi | ... | @@ -301,7 +289,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi |
| 301 | continue; | 289 | continue; |
| 302 | } | 290 | } |
| 303 | 291 | ||
| 304 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| { | 292 | if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, lib)) |archive| { |
| 305 | try self.archives.append(self.allocator, archive); | 293 | try self.archives.append(self.allocator, archive); |
| 306 | continue; | 294 | continue; |
| 307 | } | 295 | } |
| ... | @@ -989,7 +977,7 @@ fn allocateTextSegment(self: *Zld) !void { | ... | @@ -989,7 +977,7 @@ fn allocateTextSegment(self: *Zld) !void { |
| 989 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; | 977 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; |
| 990 | stubs.size += nstubs * stubs.reserved2; | 978 | stubs.size += nstubs * stubs.reserved2; |
| 991 | 979 | ||
| 992 | const stub_size: u4 = switch (self.arch.?) { | 980 | const stub_size: u4 = switch (self.target.?.cpu.arch) { |
| 993 | .x86_64 => 10, | 981 | .x86_64 => 10, |
| 994 | .aarch64 => 3 * @sizeOf(u32), | 982 | .aarch64 => 3 * @sizeOf(u32), |
| 995 | else => unreachable, | 983 | else => unreachable, |
| ... | @@ -1226,7 +1214,7 @@ fn writeStubHelperCommon(self: *Zld) !void { | ... | @@ -1226,7 +1214,7 @@ fn writeStubHelperCommon(self: *Zld) !void { |
| 1226 | const data = &data_segment.sections.items[self.data_section_index.?]; | 1214 | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 1227 | 1215 | ||
| 1228 | self.stub_helper_stubs_start_off = blk: { | 1216 | self.stub_helper_stubs_start_off = blk: { |
| 1229 | switch (self.arch.?) { | 1217 | switch (self.target.?.cpu.arch) { |
| 1230 | .x86_64 => { | 1218 | .x86_64 => { |
| 1231 | const code_size = 15; | 1219 | const code_size = 15; |
| 1232 | var code: [code_size]u8 = undefined; | 1220 | var code: [code_size]u8 = undefined; |
| ... | @@ -1358,7 +1346,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { | ... | @@ -1358,7 +1346,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { |
| 1358 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 1346 | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1359 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 1347 | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 1360 | 1348 | ||
| 1361 | const stub_size: u4 = switch (self.arch.?) { | 1349 | const stub_size: u4 = switch (self.target.?.cpu.arch) { |
| 1362 | .x86_64 => 10, | 1350 | .x86_64 => 10, |
| 1363 | .aarch64 => 3 * @sizeOf(u32), | 1351 | .aarch64 => 3 * @sizeOf(u32), |
| 1364 | else => unreachable, | 1352 | else => unreachable, |
| ... | @@ -1384,7 +1372,7 @@ fn writeStub(self: *Zld, index: u32) !void { | ... | @@ -1384,7 +1372,7 @@ fn writeStub(self: *Zld, index: u32) !void { |
| 1384 | log.debug("writing stub at 0x{x}", .{stub_off}); | 1372 | log.debug("writing stub at 0x{x}", .{stub_off}); |
| 1385 | var code = try self.allocator.alloc(u8, stubs.reserved2); | 1373 | var code = try self.allocator.alloc(u8, stubs.reserved2); |
| 1386 | defer self.allocator.free(code); | 1374 | defer self.allocator.free(code); |
| 1387 | switch (self.arch.?) { | 1375 | switch (self.target.?.cpu.arch) { |
| 1388 | .x86_64 => { | 1376 | .x86_64 => { |
| 1389 | assert(la_ptr_addr >= stub_addr + stubs.reserved2); | 1377 | assert(la_ptr_addr >= stub_addr + stubs.reserved2); |
| 1390 | const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2); | 1378 | const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2); |
| ... | @@ -1447,7 +1435,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { | ... | @@ -1447,7 +1435,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1447 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1435 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1448 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; | 1436 | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; |
| 1449 | 1437 | ||
| 1450 | const stub_size: u4 = switch (self.arch.?) { | 1438 | const stub_size: u4 = switch (self.target.?.cpu.arch) { |
| 1451 | .x86_64 => 10, | 1439 | .x86_64 => 10, |
| 1452 | .aarch64 => 3 * @sizeOf(u32), | 1440 | .aarch64 => 3 * @sizeOf(u32), |
| 1453 | else => unreachable, | 1441 | else => unreachable, |
| ... | @@ -1455,7 +1443,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { | ... | @@ -1455,7 +1443,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1455 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; | 1443 | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; |
| 1456 | var code = try self.allocator.alloc(u8, stub_size); | 1444 | var code = try self.allocator.alloc(u8, stub_size); |
| 1457 | defer self.allocator.free(code); | 1445 | defer self.allocator.free(code); |
| 1458 | switch (self.arch.?) { | 1446 | switch (self.target.?.cpu.arch) { |
| 1459 | .x86_64 => { | 1447 | .x86_64 => { |
| 1460 | const displacement = try math.cast( | 1448 | const displacement = try math.cast( |
| 1461 | i32, | 1449 | i32, |
| ... | @@ -1999,7 +1987,7 @@ fn populateMetadata(self: *Zld) !void { | ... | @@ -1999,7 +1987,7 @@ fn populateMetadata(self: *Zld) !void { |
| 1999 | if (self.text_section_index == null) { | 1987 | if (self.text_section_index == null) { |
| 2000 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1988 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2001 | self.text_section_index = @intCast(u16, text_seg.sections.items.len); | 1989 | self.text_section_index = @intCast(u16, text_seg.sections.items.len); |
| 2002 | const alignment: u2 = switch (self.arch.?) { | 1990 | const alignment: u2 = switch (self.target.?.cpu.arch) { |
| 2003 | .x86_64 => 0, | 1991 | .x86_64 => 0, |
| 2004 | .aarch64 => 2, | 1992 | .aarch64 => 2, |
| 2005 | else => unreachable, // unhandled architecture type | 1993 | else => unreachable, // unhandled architecture type |
| ... | @@ -2013,12 +2001,12 @@ fn populateMetadata(self: *Zld) !void { | ... | @@ -2013,12 +2001,12 @@ fn populateMetadata(self: *Zld) !void { |
| 2013 | if (self.stubs_section_index == null) { | 2001 | if (self.stubs_section_index == null) { |
| 2014 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2002 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2015 | self.stubs_section_index = @intCast(u16, text_seg.sections.items.len); | 2003 | self.stubs_section_index = @intCast(u16, text_seg.sections.items.len); |
| 2016 | const alignment: u2 = switch (self.arch.?) { | 2004 | const alignment: u2 = switch (self.target.?.cpu.arch) { |
| 2017 | .x86_64 => 0, | 2005 | .x86_64 => 0, |
| 2018 | .aarch64 => 2, | 2006 | .aarch64 => 2, |
| 2019 | else => unreachable, // unhandled architecture type | 2007 | else => unreachable, // unhandled architecture type |
| 2020 | }; | 2008 | }; |
| 2021 | const stub_size: u4 = switch (self.arch.?) { | 2009 | const stub_size: u4 = switch (self.target.?.cpu.arch) { |
| 2022 | .x86_64 => 6, | 2010 | .x86_64 => 6, |
| 2023 | .aarch64 => 3 * @sizeOf(u32), | 2011 | .aarch64 => 3 * @sizeOf(u32), |
| 2024 | else => unreachable, // unhandled architecture type | 2012 | else => unreachable, // unhandled architecture type |
| ... | @@ -2033,12 +2021,12 @@ fn populateMetadata(self: *Zld) !void { | ... | @@ -2033,12 +2021,12 @@ fn populateMetadata(self: *Zld) !void { |
| 2033 | if (self.stub_helper_section_index == null) { | 2021 | if (self.stub_helper_section_index == null) { |
| 2034 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2022 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2035 | self.stub_helper_section_index = @intCast(u16, text_seg.sections.items.len); | 2023 | self.stub_helper_section_index = @intCast(u16, text_seg.sections.items.len); |
| 2036 | const alignment: u2 = switch (self.arch.?) { | 2024 | const alignment: u2 = switch (self.target.?.cpu.arch) { |
| 2037 | .x86_64 => 0, | 2025 | .x86_64 => 0, |
| 2038 | .aarch64 => 2, | 2026 | .aarch64 => 2, |
| 2039 | else => unreachable, // unhandled architecture type | 2027 | else => unreachable, // unhandled architecture type |
| 2040 | }; | 2028 | }; |
| 2041 | const stub_helper_size: u6 = switch (self.arch.?) { | 2029 | const stub_helper_size: u6 = switch (self.target.?.cpu.arch) { |
| 2042 | .x86_64 => 15, | 2030 | .x86_64 => 15, |
| 2043 | .aarch64 => 6 * @sizeOf(u32), | 2031 | .aarch64 => 6 * @sizeOf(u32), |
| 2044 | else => unreachable, | 2032 | else => unreachable, |
| ... | @@ -2187,7 +2175,7 @@ fn populateMetadata(self: *Zld) !void { | ... | @@ -2187,7 +2175,7 @@ fn populateMetadata(self: *Zld) !void { |
| 2187 | try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd }); | 2175 | try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd }); |
| 2188 | } | 2176 | } |
| 2189 | 2177 | ||
| 2190 | if (self.main_cmd_index == null) { | 2178 | if (self.main_cmd_index == null and self.output.?.tag == .exe) { |
| 2191 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); | 2179 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2192 | try self.load_commands.append(self.allocator, .{ | 2180 | try self.load_commands.append(self.allocator, .{ |
| 2193 | .Main = .{ | 2181 | .Main = .{ |
| ... | @@ -2199,6 +2187,41 @@ fn populateMetadata(self: *Zld) !void { | ... | @@ -2199,6 +2187,41 @@ fn populateMetadata(self: *Zld) !void { |
| 2199 | }); | 2187 | }); |
| 2200 | } | 2188 | } |
| 2201 | 2189 | ||
| 2190 | if (self.dylib_id_cmd_index == null and self.output.?.tag == .dylib) { | ||
| 2191 | self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len); | ||
| 2192 | var dylib_cmd = try createLoadDylibCommand( | ||
| 2193 | self.allocator, | ||
| 2194 | self.output.?.install_name.?, | ||
| 2195 | 2, | ||
| 2196 | 0x10000, // TODO forward user-provided versions | ||
| 2197 | 0x10000, | ||
| 2198 | ); | ||
| 2199 | errdefer dylib_cmd.deinit(self.allocator); | ||
| 2200 | dylib_cmd.inner.cmd = macho.LC_ID_DYLIB; | ||
| 2201 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); | ||
| 2202 | } | ||
| 2203 | |||
| 2204 | if (self.version_min_cmd_index == null) { | ||
| 2205 | self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); | ||
| 2206 | const cmd: u32 = switch (self.target.?.os.tag) { | ||
| 2207 | .macos => macho.LC_VERSION_MIN_MACOSX, | ||
| 2208 | .ios => macho.LC_VERSION_MIN_IPHONEOS, | ||
| 2209 | .tvos => macho.LC_VERSION_MIN_TVOS, | ||
| 2210 | .watchos => macho.LC_VERSION_MIN_WATCHOS, | ||
| 2211 | else => unreachable, // wrong OS | ||
| 2212 | }; | ||
| 2213 | const ver = self.target.?.os.version_range.semver.min; | ||
| 2214 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; | ||
| 2215 | try self.load_commands.append(self.allocator, .{ | ||
| 2216 | .VersionMin = .{ | ||
| 2217 | .cmd = cmd, | ||
| 2218 | .cmdsize = @sizeOf(macho.version_min_command), | ||
| 2219 | .version = version, | ||
| 2220 | .sdk = version, | ||
| 2221 | }, | ||
| 2222 | }); | ||
| 2223 | } | ||
| 2224 | |||
| 2202 | if (self.source_version_cmd_index == null) { | 2225 | if (self.source_version_cmd_index == null) { |
| 2203 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); | 2226 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2204 | try self.load_commands.append(self.allocator, .{ | 2227 | try self.load_commands.append(self.allocator, .{ |
| ... | @@ -2237,7 +2260,7 @@ fn addDataInCodeLC(self: *Zld) !void { | ... | @@ -2237,7 +2260,7 @@ fn addDataInCodeLC(self: *Zld) !void { |
| 2237 | } | 2260 | } |
| 2238 | 2261 | ||
| 2239 | fn addCodeSignatureLC(self: *Zld) !void { | 2262 | fn addCodeSignatureLC(self: *Zld) !void { |
| 2240 | if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) { | 2263 | if (self.code_signature_cmd_index == null and self.target.?.cpu.arch == .aarch64) { |
| 2241 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 2264 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2242 | try self.load_commands.append(self.allocator, .{ | 2265 | try self.load_commands.append(self.allocator, .{ |
| 2243 | .LinkeditData = .{ | 2266 | .LinkeditData = .{ |
| ... | @@ -2355,19 +2378,20 @@ fn flush(self: *Zld) !void { | ... | @@ -2355,19 +2378,20 @@ fn flush(self: *Zld) !void { |
| 2355 | seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); | 2378 | seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); |
| 2356 | } | 2379 | } |
| 2357 | 2380 | ||
| 2358 | if (self.arch.? == .aarch64) { | 2381 | if (self.target.?.cpu.arch == .aarch64) { |
| 2359 | try self.writeCodeSignaturePadding(); | 2382 | try self.writeCodeSignaturePadding(); |
| 2360 | } | 2383 | } |
| 2361 | 2384 | ||
| 2362 | try self.writeLoadCommands(); | 2385 | try self.writeLoadCommands(); |
| 2363 | try self.writeHeader(); | 2386 | try self.writeHeader(); |
| 2364 | 2387 | ||
| 2365 | if (self.arch.? == .aarch64) { | 2388 | if (self.target.?.cpu.arch == .aarch64) { |
| 2366 | try self.writeCodeSignature(); | 2389 | try self.writeCodeSignature(); |
| 2367 | } | 2390 | } |
| 2368 | 2391 | ||
| 2369 | if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) { | 2392 | if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) { |
| 2370 | try fs.cwd().copyFile(self.out_path.?, fs.cwd(), self.out_path.?, .{}); | 2393 | const out_path = self.output.?.path; |
| 2394 | try fs.cwd().copyFile(out_path, fs.cwd(), out_path, .{}); | ||
| 2371 | } | 2395 | } |
| 2372 | } | 2396 | } |
| 2373 | 2397 | ||
| ... | @@ -2392,6 +2416,8 @@ fn writeGotEntries(self: *Zld) !void { | ... | @@ -2392,6 +2416,8 @@ fn writeGotEntries(self: *Zld) !void { |
| 2392 | } | 2416 | } |
| 2393 | 2417 | ||
| 2394 | fn setEntryPoint(self: *Zld) !void { | 2418 | fn setEntryPoint(self: *Zld) !void { |
| 2419 | if (self.output.?.tag != .exe) return; | ||
| 2420 | |||
| 2395 | // TODO we should respect the -entry flag passed in by the user to set a custom | 2421 | // TODO we should respect the -entry flag passed in by the user to set a custom |
| 2396 | // entrypoint. For now, assume default of `_main`. | 2422 | // entrypoint. For now, assume default of `_main`. |
| 2397 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2423 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| ... | @@ -2636,12 +2662,12 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void { | ... | @@ -2636,12 +2662,12 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void { |
| 2636 | } | 2662 | } |
| 2637 | assert(self.stubs.items.len <= offsets.items.len); | 2663 | assert(self.stubs.items.len <= offsets.items.len); |
| 2638 | 2664 | ||
| 2639 | const stub_size: u4 = switch (self.arch.?) { | 2665 | const stub_size: u4 = switch (self.target.?.cpu.arch) { |
| 2640 | .x86_64 => 10, | 2666 | .x86_64 => 10, |
| 2641 | .aarch64 => 3 * @sizeOf(u32), | 2667 | .aarch64 => 3 * @sizeOf(u32), |
| 2642 | else => unreachable, | 2668 | else => unreachable, |
| 2643 | }; | 2669 | }; |
| 2644 | const off: u4 = switch (self.arch.?) { | 2670 | const off: u4 = switch (self.target.?.cpu.arch) { |
| 2645 | .x86_64 => 1, | 2671 | .x86_64 => 1, |
| 2646 | .aarch64 => 2 * @sizeOf(u32), | 2672 | .aarch64 => 2 * @sizeOf(u32), |
| 2647 | else => unreachable, | 2673 | else => unreachable, |
| ... | @@ -2660,17 +2686,40 @@ fn writeExportInfo(self: *Zld) !void { | ... | @@ -2660,17 +2686,40 @@ fn writeExportInfo(self: *Zld) !void { |
| 2660 | defer trie.deinit(); | 2686 | defer trie.deinit(); |
| 2661 | 2687 | ||
| 2662 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2688 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2689 | const base_address = text_segment.inner.vmaddr; | ||
| 2663 | 2690 | ||
| 2664 | // TODO export items for dylibs | 2691 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 2665 | const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint; | 2692 | log.debug("writing export trie", .{}); |
| 2666 | const reg = sym.cast(Symbol.Regular) orelse unreachable; | ||
| 2667 | assert(reg.address >= text_segment.inner.vmaddr); | ||
| 2668 | 2693 | ||
| 2669 | try trie.put(.{ | 2694 | const Sorter = struct { |
| 2670 | .name = sym.name, | 2695 | fn lessThan(_: void, a: []const u8, b: []const u8) bool { |
| 2671 | .vmaddr_offset = reg.address - text_segment.inner.vmaddr, | 2696 | return mem.lessThan(u8, a, b); |
| 2672 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | 2697 | } |
| 2673 | }); | 2698 | }; |
| 2699 | |||
| 2700 | var sorted_globals = std.ArrayList([]const u8).init(self.allocator); | ||
| 2701 | defer sorted_globals.deinit(); | ||
| 2702 | |||
| 2703 | for (self.globals.values()) |sym| { | ||
| 2704 | const reg = sym.cast(Symbol.Regular) orelse continue; | ||
| 2705 | if (reg.linkage != .global) continue; | ||
| 2706 | try sorted_globals.append(sym.name); | ||
| 2707 | } | ||
| 2708 | |||
| 2709 | std.sort.sort([]const u8, sorted_globals.items, {}, Sorter.lessThan); | ||
| 2710 | |||
| 2711 | for (sorted_globals.items) |sym_name| { | ||
| 2712 | const sym = self.globals.get(sym_name) orelse unreachable; | ||
| 2713 | const reg = sym.cast(Symbol.Regular) orelse unreachable; | ||
| 2714 | |||
| 2715 | log.debug(" | putting '{s}' defined at 0x{x}", .{ reg.base.name, reg.address }); | ||
| 2716 | |||
| 2717 | try trie.put(.{ | ||
| 2718 | .name = sym.name, | ||
| 2719 | .vmaddr_offset = reg.address - base_address, | ||
| 2720 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | ||
| 2721 | }); | ||
| 2722 | } | ||
| 2674 | 2723 | ||
| 2675 | try trie.finalize(); | 2724 | try trie.finalize(); |
| 2676 | 2725 | ||
| ... | @@ -2975,7 +3024,7 @@ fn writeStringTable(self: *Zld) !void { | ... | @@ -2975,7 +3024,7 @@ fn writeStringTable(self: *Zld) !void { |
| 2975 | 3024 | ||
| 2976 | try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); | 3025 | try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); |
| 2977 | 3026 | ||
| 2978 | if (symtab.strsize > self.strtab.items.len and self.arch.? == .x86_64) { | 3027 | if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) { |
| 2979 | // This is the last section, so we need to pad it out. | 3028 | // This is the last section, so we need to pad it out. |
| 2980 | try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1); | 3029 | try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1); |
| 2981 | } | 3030 | } |
| ... | @@ -3023,7 +3072,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { | ... | @@ -3023,7 +3072,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { |
| 3023 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 3072 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 3024 | const fileoff = seg.inner.fileoff + seg.inner.filesize; | 3073 | const fileoff = seg.inner.fileoff + seg.inner.filesize; |
| 3025 | const needed_size = CodeSignature.calcCodeSignaturePaddingSize( | 3074 | const needed_size = CodeSignature.calcCodeSignaturePaddingSize( |
| 3026 | self.out_path.?, | 3075 | self.output.?.path, |
| 3027 | fileoff, | 3076 | fileoff, |
| 3028 | self.page_size.?, | 3077 | self.page_size.?, |
| 3029 | ); | 3078 | ); |
| ... | @@ -3049,7 +3098,7 @@ fn writeCodeSignature(self: *Zld) !void { | ... | @@ -3049,7 +3098,7 @@ fn writeCodeSignature(self: *Zld) !void { |
| 3049 | defer code_sig.deinit(); | 3098 | defer code_sig.deinit(); |
| 3050 | try code_sig.calcAdhocSignature( | 3099 | try code_sig.calcAdhocSignature( |
| 3051 | self.file.?, | 3100 | self.file.?, |
| 3052 | self.out_path.?, | 3101 | self.output.?.path, |
| 3053 | text_seg.inner, | 3102 | text_seg.inner, |
| 3054 | code_sig_cmd, | 3103 | code_sig_cmd, |
| 3055 | .Exe, | 3104 | .Exe, |
| ... | @@ -3091,7 +3140,7 @@ fn writeHeader(self: *Zld) !void { | ... | @@ -3091,7 +3140,7 @@ fn writeHeader(self: *Zld) !void { |
| 3091 | cpu_subtype: macho.cpu_subtype_t, | 3140 | cpu_subtype: macho.cpu_subtype_t, |
| 3092 | }; | 3141 | }; |
| 3093 | 3142 | ||
| 3094 | const cpu_info: CpuInfo = switch (self.arch.?) { | 3143 | const cpu_info: CpuInfo = switch (self.target.?.cpu.arch) { |
| 3095 | .aarch64 => .{ | 3144 | .aarch64 => .{ |
| 3096 | .cpu_type = macho.CPU_TYPE_ARM64, | 3145 | .cpu_type = macho.CPU_TYPE_ARM64, |
| 3097 | .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL, | 3146 | .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL, |
| ... | @@ -3104,8 +3153,22 @@ fn writeHeader(self: *Zld) !void { | ... | @@ -3104,8 +3153,22 @@ fn writeHeader(self: *Zld) !void { |
| 3104 | }; | 3153 | }; |
| 3105 | header.cputype = cpu_info.cpu_type; | 3154 | header.cputype = cpu_info.cpu_type; |
| 3106 | header.cpusubtype = cpu_info.cpu_subtype; | 3155 | header.cpusubtype = cpu_info.cpu_subtype; |
| 3107 | header.filetype = macho.MH_EXECUTE; | 3156 | |
| 3108 | header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; | 3157 | switch (self.output.?.tag) { |
| 3158 | .exe => { | ||
| 3159 | header.filetype = macho.MH_EXECUTE; | ||
| 3160 | header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; | ||
| 3161 | }, | ||
| 3162 | .dylib => { | ||
| 3163 | header.filetype = macho.MH_DYLIB; | ||
| 3164 | header.flags = macho.MH_NOUNDEFS | | ||
| 3165 | macho.MH_DYLDLINK | | ||
| 3166 | macho.MH_PIE | | ||
| 3167 | macho.MH_TWOLEVEL | | ||
| 3168 | macho.MH_NO_REEXPORTED_DYLIBS; | ||
| 3169 | }, | ||
| 3170 | } | ||
| 3171 | |||
| 3109 | header.reserved = 0; | 3172 | header.reserved = 0; |
| 3110 | 3173 | ||
| 3111 | if (self.tlv_section_index) |_| | 3174 | if (self.tlv_section_index) |_| |
src/main.zig-4| ... | @@ -226,7 +226,6 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v | ... | @@ -226,7 +226,6 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v |
| 226 | { | 226 | { |
| 227 | return punt_to_clang(arena, args); | 227 | return punt_to_clang(arena, args); |
| 228 | } else if (mem.eql(u8, cmd, "ld.lld") or | 228 | } else if (mem.eql(u8, cmd, "ld.lld") or |
| 229 | mem.eql(u8, cmd, "ld64.lld") or | ||
| 230 | mem.eql(u8, cmd, "lld-link") or | 229 | mem.eql(u8, cmd, "lld-link") or |
| 231 | mem.eql(u8, cmd, "wasm-ld")) | 230 | mem.eql(u8, cmd, "wasm-ld")) |
| 232 | { | 231 | { |
| ... | @@ -3384,7 +3383,6 @@ fn punt_to_llvm_ar(arena: *Allocator, args: []const []const u8) error{OutOfMemor | ... | @@ -3384,7 +3383,6 @@ fn punt_to_llvm_ar(arena: *Allocator, args: []const []const u8) error{OutOfMemor |
| 3384 | 3383 | ||
| 3385 | /// The first argument determines which backend is invoked. The options are: | 3384 | /// The first argument determines which backend is invoked. The options are: |
| 3386 | /// * `ld.lld` - ELF | 3385 | /// * `ld.lld` - ELF |
| 3387 | /// * `ld64.lld` - Mach-O | ||
| 3388 | /// * `lld-link` - COFF | 3386 | /// * `lld-link` - COFF |
| 3389 | /// * `wasm-ld` - WebAssembly | 3387 | /// * `wasm-ld` - WebAssembly |
| 3390 | /// TODO https://github.com/ziglang/zig/issues/3257 | 3388 | /// TODO https://github.com/ziglang/zig/issues/3257 |
| ... | @@ -3402,8 +3400,6 @@ pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemor | ... | @@ -3402,8 +3400,6 @@ pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemor |
| 3402 | const argc = @intCast(c_int, argv.len); | 3400 | const argc = @intCast(c_int, argv.len); |
| 3403 | if (mem.eql(u8, args[1], "ld.lld")) { | 3401 | if (mem.eql(u8, args[1], "ld.lld")) { |
| 3404 | break :rc llvm.LinkELF(argc, argv.ptr, true); | 3402 | break :rc llvm.LinkELF(argc, argv.ptr, true); |
| 3405 | } else if (mem.eql(u8, args[1], "ld64.lld")) { | ||
| 3406 | break :rc llvm.LinkMachO(argc, argv.ptr, true); | ||
| 3407 | } else if (mem.eql(u8, args[1], "lld-link")) { | 3403 | } else if (mem.eql(u8, args[1], "lld-link")) { |
| 3408 | break :rc llvm.LinkCOFF(argc, argv.ptr, true); | 3404 | break :rc llvm.LinkCOFF(argc, argv.ptr, true); |
| 3409 | } else if (mem.eql(u8, args[1], "wasm-ld")) { | 3405 | } else if (mem.eql(u8, args[1], "wasm-ld")) { |
src/zig_llvm.cpp-5| ... | @@ -1187,11 +1187,6 @@ int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early) { | ... | @@ -1187,11 +1187,6 @@ int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early) { |
| 1187 | return lld::elf::link(args, can_exit_early, llvm::outs(), llvm::errs()); | 1187 | return lld::elf::link(args, can_exit_early, llvm::outs(), llvm::errs()); |
| 1188 | } | 1188 | } |
| 1189 | 1189 | ||
| 1190 | int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early) { | ||
| 1191 | std::vector<const char *> args(argv, argv + argc); | ||
| 1192 | return lld::mach_o::link(args, can_exit_early, llvm::outs(), llvm::errs()); | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early) { | 1190 | int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early) { |
| 1196 | std::vector<const char *> args(argv, argv + argc); | 1191 | std::vector<const char *> args(argv, argv + argc); |
| 1197 | return lld::wasm::link(args, can_exit_early, llvm::outs(), llvm::errs()); | 1192 | return lld::wasm::link(args, can_exit_early, llvm::outs(), llvm::errs()); |
src/zig_llvm.h-1| ... | @@ -514,7 +514,6 @@ ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentT | ... | @@ -514,7 +514,6 @@ ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentT |
| 514 | 514 | ||
| 515 | ZIG_EXTERN_C int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early); | 515 | ZIG_EXTERN_C int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early); |
| 516 | ZIG_EXTERN_C int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early); | 516 | ZIG_EXTERN_C int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early); |
| 517 | ZIG_EXTERN_C int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early); | ||
| 518 | ZIG_EXTERN_C int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early); | 517 | ZIG_EXTERN_C int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early); |
| 519 | 518 | ||
| 520 | ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, | 519 | ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, |