authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-25 07:51:21+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-25 07:51:21+02:00
log350ead9cb2ce87485569fbf630f2906864f35a6b
tree8c0f8fe31061a60db637ffc9120f800a0379beb1
parent8216ce67895f5605d1720df4e5e6636395f2fc92
parentddd2cd73307c06906a8d120b41fd5ab8864797a1
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9229 from ziglang/zld-objc-frameworks

zig ld: link Obj-C, link frameworks, improve linker's implementation

14 files changed, 1105 insertions(+), 1256 deletions(-)

CMakeLists.txt-1
......@@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES
579579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
580580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
581581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig"
583582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
584583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
585584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/Compilation.zig+10-2
......@@ -2857,7 +2857,7 @@ pub fn addCCArgs(
28572857 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
28582858
28592859 switch (ext) {
2860 .c, .cpp, .h => {
2860 .c, .cpp, .m, .h => {
28612861 try argv.appendSlice(&[_][]const u8{
28622862 "-nostdinc",
28632863 "-fno-spell-checking",
......@@ -3148,6 +3148,7 @@ pub const FileExt = enum {
31483148 c,
31493149 cpp,
31503150 h,
3151 m,
31513152 ll,
31523153 bc,
31533154 assembly,
......@@ -3159,7 +3160,7 @@ pub const FileExt = enum {
31593160
31603161 pub fn clangSupportsDepFile(ext: FileExt) bool {
31613162 return switch (ext) {
3162 .c, .cpp, .h => true,
3163 .c, .cpp, .h, .m => true,
31633164
31643165 .ll,
31653166 .bc,
......@@ -3193,6 +3194,10 @@ pub fn hasCppExt(filename: []const u8) bool {
31933194 mem.endsWith(u8, filename, ".cxx");
31943195}
31953196
3197pub fn hasObjCExt(filename: []const u8) bool {
3198 return mem.endsWith(u8, filename, ".m");
3199}
3200
31963201pub fn hasAsmExt(filename: []const u8) bool {
31973202 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
31983203}
......@@ -3229,6 +3234,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
32293234 return .c;
32303235 } else if (hasCppExt(filename)) {
32313236 return .cpp;
3237 } else if (hasObjCExt(filename)) {
3238 return .m;
32323239 } else if (mem.endsWith(u8, filename, ".ll")) {
32333240 return .ll;
32343241 } else if (mem.endsWith(u8, filename, ".bc")) {
......@@ -3252,6 +3259,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
32523259
32533260test "classifyFileExt" {
32543261 try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));
3262 try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m"));
32553263 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));
32563264 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so"));
32573265 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1"));
src/link/MachO.zig+142-176
......@@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514514 }
515515}
516516
517fn resolvePaths(
518 arena: *Allocator,
519 resolved_paths: *std.ArrayList([]const u8),
520 syslibroot: ?[]const u8,
521 search_dirs: []const []const u8,
522 lib_names: []const []const u8,
523 kind: enum { lib, framework },
524) !void {
525 var resolved_dirs = std.ArrayList([]const u8).init(arena);
526 for (search_dirs) |dir| {
527 if (fs.path.isAbsolute(dir)) {
528 var candidates = std.ArrayList([]const u8).init(arena);
529 if (syslibroot) |root| {
530 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
531 try candidates.append(full_path);
532 }
533 try candidates.append(dir);
534
535 var found = false;
536 for (candidates.items) |candidate| {
537 // Verify that search path actually exists
538 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
539 error.FileNotFound => continue,
540 else => |e| return e,
541 };
542 defer tmp.close();
543
544 try resolved_dirs.append(candidate);
545 found = true;
546 break;
547 }
548
549 if (!found) {
550 switch (kind) {
551 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
552 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
553 }
554 }
555 } else {
556 // Verify that search path actually exists
557 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
558 error.FileNotFound => {
559 switch (kind) {
560 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
561 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
562 }
563 continue;
564 },
565 else => |e| return e,
566 };
567 defer tmp.close();
568
569 try resolved_dirs.append(dir);
570 }
571 }
572
573 // Assume ld64 default: -search_paths_first
574 // Look in each directory for a dylib (next, tbd), and then for archive
575 // TODO implement alternative: -search_dylibs_first
576 const exts = switch (kind) {
577 .lib => &[_][]const u8{ "dylib", "tbd", "a" },
578 .framework => &[_][]const u8{ "dylib", "tbd" },
579 };
580
581 for (lib_names) |lib_name| {
582 var found = false;
583
584 ext: for (exts) |ext| {
585 const lib_name_ext = blk: {
586 switch (kind) {
587 .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }),
588 .framework => {
589 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});
590 const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext });
591 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn });
592 },
593 }
594 };
595
596 for (resolved_dirs.items) |dir| {
597 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });
598
599 // Check if the lib file exists.
600 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
601 error.FileNotFound => continue,
602 else => |e| return e,
603 };
604 defer tmp.close();
605
606 try resolved_paths.append(full_path);
607 found = true;
608 break :ext;
609 }
610 }
611
612 if (!found) {
613 switch (kind) {
614 .lib => {
615 log.warn("library not found for '-l{s}'", .{lib_name});
616 log.warn("Library search paths:", .{});
617 },
618 .framework => {
619 log.warn("framework not found for '-f{s}'", .{lib_name});
620 log.warn("Framework search paths:", .{});
621 },
622 }
623 for (resolved_dirs.items) |dir| {
624 log.warn(" {s}", .{dir});
625 }
626 }
627 }
628}
629
517630fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
518631 const tracy = trace(@src());
519632 defer tracy.end();
......@@ -676,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
676789 zld.deinit();
677790 }
678791 zld.arch = target.cpu.arch;
792 zld.syslibroot = self.base.options.syslibroot;
679793 zld.stack_size = stack_size;
680794
681795 // Positional arguments to the linker such as object files and static archives.
......@@ -700,7 +814,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
700814 }
701815
702816 // Shared and static libraries passed via `-l` flag.
703 var libs = std.ArrayList([]const u8).init(arena);
704817 var search_lib_names = std.ArrayList([]const u8).init(arena);
705818
706819 const system_libs = self.base.options.system_libs.keys();
......@@ -716,84 +829,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
716829 try search_lib_names.append(link_lib);
717830 }
718831
719 var search_lib_dirs = std.ArrayList([]const u8).init(arena);
720
721 for (self.base.options.lib_dirs) |path| {
722 if (fs.path.isAbsolute(path)) {
723 var candidates = std.ArrayList([]const u8).init(arena);
724 if (self.base.options.syslibroot) |syslibroot| {
725 const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path });
726 try candidates.append(full_path);
727 }
728 try candidates.append(path);
729
730 var found = false;
731 for (candidates.items) |candidate| {
732 // Verify that search path actually exists
733 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
734 error.FileNotFound => continue,
735 else => |e| return e,
736 };
737 defer tmp.close();
738
739 try search_lib_dirs.append(candidate);
740 found = true;
741 break;
742 }
743
744 if (!found) {
745 log.warn("directory not found for '-L{s}'", .{path});
746 }
747 } else {
748 // Verify that search path actually exists
749 var tmp = fs.cwd().openDir(path, .{}) catch |err| switch (err) {
750 error.FileNotFound => {
751 log.warn("directory not found for '-L{s}'", .{path});
752 continue;
753 },
754 else => |e| return e,
755 };
756 defer tmp.close();
757
758 try search_lib_dirs.append(path);
759 }
760 }
761
762 // Assume ld64 default: -search_paths_first
763 // Look in each directory for a dylib (next, tbd), and then for archive
764 // TODO implement alternative: -search_dylibs_first
765 const exts = &[_][]const u8{ "dylib", "tbd", "a" };
766
767 for (search_lib_names.items) |l_name| {
768 var found = false;
769
770 ext: for (exts) |ext| {
771 const l_name_ext = try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ l_name, ext });
772
773 for (search_lib_dirs.items) |lib_dir| {
774 const full_path = try fs.path.join(arena, &[_][]const u8{ lib_dir, l_name_ext });
775
776 // Check if the lib file exists.
777 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
778 error.FileNotFound => continue,
779 else => |e| return e,
780 };
781 defer tmp.close();
782
783 try libs.append(full_path);
784 found = true;
785 break :ext;
786 }
787 }
788
789 if (!found) {
790 log.warn("library not found for '-l{s}'", .{l_name});
791 log.warn("Library search paths:", .{});
792 for (search_lib_dirs.items) |lib_dir| {
793 log.warn(" {s}", .{lib_dir});
794 }
795 }
796 }
832 var libs = std.ArrayList([]const u8).init(arena);
833 try resolvePaths(
834 arena,
835 &libs,
836 self.base.options.syslibroot,
837 self.base.options.lib_dirs,
838 search_lib_names.items,
839 .lib,
840 );
797841
798842 // rpaths
799843 var rpath_table = std.StringArrayHashMap(void).init(arena);
......@@ -809,9 +853,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
809853 }
810854
811855 // frameworks
812 for (self.base.options.frameworks) |framework| {
813 log.warn("frameworks not yet supported for '-framework {s}'", .{framework});
814 }
856 try resolvePaths(
857 arena,
858 &libs,
859 self.base.options.syslibroot,
860 self.base.options.framework_dirs,
861 self.base.options.frameworks,
862 .framework,
863 );
815864
816865 if (self.base.options.verbose_link) {
817866 var argv = std.ArrayList([]const u8).init(arena);
......@@ -1731,18 +1780,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
17311780 if (self.pagezero_segment_cmd_index == null) {
17321781 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
17331782 try self.load_commands.append(self.base.allocator, .{
1734 .Segment = SegmentCommand.empty(.{
1735 .cmd = macho.LC_SEGMENT_64,
1736 .cmdsize = @sizeOf(macho.segment_command_64),
1737 .segname = makeStaticString("__PAGEZERO"),
1738 .vmaddr = 0,
1783 .Segment = SegmentCommand.empty("__PAGEZERO", .{
17391784 .vmsize = 0x100000000, // size always set to 4GB
1740 .fileoff = 0,
1741 .filesize = 0,
1742 .maxprot = 0,
1743 .initprot = 0,
1744 .nsects = 0,
1745 .flags = 0,
17461785 }),
17471786 });
17481787 self.header_dirty = true;
......@@ -1761,18 +1800,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
17611800 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
17621801
17631802 try self.load_commands.append(self.base.allocator, .{
1764 .Segment = SegmentCommand.empty(.{
1765 .cmd = macho.LC_SEGMENT_64,
1766 .cmdsize = @sizeOf(macho.segment_command_64),
1767 .segname = makeStaticString("__TEXT"),
1803 .Segment = SegmentCommand.empty("__TEXT", .{
17681804 .vmaddr = 0x100000000, // always starts at 4GB
17691805 .vmsize = needed_size,
1770 .fileoff = 0,
17711806 .filesize = needed_size,
17721807 .maxprot = maxprot,
17731808 .initprot = initprot,
1774 .nsects = 0,
1775 .flags = 0,
17761809 }),
17771810 });
17781811 self.header_dirty = true;
......@@ -1793,19 +1826,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
17931826
17941827 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
17951828
1796 try text_segment.addSection(self.base.allocator, .{
1797 .sectname = makeStaticString("__text"),
1798 .segname = makeStaticString("__TEXT"),
1829 try text_segment.addSection(self.base.allocator, "__text", .{
17991830 .addr = text_segment.inner.vmaddr + off,
18001831 .size = @intCast(u32, needed_size),
18011832 .offset = @intCast(u32, off),
18021833 .@"align" = alignment,
1803 .reloff = 0,
1804 .nreloc = 0,
18051834 .flags = flags,
1806 .reserved1 = 0,
1807 .reserved2 = 0,
1808 .reserved3 = 0,
18091835 });
18101836 self.header_dirty = true;
18111837 self.load_commands_dirty = true;
......@@ -1831,19 +1857,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
18311857
18321858 log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
18331859
1834 try text_segment.addSection(self.base.allocator, .{
1835 .sectname = makeStaticString("__stubs"),
1836 .segname = makeStaticString("__TEXT"),
1860 try text_segment.addSection(self.base.allocator, "__stubs", .{
18371861 .addr = text_segment.inner.vmaddr + off,
18381862 .size = needed_size,
18391863 .offset = @intCast(u32, off),
18401864 .@"align" = alignment,
1841 .reloff = 0,
1842 .nreloc = 0,
18431865 .flags = flags,
1844 .reserved1 = 0,
18451866 .reserved2 = stub_size,
1846 .reserved3 = 0,
18471867 });
18481868 self.header_dirty = true;
18491869 self.load_commands_dirty = true;
......@@ -1864,19 +1884,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
18641884
18651885 log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
18661886
1867 try text_segment.addSection(self.base.allocator, .{
1868 .sectname = makeStaticString("__stub_helper"),
1869 .segname = makeStaticString("__TEXT"),
1887 try text_segment.addSection(self.base.allocator, "__stub_helper", .{
18701888 .addr = text_segment.inner.vmaddr + off,
18711889 .size = needed_size,
18721890 .offset = @intCast(u32, off),
18731891 .@"align" = alignment,
1874 .reloff = 0,
1875 .nreloc = 0,
18761892 .flags = flags,
1877 .reserved1 = 0,
1878 .reserved2 = 0,
1879 .reserved3 = 0,
18801893 });
18811894 self.header_dirty = true;
18821895 self.load_commands_dirty = true;
......@@ -1893,18 +1906,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
18931906 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
18941907
18951908 try self.load_commands.append(self.base.allocator, .{
1896 .Segment = SegmentCommand.empty(.{
1897 .cmd = macho.LC_SEGMENT_64,
1898 .cmdsize = @sizeOf(macho.segment_command_64),
1899 .segname = makeStaticString("__DATA_CONST"),
1909 .Segment = SegmentCommand.empty("__DATA_CONST", .{
19001910 .vmaddr = address_and_offset.address,
19011911 .vmsize = needed_size,
19021912 .fileoff = address_and_offset.offset,
19031913 .filesize = needed_size,
19041914 .maxprot = maxprot,
19051915 .initprot = initprot,
1906 .nsects = 0,
1907 .flags = 0,
19081916 }),
19091917 });
19101918 self.header_dirty = true;
......@@ -1921,19 +1929,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19211929
19221930 log.debug("found __got section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
19231931
1924 try dc_segment.addSection(self.base.allocator, .{
1925 .sectname = makeStaticString("__got"),
1926 .segname = makeStaticString("__DATA_CONST"),
1932 try dc_segment.addSection(self.base.allocator, "__got", .{
19271933 .addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff,
19281934 .size = needed_size,
19291935 .offset = @intCast(u32, off),
19301936 .@"align" = 3, // 2^3 = @sizeOf(u64)
1931 .reloff = 0,
1932 .nreloc = 0,
19331937 .flags = flags,
1934 .reserved1 = 0,
1935 .reserved2 = 0,
1936 .reserved3 = 0,
19371938 });
19381939 self.header_dirty = true;
19391940 self.load_commands_dirty = true;
......@@ -1950,18 +1951,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19501951 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
19511952
19521953 try self.load_commands.append(self.base.allocator, .{
1953 .Segment = SegmentCommand.empty(.{
1954 .cmd = macho.LC_SEGMENT_64,
1955 .cmdsize = @sizeOf(macho.segment_command_64),
1956 .segname = makeStaticString("__DATA"),
1954 .Segment = SegmentCommand.empty("__DATA", .{
19571955 .vmaddr = address_and_offset.address,
19581956 .vmsize = needed_size,
19591957 .fileoff = address_and_offset.offset,
19601958 .filesize = needed_size,
19611959 .maxprot = maxprot,
19621960 .initprot = initprot,
1963 .nsects = 0,
1964 .flags = 0,
19651961 }),
19661962 });
19671963 self.header_dirty = true;
......@@ -1978,19 +1974,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19781974
19791975 log.debug("found __la_symbol_ptr section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
19801976
1981 try data_segment.addSection(self.base.allocator, .{
1982 .sectname = makeStaticString("__la_symbol_ptr"),
1983 .segname = makeStaticString("__DATA"),
1977 try data_segment.addSection(self.base.allocator, "__la_symbol_ptr", .{
19841978 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
19851979 .size = needed_size,
19861980 .offset = @intCast(u32, off),
19871981 .@"align" = 3, // 2^3 = @sizeOf(u64)
1988 .reloff = 0,
1989 .nreloc = 0,
19901982 .flags = flags,
1991 .reserved1 = 0,
1992 .reserved2 = 0,
1993 .reserved3 = 0,
19941983 });
19951984 self.header_dirty = true;
19961985 self.load_commands_dirty = true;
......@@ -1999,26 +1988,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19991988 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
20001989 self.data_section_index = @intCast(u16, data_segment.sections.items.len);
20011990
2002 const flags = macho.S_REGULAR;
20031991 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
20041992 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);
20051993 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.
20061994
20071995 log.debug("found __data section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
20081996
2009 try data_segment.addSection(self.base.allocator, .{
2010 .sectname = makeStaticString("__data"),
2011 .segname = makeStaticString("__DATA"),
1997 try data_segment.addSection(self.base.allocator, "__data", .{
20121998 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
20131999 .size = needed_size,
20142000 .offset = @intCast(u32, off),
20152001 .@"align" = 3, // 2^3 = @sizeOf(u64)
2016 .reloff = 0,
2017 .nreloc = 0,
2018 .flags = flags,
2019 .reserved1 = 0,
2020 .reserved2 = 0,
2021 .reserved3 = 0,
20222002 });
20232003 self.header_dirty = true;
20242004 self.load_commands_dirty = true;
......@@ -2033,18 +2013,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
20332013 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
20342014
20352015 try self.load_commands.append(self.base.allocator, .{
2036 .Segment = SegmentCommand.empty(.{
2037 .cmd = macho.LC_SEGMENT_64,
2038 .cmdsize = @sizeOf(macho.segment_command_64),
2039 .segname = makeStaticString("__LINKEDIT"),
2016 .Segment = SegmentCommand.empty("__LINKEDIT", .{
20402017 .vmaddr = address_and_offset.address,
2041 .vmsize = 0,
20422018 .fileoff = address_and_offset.offset,
2043 .filesize = 0,
20442019 .maxprot = maxprot,
20452020 .initprot = initprot,
2046 .nsects = 0,
2047 .flags = 0,
20482021 }),
20492022 });
20502023 self.header_dirty = true;
......@@ -2402,13 +2375,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
24022375 return vaddr;
24032376}
24042377
2405pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {
2406 var buf = [_]u8{0} ** 16;
2407 if (bytes.len > buf.len) @compileError("string too long; max 16 bytes");
2408 mem.copy(u8, &buf, bytes);
2409 return buf;
2410}
2411
24122378fn makeString(self: *MachO, bytes: []const u8) !u32 {
24132379 if (self.string_table_directory.get(bytes)) |offset| {
24142380 log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });
src/link/MachO/Archive.zig+41-22
......@@ -8,12 +8,13 @@ const macho = std.macho;
88const mem = std.mem;
99
1010const Allocator = mem.Allocator;
11const Arch = std.Target.Cpu.Arch;
1112const Object = @import("Object.zig");
1213
1314usingnamespace @import("commands.zig");
1415
1516allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,
17arch: ?Arch = null,
1718file: ?fs.File = null,
1819header: ?ar_hdr = null,
1920name: ?[]const u8 = null,
......@@ -85,10 +86,36 @@ const ar_hdr = extern struct {
8586 }
8687};
8788
88pub fn init(allocator: *Allocator) Archive {
89 return .{
89pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
90 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
91 error.FileNotFound => return null,
92 else => |e| return e,
93 };
94 errdefer file.close();
95
96 const archive = try allocator.create(Archive);
97 errdefer allocator.destroy(archive);
98
99 const name = try allocator.dupe(u8, path);
100 errdefer allocator.free(name);
101
102 archive.* = .{
90103 .allocator = allocator,
104 .arch = arch,
105 .name = name,
106 .file = file,
107 };
108
109 archive.parse() catch |err| switch (err) {
110 error.EndOfStream, error.NotArchive => {
111 archive.deinit();
112 allocator.destroy(archive);
113 return null;
114 },
115 else => |e| return e,
91116 };
117
118 return archive;
92119}
93120
94121pub fn deinit(self: *Archive) void {
......@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {
116143 const magic = try reader.readBytesNoEof(SARMAG);
117144
118145 if (!mem.eql(u8, &magic, ARMAG)) {
119 log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
120 return error.MalformedArchive;
146 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
147 return error.NotArchive;
121148 }
122149
123150 self.header = try reader.readStruct(ar_hdr);
124151
125152 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
126 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
127 return error.MalformedArchive;
153 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
154 return error.NotArchive;
128155 }
129156
130157 var embedded_name = try parseName(self.allocator, self.header.?, reader);
......@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
222249 var object = try self.allocator.create(Object);
223250 errdefer self.allocator.destroy(object);
224251
225 object.* = Object.init(self.allocator);
226 object.arch = self.arch.?;
227 object.file = try fs.cwd().openFile(self.name.?, .{});
228 object.name = name;
229 object.file_offset = @intCast(u32, try reader.context.getPos());
252 object.* = .{
253 .allocator = self.allocator,
254 .arch = self.arch.?,
255 .file = try fs.cwd().openFile(self.name.?, .{}),
256 .name = name,
257 .file_offset = @intCast(u32, try reader.context.getPos()),
258 };
230259 try object.parse();
231
232260 try reader.context.seekTo(0);
233261
234262 return object;
235263}
236
237pub fn isArchive(file: fs.File) !bool {
238 const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch |err| switch (err) {
239 error.EndOfStream => return false,
240 else => |e| return e,
241 };
242 try file.seekTo(0);
243 return mem.eql(u8, &magic, Archive.ARMAG);
244}
src/link/MachO/DebugSymbols.zig+7-59
......@@ -19,7 +19,6 @@ const MachO = @import("../MachO.zig");
1919const SrcFn = MachO.SrcFn;
2020const TextBlock = MachO.TextBlock;
2121const padToIdeal = MachO.padToIdeal;
22const makeStaticString = MachO.makeStaticString;
2322
2423usingnamespace @import("commands.zig");
2524
......@@ -212,18 +211,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
212211 log.debug("found dSym __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
213212
214213 try self.load_commands.append(allocator, .{
215 .Segment = SegmentCommand.empty(.{
216 .cmd = macho.LC_SEGMENT_64,
217 .cmdsize = @sizeOf(macho.segment_command_64),
218 .segname = makeStaticString("__DWARF"),
214 .Segment = SegmentCommand.empty("__DWARF", .{
219215 .vmaddr = vmaddr,
220216 .vmsize = needed_size,
221217 .fileoff = off,
222218 .filesize = needed_size,
223 .maxprot = 0,
224 .initprot = 0,
225 .nsects = 0,
226 .flags = 0,
227219 }),
228220 });
229221 self.header_dirty = true;
......@@ -234,19 +226,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
234226 self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len);
235227 assert(self.debug_string_table.items.len == 0);
236228
237 try dwarf_segment.addSection(allocator, .{
238 .sectname = makeStaticString("__debug_str"),
239 .segname = makeStaticString("__DWARF"),
229 try dwarf_segment.addSection(allocator, "__debug_str", .{
240230 .addr = dwarf_segment.inner.vmaddr,
241231 .size = @intCast(u32, self.debug_string_table.items.len),
242232 .offset = @intCast(u32, dwarf_segment.inner.fileoff),
243233 .@"align" = 1,
244 .reloff = 0,
245 .nreloc = 0,
246 .flags = macho.S_REGULAR,
247 .reserved1 = 0,
248 .reserved2 = 0,
249 .reserved3 = 0,
250234 });
251235 self.header_dirty = true;
252236 self.load_commands_dirty = true;
......@@ -262,19 +246,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
262246
263247 log.debug("found dSym __debug_info free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
264248
265 try dwarf_segment.addSection(allocator, .{
266 .sectname = makeStaticString("__debug_info"),
267 .segname = makeStaticString("__DWARF"),
249 try dwarf_segment.addSection(allocator, "__debug_info", .{
268250 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
269251 .size = file_size_hint,
270252 .offset = @intCast(u32, off),
271253 .@"align" = p_align,
272 .reloff = 0,
273 .nreloc = 0,
274 .flags = macho.S_REGULAR,
275 .reserved1 = 0,
276 .reserved2 = 0,
277 .reserved3 = 0,
278254 });
279255 self.header_dirty = true;
280256 self.load_commands_dirty = true;
......@@ -290,19 +266,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
290266
291267 log.debug("found dSym __debug_abbrev free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
292268
293 try dwarf_segment.addSection(allocator, .{
294 .sectname = makeStaticString("__debug_abbrev"),
295 .segname = makeStaticString("__DWARF"),
269 try dwarf_segment.addSection(allocator, "__debug_abbrev", .{
296270 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
297271 .size = file_size_hint,
298272 .offset = @intCast(u32, off),
299273 .@"align" = p_align,
300 .reloff = 0,
301 .nreloc = 0,
302 .flags = macho.S_REGULAR,
303 .reserved1 = 0,
304 .reserved2 = 0,
305 .reserved3 = 0,
306274 });
307275 self.header_dirty = true;
308276 self.load_commands_dirty = true;
......@@ -318,19 +286,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
318286
319287 log.debug("found dSym __debug_aranges free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
320288
321 try dwarf_segment.addSection(allocator, .{
322 .sectname = makeStaticString("__debug_aranges"),
323 .segname = makeStaticString("__DWARF"),
289 try dwarf_segment.addSection(allocator, "__debug_aranges", .{
324290 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
325291 .size = file_size_hint,
326292 .offset = @intCast(u32, off),
327293 .@"align" = p_align,
328 .reloff = 0,
329 .nreloc = 0,
330 .flags = macho.S_REGULAR,
331 .reserved1 = 0,
332 .reserved2 = 0,
333 .reserved3 = 0,
334294 });
335295 self.header_dirty = true;
336296 self.load_commands_dirty = true;
......@@ -346,19 +306,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
346306
347307 log.debug("found dSym __debug_line free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });
348308
349 try dwarf_segment.addSection(allocator, .{
350 .sectname = makeStaticString("__debug_line"),
351 .segname = makeStaticString("__DWARF"),
309 try dwarf_segment.addSection(allocator, "__debug_line", .{
352310 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
353311 .size = file_size_hint,
354312 .offset = @intCast(u32, off),
355313 .@"align" = p_align,
356 .reloff = 0,
357 .nreloc = 0,
358 .flags = macho.S_REGULAR,
359 .reserved1 = 0,
360 .reserved2 = 0,
361 .reserved3 = 0,
362314 });
363315 self.header_dirty = true;
364316 self.load_commands_dirty = true;
......@@ -692,14 +644,10 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {
692644}
693645
694646fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {
695 var cmd = SegmentCommand.empty(.{
696 .cmd = macho.LC_SEGMENT_64,
647 var cmd = SegmentCommand.empty("", .{
697648 .cmdsize = base_cmd.inner.cmdsize,
698 .segname = undefined,
699649 .vmaddr = base_cmd.inner.vmaddr,
700650 .vmsize = base_cmd.inner.vmsize,
701 .fileoff = 0,
702 .filesize = 0,
703651 .maxprot = base_cmd.inner.maxprot,
704652 .initprot = base_cmd.inner.initprot,
705653 .nsects = base_cmd.inner.nsects,
src/link/MachO/Dylib.zig+305-21
......@@ -3,20 +3,26 @@ const Dylib = @This();
33const std = @import("std");
44const assert = std.debug.assert;
55const fs = std.fs;
6const fmt = std.fmt;
67const log = std.log.scoped(.dylib);
78const macho = std.macho;
9const math = std.math;
810const mem = std.mem;
911
1012const Allocator = mem.Allocator;
13const Arch = std.Target.Cpu.Arch;
1114const Symbol = @import("Symbol.zig");
15const LibStub = @import("../tapi.zig").LibStub;
1216
1317usingnamespace @import("commands.zig");
1418
1519allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,
20
21arch: ?Arch = null,
1722header: ?macho.mach_header_64 = null,
1823file: ?fs.File = null,
1924name: ?[]const u8 = null,
25syslibroot: ?[]const u8 = null,
2026
2127ordinal: ?u16 = null,
2228
......@@ -33,19 +39,139 @@ id: ?Id = null,
3339/// a symbol is referenced by an object file.
3440symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3541
42// TODO add parsing re-exported libs from binary dylibs
43dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
44
3645pub const Id = struct {
3746 name: []const u8,
3847 timestamp: u32,
3948 current_version: u32,
4049 compatibility_version: u32,
4150
51 pub fn default(name: []const u8) Id {
52 return .{
53 .name = name,
54 .timestamp = 2,
55 .current_version = 0x10000,
56 .compatibility_version = 0x10000,
57 };
58 }
59
4260 pub fn deinit(id: *Id, allocator: *Allocator) void {
4361 allocator.free(id.name);
4462 }
63
64 const ParseError = fmt.ParseIntError || fmt.BufPrintError;
65
66 pub fn parseCurrentVersion(id: *Id, version: anytype) ParseError!void {
67 id.current_version = try parseVersion(version);
68 }
69
70 pub fn parseCompatibilityVersion(id: *Id, version: anytype) ParseError!void {
71 id.compatibility_version = try parseVersion(version);
72 }
73
74 fn parseVersion(version: anytype) ParseError!u32 {
75 const string = blk: {
76 switch (version) {
77 .int => |int| {
78 var out: u32 = 0;
79 const major = try math.cast(u16, int);
80 out += @intCast(u32, major) << 16;
81 return out;
82 },
83 .float => |float| {
84 var buf: [256]u8 = undefined;
85 break :blk try fmt.bufPrint(&buf, "{d:.2}", .{float});
86 },
87 .string => |string| {
88 break :blk string;
89 },
90 }
91 };
92
93 var out: u32 = 0;
94 var values: [3][]const u8 = undefined;
95
96 var split = mem.split(string, ".");
97 var count: u4 = 0;
98 while (split.next()) |value| {
99 if (count > 2) {
100 log.warn("malformed version field: {s}", .{string});
101 return 0x10000;
102 }
103 values[count] = value;
104 count += 1;
105 }
106
107 if (count > 2) {
108 out += try fmt.parseInt(u8, values[2], 10);
109 }
110 if (count > 1) {
111 out += @intCast(u32, try fmt.parseInt(u8, values[1], 10)) << 8;
112 }
113 out += @intCast(u32, try fmt.parseInt(u16, values[0], 10)) << 16;
114
115 return out;
116 }
45117};
46118
47pub fn init(allocator: *Allocator) Dylib {
48 return .{ .allocator = allocator };
119pub const Error = error{
120 OutOfMemory,
121 EmptyStubFile,
122 MismatchedCpuArchitecture,
123 UnsupportedCpuArchitecture,
124} || fs.File.OpenError || std.os.PReadError || Id.ParseError;
125
126pub fn createAndParseFromPath(
127 allocator: *Allocator,
128 arch: Arch,
129 path: []const u8,
130 syslibroot: ?[]const u8,
131) Error!?[]*Dylib {
132 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
133 error.FileNotFound => return null,
134 else => |e| return e,
135 };
136 errdefer file.close();
137
138 const dylib = try allocator.create(Dylib);
139 errdefer allocator.destroy(dylib);
140
141 const name = try allocator.dupe(u8, path);
142 errdefer allocator.free(name);
143
144 dylib.* = .{
145 .allocator = allocator,
146 .arch = arch,
147 .name = name,
148 .file = file,
149 .syslibroot = syslibroot,
150 };
151
152 dylib.parse() catch |err| switch (err) {
153 error.EndOfStream, error.NotDylib => {
154 try file.seekTo(0);
155
156 var lib_stub = LibStub.loadFromFile(allocator, file) catch {
157 dylib.deinit();
158 allocator.destroy(dylib);
159 return null;
160 };
161 defer lib_stub.deinit();
162
163 try dylib.parseFromStub(lib_stub);
164 },
165 else => |e| return e,
166 };
167
168 var dylibs = std.ArrayList(*Dylib).init(allocator);
169 defer dylibs.deinit();
170
171 try dylibs.append(dylib);
172 try dylib.parseDependentLibs(&dylibs);
173
174 return dylibs.toOwnedSlice();
49175}
50176
51177pub fn deinit(self: *Dylib) void {
......@@ -59,6 +185,11 @@ pub fn deinit(self: *Dylib) void {
59185 }
60186 self.symbols.deinit(self.allocator);
61187
188 for (self.dependent_libs.keys()) |key| {
189 self.allocator.free(key);
190 }
191 self.dependent_libs.deinit(self.allocator);
192
62193 if (self.name) |name| {
63194 self.allocator.free(name);
64195 }
......@@ -81,8 +212,8 @@ pub fn parse(self: *Dylib) !void {
81212 self.header = try reader.readStruct(macho.mach_header_64);
82213
83214 if (self.header.?.filetype != macho.MH_DYLIB) {
84 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
85 return error.MalformedDylib;
215 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
216 return error.NotDylib;
86217 }
87218
88219 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
......@@ -103,7 +234,7 @@ pub fn parse(self: *Dylib) !void {
103234 try self.parseSymbols();
104235}
105236
106pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
237fn readLoadCommands(self: *Dylib, reader: anytype) !void {
107238 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
108239
109240 var i: u16 = 0;
......@@ -127,15 +258,10 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
127258 }
128259}
129260
130pub fn parseId(self: *Dylib) !void {
261fn parseId(self: *Dylib) !void {
131262 const index = self.id_cmd_index orelse {
132263 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
133 self.id = .{
134 .name = try self.allocator.dupe(u8, self.name.?),
135 .timestamp = 2,
136 .current_version = 0,
137 .compatibility_version = 0,
138 };
264 self.id = Id.default(try self.allocator.dupe(u8, self.name.?));
139265 return;
140266 };
141267 const id_cmd = self.load_commands.items[index].Dylib;
......@@ -153,7 +279,7 @@ pub fn parseId(self: *Dylib) !void {
153279 };
154280}
155281
156pub fn parseSymbols(self: *Dylib) !void {
282fn parseSymbols(self: *Dylib) !void {
157283 const index = self.symtab_cmd_index orelse return;
158284 const symtab_cmd = self.load_commands.items[index].Symtab;
159285
......@@ -176,13 +302,171 @@ pub fn parseSymbols(self: *Dylib) !void {
176302 }
177303}
178304
179pub fn isDylib(file: fs.File) !bool {
180 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
181 error.EndOfStream => return false,
182 else => |e| return e,
305fn hasTarget(targets: []const []const u8, target: []const u8) bool {
306 for (targets) |t| {
307 if (mem.eql(u8, t, target)) return true;
308 }
309 return false;
310}
311
312fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
313 const expanded = &[_][]const u8{
314 try std.fmt.allocPrint(self.allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
315 try std.fmt.allocPrint(self.allocator, "_OBJC_METACLASS_$_{s}", .{sym_name}),
316 };
317
318 for (expanded) |sym| {
319 if (self.symbols.contains(sym)) continue;
320 try self.symbols.putNoClobber(self.allocator, sym, .{});
321 }
322}
323
324pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
325 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
326
327 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
328
329 const umbrella_lib = lib_stub.inner[0];
330
331 var id = Id.default(try self.allocator.dupe(u8, umbrella_lib.install_name));
332 if (umbrella_lib.current_version) |version| {
333 try id.parseCurrentVersion(version);
334 }
335 if (umbrella_lib.compatibility_version) |version| {
336 try id.parseCompatibilityVersion(version);
337 }
338 self.id = id;
339
340 const target_string: []const u8 = switch (self.arch.?) {
341 .aarch64 => "arm64-macos",
342 .x86_64 => "x86_64-macos",
343 else => unreachable,
183344 };
184 try file.seekTo(0);
185 return header.filetype == macho.MH_DYLIB;
345
346 var umbrella_libs = std.StringHashMap(void).init(self.allocator);
347 defer umbrella_libs.deinit();
348
349 for (lib_stub.inner) |stub, stub_index| {
350 if (!hasTarget(stub.targets, target_string)) continue;
351
352 if (stub_index > 0) {
353 // TODO I thought that we could switch on presence of `parent-umbrella` map;
354 // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib`
355 // BUT does not feature a `parent-umbrella` map as the only sublib. Apple's bug perhaps?
356 try umbrella_libs.put(stub.install_name, .{});
357 }
358
359 if (stub.exports) |exports| {
360 for (exports) |exp| {
361 if (!hasTarget(exp.targets, target_string)) continue;
362
363 if (exp.symbols) |symbols| {
364 for (symbols) |sym_name| {
365 if (self.symbols.contains(sym_name)) continue;
366 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
367 }
368 }
369
370 if (exp.objc_classes) |classes| {
371 for (classes) |sym_name| {
372 try self.addObjCClassSymbols(sym_name);
373 }
374 }
375 }
376 }
377
378 if (stub.reexports) |reexports| {
379 for (reexports) |reexp| {
380 if (!hasTarget(reexp.targets, target_string)) continue;
381
382 if (reexp.symbols) |symbols| {
383 for (symbols) |sym_name| {
384 if (self.symbols.contains(sym_name)) continue;
385 try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
386 }
387 }
388
389 if (reexp.objc_classes) |classes| {
390 for (classes) |sym_name| {
391 try self.addObjCClassSymbols(sym_name);
392 }
393 }
394 }
395 }
396
397 if (stub.objc_classes) |classes| {
398 for (classes) |sym_name| {
399 try self.addObjCClassSymbols(sym_name);
400 }
401 }
402 }
403
404 log.debug("{s}", .{umbrella_lib.install_name});
405
406 // TODO track which libs were already parsed in different steps
407 for (lib_stub.inner) |stub| {
408 if (!hasTarget(stub.targets, target_string)) continue;
409
410 if (stub.reexported_libraries) |reexports| {
411 for (reexports) |reexp| {
412 if (!hasTarget(reexp.targets, target_string)) continue;
413
414 for (reexp.libraries) |lib| {
415 if (umbrella_libs.contains(lib)) {
416 log.debug(" | {s} <= {s}", .{ lib, umbrella_lib.install_name });
417 continue;
418 }
419
420 log.debug(" | {s}", .{lib});
421 try self.dependent_libs.put(self.allocator, try self.allocator.dupe(u8, lib), {});
422 }
423 }
424 }
425 }
426}
427
428pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {
429 outer: for (self.dependent_libs.keys()) |lib| {
430 const dirname = fs.path.dirname(lib) orelse {
431 log.warn("unable to resolve dependency {s}", .{lib});
432 continue;
433 };
434 const filename = fs.path.basename(lib);
435 const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index|
436 filename[0..index]
437 else
438 filename;
439
440 for (&[_][]const u8{ "dylib", "tbd" }) |ext| {
441 const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{
442 without_ext,
443 ext,
444 });
445 defer self.allocator.free(with_ext);
446
447 const lib_path = if (self.syslibroot) |syslibroot|
448 try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext })
449 else
450 try fs.path.join(self.allocator, &.{ dirname, with_ext });
451
452 log.debug("trying dependency at fully resolved path {s}", .{lib_path});
453
454 const dylibs = (try createAndParseFromPath(
455 self.allocator,
456 self.arch.?,
457 lib_path,
458 self.syslibroot,
459 )) orelse {
460 continue;
461 };
462
463 try out.appendSlice(dylibs);
464
465 continue :outer;
466 } else {
467 log.warn("unable to resolve dependency {s}", .{lib});
468 }
469 }
186470}
187471
188472pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
......@@ -197,7 +481,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
197481 .@"type" = .proxy,
198482 .name = name,
199483 },
200 .file = .{ .dylib = self },
484 .file = self,
201485 };
202486
203487 return &proxy.base;
src/link/MachO/Object.zig+37-15
......@@ -11,6 +11,7 @@ const mem = std.mem;
1111const reloc = @import("reloc.zig");
1212
1313const Allocator = mem.Allocator;
14const Arch = std.Target.Cpu.Arch;
1415const Relocation = reloc.Relocation;
1516const Symbol = @import("Symbol.zig");
1617const parseName = @import("Zld.zig").parseName;
......@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;
1819usingnamespace @import("commands.zig");
1920
2021allocator: *Allocator,
21arch: ?std.Target.Cpu.Arch = null,
22arch: ?Arch = null,
2223header: ?macho.mach_header_64 = null,
2324file: ?fs.File = null,
2425file_offset: ?u32 = null,
......@@ -173,10 +174,36 @@ const DebugInfo = struct {
173174 }
174175};
175176
176pub fn init(allocator: *Allocator) Object {
177 return .{
177pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
178 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
179 error.FileNotFound => return null,
180 else => |e| return e,
181 };
182 errdefer file.close();
183
184 const object = try allocator.create(Object);
185 errdefer allocator.destroy(object);
186
187 const name = try allocator.dupe(u8, path);
188 errdefer allocator.free(name);
189
190 object.* = .{
178191 .allocator = allocator,
192 .arch = arch,
193 .name = name,
194 .file = file,
179195 };
196
197 object.parse() catch |err| switch (err) {
198 error.EndOfStream, error.NotObject => {
199 object.deinit();
200 allocator.destroy(object);
201 return null;
202 },
203 else => |e| return e,
204 };
205
206 return object;
180207}
181208
182209pub fn deinit(self: *Object) void {
......@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {
223250 self.header = try reader.readStruct(macho.mach_header_64);
224251
225252 if (self.header.?.filetype != macho.MH_OBJECT) {
226 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype });
227 return error.MalformedObject;
253 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
254 macho.MH_OBJECT,
255 self.header.?.filetype,
256 });
257
258 return error.NotObject;
228259 }
229260
230 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
261 const this_arch: Arch = switch (self.header.?.cputype) {
231262 macho.CPU_TYPE_ARM64 => .aarch64,
232263 macho.CPU_TYPE_X86_64 => .x86_64,
233264 else => |value| {
......@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {
533564 try self.data_in_code_entries.append(self.allocator, dice);
534565 }
535566}
536
537pub fn isObject(file: fs.File) !bool {
538 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
539 error.EndOfStream => return false,
540 else => |e| return e,
541 };
542 try file.seekTo(0);
543 return header.filetype == macho.MH_OBJECT;
544}
src/link/MachO/Stub.zig deleted-130
......@@ -1,130 +0,0 @@
1const Stub = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const fs = std.fs;
6const log = std.log.scoped(.stub);
7const macho = std.macho;
8const mem = std.mem;
9
10const Allocator = mem.Allocator;
11const Symbol = @import("Symbol.zig");
12pub const LibStub = @import("../tapi.zig").LibStub;
13
14allocator: *Allocator,
15arch: ?std.Target.Cpu.Arch = null,
16lib_stub: ?LibStub = null,
17name: ?[]const u8 = null,
18
19ordinal: ?u16 = null,
20
21id: ?Id = null,
22
23/// Parsed symbol table represented as hash map of symbols'
24/// names. We can and should defer creating *Symbols until
25/// a symbol is referenced by an object file.
26symbols: std.StringArrayHashMapUnmanaged(void) = .{},
27
28pub const Id = struct {
29 name: []const u8,
30 timestamp: u32,
31 current_version: u32,
32 compatibility_version: u32,
33
34 pub fn deinit(id: *Id, allocator: *Allocator) void {
35 allocator.free(id.name);
36 }
37};
38
39pub fn init(allocator: *Allocator) Stub {
40 return .{ .allocator = allocator };
41}
42
43pub fn deinit(self: *Stub) void {
44 self.symbols.deinit(self.allocator);
45
46 if (self.lib_stub) |*lib_stub| {
47 lib_stub.deinit();
48 }
49
50 if (self.name) |name| {
51 self.allocator.free(name);
52 }
53
54 if (self.id) |*id| {
55 id.deinit(self.allocator);
56 }
57}
58
59pub fn parse(self: *Stub) !void {
60 const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
61 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
62
63 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
64
65 const umbrella_lib = lib_stub.inner[0];
66 self.id = .{
67 .name = try self.allocator.dupe(u8, umbrella_lib.install_name),
68 // TODO parse from the stub
69 .timestamp = 2,
70 .current_version = 0,
71 .compatibility_version = 0,
72 };
73
74 const target_string: []const u8 = switch (self.arch.?) {
75 .aarch64 => "arm64-macos",
76 .x86_64 => "x86_64-macos",
77 else => unreachable,
78 };
79
80 for (lib_stub.inner) |stub| {
81 if (!hasTarget(stub.targets, target_string)) continue;
82
83 if (stub.exports) |exports| {
84 for (exports) |exp| {
85 if (!hasTarget(exp.targets, target_string)) continue;
86
87 for (exp.symbols) |sym_name| {
88 if (self.symbols.contains(sym_name)) continue;
89 try self.symbols.putNoClobber(self.allocator, sym_name, {});
90 }
91 }
92 }
93
94 if (stub.reexports) |reexports| {
95 for (reexports) |reexp| {
96 if (!hasTarget(reexp.targets, target_string)) continue;
97
98 for (reexp.symbols) |sym_name| {
99 if (self.symbols.contains(sym_name)) continue;
100 try self.symbols.putNoClobber(self.allocator, sym_name, {});
101 }
102 }
103 }
104 }
105}
106
107fn hasTarget(targets: []const []const u8, target: []const u8) bool {
108 for (targets) |t| {
109 if (mem.eql(u8, t, target)) return true;
110 }
111 return false;
112}
113
114pub fn createProxy(self: *Stub, sym_name: []const u8) !?*Symbol {
115 if (!self.symbols.contains(sym_name)) return null;
116
117 const name = try self.allocator.dupe(u8, sym_name);
118 const proxy = try self.allocator.create(Symbol.Proxy);
119 errdefer self.allocator.destroy(proxy);
120
121 proxy.* = .{
122 .base = .{
123 .@"type" = .proxy,
124 .name = name,
125 },
126 .file = .{ .stub = self },
127 };
128
129 return &proxy.base;
130}
src/link/MachO/Symbol.zig+19-11
......@@ -7,7 +7,6 @@ const mem = std.mem;
77const Allocator = mem.Allocator;
88const Dylib = @import("Dylib.zig");
99const Object = @import("Object.zig");
10const Stub = @import("Stub.zig");
1110
1211pub const Type = enum {
1312 regular,
......@@ -85,21 +84,26 @@ pub const Regular = struct {
8584pub const Proxy = struct {
8685 base: Symbol,
8786
88 /// Dylib or stub where to locate this symbol.
87 /// Dynamic binding info - spots within the final
88 /// executable where this proxy is referenced from.
89 bind_info: std.ArrayListUnmanaged(struct {
90 segment_id: u16,
91 address: u64,
92 }) = .{},
93
94 /// Dylib where to locate this symbol.
8995 /// null means self-reference.
90 file: ?union(enum) {
91 dylib: *Dylib,
92 stub: *Stub,
93 } = null,
96 file: ?*Dylib = null,
9497
9598 pub const base_type: Symbol.Type = .proxy;
9699
100 pub fn deinit(proxy: *Proxy, allocator: *Allocator) void {
101 proxy.bind_info.deinit(allocator);
102 }
103
97104 pub fn dylibOrdinal(proxy: *Proxy) u16 {
98 const file = proxy.file orelse return 0;
99 return switch (file) {
100 .dylib => |dylib| dylib.ordinal.?,
101 .stub => |stub| stub.ordinal.?,
102 };
105 const dylib = proxy.file orelse return 0;
106 return dylib.ordinal.?;
103107 }
104108};
105109
......@@ -129,6 +133,10 @@ pub const Tentative = struct {
129133
130134pub fn deinit(base: *Symbol, allocator: *Allocator) void {
131135 allocator.free(base.name);
136 switch (base.@"type") {
137 .proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator),
138 else => {},
139 }
132140}
133141
134142pub fn cast(base: *Symbol, comptime T: type) ?*T {
src/link/MachO/Zld.zig+462-805
......@@ -17,7 +17,6 @@ const Archive = @import("Archive.zig");
1717const CodeSignature = @import("CodeSignature.zig");
1818const Dylib = @import("Dylib.zig");
1919const Object = @import("Object.zig");
20const Stub = @import("Stub.zig");
2120const Symbol = @import("Symbol.zig");
2221const Trie = @import("Trie.zig");
2322
......@@ -33,14 +32,14 @@ out_path: ?[]const u8 = null,
3332
3433// TODO these args will become obselete once Zld is coalesced with incremental
3534// linker.
35syslibroot: ?[]const u8 = null,
3636stack_size: u64 = 0,
3737
3838objects: std.ArrayListUnmanaged(*Object) = .{},
3939archives: std.ArrayListUnmanaged(*Archive) = .{},
4040dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
41lib_stubs: std.ArrayListUnmanaged(*Stub) = .{},
4241
43libsystem_stub_index: ?u16 = null,
42libsystem_dylib_index: ?u16 = null,
4443next_dylib_ordinal: u16 = 1,
4544
4645load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
......@@ -73,12 +72,21 @@ gcc_except_tab_section_index: ?u16 = null,
7372unwind_info_section_index: ?u16 = null,
7473eh_frame_section_index: ?u16 = null,
7574
75objc_methlist_section_index: ?u16 = null,
76objc_methname_section_index: ?u16 = null,
77objc_methtype_section_index: ?u16 = null,
78objc_classname_section_index: ?u16 = null,
79
7680// __DATA_CONST segment sections
7781got_section_index: ?u16 = null,
7882mod_init_func_section_index: ?u16 = null,
7983mod_term_func_section_index: ?u16 = null,
8084data_const_section_index: ?u16 = null,
8185
86objc_cfstring_section_index: ?u16 = null,
87objc_classlist_section_index: ?u16 = null,
88objc_imageinfo_section_index: ?u16 = null,
89
8290// __DATA segment sections
8391tlv_section_index: ?u16 = null,
8492tlv_data_section_index: ?u16 = null,
......@@ -88,6 +96,11 @@ data_section_index: ?u16 = null,
8896bss_section_index: ?u16 = null,
8997common_section_index: ?u16 = null,
9098
99objc_const_section_index: ?u16 = null,
100objc_selrefs_section_index: ?u16 = null,
101objc_classrefs_section_index: ?u16 = null,
102objc_data_section_index: ?u16 = null,
103
91104globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
92105imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
93106unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
......@@ -120,10 +133,6 @@ const TlvOffset = struct {
120133/// Default path to dyld
121134const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
122135
123const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
124/// TODO this should be inferred from included libSystem.tbd or similar.
125const LIB_SYSTEM_PATH: [*:0]const u8 = "/usr/lib/libSystem.B.dylib";
126
127136pub fn init(allocator: *Allocator) Zld {
128137 return .{ .allocator = allocator };
129138}
......@@ -157,12 +166,6 @@ pub fn deinit(self: *Zld) void {
157166 }
158167 self.dylibs.deinit(self.allocator);
159168
160 for (self.lib_stubs.items) |stub| {
161 stub.deinit();
162 self.allocator.destroy(stub);
163 }
164 self.lib_stubs.deinit(self.allocator);
165
166169 for (self.imports.values()) |proxy| {
167170 proxy.deinit(self.allocator);
168171 self.allocator.destroy(proxy);
......@@ -235,7 +238,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
235238 });
236239
237240 try self.populateMetadata();
238 try self.addRpaths(args.rpaths);
239241 try self.parseInputFiles(files);
240242 try self.parseLibs(args.libs);
241243 try self.parseLibSystem(args.libc_stub_path);
......@@ -243,217 +245,92 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
243245 try self.resolveStubsAndGotEntries();
244246 try self.updateMetadata();
245247 try self.sortSections();
248 try self.addRpaths(args.rpaths);
249 try self.addDataInCodeLC();
250 try self.addCodeSignatureLC();
246251 try self.allocateTextSegment();
247252 try self.allocateDataConstSegment();
248253 try self.allocateDataSegment();
249254 self.allocateLinkeditSegment();
250255 try self.allocateSymbols();
251256 try self.allocateTentativeSymbols();
257 try self.allocateProxyBindAddresses();
252258 try self.flush();
253259}
254260
255261fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
256 const Input = struct {
257 kind: enum {
258 object,
259 archive,
260 dylib,
261 stub,
262 },
263 origin: union {
264 file: fs.File,
265 stub: Stub.LibStub,
266 },
267 name: []const u8,
268 };
269 var classified = std.ArrayList(Input).init(self.allocator);
270 defer classified.deinit();
271
272 // First, classify input files: object, archive, dylib or stub (tbd).
273262 for (files) |file_name| {
274 const file = try fs.cwd().openFile(file_name, .{});
275263 const full_path = full_path: {
276264 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
277265 const path = try std.fs.realpath(file_name, &buffer);
278266 break :full_path try self.allocator.dupe(u8, path);
279267 };
280268
281 try_object: {
282 if (!(try Object.isObject(file))) break :try_object;
283 try classified.append(.{
284 .kind = .object,
285 .origin = .{ .file = file },
286 .name = full_path,
287 });
288 continue;
289 }
290
291 try_archive: {
292 if (!(try Archive.isArchive(file))) break :try_archive;
293 try classified.append(.{
294 .kind = .archive,
295 .origin = .{ .file = file },
296 .name = full_path,
297 });
269 if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
270 try self.objects.append(self.allocator, object);
298271 continue;
299272 }
300273
301 try_dylib: {
302 if (!(try Dylib.isDylib(file))) break :try_dylib;
303 try classified.append(.{
304 .kind = .dylib,
305 .origin = .{ .file = file },
306 .name = full_path,
307 });
274 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
275 try self.archives.append(self.allocator, archive);
308276 continue;
309277 }
310278
311 try_stub: {
312 var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch {
313 break :try_stub;
314 };
315 try classified.append(.{
316 .kind = .stub,
317 .origin = .{ .stub = lib_stub },
318 .name = full_path,
319 });
320 file.close();
279 if (try Dylib.createAndParseFromPath(
280 self.allocator,
281 self.arch.?,
282 full_path,
283 self.syslibroot,
284 )) |dylibs| {
285 defer self.allocator.free(dylibs);
286 try self.dylibs.appendSlice(self.allocator, dylibs);
321287 continue;
322288 }
323289
324 file.close();
325290 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
326291 }
327
328 // Based on our classification, proceed with parsing.
329 for (classified.items) |input| {
330 switch (input.kind) {
331 .object => {
332 const object = try self.allocator.create(Object);
333 errdefer self.allocator.destroy(object);
334
335 object.* = Object.init(self.allocator);
336 object.arch = self.arch.?;
337 object.name = input.name;
338 object.file = input.origin.file;
339
340 try object.parse();
341 try self.objects.append(self.allocator, object);
342 },
343 .archive => {
344 const archive = try self.allocator.create(Archive);
345 errdefer self.allocator.destroy(archive);
346
347 archive.* = Archive.init(self.allocator);
348 archive.arch = self.arch.?;
349 archive.name = input.name;
350 archive.file = input.origin.file;
351
352 try archive.parse();
353 try self.archives.append(self.allocator, archive);
354 },
355 .dylib => {
356 const dylib = try self.allocator.create(Dylib);
357 errdefer self.allocator.destroy(dylib);
358
359 dylib.* = Dylib.init(self.allocator);
360 dylib.arch = self.arch.?;
361 dylib.name = input.name;
362 dylib.file = input.origin.file;
363
364 try dylib.parse();
365 try self.dylibs.append(self.allocator, dylib);
366 },
367 .stub => {
368 const stub = try self.allocator.create(Stub);
369 errdefer self.allocator.destroy(stub);
370
371 stub.* = Stub.init(self.allocator);
372 stub.arch = self.arch.?;
373 stub.name = input.name;
374 stub.lib_stub = input.origin.stub;
375
376 try stub.parse();
377 try self.lib_stubs.append(self.allocator, stub);
378 },
379 }
380 }
381292}
382293
383294fn parseLibs(self: *Zld, libs: []const []const u8) !void {
384295 for (libs) |lib| {
385 const file = try fs.cwd().openFile(lib, .{});
386
387 if (try Dylib.isDylib(file)) {
388 const dylib = try self.allocator.create(Dylib);
389 errdefer self.allocator.destroy(dylib);
390
391 dylib.* = Dylib.init(self.allocator);
392 dylib.arch = self.arch.?;
393 dylib.name = try self.allocator.dupe(u8, lib);
394 dylib.file = file;
296 if (try Dylib.createAndParseFromPath(
297 self.allocator,
298 self.arch.?,
299 lib,
300 self.syslibroot,
301 )) |dylibs| {
302 defer self.allocator.free(dylibs);
303 try self.dylibs.appendSlice(self.allocator, dylibs);
304 continue;
305 }
395306
396 try dylib.parse();
397 try self.dylibs.append(self.allocator, dylib);
398 } else {
399 // Try tbd stub file next.
400 if (Stub.LibStub.loadFromFile(self.allocator, file)) |lib_stub| {
401 const stub = try self.allocator.create(Stub);
402 errdefer self.allocator.destroy(stub);
403
404 stub.* = Stub.init(self.allocator);
405 stub.arch = self.arch.?;
406 stub.name = try self.allocator.dupe(u8, lib);
407 stub.lib_stub = lib_stub;
408
409 try stub.parse();
410 try self.lib_stubs.append(self.allocator, stub);
411 } else |_| {
412 // TODO this entire logic has to be cleaned up.
413 try file.seekTo(0);
414
415 if (try Archive.isArchive(file)) {
416 const archive = try self.allocator.create(Archive);
417 errdefer self.allocator.destroy(archive);
418
419 archive.* = Archive.init(self.allocator);
420 archive.arch = self.arch.?;
421 archive.name = try self.allocator.dupe(u8, lib);
422 archive.file = file;
423
424 try archive.parse();
425 try self.archives.append(self.allocator, archive);
426 } else {
427 file.close();
428 log.warn("unknown filetype for a library: '{s}'", .{lib});
429 }
430 }
307 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
308 try self.archives.append(self.allocator, archive);
309 continue;
431310 }
311
312 log.warn("unknown filetype for a library: '{s}'", .{lib});
432313 }
433314}
434315
435316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
436 const file = try fs.cwd().openFile(libc_stub_path, .{});
437 defer file.close();
438
439 var lib_stub = try Stub.LibStub.loadFromFile(self.allocator, file);
440
441 const stub = try self.allocator.create(Stub);
442 errdefer self.allocator.destroy(stub);
443
444 stub.* = Stub.init(self.allocator);
445 stub.arch = self.arch.?;
446 stub.name = try self.allocator.dupe(u8, libc_stub_path);
447 stub.lib_stub = lib_stub;
317 const dylibs = (try Dylib.createAndParseFromPath(
318 self.allocator,
319 self.arch.?,
320 libc_stub_path,
321 self.syslibroot,
322 )) orelse return error.FailedToParseLibSystem;
323 defer self.allocator.free(dylibs);
448324
449 try stub.parse();
325 assert(dylibs.len == 1); // More than one dylib output from parsing libSystem!
326 const dylib = dylibs[0];
450327
451 self.libsystem_stub_index = @intCast(u16, self.lib_stubs.items.len);
452 try self.lib_stubs.append(self.allocator, stub);
328 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
329 try self.dylibs.append(self.allocator, dylib);
453330
454331 // Add LC_LOAD_DYLIB load command.
455 stub.ordinal = self.next_dylib_ordinal;
456 const dylib_id = stub.id orelse unreachable;
332 dylib.ordinal = self.next_dylib_ordinal;
333 const dylib_id = dylib.id orelse unreachable;
457334 var dylib_cmd = try createLoadDylibCommand(
458335 self.allocator,
459336 dylib_id.name,
......@@ -501,428 +378,22 @@ fn mapAndUpdateSections(
501378
502379fn updateMetadata(self: *Zld) !void {
503380 for (self.objects.items) |object| {
504 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
505 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
506 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
507
508 // Create missing metadata
509 for (object.sections.items) |sect| {
510 const segname = sect.segname();
511 const sectname = sect.sectname();
512
513 switch (sect.sectionType()) {
514 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => {
515 if (self.text_const_section_index != null) continue;
516
517 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
518 try text_seg.addSection(self.allocator, .{
519 .sectname = makeStaticString("__const"),
520 .segname = makeStaticString("__TEXT"),
521 .addr = 0,
522 .size = 0,
523 .offset = 0,
524 .@"align" = 0,
525 .reloff = 0,
526 .nreloc = 0,
527 .flags = macho.S_REGULAR,
528 .reserved1 = 0,
529 .reserved2 = 0,
530 .reserved3 = 0,
531 });
532 continue;
533 },
534 macho.S_CSTRING_LITERALS => {
535 if (self.cstring_section_index != null) continue;
536
537 self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);
538 try text_seg.addSection(self.allocator, .{
539 .sectname = makeStaticString("__cstring"),
540 .segname = makeStaticString("__TEXT"),
541 .addr = 0,
542 .size = 0,
543 .offset = 0,
544 .@"align" = 0,
545 .reloff = 0,
546 .nreloc = 0,
547 .flags = macho.S_CSTRING_LITERALS,
548 .reserved1 = 0,
549 .reserved2 = 0,
550 .reserved3 = 0,
551 });
552 continue;
553 },
554 macho.S_MOD_INIT_FUNC_POINTERS => {
555 if (self.mod_init_func_section_index != null) continue;
556
557 self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
558 try data_const_seg.addSection(self.allocator, .{
559 .sectname = makeStaticString("__mod_init_func"),
560 .segname = makeStaticString("__DATA_CONST"),
561 .addr = 0,
562 .size = 0,
563 .offset = 0,
564 .@"align" = 0,
565 .reloff = 0,
566 .nreloc = 0,
567 .flags = macho.S_MOD_INIT_FUNC_POINTERS,
568 .reserved1 = 0,
569 .reserved2 = 0,
570 .reserved3 = 0,
571 });
572 continue;
573 },
574 macho.S_MOD_TERM_FUNC_POINTERS => {
575 if (self.mod_term_func_section_index != null) continue;
576
577 self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
578 try data_const_seg.addSection(self.allocator, .{
579 .sectname = makeStaticString("__mod_term_func"),
580 .segname = makeStaticString("__DATA_CONST"),
581 .addr = 0,
582 .size = 0,
583 .offset = 0,
584 .@"align" = 0,
585 .reloff = 0,
586 .nreloc = 0,
587 .flags = macho.S_MOD_TERM_FUNC_POINTERS,
588 .reserved1 = 0,
589 .reserved2 = 0,
590 .reserved3 = 0,
591 });
592 continue;
593 },
594 macho.S_ZEROFILL => {
595 if (mem.eql(u8, sectname, "__common")) {
596 if (self.common_section_index != null) continue;
597
598 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
599 try data_seg.addSection(self.allocator, .{
600 .sectname = makeStaticString("__common"),
601 .segname = makeStaticString("__DATA"),
602 .addr = 0,
603 .size = 0,
604 .offset = 0,
605 .@"align" = 0,
606 .reloff = 0,
607 .nreloc = 0,
608 .flags = macho.S_ZEROFILL,
609 .reserved1 = 0,
610 .reserved2 = 0,
611 .reserved3 = 0,
612 });
613 } else {
614 if (self.bss_section_index != null) continue;
615
616 self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
617 try data_seg.addSection(self.allocator, .{
618 .sectname = makeStaticString("__bss"),
619 .segname = makeStaticString("__DATA"),
620 .addr = 0,
621 .size = 0,
622 .offset = 0,
623 .@"align" = 0,
624 .reloff = 0,
625 .nreloc = 0,
626 .flags = macho.S_ZEROFILL,
627 .reserved1 = 0,
628 .reserved2 = 0,
629 .reserved3 = 0,
630 });
631 }
632 continue;
633 },
634 macho.S_THREAD_LOCAL_VARIABLES => {
635 if (self.tlv_section_index != null) continue;
636
637 self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);
638 try data_seg.addSection(self.allocator, .{
639 .sectname = makeStaticString("__thread_vars"),
640 .segname = makeStaticString("__DATA"),
641 .addr = 0,
642 .size = 0,
643 .offset = 0,
644 .@"align" = 0,
645 .reloff = 0,
646 .nreloc = 0,
647 .flags = macho.S_THREAD_LOCAL_VARIABLES,
648 .reserved1 = 0,
649 .reserved2 = 0,
650 .reserved3 = 0,
651 });
652 continue;
653 },
654 macho.S_THREAD_LOCAL_REGULAR => {
655 if (self.tlv_data_section_index != null) continue;
656
657 self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);
658 try data_seg.addSection(self.allocator, .{
659 .sectname = makeStaticString("__thread_data"),
660 .segname = makeStaticString("__DATA"),
661 .addr = 0,
662 .size = 0,
663 .offset = 0,
664 .@"align" = 0,
665 .reloff = 0,
666 .nreloc = 0,
667 .flags = macho.S_THREAD_LOCAL_REGULAR,
668 .reserved1 = 0,
669 .reserved2 = 0,
670 .reserved3 = 0,
671 });
672 continue;
673 },
674 macho.S_THREAD_LOCAL_ZEROFILL => {
675 if (self.tlv_bss_section_index != null) continue;
676
677 self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);
678 try data_seg.addSection(self.allocator, .{
679 .sectname = makeStaticString("__thread_bss"),
680 .segname = makeStaticString("__DATA"),
681 .addr = 0,
682 .size = 0,
683 .offset = 0,
684 .@"align" = 0,
685 .reloff = 0,
686 .nreloc = 0,
687 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
688 .reserved1 = 0,
689 .reserved2 = 0,
690 .reserved3 = 0,
691 });
692 continue;
693 },
694 macho.S_COALESCED => {
695 if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {
696 // TODO I believe __eh_frame is currently part of __unwind_info section
697 // in the latest ld64 output.
698 if (self.eh_frame_section_index != null) continue;
699
700 self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len);
701 try text_seg.addSection(self.allocator, .{
702 .sectname = makeStaticString("__eh_frame"),
703 .segname = makeStaticString("__TEXT"),
704 .addr = 0,
705 .size = 0,
706 .offset = 0,
707 .@"align" = 0,
708 .reloff = 0,
709 .nreloc = 0,
710 .flags = macho.S_REGULAR,
711 .reserved1 = 0,
712 .reserved2 = 0,
713 .reserved3 = 0,
714 });
715 continue;
716 }
717
718 // TODO audit this: is this the right mapping?
719 if (self.data_const_section_index != null) continue;
720
721 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
722 try data_const_seg.addSection(self.allocator, .{
723 .sectname = makeStaticString("__const"),
724 .segname = makeStaticString("__DATA_CONST"),
725 .addr = 0,
726 .size = 0,
727 .offset = 0,
728 .@"align" = 0,
729 .reloff = 0,
730 .nreloc = 0,
731 .flags = macho.S_REGULAR,
732 .reserved1 = 0,
733 .reserved2 = 0,
734 .reserved3 = 0,
735 });
736 continue;
737 },
738 macho.S_REGULAR => {
739 if (sect.isCode()) {
740 if (self.text_section_index != null) continue;
741
742 self.text_section_index = @intCast(u16, text_seg.sections.items.len);
743 try text_seg.addSection(self.allocator, .{
744 .sectname = makeStaticString("__text"),
745 .segname = makeStaticString("__TEXT"),
746 .addr = 0,
747 .size = 0,
748 .offset = 0,
749 .@"align" = 0,
750 .reloff = 0,
751 .nreloc = 0,
752 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
753 .reserved1 = 0,
754 .reserved2 = 0,
755 .reserved3 = 0,
756 });
757 continue;
758 }
759
760 if (sect.isDebug()) {
761 if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
762 log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
763 sect.flags(), segname, sectname,
764 });
765 }
766 continue;
767 }
768
769 if (mem.eql(u8, segname, "__TEXT")) {
770 if (mem.eql(u8, sectname, "__ustring")) {
771 if (self.ustring_section_index != null) continue;
772
773 self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);
774 try text_seg.addSection(self.allocator, .{
775 .sectname = makeStaticString("__ustring"),
776 .segname = makeStaticString("__TEXT"),
777 .addr = 0,
778 .size = 0,
779 .offset = 0,
780 .@"align" = 0,
781 .reloff = 0,
782 .nreloc = 0,
783 .flags = macho.S_REGULAR,
784 .reserved1 = 0,
785 .reserved2 = 0,
786 .reserved3 = 0,
787 });
788 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
789 if (self.gcc_except_tab_section_index != null) continue;
790
791 self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len);
792 try text_seg.addSection(self.allocator, .{
793 .sectname = makeStaticString("__gcc_except_tab"),
794 .segname = makeStaticString("__TEXT"),
795 .addr = 0,
796 .size = 0,
797 .offset = 0,
798 .@"align" = 0,
799 .reloff = 0,
800 .nreloc = 0,
801 .flags = macho.S_REGULAR,
802 .reserved1 = 0,
803 .reserved2 = 0,
804 .reserved3 = 0,
805 });
806 } else {
807 if (self.text_const_section_index != null) continue;
808
809 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
810 try text_seg.addSection(self.allocator, .{
811 .sectname = makeStaticString("__const"),
812 .segname = makeStaticString("__TEXT"),
813 .addr = 0,
814 .size = 0,
815 .offset = 0,
816 .@"align" = 0,
817 .reloff = 0,
818 .nreloc = 0,
819 .flags = macho.S_REGULAR,
820 .reserved1 = 0,
821 .reserved2 = 0,
822 .reserved3 = 0,
823 });
824 }
825 continue;
826 }
827
828 if (mem.eql(u8, segname, "__DATA_CONST")) {
829 if (self.data_const_section_index != null) continue;
830
831 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
832 try data_const_seg.addSection(self.allocator, .{
833 .sectname = makeStaticString("__const"),
834 .segname = makeStaticString("__DATA_CONST"),
835 .addr = 0,
836 .size = 0,
837 .offset = 0,
838 .@"align" = 0,
839 .reloff = 0,
840 .nreloc = 0,
841 .flags = macho.S_REGULAR,
842 .reserved1 = 0,
843 .reserved2 = 0,
844 .reserved3 = 0,
845 });
846 continue;
847 }
848
849 if (mem.eql(u8, segname, "__DATA")) {
850 if (mem.eql(u8, sectname, "__const")) {
851 if (self.data_const_section_index != null) continue;
852
853 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
854 try data_const_seg.addSection(self.allocator, .{
855 .sectname = makeStaticString("__const"),
856 .segname = makeStaticString("__DATA_CONST"),
857 .addr = 0,
858 .size = 0,
859 .offset = 0,
860 .@"align" = 0,
861 .reloff = 0,
862 .nreloc = 0,
863 .flags = macho.S_REGULAR,
864 .reserved1 = 0,
865 .reserved2 = 0,
866 .reserved3 = 0,
867 });
868 } else {
869 if (self.data_section_index != null) continue;
870
871 self.data_section_index = @intCast(u16, data_seg.sections.items.len);
872 try data_seg.addSection(self.allocator, .{
873 .sectname = makeStaticString("__data"),
874 .segname = makeStaticString("__DATA"),
875 .addr = 0,
876 .size = 0,
877 .offset = 0,
878 .@"align" = 0,
879 .reloff = 0,
880 .nreloc = 0,
881 .flags = macho.S_REGULAR,
882 .reserved1 = 0,
883 .reserved2 = 0,
884 .reserved3 = 0,
885 });
886 }
887
888 continue;
889 }
890
891 if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) {
892 log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{
893 sect.flags(), segname, sectname,
894 });
895 continue;
896 }
897 },
898 else => {},
899 }
900
901 log.err("{s}: unhandled section type 0x{x} for '{s},{s}'", .{
902 object.name.?,
903 sect.flags(),
904 segname,
905 sectname,
906 });
907 return error.UnhandledSection;
908 }
909
910 // Find ideal section alignment.
911 for (object.sections.items) |sect| {
912 if (self.getMatchingSection(sect)) |res| {
913 const target_seg = &self.load_commands.items[res.seg].Segment;
914 const target_sect = &target_seg.sections.items[res.sect];
915 target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align");
916 }
917 }
918
919 // Update section mappings
381 // Find ideal section alignment and update section mappings
920382 for (object.sections.items) |sect, sect_id| {
921 if (self.getMatchingSection(sect)) |res| {
922 try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect);
383 const match = (try self.getMatchingSection(sect)) orelse {
384 log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{
385 object.name.?,
386 sect.flags(),
387 sect.segname(),
388 sect.sectname(),
389 });
923390 continue;
924 }
925 log.debug("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() });
391 };
392 const target_seg = &self.load_commands.items[match.seg].Segment;
393 const target_sect = &target_seg.sections.items[match.sect];
394 target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align");
395
396 try self.mapAndUpdateSections(object, @intCast(u16, sect_id), match.seg, match.sect);
926397 }
927398 }
928399
......@@ -932,19 +403,8 @@ fn updateMetadata(self: *Zld) !void {
932403 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
933404 const common_section_index = self.common_section_index orelse ind: {
934405 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
935 try data_seg.addSection(self.allocator, .{
936 .sectname = makeStaticString("__common"),
937 .segname = makeStaticString("__DATA"),
938 .addr = 0,
939 .size = 0,
940 .offset = 0,
941 .@"align" = 0,
942 .reloff = 0,
943 .nreloc = 0,
406 try data_seg.addSection(self.allocator, "__common", .{
944407 .flags = macho.S_ZEROFILL,
945 .reserved1 = 0,
946 .reserved2 = 0,
947 .reserved3 = 0,
948408 });
949409 break :ind self.common_section_index.?;
950410 };
......@@ -1018,31 +478,116 @@ const MatchingSection = struct {
1018478 sect: u16,
1019479};
1020480
1021fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
481fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection {
482 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
483 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
484 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1022485 const segname = sect.segname();
1023486 const sectname = sect.sectname();
1024487
1025488 const res: ?MatchingSection = blk: {
1026489 switch (sect.sectionType()) {
1027 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => {
490 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
491 if (self.text_const_section_index == null) {
492 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
493 try text_seg.addSection(self.allocator, "__const", .{});
494 }
495
1028496 break :blk .{
1029497 .seg = self.text_segment_cmd_index.?,
1030498 .sect = self.text_const_section_index.?,
1031499 };
1032500 },
1033501 macho.S_CSTRING_LITERALS => {
502 if (mem.eql(u8, sectname, "__objc_methname")) {
503 // TODO it seems the common values within the sections in objects are deduplicated/merged
504 // on merging the sections' contents.
505 if (self.objc_methname_section_index == null) {
506 self.objc_methname_section_index = @intCast(u16, text_seg.sections.items.len);
507 try text_seg.addSection(self.allocator, "__objc_methname", .{
508 .flags = macho.S_CSTRING_LITERALS,
509 });
510 }
511
512 break :blk .{
513 .seg = self.text_segment_cmd_index.?,
514 .sect = self.objc_methname_section_index.?,
515 };
516 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
517 if (self.objc_methtype_section_index == null) {
518 self.objc_methtype_section_index = @intCast(u16, text_seg.sections.items.len);
519 try text_seg.addSection(self.allocator, "__objc_methtype", .{
520 .flags = macho.S_CSTRING_LITERALS,
521 });
522 }
523
524 break :blk .{
525 .seg = self.text_segment_cmd_index.?,
526 .sect = self.objc_methtype_section_index.?,
527 };
528 } else if (mem.eql(u8, sectname, "__objc_classname")) {
529 if (self.objc_classname_section_index == null) {
530 self.objc_classname_section_index = @intCast(u16, text_seg.sections.items.len);
531 try text_seg.addSection(self.allocator, "__objc_classname", .{});
532 }
533
534 break :blk .{
535 .seg = self.text_segment_cmd_index.?,
536 .sect = self.objc_classname_section_index.?,
537 };
538 }
539
540 if (self.cstring_section_index == null) {
541 self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);
542 try text_seg.addSection(self.allocator, "__cstring", .{
543 .flags = macho.S_CSTRING_LITERALS,
544 });
545 }
546
1034547 break :blk .{
1035548 .seg = self.text_segment_cmd_index.?,
1036549 .sect = self.cstring_section_index.?,
1037550 };
1038551 },
552 macho.S_LITERAL_POINTERS => {
553 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
554 if (self.objc_selrefs_section_index == null) {
555 self.objc_selrefs_section_index = @intCast(u16, data_seg.sections.items.len);
556 try data_seg.addSection(self.allocator, "__objc_selrefs", .{
557 .flags = macho.S_LITERAL_POINTERS,
558 });
559 }
560
561 break :blk .{
562 .seg = self.data_segment_cmd_index.?,
563 .sect = self.objc_selrefs_section_index.?,
564 };
565 }
566
567 // TODO investigate
568 break :blk null;
569 },
1039570 macho.S_MOD_INIT_FUNC_POINTERS => {
571 if (self.mod_init_func_section_index == null) {
572 self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
573 try data_const_seg.addSection(self.allocator, "__mod_init_func", .{
574 .flags = macho.S_MOD_INIT_FUNC_POINTERS,
575 });
576 }
577
1040578 break :blk .{
1041579 .seg = self.data_const_segment_cmd_index.?,
1042580 .sect = self.mod_init_func_section_index.?,
1043581 };
1044582 },
1045583 macho.S_MOD_TERM_FUNC_POINTERS => {
584 if (self.mod_term_func_section_index == null) {
585 self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
586 try data_const_seg.addSection(self.allocator, "__mod_term_func", .{
587 .flags = macho.S_MOD_TERM_FUNC_POINTERS,
588 });
589 }
590
1046591 break :blk .{
1047592 .seg = self.data_const_segment_cmd_index.?,
1048593 .sect = self.mod_term_func_section_index.?,
......@@ -1050,11 +595,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1050595 },
1051596 macho.S_ZEROFILL => {
1052597 if (mem.eql(u8, sectname, "__common")) {
598 if (self.common_section_index == null) {
599 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
600 try data_seg.addSection(self.allocator, "__common", .{
601 .flags = macho.S_ZEROFILL,
602 });
603 }
604
1053605 break :blk .{
1054606 .seg = self.data_segment_cmd_index.?,
1055607 .sect = self.common_section_index.?,
1056608 };
1057609 } else {
610 if (self.bss_section_index == null) {
611 self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
612 try data_seg.addSection(self.allocator, "__bss", .{
613 .flags = macho.S_ZEROFILL,
614 });
615 }
616
1058617 break :blk .{
1059618 .seg = self.data_segment_cmd_index.?,
1060619 .sect = self.bss_section_index.?,
......@@ -1062,18 +621,39 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1062621 }
1063622 },
1064623 macho.S_THREAD_LOCAL_VARIABLES => {
624 if (self.tlv_section_index == null) {
625 self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);
626 try data_seg.addSection(self.allocator, "__thread_vars", .{
627 .flags = macho.S_THREAD_LOCAL_VARIABLES,
628 });
629 }
630
1065631 break :blk .{
1066632 .seg = self.data_segment_cmd_index.?,
1067633 .sect = self.tlv_section_index.?,
1068634 };
1069635 },
1070636 macho.S_THREAD_LOCAL_REGULAR => {
637 if (self.tlv_data_section_index == null) {
638 self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);
639 try data_seg.addSection(self.allocator, "__thread_data", .{
640 .flags = macho.S_THREAD_LOCAL_REGULAR,
641 });
642 }
643
1071644 break :blk .{
1072645 .seg = self.data_segment_cmd_index.?,
1073646 .sect = self.tlv_data_section_index.?,
1074647 };
1075648 },
1076649 macho.S_THREAD_LOCAL_ZEROFILL => {
650 if (self.tlv_bss_section_index == null) {
651 self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);
652 try data_seg.addSection(self.allocator, "__thread_bss", .{
653 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
654 });
655 }
656
1077657 break :blk .{
1078658 .seg = self.data_segment_cmd_index.?,
1079659 .sect = self.tlv_bss_section_index.?,
......@@ -1081,12 +661,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1081661 },
1082662 macho.S_COALESCED => {
1083663 if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {
664 // TODO I believe __eh_frame is currently part of __unwind_info section
665 // in the latest ld64 output.
666 if (self.eh_frame_section_index == null) {
667 self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len);
668 try text_seg.addSection(self.allocator, "__eh_frame", .{});
669 }
670
1084671 break :blk .{
1085672 .seg = self.text_segment_cmd_index.?,
1086673 .sect = self.eh_frame_section_index.?,
1087674 };
1088675 }
1089676
677 // TODO audit this: is this the right mapping?
678 if (self.data_const_section_index == null) {
679 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
680 try data_const_seg.addSection(self.allocator, "__const", .{});
681 }
682
1090683 break :blk .{
1091684 .seg = self.data_const_segment_cmd_index.?,
1092685 .sect = self.data_const_section_index.?,
......@@ -1094,6 +687,13 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1094687 },
1095688 macho.S_REGULAR => {
1096689 if (sect.isCode()) {
690 if (self.text_section_index == null) {
691 self.text_section_index = @intCast(u16, text_seg.sections.items.len);
692 try text_seg.addSection(self.allocator, "__text", .{
693 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
694 });
695 }
696
1097697 break :blk .{
1098698 .seg = self.text_segment_cmd_index.?,
1099699 .sect = self.text_section_index.?,
......@@ -1101,21 +701,51 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1101701 }
1102702 if (sect.isDebug()) {
1103703 // TODO debug attributes
704 if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
705 log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
706 sect.flags(), segname, sectname,
707 });
708 }
1104709 break :blk null;
1105710 }
1106711
1107712 if (mem.eql(u8, segname, "__TEXT")) {
1108713 if (mem.eql(u8, sectname, "__ustring")) {
714 if (self.ustring_section_index == null) {
715 self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);
716 try text_seg.addSection(self.allocator, "__ustring", .{});
717 }
718
1109719 break :blk .{
1110720 .seg = self.text_segment_cmd_index.?,
1111721 .sect = self.ustring_section_index.?,
1112722 };
1113723 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
724 if (self.gcc_except_tab_section_index == null) {
725 self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len);
726 try text_seg.addSection(self.allocator, "__gcc_except_tab", .{});
727 }
728
1114729 break :blk .{
1115730 .seg = self.text_segment_cmd_index.?,
1116731 .sect = self.gcc_except_tab_section_index.?,
1117732 };
733 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
734 if (self.objc_methlist_section_index == null) {
735 self.objc_methlist_section_index = @intCast(u16, text_seg.sections.items.len);
736 try text_seg.addSection(self.allocator, "__objc_methlist", .{});
737 }
738
739 break :blk .{
740 .seg = self.text_segment_cmd_index.?,
741 .sect = self.objc_methlist_section_index.?,
742 };
1118743 } else {
744 if (self.text_const_section_index == null) {
745 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
746 try text_seg.addSection(self.allocator, "__const", .{});
747 }
748
1119749 break :blk .{
1120750 .seg = self.text_segment_cmd_index.?,
1121751 .sect = self.text_const_section_index.?,
......@@ -1124,6 +754,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1124754 }
1125755
1126756 if (mem.eql(u8, segname, "__DATA_CONST")) {
757 if (self.data_const_section_index == null) {
758 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
759 try data_const_seg.addSection(self.allocator, "__const", .{});
760 }
761
1127762 break :blk .{
1128763 .seg = self.data_const_segment_cmd_index.?,
1129764 .sect = self.data_const_section_index.?,
......@@ -1132,15 +767,92 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1132767
1133768 if (mem.eql(u8, segname, "__DATA")) {
1134769 if (mem.eql(u8, sectname, "__const")) {
770 if (self.data_const_section_index == null) {
771 self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
772 try data_const_seg.addSection(self.allocator, "__const", .{});
773 }
774
1135775 break :blk .{
1136776 .seg = self.data_const_segment_cmd_index.?,
1137777 .sect = self.data_const_section_index.?,
1138778 };
779 } else if (mem.eql(u8, sectname, "__cfstring")) {
780 if (self.objc_cfstring_section_index == null) {
781 self.objc_cfstring_section_index = @intCast(u16, data_const_seg.sections.items.len);
782 try data_const_seg.addSection(self.allocator, "__cfstring", .{});
783 }
784
785 break :blk .{
786 .seg = self.data_const_segment_cmd_index.?,
787 .sect = self.objc_cfstring_section_index.?,
788 };
789 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
790 if (self.objc_classlist_section_index == null) {
791 self.objc_classlist_section_index = @intCast(u16, data_const_seg.sections.items.len);
792 try data_const_seg.addSection(self.allocator, "__objc_classlist", .{});
793 }
794
795 break :blk .{
796 .seg = self.data_const_segment_cmd_index.?,
797 .sect = self.objc_classlist_section_index.?,
798 };
799 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
800 if (self.objc_imageinfo_section_index == null) {
801 self.objc_imageinfo_section_index = @intCast(u16, data_const_seg.sections.items.len);
802 try data_const_seg.addSection(self.allocator, "__objc_imageinfo", .{});
803 }
804
805 break :blk .{
806 .seg = self.data_const_segment_cmd_index.?,
807 .sect = self.objc_imageinfo_section_index.?,
808 };
809 } else if (mem.eql(u8, sectname, "__objc_const")) {
810 if (self.objc_const_section_index == null) {
811 self.objc_const_section_index = @intCast(u16, data_seg.sections.items.len);
812 try data_seg.addSection(self.allocator, "__objc_const", .{});
813 }
814
815 break :blk .{
816 .seg = self.data_segment_cmd_index.?,
817 .sect = self.objc_const_section_index.?,
818 };
819 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
820 if (self.objc_classrefs_section_index == null) {
821 self.objc_classrefs_section_index = @intCast(u16, data_seg.sections.items.len);
822 try data_seg.addSection(self.allocator, "__objc_classrefs", .{});
823 }
824
825 break :blk .{
826 .seg = self.data_segment_cmd_index.?,
827 .sect = self.objc_classrefs_section_index.?,
828 };
829 } else if (mem.eql(u8, sectname, "__objc_data")) {
830 if (self.objc_data_section_index == null) {
831 self.objc_data_section_index = @intCast(u16, data_seg.sections.items.len);
832 try data_seg.addSection(self.allocator, "__objc_data", .{});
833 }
834
835 break :blk .{
836 .seg = self.data_segment_cmd_index.?,
837 .sect = self.objc_data_section_index.?,
838 };
839 } else {
840 if (self.data_section_index == null) {
841 self.data_section_index = @intCast(u16, data_seg.sections.items.len);
842 try data_seg.addSection(self.allocator, "__data", .{});
843 }
844
845 break :blk .{
846 .seg = self.data_segment_cmd_index.?,
847 .sect = self.data_section_index.?,
848 };
1139849 }
1140 break :blk .{
1141 .seg = self.data_segment_cmd_index.?,
1142 .sect = self.data_section_index.?,
1143 };
850 }
851
852 if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) {
853 log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{
854 sect.flags(), segname, sectname,
855 });
1144856 }
1145857
1146858 break :blk null;
......@@ -1175,6 +887,9 @@ fn sortSections(self: *Zld) !void {
1175887 &self.cstring_section_index,
1176888 &self.ustring_section_index,
1177889 &self.text_const_section_index,
890 &self.objc_methname_section_index,
891 &self.objc_methtype_section_index,
892 &self.objc_classname_section_index,
1178893 &self.eh_frame_section_index,
1179894 };
1180895 for (indices) |maybe_index| {
......@@ -1200,6 +915,9 @@ fn sortSections(self: *Zld) !void {
1200915 &self.mod_init_func_section_index,
1201916 &self.mod_term_func_section_index,
1202917 &self.data_const_section_index,
918 &self.objc_cfstring_section_index,
919 &self.objc_classlist_section_index,
920 &self.objc_imageinfo_section_index,
1203921 };
1204922 for (indices) |maybe_index| {
1205923 const new_index: u16 = if (maybe_index.*) |index| blk: {
......@@ -1222,6 +940,10 @@ fn sortSections(self: *Zld) !void {
1222940 // __DATA segment
1223941 const indices = &[_]*?u16{
1224942 &self.la_symbol_ptr_section_index,
943 &self.objc_const_section_index,
944 &self.objc_selrefs_section_index,
945 &self.objc_classrefs_section_index,
946 &self.objc_data_section_index,
1225947 &self.data_section_index,
1226948 &self.tlv_section_index,
1227949 &self.tlv_data_section_index,
......@@ -1487,6 +1209,31 @@ fn allocateTentativeSymbols(self: *Zld) !void {
14871209 }
14881210}
14891211
1212fn allocateProxyBindAddresses(self: *Zld) !void {
1213 for (self.objects.items) |object| {
1214 for (object.sections.items) |sect| {
1215 const relocs = sect.relocs orelse continue;
1216
1217 for (relocs) |rel| {
1218 if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased
1219 if (rel.target != .symbol) continue;
1220
1221 const sym = rel.target.symbol.getTopmostAlias();
1222 if (sym.cast(Symbol.Proxy)) |proxy| {
1223 const target_map = sect.target_map orelse continue;
1224 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1225 const target_sect = target_seg.sections.items[target_map.section_id];
1226
1227 try proxy.bind_info.append(self.allocator, .{
1228 .segment_id = target_map.segment_id,
1229 .address = target_sect.addr + target_map.offset + rel.offset,
1230 });
1231 }
1232 }
1233 }
1234 }
1235}
1236
14901237fn writeStubHelperCommon(self: *Zld) !void {
14911238 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
14921239 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1893,25 +1640,16 @@ fn resolveSymbols(self: *Zld) !void {
18931640 }
18941641 self.unresolved.clearRetainingCapacity();
18951642
1896 var referenced = std.AutoHashMap(union(enum) {
1897 dylib: *Dylib,
1898 stub: *Stub,
1899 }, void).init(self.allocator);
1643 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
19001644 defer referenced.deinit();
19011645
19021646 loop: while (unresolved.popOrNull()) |undef| {
19031647 const proxy = self.imports.get(undef.name) orelse outer: {
19041648 const proxy = inner: {
1905 for (self.dylibs.items) |dylib| {
1649 for (self.dylibs.items) |dylib, i| {
19061650 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
1907 try referenced.put(.{ .dylib = dylib }, {});
1908 break :inner proxy;
1909 }
1910 for (self.lib_stubs.items) |stub, i| {
1911 const proxy = (try stub.createProxy(undef.name)) orelse continue;
1912 if (self.libsystem_stub_index.? != @intCast(u16, i)) {
1913 // LibSystem gets its load command separately.
1914 try referenced.put(.{ .stub = stub }, {});
1651 if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately.
1652 try referenced.put(dylib, {});
19151653 }
19161654 break :inner proxy;
19171655 }
......@@ -1944,33 +1682,17 @@ fn resolveSymbols(self: *Zld) !void {
19441682
19451683 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.
19461684 var it = referenced.iterator();
1947 while (it.next()) |key| {
1948 var dylib_cmd = blk: {
1949 switch (key.key_ptr.*) {
1950 .dylib => |dylib| {
1951 dylib.ordinal = self.next_dylib_ordinal;
1952 const dylib_id = dylib.id orelse unreachable;
1953 break :blk try createLoadDylibCommand(
1954 self.allocator,
1955 dylib_id.name,
1956 dylib_id.timestamp,
1957 dylib_id.current_version,
1958 dylib_id.compatibility_version,
1959 );
1960 },
1961 .stub => |stub| {
1962 stub.ordinal = self.next_dylib_ordinal;
1963 const dylib_id = stub.id orelse unreachable;
1964 break :blk try createLoadDylibCommand(
1965 self.allocator,
1966 dylib_id.name,
1967 dylib_id.timestamp,
1968 dylib_id.current_version,
1969 dylib_id.compatibility_version,
1970 );
1971 },
1972 }
1973 };
1685 while (it.next()) |entry| {
1686 const dylib = entry.key_ptr.*;
1687 dylib.ordinal = self.next_dylib_ordinal;
1688 const dylib_id = dylib.id orelse unreachable;
1689 var dylib_cmd = try createLoadDylibCommand(
1690 self.allocator,
1691 dylib_id.name,
1692 dylib_id.timestamp,
1693 dylib_id.current_version,
1694 dylib_id.compatibility_version,
1695 );
19741696 errdefer dylib_cmd.deinit(self.allocator);
19751697 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
19761698 self.next_dylib_ordinal += 1;
......@@ -1988,8 +1710,8 @@ fn resolveSymbols(self: *Zld) !void {
19881710 }
19891711
19901712 // Finally put dyld_stub_binder as an Import
1991 const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?];
1992 const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse {
1713 const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?];
1714 const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse {
19931715 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});
19941716 return error.UndefinedSymbolReference;
19951717 };
......@@ -2004,6 +1726,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
20041726 const relocs = sect.relocs orelse continue;
20051727 for (relocs) |rel| {
20061728 switch (rel.@"type") {
1729 .unsigned => continue,
20071730 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
20081731 const sym = rel.target.symbol.getTopmostAlias();
20091732 if (sym.got_index != null) continue;
......@@ -2089,29 +1812,52 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
20891812 args.source_target_sect_addr = source_sect.inner.addr;
20901813 }
20911814
2092 rebases: {
2093 var hit: bool = false;
2094 if (target_map.segment_id == self.data_segment_cmd_index.?) {
2095 if (self.data_section_index) |index| {
2096 if (index == target_map.section_id) hit = true;
1815 const flags = @truncate(u8, target_sect.flags & 0xff);
1816 const should_rebase = rebase: {
1817 if (!unsigned.is_64bit) break :rebase false;
1818
1819 // TODO actually, a check similar to what dyld is doing, that is, verifying
1820 // that the segment is writable should be enough here.
1821 const is_right_segment = blk: {
1822 if (self.data_segment_cmd_index) |idx| {
1823 if (target_map.segment_id == idx) {
1824 break :blk true;
1825 }
1826 }
1827 if (self.data_const_segment_cmd_index) |idx| {
1828 if (target_map.segment_id == idx) {
1829 break :blk true;
1830 }
20971831 }
1832 break :blk false;
1833 };
1834
1835 if (!is_right_segment) break :rebase false;
1836 if (flags != macho.S_LITERAL_POINTERS and
1837 flags != macho.S_REGULAR)
1838 {
1839 break :rebase false;
20981840 }
2099 if (target_map.segment_id == self.data_const_segment_cmd_index.?) {
2100 if (self.data_const_section_index) |index| {
2101 if (index == target_map.section_id) hit = true;
1841 if (rel.target == .symbol) {
1842 const final = rel.target.symbol.getTopmostAlias();
1843 if (final.cast(Symbol.Proxy)) |_| {
1844 break :rebase false;
21021845 }
21031846 }
21041847
2105 if (!hit) break :rebases;
1848 break :rebase true;
1849 };
21061850
1851 if (should_rebase) {
21071852 try self.local_rebases.append(self.allocator, .{
21081853 .offset = source_addr - target_seg.inner.vmaddr,
21091854 .segment_id = target_map.segment_id,
21101855 });
21111856 }
1857
21121858 // TLV is handled via a separate offset mechanism.
21131859 // Calculate the offset to the initializer.
2114 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1860 if (flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
21151861 // TODO we don't want to save offset to tlv_bootstrap
21161862 if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv;
21171863
......@@ -2208,7 +1954,13 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T
22081954 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
22091955 const stubs = segment.sections.items[self.stubs_section_index.?];
22101956 const stubs_index = proxy.base.stubs_index orelse {
2211 log.err("expected stubs index when relocating symbol '{s}'", .{final.name});
1957 if (proxy.bind_info.items.len > 0) {
1958 break :blk 0; // Dynamically bound by dyld.
1959 }
1960 log.err(
1961 "expected stubs index or dynamic bind address when relocating symbol '{s}'",
1962 .{final.name},
1963 );
22121964 log.err("this is an internal linker error", .{});
22131965 return error.FailedToResolveRelocationTarget;
22141966 };
......@@ -2240,18 +1992,8 @@ fn populateMetadata(self: *Zld) !void {
22401992 if (self.pagezero_segment_cmd_index == null) {
22411993 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
22421994 try self.load_commands.append(self.allocator, .{
2243 .Segment = SegmentCommand.empty(.{
2244 .cmd = macho.LC_SEGMENT_64,
2245 .cmdsize = @sizeOf(macho.segment_command_64),
2246 .segname = makeStaticString("__PAGEZERO"),
2247 .vmaddr = 0,
1995 .Segment = SegmentCommand.empty("__PAGEZERO", .{
22481996 .vmsize = 0x100000000, // size always set to 4GB
2249 .fileoff = 0,
2250 .filesize = 0,
2251 .maxprot = 0,
2252 .initprot = 0,
2253 .nsects = 0,
2254 .flags = 0,
22551997 }),
22561998 });
22571999 }
......@@ -2259,18 +2001,10 @@ fn populateMetadata(self: *Zld) !void {
22592001 if (self.text_segment_cmd_index == null) {
22602002 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
22612003 try self.load_commands.append(self.allocator, .{
2262 .Segment = SegmentCommand.empty(.{
2263 .cmd = macho.LC_SEGMENT_64,
2264 .cmdsize = @sizeOf(macho.segment_command_64),
2265 .segname = makeStaticString("__TEXT"),
2004 .Segment = SegmentCommand.empty("__TEXT", .{
22662005 .vmaddr = 0x100000000, // always starts at 4GB
2267 .vmsize = 0,
2268 .fileoff = 0,
2269 .filesize = 0,
22702006 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
22712007 .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
2272 .nsects = 0,
2273 .flags = 0,
22742008 }),
22752009 });
22762010 }
......@@ -2283,19 +2017,9 @@ fn populateMetadata(self: *Zld) !void {
22832017 .aarch64 => 2,
22842018 else => unreachable, // unhandled architecture type
22852019 };
2286 try text_seg.addSection(self.allocator, .{
2287 .sectname = makeStaticString("__text"),
2288 .segname = makeStaticString("__TEXT"),
2289 .addr = 0,
2290 .size = 0,
2291 .offset = 0,
2020 try text_seg.addSection(self.allocator, "__text", .{
22922021 .@"align" = alignment,
2293 .reloff = 0,
2294 .nreloc = 0,
22952022 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2296 .reserved1 = 0,
2297 .reserved2 = 0,
2298 .reserved3 = 0,
22992023 });
23002024 }
23012025
......@@ -2312,19 +2036,10 @@ fn populateMetadata(self: *Zld) !void {
23122036 .aarch64 => 3 * @sizeOf(u32),
23132037 else => unreachable, // unhandled architecture type
23142038 };
2315 try text_seg.addSection(self.allocator, .{
2316 .sectname = makeStaticString("__stubs"),
2317 .segname = makeStaticString("__TEXT"),
2318 .addr = 0,
2319 .size = 0,
2320 .offset = 0,
2039 try text_seg.addSection(self.allocator, "__stubs", .{
23212040 .@"align" = alignment,
2322 .reloff = 0,
2323 .nreloc = 0,
23242041 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2325 .reserved1 = 0,
23262042 .reserved2 = stub_size,
2327 .reserved3 = 0,
23282043 });
23292044 }
23302045
......@@ -2341,37 +2056,19 @@ fn populateMetadata(self: *Zld) !void {
23412056 .aarch64 => 6 * @sizeOf(u32),
23422057 else => unreachable,
23432058 };
2344 try text_seg.addSection(self.allocator, .{
2345 .sectname = makeStaticString("__stub_helper"),
2346 .segname = makeStaticString("__TEXT"),
2347 .addr = 0,
2059 try text_seg.addSection(self.allocator, "__stub_helper", .{
23482060 .size = stub_helper_size,
2349 .offset = 0,
23502061 .@"align" = alignment,
2351 .reloff = 0,
2352 .nreloc = 0,
23532062 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2354 .reserved1 = 0,
2355 .reserved2 = 0,
2356 .reserved3 = 0,
23572063 });
23582064 }
23592065
23602066 if (self.data_const_segment_cmd_index == null) {
23612067 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
23622068 try self.load_commands.append(self.allocator, .{
2363 .Segment = SegmentCommand.empty(.{
2364 .cmd = macho.LC_SEGMENT_64,
2365 .cmdsize = @sizeOf(macho.segment_command_64),
2366 .segname = makeStaticString("__DATA_CONST"),
2367 .vmaddr = 0,
2368 .vmsize = 0,
2369 .fileoff = 0,
2370 .filesize = 0,
2069 .Segment = SegmentCommand.empty("__DATA_CONST", .{
23712070 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
23722071 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2373 .nsects = 0,
2374 .flags = 0,
23752072 }),
23762073 });
23772074 }
......@@ -2379,37 +2076,18 @@ fn populateMetadata(self: *Zld) !void {
23792076 if (self.got_section_index == null) {
23802077 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
23812078 self.got_section_index = @intCast(u16, data_const_seg.sections.items.len);
2382 try data_const_seg.addSection(self.allocator, .{
2383 .sectname = makeStaticString("__got"),
2384 .segname = makeStaticString("__DATA_CONST"),
2385 .addr = 0,
2386 .size = 0,
2387 .offset = 0,
2079 try data_const_seg.addSection(self.allocator, "__got", .{
23882080 .@"align" = 3, // 2^3 = @sizeOf(u64)
2389 .reloff = 0,
2390 .nreloc = 0,
23912081 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
2392 .reserved1 = 0,
2393 .reserved2 = 0,
2394 .reserved3 = 0,
23952082 });
23962083 }
23972084
23982085 if (self.data_segment_cmd_index == null) {
23992086 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
24002087 try self.load_commands.append(self.allocator, .{
2401 .Segment = SegmentCommand.empty(.{
2402 .cmd = macho.LC_SEGMENT_64,
2403 .cmdsize = @sizeOf(macho.segment_command_64),
2404 .segname = makeStaticString("__DATA"),
2405 .vmaddr = 0,
2406 .vmsize = 0,
2407 .fileoff = 0,
2408 .filesize = 0,
2088 .Segment = SegmentCommand.empty("__DATA", .{
24092089 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
24102090 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2411 .nsects = 0,
2412 .flags = 0,
24132091 }),
24142092 });
24152093 }
......@@ -2417,56 +2095,26 @@ fn populateMetadata(self: *Zld) !void {
24172095 if (self.la_symbol_ptr_section_index == null) {
24182096 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
24192097 self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len);
2420 try data_seg.addSection(self.allocator, .{
2421 .sectname = makeStaticString("__la_symbol_ptr"),
2422 .segname = makeStaticString("__DATA"),
2423 .addr = 0,
2424 .size = 0,
2425 .offset = 0,
2098 try data_seg.addSection(self.allocator, "__la_symbol_ptr", .{
24262099 .@"align" = 3, // 2^3 = @sizeOf(u64)
2427 .reloff = 0,
2428 .nreloc = 0,
24292100 .flags = macho.S_LAZY_SYMBOL_POINTERS,
2430 .reserved1 = 0,
2431 .reserved2 = 0,
2432 .reserved3 = 0,
24332101 });
24342102 }
24352103
24362104 if (self.data_section_index == null) {
24372105 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
24382106 self.data_section_index = @intCast(u16, data_seg.sections.items.len);
2439 try data_seg.addSection(self.allocator, .{
2440 .sectname = makeStaticString("__data"),
2441 .segname = makeStaticString("__DATA"),
2442 .addr = 0,
2443 .size = 0,
2444 .offset = 0,
2107 try data_seg.addSection(self.allocator, "__data", .{
24452108 .@"align" = 3, // 2^3 = @sizeOf(u64)
2446 .reloff = 0,
2447 .nreloc = 0,
2448 .flags = macho.S_REGULAR,
2449 .reserved1 = 0,
2450 .reserved2 = 0,
2451 .reserved3 = 0,
24522109 });
24532110 }
24542111
24552112 if (self.linkedit_segment_cmd_index == null) {
24562113 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
24572114 try self.load_commands.append(self.allocator, .{
2458 .Segment = SegmentCommand.empty(.{
2459 .cmd = macho.LC_SEGMENT_64,
2460 .cmdsize = @sizeOf(macho.segment_command_64),
2461 .segname = makeStaticString("__LINKEDIT"),
2462 .vmaddr = 0,
2463 .vmsize = 0,
2464 .fileoff = 0,
2465 .filesize = 0,
2115 .Segment = SegmentCommand.empty("__LINKEDIT", .{
24662116 .maxprot = macho.VM_PROT_READ,
24672117 .initprot = macho.VM_PROT_READ,
2468 .nsects = 0,
2469 .flags = 0,
24702118 }),
24712119 });
24722120 }
......@@ -2585,24 +2233,28 @@ fn populateMetadata(self: *Zld) !void {
25852233 std.crypto.random.bytes(&uuid_cmd.uuid);
25862234 try self.load_commands.append(self.allocator, .{ .Uuid = uuid_cmd });
25872235 }
2236}
25882237
2589 if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) {
2590 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
2238fn addDataInCodeLC(self: *Zld) !void {
2239 if (self.data_in_code_cmd_index == null) {
2240 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
25912241 try self.load_commands.append(self.allocator, .{
25922242 .LinkeditData = .{
2593 .cmd = macho.LC_CODE_SIGNATURE,
2243 .cmd = macho.LC_DATA_IN_CODE,
25942244 .cmdsize = @sizeOf(macho.linkedit_data_command),
25952245 .dataoff = 0,
25962246 .datasize = 0,
25972247 },
25982248 });
25992249 }
2250}
26002251
2601 if (self.data_in_code_cmd_index == null and self.arch.? == .x86_64) {
2602 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
2252fn addCodeSignatureLC(self: *Zld) !void {
2253 if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) {
2254 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
26032255 try self.load_commands.append(self.allocator, .{
26042256 .LinkeditData = .{
2605 .cmd = macho.LC_DATA_IN_CODE,
2257 .cmd = macho.LC_CODE_SIGNATURE,
26062258 .cmdsize = @sizeOf(macho.linkedit_data_command),
26072259 .dataoff = 0,
26082260 .datasize = 0,
......@@ -2698,9 +2350,7 @@ fn flush(self: *Zld) !void {
26982350 try self.writeBindInfoTable();
26992351 try self.writeLazyBindInfoTable();
27002352 try self.writeExportInfo();
2701 if (self.arch.? == .x86_64) {
2702 try self.writeDataInCode();
2703 }
2353 try self.writeDataInCode();
27042354
27052355 {
27062356 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
......@@ -2862,6 +2512,20 @@ fn writeBindInfoTable(self: *Zld) !void {
28622512 }
28632513 }
28642514
2515 for (self.imports.values()) |sym| {
2516 if (sym.cast(Symbol.Proxy)) |proxy| {
2517 for (proxy.bind_info.items) |info| {
2518 const seg = self.load_commands.items[info.segment_id].Segment;
2519 try pointers.append(.{
2520 .offset = info.address - seg.inner.vmaddr,
2521 .segment_id = info.segment_id,
2522 .dylib_ordinal = proxy.dylibOrdinal(),
2523 .name = proxy.base.name,
2524 });
2525 }
2526 }
2527 }
2528
28652529 if (self.tlv_section_index) |idx| {
28662530 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
28672531 const sect = seg.sections.items[idx];
......@@ -3469,13 +3133,6 @@ fn writeHeader(self: *Zld) !void {
34693133 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
34703134}
34713135
3472pub fn makeStaticString(bytes: []const u8) [16]u8 {
3473 var buf = [_]u8{0} ** 16;
3474 assert(bytes.len <= buf.len);
3475 mem.copy(u8, &buf, bytes);
3476 return buf;
3477}
3478
34793136fn makeString(self: *Zld, bytes: []const u8) !u32 {
34803137 if (self.strtab_dir.get(bytes)) |offset| {
34813138 log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });
src/link/MachO/commands.zig+69-4
......@@ -9,7 +9,6 @@ const assert = std.debug.assert;
99
1010const Allocator = std.mem.Allocator;
1111const MachO = @import("../MachO.zig");
12const makeStaticString = MachO.makeStaticString;
1312const padToIdeal = MachO.padToIdeal;
1413
1514pub const LoadCommand = union(enum) {
......@@ -187,11 +186,70 @@ pub const SegmentCommand = struct {
187186 inner: macho.segment_command_64,
188187 sections: std.ArrayListUnmanaged(macho.section_64) = .{},
189188
190 pub fn empty(inner: macho.segment_command_64) SegmentCommand {
191 return .{ .inner = inner };
189 const SegmentOptions = struct {
190 cmdsize: u32 = @sizeOf(macho.segment_command_64),
191 vmaddr: u64 = 0,
192 vmsize: u64 = 0,
193 fileoff: u64 = 0,
194 filesize: u64 = 0,
195 maxprot: macho.vm_prot_t = macho.VM_PROT_NONE,
196 initprot: macho.vm_prot_t = macho.VM_PROT_NONE,
197 nsects: u32 = 0,
198 flags: u32 = 0,
199 };
200
201 pub fn empty(comptime segname: []const u8, opts: SegmentOptions) SegmentCommand {
202 return .{
203 .inner = .{
204 .cmd = macho.LC_SEGMENT_64,
205 .cmdsize = opts.cmdsize,
206 .segname = makeStaticString(segname),
207 .vmaddr = opts.vmaddr,
208 .vmsize = opts.vmsize,
209 .fileoff = opts.fileoff,
210 .filesize = opts.filesize,
211 .maxprot = opts.maxprot,
212 .initprot = opts.initprot,
213 .nsects = opts.nsects,
214 .flags = opts.flags,
215 },
216 };
192217 }
193218
194 pub fn addSection(self: *SegmentCommand, alloc: *Allocator, section: macho.section_64) !void {
219 const SectionOptions = struct {
220 addr: u64 = 0,
221 size: u64 = 0,
222 offset: u32 = 0,
223 @"align": u32 = 0,
224 reloff: u32 = 0,
225 nreloc: u32 = 0,
226 flags: u32 = macho.S_REGULAR,
227 reserved1: u32 = 0,
228 reserved2: u32 = 0,
229 reserved3: u32 = 0,
230 };
231
232 pub fn addSection(
233 self: *SegmentCommand,
234 alloc: *Allocator,
235 comptime sectname: []const u8,
236 opts: SectionOptions,
237 ) !void {
238 var section = macho.section_64{
239 .sectname = makeStaticString(sectname),
240 .segname = undefined,
241 .addr = opts.addr,
242 .size = opts.size,
243 .offset = opts.offset,
244 .@"align" = opts.@"align",
245 .reloff = opts.reloff,
246 .nreloc = opts.nreloc,
247 .flags = opts.flags,
248 .reserved1 = opts.reserved1,
249 .reserved2 = opts.reserved2,
250 .reserved3 = opts.reserved3,
251 };
252 mem.copy(u8, &section.segname, &self.inner.segname);
195253 try self.sections.append(alloc, section);
196254 self.inner.cmdsize += @sizeOf(macho.section_64);
197255 self.inner.nsects += 1;
......@@ -338,6 +396,13 @@ pub fn createLoadDylibCommand(
338396 return dylib_cmd;
339397}
340398
399fn makeStaticString(bytes: []const u8) [16]u8 {
400 var buf = [_]u8{0} ** 16;
401 assert(bytes.len <= buf.len);
402 mem.copy(u8, &buf, bytes);
403 return buf;
404}
405
341406fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {
342407 var stream = io.fixedBufferStream(buffer);
343408 var given = try LoadCommand.read(allocator, stream.reader());
src/link/tapi.zig+9-2
......@@ -26,6 +26,11 @@ pub const LibStub = struct {
2626 float: f64,
2727 int: u64,
2828 },
29 compatibility_version: ?union(enum) {
30 string: []const u8,
31 float: f64,
32 int: u64,
33 },
2934 reexported_libraries: ?[]const struct {
3035 targets: []const []const u8,
3136 libraries: []const []const u8,
......@@ -36,11 +41,13 @@ pub const LibStub = struct {
3641 },
3742 exports: ?[]const struct {
3843 targets: []const []const u8,
39 symbols: []const []const u8,
44 symbols: ?[]const []const u8,
45 objc_classes: ?[]const []const u8,
4046 },
4147 reexports: ?[]const struct {
4248 targets: []const []const u8,
43 symbols: []const []const u8,
49 symbols: ?[]const []const u8,
50 objc_classes: ?[]const []const u8,
4451 },
4552 allowable_clients: ?[]const struct {
4653 targets: []const []const u8,
src/link/tapi/parse.zig+1-6
......@@ -42,7 +42,7 @@ pub const Node = struct {
4242 .doc => @fieldParentPtr(Node.Doc, "base", self).deinit(allocator),
4343 .map => @fieldParentPtr(Node.Map, "base", self).deinit(allocator),
4444 .list => @fieldParentPtr(Node.List, "base", self).deinit(allocator),
45 .value => @fieldParentPtr(Node.Value, "base", self).deinit(allocator),
45 .value => {},
4646 }
4747 }
4848
......@@ -180,11 +180,6 @@ pub const Node = struct {
180180
181181 pub const base_tag: Node.Tag = .value;
182182
183 pub fn deinit(self: *Value, allocator: *Allocator) void {
184 _ = self;
185 _ = allocator;
186 }
187
188183 pub fn format(
189184 self: *const Value,
190185 comptime fmt: []const u8,
src/main.zig+3-2
......@@ -290,6 +290,7 @@ const usage_build_generic =
290290 \\ .c C source code (requires LLVM extensions)
291291 \\ .cpp C++ source code (requires LLVM extensions)
292292 \\ Other C++ extensions: .C .cc .cxx
293 \\ .m Objective-C source code (requires LLVM extensions)
293294 \\
294295 \\General Options:
295296 \\ -h, --help Print this help and exit
......@@ -1072,7 +1073,7 @@ fn buildOutputType(
10721073 .object, .static_library, .shared_library => {
10731074 try link_objects.append(arg);
10741075 },
1075 .assembly, .c, .cpp, .h, .ll, .bc => {
1076 .assembly, .c, .cpp, .h, .ll, .bc, .m => {
10761077 try c_source_files.append(.{
10771078 .src_path = arg,
10781079 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
......@@ -1135,7 +1136,7 @@ fn buildOutputType(
11351136 .positional => {
11361137 const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg));
11371138 switch (file_ext) {
1138 .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(.{ .src_path = it.only_arg }),
1139 .assembly, .c, .cpp, .ll, .bc, .h, .m => try c_source_files.append(.{ .src_path = it.only_arg }),
11391140 .unknown, .shared_library, .object, .static_library => {
11401141 try link_objects.append(it.only_arg);
11411142 },