authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-30 00:03:55+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-30 00:03:55+02:00
log81bf05bf6c1249c39273b494d3e337d300b4ddd5
tree9b53744d1d3a31ac82e153173bb9abe7bb52c999
parent37fbf5b0d3b0be131903e4895ee3703393b32d8f
parent0e15205521b9a8c95db3c1714dffe3be1df5cda1
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9266 from ziglang/zld-dylibs

zig ld can create dylibs now; remove system linker hack and any mention of ld64.lld from the codebase

10 files changed, 303 insertions(+), 535 deletions(-)

cmake/Findlld.cmake-1
......@@ -42,7 +42,6 @@ else()
4242 FIND_AND_ADD_LLD_LIB(lldMinGW)
4343 FIND_AND_ADD_LLD_LIB(lldELF)
4444 FIND_AND_ADD_LLD_LIB(lldCOFF)
45 FIND_AND_ADD_LLD_LIB(lldMachO)
4645 FIND_AND_ADD_LLD_LIB(lldWasm)
4746 FIND_AND_ADD_LLD_LIB(lldReaderWriter)
4847 FIND_AND_ADD_LLD_LIB(lldCore)
src/Compilation.zig+2-13
......@@ -879,24 +879,16 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
879879 break :blk false;
880880 };
881881
882 const darwin_can_use_system_linker_and_sdk =
882 const darwin_can_use_system_sdk =
883883 // comptime conditions
884884 ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and
885885 // runtime conditions
886886 (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()));
887887
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
896888 const sysroot = blk: {
897889 if (options.sysroot) |sysroot| {
898890 break :blk sysroot;
899 } else if (darwin_can_use_system_linker_and_sdk) {
891 } else if (darwin_can_use_system_sdk) {
900892 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
901893 // See https://github.com/ziglang/zig/issues/6996
902894 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 {
915907 break :blk false;
916908 } else if (options.c_source_files.len == 0) {
917909 break :blk false;
918 } else if (darwin_system_linker_hack) {
919 break :blk false;
920910 } else switch (options.output_mode) {
921911 .Lib, .Obj => break :blk false,
922912 .Exe => switch (options.optimize_mode) {
......@@ -1295,7 +1285,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12951285 .optimize_mode = options.optimize_mode,
12961286 .use_lld = use_lld,
12971287 .use_llvm = use_llvm,
1298 .system_linker_hack = darwin_system_linker_hack,
12991288 .link_libc = link_libc,
13001289 .link_libcpp = link_libcpp,
13011290 .link_libunwind = link_libunwind,
src/codegen/llvm/bindings.zig-2
......@@ -496,12 +496,10 @@ fn LLVMInitializeAllAsmParsers() callconv(.C) void {
496496
497497extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
498498extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
499extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
500499extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
501500
502501pub const LinkCOFF = ZigLLDLinkCOFF;
503502pub const LinkELF = ZigLLDLinkELF;
504pub const LinkMachO = ZigLLDLinkMachO;
505503pub const LinkWasm = ZigLLDLinkWasm;
506504
507505pub const ObjectFormatType = enum(c_int) {
src/link.zig-3
......@@ -61,9 +61,6 @@ pub const Options = struct {
6161 /// other objects.
6262 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
6363 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,
6764 link_libc: bool,
6865 link_libcpp: bool,
6966 link_libunwind: bool,
src/link/MachO.zig+171-440
......@@ -430,7 +430,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
430430
431431pub fn flush(self: *MachO, comp: *Compilation) !void {
432432 if (build_options.have_llvm and self.base.options.use_lld) {
433 return self.linkWithLLD(comp);
433 return self.linkWithZld(comp);
434434 } else {
435435 switch (self.base.options.effectiveOutputMode()) {
436436 .Exe, .Obj => {},
......@@ -593,7 +593,7 @@ fn resolveFramework(
593593 return null;
594594}
595595
596fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
596fn linkWithZld(self: *MachO, comp: *Compilation) !void {
597597 const tracy = trace(@src());
598598 defer tracy.end();
599599
......@@ -631,7 +631,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
631631 const stack_size = self.base.options.stack_size_override orelse 0;
632632 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
633633
634 const id_symlink_basename = "lld.id";
634 const id_symlink_basename = "zld.id";
635635
636636 var man: Cache.Manifest = undefined;
637637 defer if (!self.base.options.disable_lld_caching) man.deinit();
......@@ -669,7 +669,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
669669 man.hash.addStringSet(self.base.options.system_libs);
670670 man.hash.add(allow_shlib_undefined);
671671 man.hash.add(self.base.options.bind_global_refs_locally);
672 man.hash.add(self.base.options.system_linker_hack);
673672 man.hash.addOptionalBytes(self.base.options.sysroot);
674673
675674 // 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 {
682681 id_symlink_basename,
683682 &prev_digest_buf,
684683 ) 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) });
686685 // Handle this as a cache miss.
687686 break :blk prev_digest_buf[0..0];
688687 };
689688 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)});
691690 // Hot diggity dog! The output binary is already there.
692691 self.base.lock = man.toOwnedLock();
693692 return;
694693 }
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) });
696695
697696 // We are about to change the output file to be different, so we invalidate the build hash now.
698697 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
......@@ -726,495 +725,227 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
726725 if (!mem.eql(u8, the_object_path, full_out_path)) {
727726 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
728727 }
729 } else outer: {
730 const use_zld = blk: {
731 if (self.base.options.is_native_os and self.base.options.system_linker_hack) {
732 // If the user forces the use of ld64, make sure we are running native!
733 break :blk false;
734 }
735
736 if (self.base.options.target.cpu.arch == .aarch64) {
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 }
728 } else {
729 var zld = Zld.init(self.base.allocator);
730 defer {
731 zld.closeFiles();
732 zld.deinit();
733 }
734 zld.target = target;
735 zld.stack_size = stack_size;
747736
748 break :blk true;
749 };
737 // Positional arguments to the linker such as object files and static archives.
738 var positionals = std.ArrayList([]const u8).init(arena);
750739
751 if (use_zld) {
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;
740 try positionals.appendSlice(self.base.options.objects);
759741
760 // Positional arguments to the linker such as object files and static archives.
761 var positionals = std.ArrayList([]const u8).init(arena);
742 for (comp.c_object_table.keys()) |key| {
743 try positionals.append(key.status.success.object_path);
744 }
762745
763 try positionals.appendSlice(self.base.options.objects);
746 if (module_obj_path) |p| {
747 try positionals.append(p);
748 }
764749
765 for (comp.c_object_table.keys()) |key| {
766 try positionals.append(key.status.success.object_path);
767 }
750 try positionals.append(comp.compiler_rt_static_lib.?.full_object_path);
768751
769 if (module_obj_path) |p| {
770 try positionals.append(p);
771 }
752 // libc++ dep
753 if (self.base.options.link_libcpp) {
754 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
755 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
756 }
772757
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);
774760
775 // libc++ dep
776 if (self.base.options.link_libcpp) {
777 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
778 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
761 const system_libs = self.base.options.system_libs.keys();
762 for (system_libs) |link_lib| {
763 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
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;
779769 }
780770
781 // Shared and static libraries passed via `-l` flag.
782 var search_lib_names = std.ArrayList([]const u8).init(arena);
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 }
771 try search_lib_names.append(link_lib);
772 }
793773
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});
795780 }
781 }
796782
797 var lib_dirs = std.ArrayList([]const u8).init(arena);
798 for (self.base.options.lib_dirs) |dir| {
799 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
800 try lib_dirs.append(search_dir);
801 } else {
802 log.warn("directory not found for '-L{s}'", .{dir});
783 var libs = std.ArrayList([]const u8).init(arena);
784 var lib_not_found = false;
785 for (search_lib_names.items) |lib_name| {
786 // Assume ld64 default: -search_paths_first
787 // Look in each directory for a dylib (stub first), and then for archive
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;
803793 }
794 } else {
795 log.warn("library not found for '-l{s}'", .{lib_name});
796 lib_not_found = true;
804797 }
798 }
805799
806 var libs = std.ArrayList([]const u8).init(arena);
807 var lib_not_found = false;
808 for (search_lib_names.items) |lib_name| {
809 // Assume ld64 default: -search_paths_first
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 }
800 if (lib_not_found) {
801 log.warn("Library search paths:", .{});
802 for (lib_dirs.items) |dir| {
803 log.warn(" {s}", .{dir});
821804 }
805 }
822806
823 if (lib_not_found) {
824 log.warn("Library search paths:", .{});
825 for (lib_dirs.items) |dir| {
826 log.warn(" {s}", .{dir});
827 }
807 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
808 // we link against that instead of embedded libSystem.B.tbd file.
809 var native_libsystem_available = false;
810 if (self.base.options.is_native_os) blk: {
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;
828817 }
829
830 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
831 // we link against that instead of embedded libSystem.B.tbd file.
832 var native_libsystem_available = false;
833 if (self.base.options.is_native_os) blk: {
834 // Try stub file first. If we hit it, then we're done as the stub file
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);
818 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
819 // doesn't export libc.dylib which we'll need to resolve subsequently also.
820 if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| {
821 if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
822 try libs.append(libsystem_path);
823 try libs.append(libc_path);
838824 native_libsystem_available = true;
839825 break :blk;
840826 }
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 }
851827 }
852 if (!native_libsystem_available) {
853 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
854 "libc", "darwin", "libSystem.B.tbd",
855 });
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,
828 }
829 if (!native_libsystem_available) {
830 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
831 "libc", "darwin", "libSystem.B.tbd",
943832 });
944
945 break :outer;
833 try libs.append(full_path);
946834 }
947835
948 // Create an LLD command line and invoke it.
949 var argv = std.ArrayList([]const u8).init(self.base.allocator);
950 defer argv.deinit();
951
952 // TODO https://github.com/ziglang/zig/issues/6971
953 // Note that there is no need to check if running natively since we do that already
954 // when setting `system_linker_hack` in Compilation struct.
955 if (self.base.options.system_linker_hack) {
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");
836 // frameworks
837 var framework_dirs = std.ArrayList([]const u8).init(arena);
838 for (self.base.options.framework_dirs) |dir| {
839 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
840 try framework_dirs.append(search_dir);
841 } else {
842 log.warn("directory not found for '-F{s}'", .{dir});
843 }
965844 }
966845
967 if (self.base.options.lto) {
968 switch (self.base.options.optimize_mode) {
969 .Debug => {},
970 .ReleaseSmall => try argv.append("-O2"),
971 .ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
846 var framework_not_found = false;
847 for (self.base.options.frameworks) |framework| {
848 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
849 if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
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;
972856 }
973857 }
974 try argv.append("-demangle");
975858
976 if (self.base.options.rdynamic and !self.base.options.system_linker_hack) {
977 try argv.append("--export-dynamic");
859 if (framework_not_found) {
860 log.warn("Framework search paths:", .{});
861 for (framework_dirs.items) |dir| {
862 log.warn(" {s}", .{dir});
863 }
978864 }
979865
980 try argv.appendSlice(self.base.options.extra_lld_args);
981
982 if (self.base.options.z_nodelete) {
983 try argv.append("-z");
984 try argv.append("nodelete");
985 }
986 if (self.base.options.z_defs) {
987 try argv.append("-z");
988 try argv.append("defs");
866 // rpaths
867 var rpath_table = std.StringArrayHashMap(void).init(arena);
868 for (self.base.options.rpath_list) |rpath| {
869 if (rpath_table.contains(rpath)) continue;
870 try rpath_table.putNoClobber(rpath, {});
989871 }
990872
991 if (is_exe_or_dyn_lib) {
992 try argv.append("-dynamic");
873 var rpaths = std.ArrayList([]const u8).init(arena);
874 try rpaths.ensureCapacity(rpath_table.count());
875 for (rpath_table.keys()) |*key| {
876 rpaths.appendAssumeCapacity(key.*);
993877 }
994878
995 if (is_dyn_lib) {
996 try argv.append("-dylib");
997
998 if (self.base.options.version) |ver| {
999 const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major});
1000 try argv.append("-compatibility_version");
1001 try argv.append(compat_vers);
1002
1003 const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
1004 try argv.append("-current_version");
1005 try argv.append(cur_vers);
879 const output: Zld.Output = output: {
880 if (is_dyn_lib) {
881 const install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{
882 self.base.options.emit.?.sub_path,
883 });
884 break :output .{
885 .tag = .dylib,
886 .path = full_out_path,
887 .install_name = install_name,
888 };
1006889 }
890 break :output .{
891 .tag = .exe,
892 .path = full_out_path,
893 };
894 };
1007895
1008 const dylib_install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{self.base.options.emit.?.sub_path});
1009 try argv.append("-install_name");
1010 try argv.append(dylib_install_name);
1011 }
896 if (self.base.options.verbose_link) {
897 var argv = std.ArrayList([]const u8).init(arena);
1012898
1013 try argv.append("-arch");
1014 try argv.append(darwinArchString(target.cpu.arch));
899 try argv.append("zig");
900 try argv.append("ld");
1015901
1016 switch (target.os.tag) {
1017 .macos => {
1018 try argv.append("-macosx_version_min");
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);
902 if (is_exe_or_dyn_lib) {
903 try argv.append("-dynamic");
904 }
1033905
1034 try argv.append("-sdk_version");
1035 try argv.append(version_string);
906 if (is_dyn_lib) {
907 try argv.append("-dylib");
1036908
1037 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
1038 try argv.append("-pie");
1039 }
909 try argv.append("-install_name");
910 try argv.append(output.install_name.?);
911 }
1040912
1041 try argv.append("-o");
1042 try argv.append(full_out_path);
913 if (self.base.options.sysroot) |syslibroot| {
914 try argv.append("-syslibroot");
915 try argv.append(syslibroot);
916 }
1043917
1044 // rpaths
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) {
918 for (rpaths.items) |rpath| {
1049919 try argv.append("-rpath");
1050920 try argv.append(rpath);
1051921 }
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 }
1079922
1080 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
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 }
923 try argv.appendSlice(positionals.items);
1084924
1085 // Shared libraries.
1086 const system_libs = self.base.options.system_libs.keys();
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 }
925 try argv.append("-o");
926 try argv.append(output.path);
1102927
1103 // On Darwin, libSystem has libc in it, but also you have to use it
1104 // to make syscalls because the syscall numbers are not documented
1105 // and change between versions. So we always link against libSystem.
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);
928 if (native_libsystem_available) {
929 try argv.append("-lSystem");
930 try argv.append("-lc");
1144931 }
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);
1192932
1193 const term = child.wait() catch |err| {
1194 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
1195 return error.UnableToSpawnSelf;
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 }
933 for (search_lib_names.items) |l_name| {
934 try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name}));
935 }
1212936
1213 if (stderr.len != 0) {
1214 log.warn("unexpected LLD stderr:\n{s}", .{stderr});
1215 }
937 for (self.base.options.lib_dirs) |lib_dir| {
938 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
1216939 }
940
941 Compilation.dump_argv(argv.items);
1217942 }
943
944 try zld.link(positionals.items, output, .{
945 .syslibroot = self.base.options.sysroot,
946 .libs = libs.items,
947 .rpaths = rpaths.items,
948 });
1218949 }
1219950
1220951 if (!self.base.options.disable_lld_caching) {
src/link/MachO/Trie.zig+3-2
......@@ -334,8 +334,9 @@ pub fn finalize(self: *Trie) !void {
334334 self.ordered_nodes.shrinkRetainingCapacity(0);
335335 try self.ordered_nodes.ensureCapacity(self.allocator, self.node_count);
336336
337 const Fifo = std.fifo.LinearFifo(*Node, .{ .Static = std.math.maxInt(u8) });
338 var fifo = Fifo.init();
337 var fifo = std.fifo.LinearFifo(*Node, .Dynamic).init(self.allocator);
338 defer fifo.deinit();
339
339340 try fifo.writeItem(self.root.?);
340341
341342 while (fifo.readItem()) |next| {
src/link/MachO/Zld.zig+127-64
......@@ -25,10 +25,10 @@ usingnamespace @import("bind.zig");
2525
2626allocator: *Allocator,
2727
28arch: ?std.Target.Cpu.Arch = null,
28target: ?std.Target = null,
2929page_size: ?u16 = null,
3030file: ?fs.File = null,
31out_path: ?[]const u8 = null,
31output: ?Output = null,
3232
3333// TODO these args will become obselete once Zld is coalesced with incremental
3434// linker.
......@@ -54,6 +54,7 @@ dylinker_cmd_index: ?u16 = null,
5454data_in_code_cmd_index: ?u16 = null,
5555function_starts_cmd_index: ?u16 = null,
5656main_cmd_index: ?u16 = null,
57dylib_id_cmd_index: ?u16 = null,
5758version_min_cmd_index: ?u16 = null,
5859source_version_cmd_index: ?u16 = null,
5960uuid_cmd_index: ?u16 = null,
......@@ -118,6 +119,12 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
118119
119120stub_helper_stubs_start_off: ?u64 = null,
120121
122pub const Output = struct {
123 tag: enum { exe, dylib },
124 path: []const u8,
125 install_name: ?[]const u8 = null,
126};
127
121128const TlvOffset = struct {
122129 source_addr: u64,
123130 offset: u64,
......@@ -200,36 +207,17 @@ const LinkArgs = struct {
200207 rpaths: []const []const u8,
201208};
202209
203pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
210pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArgs) !void {
204211 if (files.len == 0) return error.NoInputFiles;
205 if (out_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 }
212 if (output.path.len == 0) return error.EmptyOutputPath;
225213
226 self.page_size = switch (self.arch.?) {
214 self.page_size = switch (self.target.?.cpu.arch) {
227215 .aarch64 => 0x4000,
228216 .x86_64 => 0x1000,
229217 else => unreachable,
230218 };
231 self.out_path = out_path;
232 self.file = try fs.cwd().createFile(out_path, .{
219 self.output = output;
220 self.file = try fs.cwd().createFile(self.output.?.path, .{
233221 .truncate = true,
234222 .read = true,
235223 .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
263251 break :full_path try self.allocator.dupe(u8, path);
264252 };
265253
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| {
267255 try self.objects.append(self.allocator, object);
268256 continue;
269257 }
270258
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| {
272260 try self.archives.append(self.allocator, archive);
273261 continue;
274262 }
275263
276264 if (try Dylib.createAndParseFromPath(
277265 self.allocator,
278 self.arch.?,
266 self.target.?.cpu.arch,
279267 full_path,
280268 .{ .syslibroot = syslibroot },
281269 )) |dylibs| {
......@@ -292,7 +280,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
292280 for (libs) |lib| {
293281 if (try Dylib.createAndParseFromPath(
294282 self.allocator,
295 self.arch.?,
283 self.target.?.cpu.arch,
296284 lib,
297285 .{ .syslibroot = syslibroot },
298286 )) |dylibs| {
......@@ -301,7 +289,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
301289 continue;
302290 }
303291
304 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
292 if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, lib)) |archive| {
305293 try self.archives.append(self.allocator, archive);
306294 continue;
307295 }
......@@ -989,7 +977,7 @@ fn allocateTextSegment(self: *Zld) !void {
989977 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
990978 stubs.size += nstubs * stubs.reserved2;
991979
992 const stub_size: u4 = switch (self.arch.?) {
980 const stub_size: u4 = switch (self.target.?.cpu.arch) {
993981 .x86_64 => 10,
994982 .aarch64 => 3 * @sizeOf(u32),
995983 else => unreachable,
......@@ -1226,7 +1214,7 @@ fn writeStubHelperCommon(self: *Zld) !void {
12261214 const data = &data_segment.sections.items[self.data_section_index.?];
12271215
12281216 self.stub_helper_stubs_start_off = blk: {
1229 switch (self.arch.?) {
1217 switch (self.target.?.cpu.arch) {
12301218 .x86_64 => {
12311219 const code_size = 15;
12321220 var code: [code_size]u8 = undefined;
......@@ -1358,7 +1346,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void {
13581346 const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
13591347 const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?];
13601348
1361 const stub_size: u4 = switch (self.arch.?) {
1349 const stub_size: u4 = switch (self.target.?.cpu.arch) {
13621350 .x86_64 => 10,
13631351 .aarch64 => 3 * @sizeOf(u32),
13641352 else => unreachable,
......@@ -1384,7 +1372,7 @@ fn writeStub(self: *Zld, index: u32) !void {
13841372 log.debug("writing stub at 0x{x}", .{stub_off});
13851373 var code = try self.allocator.alloc(u8, stubs.reserved2);
13861374 defer self.allocator.free(code);
1387 switch (self.arch.?) {
1375 switch (self.target.?.cpu.arch) {
13881376 .x86_64 => {
13891377 assert(la_ptr_addr >= stub_addr + stubs.reserved2);
13901378 const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2);
......@@ -1447,7 +1435,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
14471435 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
14481436 const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?];
14491437
1450 const stub_size: u4 = switch (self.arch.?) {
1438 const stub_size: u4 = switch (self.target.?.cpu.arch) {
14511439 .x86_64 => 10,
14521440 .aarch64 => 3 * @sizeOf(u32),
14531441 else => unreachable,
......@@ -1455,7 +1443,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
14551443 const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size;
14561444 var code = try self.allocator.alloc(u8, stub_size);
14571445 defer self.allocator.free(code);
1458 switch (self.arch.?) {
1446 switch (self.target.?.cpu.arch) {
14591447 .x86_64 => {
14601448 const displacement = try math.cast(
14611449 i32,
......@@ -1999,7 +1987,7 @@ fn populateMetadata(self: *Zld) !void {
19991987 if (self.text_section_index == null) {
20001988 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20011989 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) {
20031991 .x86_64 => 0,
20041992 .aarch64 => 2,
20051993 else => unreachable, // unhandled architecture type
......@@ -2013,12 +2001,12 @@ fn populateMetadata(self: *Zld) !void {
20132001 if (self.stubs_section_index == null) {
20142002 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20152003 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) {
20172005 .x86_64 => 0,
20182006 .aarch64 => 2,
20192007 else => unreachable, // unhandled architecture type
20202008 };
2021 const stub_size: u4 = switch (self.arch.?) {
2009 const stub_size: u4 = switch (self.target.?.cpu.arch) {
20222010 .x86_64 => 6,
20232011 .aarch64 => 3 * @sizeOf(u32),
20242012 else => unreachable, // unhandled architecture type
......@@ -2033,12 +2021,12 @@ fn populateMetadata(self: *Zld) !void {
20332021 if (self.stub_helper_section_index == null) {
20342022 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20352023 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) {
20372025 .x86_64 => 0,
20382026 .aarch64 => 2,
20392027 else => unreachable, // unhandled architecture type
20402028 };
2041 const stub_helper_size: u6 = switch (self.arch.?) {
2029 const stub_helper_size: u6 = switch (self.target.?.cpu.arch) {
20422030 .x86_64 => 15,
20432031 .aarch64 => 6 * @sizeOf(u32),
20442032 else => unreachable,
......@@ -2187,7 +2175,7 @@ fn populateMetadata(self: *Zld) !void {
21872175 try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd });
21882176 }
21892177
2190 if (self.main_cmd_index == null) {
2178 if (self.main_cmd_index == null and self.output.?.tag == .exe) {
21912179 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
21922180 try self.load_commands.append(self.allocator, .{
21932181 .Main = .{
......@@ -2199,6 +2187,41 @@ fn populateMetadata(self: *Zld) !void {
21992187 });
22002188 }
22012189
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
22022225 if (self.source_version_cmd_index == null) {
22032226 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
22042227 try self.load_commands.append(self.allocator, .{
......@@ -2237,7 +2260,7 @@ fn addDataInCodeLC(self: *Zld) !void {
22372260}
22382261
22392262fn 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) {
22412264 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
22422265 try self.load_commands.append(self.allocator, .{
22432266 .LinkeditData = .{
......@@ -2355,19 +2378,20 @@ fn flush(self: *Zld) !void {
23552378 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?);
23562379 }
23572380
2358 if (self.arch.? == .aarch64) {
2381 if (self.target.?.cpu.arch == .aarch64) {
23592382 try self.writeCodeSignaturePadding();
23602383 }
23612384
23622385 try self.writeLoadCommands();
23632386 try self.writeHeader();
23642387
2365 if (self.arch.? == .aarch64) {
2388 if (self.target.?.cpu.arch == .aarch64) {
23662389 try self.writeCodeSignature();
23672390 }
23682391
23692392 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, .{});
23712395 }
23722396}
23732397
......@@ -2392,6 +2416,8 @@ fn writeGotEntries(self: *Zld) !void {
23922416}
23932417
23942418fn setEntryPoint(self: *Zld) !void {
2419 if (self.output.?.tag != .exe) return;
2420
23952421 // TODO we should respect the -entry flag passed in by the user to set a custom
23962422 // entrypoint. For now, assume default of `_main`.
23972423 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
......@@ -2636,12 +2662,12 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
26362662 }
26372663 assert(self.stubs.items.len <= offsets.items.len);
26382664
2639 const stub_size: u4 = switch (self.arch.?) {
2665 const stub_size: u4 = switch (self.target.?.cpu.arch) {
26402666 .x86_64 => 10,
26412667 .aarch64 => 3 * @sizeOf(u32),
26422668 else => unreachable,
26432669 };
2644 const off: u4 = switch (self.arch.?) {
2670 const off: u4 = switch (self.target.?.cpu.arch) {
26452671 .x86_64 => 1,
26462672 .aarch64 => 2 * @sizeOf(u32),
26472673 else => unreachable,
......@@ -2660,17 +2686,40 @@ fn writeExportInfo(self: *Zld) !void {
26602686 defer trie.deinit();
26612687
26622688 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2689 const base_address = text_segment.inner.vmaddr;
26632690
2664 // TODO export items for dylibs
2665 const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint;
2666 const reg = sym.cast(Symbol.Regular) orelse unreachable;
2667 assert(reg.address >= text_segment.inner.vmaddr);
2691 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
2692 log.debug("writing export trie", .{});
26682693
2669 try trie.put(.{
2670 .name = sym.name,
2671 .vmaddr_offset = reg.address - text_segment.inner.vmaddr,
2672 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2673 });
2694 const Sorter = struct {
2695 fn lessThan(_: void, a: []const u8, b: []const u8) bool {
2696 return mem.lessThan(u8, a, b);
2697 }
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 }
26742723
26752724 try trie.finalize();
26762725
......@@ -2975,7 +3024,7 @@ fn writeStringTable(self: *Zld) !void {
29753024
29763025 try self.file.?.pwriteAll(self.strtab.items, symtab.stroff);
29773026
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) {
29793028 // This is the last section, so we need to pad it out.
29803029 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
29813030 }
......@@ -3023,7 +3072,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void {
30233072 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
30243073 const fileoff = seg.inner.fileoff + seg.inner.filesize;
30253074 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
3026 self.out_path.?,
3075 self.output.?.path,
30273076 fileoff,
30283077 self.page_size.?,
30293078 );
......@@ -3049,7 +3098,7 @@ fn writeCodeSignature(self: *Zld) !void {
30493098 defer code_sig.deinit();
30503099 try code_sig.calcAdhocSignature(
30513100 self.file.?,
3052 self.out_path.?,
3101 self.output.?.path,
30533102 text_seg.inner,
30543103 code_sig_cmd,
30553104 .Exe,
......@@ -3091,7 +3140,7 @@ fn writeHeader(self: *Zld) !void {
30913140 cpu_subtype: macho.cpu_subtype_t,
30923141 };
30933142
3094 const cpu_info: CpuInfo = switch (self.arch.?) {
3143 const cpu_info: CpuInfo = switch (self.target.?.cpu.arch) {
30953144 .aarch64 => .{
30963145 .cpu_type = macho.CPU_TYPE_ARM64,
30973146 .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL,
......@@ -3104,8 +3153,22 @@ fn writeHeader(self: *Zld) !void {
31043153 };
31053154 header.cputype = cpu_info.cpu_type;
31063155 header.cpusubtype = cpu_info.cpu_subtype;
3107 header.filetype = macho.MH_EXECUTE;
3108 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
3156
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
31093172 header.reserved = 0;
31103173
31113174 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
226226 {
227227 return punt_to_clang(arena, args);
228228 } else if (mem.eql(u8, cmd, "ld.lld") or
229 mem.eql(u8, cmd, "ld64.lld") or
230229 mem.eql(u8, cmd, "lld-link") or
231230 mem.eql(u8, cmd, "wasm-ld"))
232231 {
......@@ -3384,7 +3383,6 @@ fn punt_to_llvm_ar(arena: *Allocator, args: []const []const u8) error{OutOfMemor
33843383
33853384/// The first argument determines which backend is invoked. The options are:
33863385/// * `ld.lld` - ELF
3387/// * `ld64.lld` - Mach-O
33883386/// * `lld-link` - COFF
33893387/// * `wasm-ld` - WebAssembly
33903388/// 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
34023400 const argc = @intCast(c_int, argv.len);
34033401 if (mem.eql(u8, args[1], "ld.lld")) {
34043402 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);
34073403 } else if (mem.eql(u8, args[1], "lld-link")) {
34083404 break :rc llvm.LinkCOFF(argc, argv.ptr, true);
34093405 } 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) {
11871187 return lld::elf::link(args, can_exit_early, llvm::outs(), llvm::errs());
11881188}
11891189
1190int 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
11951190int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early) {
11961191 std::vector<const char *> args(argv, argv + argc);
11971192 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
514514
515515ZIG_EXTERN_C int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early);
516516ZIG_EXTERN_C int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early);
517ZIG_EXTERN_C int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early);
518517ZIG_EXTERN_C int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early);
519518
520519ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,