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...@@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES
579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"579 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"580 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"581 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig"
583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/Compilation.zig+10-2
...@@ -2857,7 +2857,7 @@ pub fn addCCArgs(...@@ -2857,7 +2857,7 @@ pub fn addCCArgs(
2857 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });2857 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
28582858
2859 switch (ext) {2859 switch (ext) {
2860 .c, .cpp, .h => {2860 .c, .cpp, .m, .h => {
2861 try argv.appendSlice(&[_][]const u8{2861 try argv.appendSlice(&[_][]const u8{
2862 "-nostdinc",2862 "-nostdinc",
2863 "-fno-spell-checking",2863 "-fno-spell-checking",
...@@ -3148,6 +3148,7 @@ pub const FileExt = enum {...@@ -3148,6 +3148,7 @@ pub const FileExt = enum {
3148 c,3148 c,
3149 cpp,3149 cpp,
3150 h,3150 h,
3151 m,
3151 ll,3152 ll,
3152 bc,3153 bc,
3153 assembly,3154 assembly,
...@@ -3159,7 +3160,7 @@ pub const FileExt = enum {...@@ -3159,7 +3160,7 @@ pub const FileExt = enum {
31593160
3160 pub fn clangSupportsDepFile(ext: FileExt) bool {3161 pub fn clangSupportsDepFile(ext: FileExt) bool {
3161 return switch (ext) {3162 return switch (ext) {
3162 .c, .cpp, .h => true,3163 .c, .cpp, .h, .m => true,
31633164
3164 .ll,3165 .ll,
3165 .bc,3166 .bc,
...@@ -3193,6 +3194,10 @@ pub fn hasCppExt(filename: []const u8) bool {...@@ -3193,6 +3194,10 @@ pub fn hasCppExt(filename: []const u8) bool {
3193 mem.endsWith(u8, filename, ".cxx");3194 mem.endsWith(u8, filename, ".cxx");
3194}3195}
31953196
3197pub fn hasObjCExt(filename: []const u8) bool {
3198 return mem.endsWith(u8, filename, ".m");
3199}
3200
3196pub fn hasAsmExt(filename: []const u8) bool {3201pub fn hasAsmExt(filename: []const u8) bool {
3197 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");3202 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
3198}3203}
...@@ -3229,6 +3234,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt {...@@ -3229,6 +3234,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
3229 return .c;3234 return .c;
3230 } else if (hasCppExt(filename)) {3235 } else if (hasCppExt(filename)) {
3231 return .cpp;3236 return .cpp;
3237 } else if (hasObjCExt(filename)) {
3238 return .m;
3232 } else if (mem.endsWith(u8, filename, ".ll")) {3239 } else if (mem.endsWith(u8, filename, ".ll")) {
3233 return .ll;3240 return .ll;
3234 } else if (mem.endsWith(u8, filename, ".bc")) {3241 } else if (mem.endsWith(u8, filename, ".bc")) {
...@@ -3252,6 +3259,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt {...@@ -3252,6 +3259,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
32523259
3253test "classifyFileExt" {3260test "classifyFileExt" {
3254 try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));3261 try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));
3262 try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m"));
3255 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));3263 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));
3256 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so"));3264 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so"));
3257 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1"));3265 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 {...@@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514 }514 }
515}515}
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
517fn linkWithLLD(self: *MachO, comp: *Compilation) !void {630fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
518 const tracy = trace(@src());631 const tracy = trace(@src());
519 defer tracy.end();632 defer tracy.end();
...@@ -676,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -676,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
676 zld.deinit();789 zld.deinit();
677 }790 }
678 zld.arch = target.cpu.arch;791 zld.arch = target.cpu.arch;
792 zld.syslibroot = self.base.options.syslibroot;
679 zld.stack_size = stack_size;793 zld.stack_size = stack_size;
680794
681 // Positional arguments to the linker such as object files and static archives.795 // Positional arguments to the linker such as object files and static archives.
...@@ -700,7 +814,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -700,7 +814,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
700 }814 }
701815
702 // Shared and static libraries passed via `-l` flag.816 // Shared and static libraries passed via `-l` flag.
703 var libs = std.ArrayList([]const u8).init(arena);
704 var search_lib_names = std.ArrayList([]const u8).init(arena);817 var search_lib_names = std.ArrayList([]const u8).init(arena);
705818
706 const system_libs = self.base.options.system_libs.keys();819 const system_libs = self.base.options.system_libs.keys();
...@@ -716,84 +829,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -716,84 +829,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
716 try search_lib_names.append(link_lib);829 try search_lib_names.append(link_lib);
717 }830 }
718831
719 var search_lib_dirs = std.ArrayList([]const u8).init(arena);832 var libs = std.ArrayList([]const u8).init(arena);
720833 try resolvePaths(
721 for (self.base.options.lib_dirs) |path| {834 arena,
722 if (fs.path.isAbsolute(path)) {835 &libs,
723 var candidates = std.ArrayList([]const u8).init(arena);836 self.base.options.syslibroot,
724 if (self.base.options.syslibroot) |syslibroot| {837 self.base.options.lib_dirs,
725 const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path });838 search_lib_names.items,
726 try candidates.append(full_path);839 .lib,
727 }840 );
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 }
797841
798 // rpaths842 // rpaths
799 var rpath_table = std.StringArrayHashMap(void).init(arena);843 var rpath_table = std.StringArrayHashMap(void).init(arena);
...@@ -809,9 +853,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -809,9 +853,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
809 }853 }
810854
811 // frameworks855 // frameworks
812 for (self.base.options.frameworks) |framework| {856 try resolvePaths(
813 log.warn("frameworks not yet supported for '-framework {s}'", .{framework});857 arena,
814 }858 &libs,
859 self.base.options.syslibroot,
860 self.base.options.framework_dirs,
861 self.base.options.frameworks,
862 .framework,
863 );
815864
816 if (self.base.options.verbose_link) {865 if (self.base.options.verbose_link) {
817 var argv = std.ArrayList([]const u8).init(arena);866 var argv = std.ArrayList([]const u8).init(arena);
...@@ -1731,18 +1780,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1731,18 +1780,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1731 if (self.pagezero_segment_cmd_index == null) {1780 if (self.pagezero_segment_cmd_index == null) {
1732 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1781 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
1733 try self.load_commands.append(self.base.allocator, .{1782 try self.load_commands.append(self.base.allocator, .{
1734 .Segment = SegmentCommand.empty(.{1783 .Segment = SegmentCommand.empty("__PAGEZERO", .{
1735 .cmd = macho.LC_SEGMENT_64,
1736 .cmdsize = @sizeOf(macho.segment_command_64),
1737 .segname = makeStaticString("__PAGEZERO"),
1738 .vmaddr = 0,
1739 .vmsize = 0x100000000, // size always set to 4GB1784 .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,
1746 }),1785 }),
1747 });1786 });
1748 self.header_dirty = true;1787 self.header_dirty = true;
...@@ -1761,18 +1800,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1761,18 +1800,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1761 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });1800 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
17621801
1763 try self.load_commands.append(self.base.allocator, .{1802 try self.load_commands.append(self.base.allocator, .{
1764 .Segment = SegmentCommand.empty(.{1803 .Segment = SegmentCommand.empty("__TEXT", .{
1765 .cmd = macho.LC_SEGMENT_64,
1766 .cmdsize = @sizeOf(macho.segment_command_64),
1767 .segname = makeStaticString("__TEXT"),
1768 .vmaddr = 0x100000000, // always starts at 4GB1804 .vmaddr = 0x100000000, // always starts at 4GB
1769 .vmsize = needed_size,1805 .vmsize = needed_size,
1770 .fileoff = 0,
1771 .filesize = needed_size,1806 .filesize = needed_size,
1772 .maxprot = maxprot,1807 .maxprot = maxprot,
1773 .initprot = initprot,1808 .initprot = initprot,
1774 .nsects = 0,
1775 .flags = 0,
1776 }),1809 }),
1777 });1810 });
1778 self.header_dirty = true;1811 self.header_dirty = true;
...@@ -1793,19 +1826,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1793,19 +1826,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
17931826
1794 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1827 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, .{1829 try text_segment.addSection(self.base.allocator, "__text", .{
1797 .sectname = makeStaticString("__text"),
1798 .segname = makeStaticString("__TEXT"),
1799 .addr = text_segment.inner.vmaddr + off,1830 .addr = text_segment.inner.vmaddr + off,
1800 .size = @intCast(u32, needed_size),1831 .size = @intCast(u32, needed_size),
1801 .offset = @intCast(u32, off),1832 .offset = @intCast(u32, off),
1802 .@"align" = alignment,1833 .@"align" = alignment,
1803 .reloff = 0,
1804 .nreloc = 0,
1805 .flags = flags,1834 .flags = flags,
1806 .reserved1 = 0,
1807 .reserved2 = 0,
1808 .reserved3 = 0,
1809 });1835 });
1810 self.header_dirty = true;1836 self.header_dirty = true;
1811 self.load_commands_dirty = true;1837 self.load_commands_dirty = true;
...@@ -1831,19 +1857,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1831,19 +1857,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
18311857
1832 log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1858 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, .{1860 try text_segment.addSection(self.base.allocator, "__stubs", .{
1835 .sectname = makeStaticString("__stubs"),
1836 .segname = makeStaticString("__TEXT"),
1837 .addr = text_segment.inner.vmaddr + off,1861 .addr = text_segment.inner.vmaddr + off,
1838 .size = needed_size,1862 .size = needed_size,
1839 .offset = @intCast(u32, off),1863 .offset = @intCast(u32, off),
1840 .@"align" = alignment,1864 .@"align" = alignment,
1841 .reloff = 0,
1842 .nreloc = 0,
1843 .flags = flags,1865 .flags = flags,
1844 .reserved1 = 0,
1845 .reserved2 = stub_size,1866 .reserved2 = stub_size,
1846 .reserved3 = 0,
1847 });1867 });
1848 self.header_dirty = true;1868 self.header_dirty = true;
1849 self.load_commands_dirty = true;1869 self.load_commands_dirty = true;
...@@ -1864,19 +1884,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1864,19 +1884,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
18641884
1865 log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1885 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, .{1887 try text_segment.addSection(self.base.allocator, "__stub_helper", .{
1868 .sectname = makeStaticString("__stub_helper"),
1869 .segname = makeStaticString("__TEXT"),
1870 .addr = text_segment.inner.vmaddr + off,1888 .addr = text_segment.inner.vmaddr + off,
1871 .size = needed_size,1889 .size = needed_size,
1872 .offset = @intCast(u32, off),1890 .offset = @intCast(u32, off),
1873 .@"align" = alignment,1891 .@"align" = alignment,
1874 .reloff = 0,
1875 .nreloc = 0,
1876 .flags = flags,1892 .flags = flags,
1877 .reserved1 = 0,
1878 .reserved2 = 0,
1879 .reserved3 = 0,
1880 });1893 });
1881 self.header_dirty = true;1894 self.header_dirty = true;
1882 self.load_commands_dirty = true;1895 self.load_commands_dirty = true;
...@@ -1893,18 +1906,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1893,18 +1906,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1893 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });1906 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
18941907
1895 try self.load_commands.append(self.base.allocator, .{1908 try self.load_commands.append(self.base.allocator, .{
1896 .Segment = SegmentCommand.empty(.{1909 .Segment = SegmentCommand.empty("__DATA_CONST", .{
1897 .cmd = macho.LC_SEGMENT_64,
1898 .cmdsize = @sizeOf(macho.segment_command_64),
1899 .segname = makeStaticString("__DATA_CONST"),
1900 .vmaddr = address_and_offset.address,1910 .vmaddr = address_and_offset.address,
1901 .vmsize = needed_size,1911 .vmsize = needed_size,
1902 .fileoff = address_and_offset.offset,1912 .fileoff = address_and_offset.offset,
1903 .filesize = needed_size,1913 .filesize = needed_size,
1904 .maxprot = maxprot,1914 .maxprot = maxprot,
1905 .initprot = initprot,1915 .initprot = initprot,
1906 .nsects = 0,
1907 .flags = 0,
1908 }),1916 }),
1909 });1917 });
1910 self.header_dirty = true;1918 self.header_dirty = true;
...@@ -1921,19 +1929,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1921,19 +1929,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19211929
1922 log.debug("found __got section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1930 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, .{1932 try dc_segment.addSection(self.base.allocator, "__got", .{
1925 .sectname = makeStaticString("__got"),
1926 .segname = makeStaticString("__DATA_CONST"),
1927 .addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff,1933 .addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff,
1928 .size = needed_size,1934 .size = needed_size,
1929 .offset = @intCast(u32, off),1935 .offset = @intCast(u32, off),
1930 .@"align" = 3, // 2^3 = @sizeOf(u64)1936 .@"align" = 3, // 2^3 = @sizeOf(u64)
1931 .reloff = 0,
1932 .nreloc = 0,
1933 .flags = flags,1937 .flags = flags,
1934 .reserved1 = 0,
1935 .reserved2 = 0,
1936 .reserved3 = 0,
1937 });1938 });
1938 self.header_dirty = true;1939 self.header_dirty = true;
1939 self.load_commands_dirty = true;1940 self.load_commands_dirty = true;
...@@ -1950,18 +1951,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1950,18 +1951,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1950 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });1951 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
19511952
1952 try self.load_commands.append(self.base.allocator, .{1953 try self.load_commands.append(self.base.allocator, .{
1953 .Segment = SegmentCommand.empty(.{1954 .Segment = SegmentCommand.empty("__DATA", .{
1954 .cmd = macho.LC_SEGMENT_64,
1955 .cmdsize = @sizeOf(macho.segment_command_64),
1956 .segname = makeStaticString("__DATA"),
1957 .vmaddr = address_and_offset.address,1955 .vmaddr = address_and_offset.address,
1958 .vmsize = needed_size,1956 .vmsize = needed_size,
1959 .fileoff = address_and_offset.offset,1957 .fileoff = address_and_offset.offset,
1960 .filesize = needed_size,1958 .filesize = needed_size,
1961 .maxprot = maxprot,1959 .maxprot = maxprot,
1962 .initprot = initprot,1960 .initprot = initprot,
1963 .nsects = 0,
1964 .flags = 0,
1965 }),1961 }),
1966 });1962 });
1967 self.header_dirty = true;1963 self.header_dirty = true;
...@@ -1978,19 +1974,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1978,19 +1974,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
19781974
1979 log.debug("found __la_symbol_ptr section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1975 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, .{1977 try data_segment.addSection(self.base.allocator, "__la_symbol_ptr", .{
1982 .sectname = makeStaticString("__la_symbol_ptr"),
1983 .segname = makeStaticString("__DATA"),
1984 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,1978 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
1985 .size = needed_size,1979 .size = needed_size,
1986 .offset = @intCast(u32, off),1980 .offset = @intCast(u32, off),
1987 .@"align" = 3, // 2^3 = @sizeOf(u64)1981 .@"align" = 3, // 2^3 = @sizeOf(u64)
1988 .reloff = 0,
1989 .nreloc = 0,
1990 .flags = flags,1982 .flags = flags,
1991 .reserved1 = 0,
1992 .reserved2 = 0,
1993 .reserved3 = 0,
1994 });1983 });
1995 self.header_dirty = true;1984 self.header_dirty = true;
1996 self.load_commands_dirty = true;1985 self.load_commands_dirty = true;
...@@ -1999,26 +1988,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1999,26 +1988,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1999 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;1988 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2000 self.data_section_index = @intCast(u16, data_segment.sections.items.len);1989 self.data_section_index = @intCast(u16, data_segment.sections.items.len);
20011990
2002 const flags = macho.S_REGULAR;
2003 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;1991 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
2004 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);1992 const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);
2005 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.1993 assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.
20061994
2007 log.debug("found __data section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1995 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, .{1997 try data_segment.addSection(self.base.allocator, "__data", .{
2010 .sectname = makeStaticString("__data"),
2011 .segname = makeStaticString("__DATA"),
2012 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,1998 .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff,
2013 .size = needed_size,1999 .size = needed_size,
2014 .offset = @intCast(u32, off),2000 .offset = @intCast(u32, off),
2015 .@"align" = 3, // 2^3 = @sizeOf(u64)2001 .@"align" = 3, // 2^3 = @sizeOf(u64)
2016 .reloff = 0,
2017 .nreloc = 0,
2018 .flags = flags,
2019 .reserved1 = 0,
2020 .reserved2 = 0,
2021 .reserved3 = 0,
2022 });2002 });
2023 self.header_dirty = true;2003 self.header_dirty = true;
2024 self.load_commands_dirty = true;2004 self.load_commands_dirty = true;
...@@ -2033,18 +2013,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -2033,18 +2013,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
2033 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});2013 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
20342014
2035 try self.load_commands.append(self.base.allocator, .{2015 try self.load_commands.append(self.base.allocator, .{
2036 .Segment = SegmentCommand.empty(.{2016 .Segment = SegmentCommand.empty("__LINKEDIT", .{
2037 .cmd = macho.LC_SEGMENT_64,
2038 .cmdsize = @sizeOf(macho.segment_command_64),
2039 .segname = makeStaticString("__LINKEDIT"),
2040 .vmaddr = address_and_offset.address,2017 .vmaddr = address_and_offset.address,
2041 .vmsize = 0,
2042 .fileoff = address_and_offset.offset,2018 .fileoff = address_and_offset.offset,
2043 .filesize = 0,
2044 .maxprot = maxprot,2019 .maxprot = maxprot,
2045 .initprot = initprot,2020 .initprot = initprot,
2046 .nsects = 0,
2047 .flags = 0,
2048 }),2021 }),
2049 });2022 });
2050 self.header_dirty = true;2023 self.header_dirty = true;
...@@ -2402,13 +2375,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -2402,13 +2375,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
2402 return vaddr;2375 return vaddr;
2403}2376}
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
2412fn makeString(self: *MachO, bytes: []const u8) !u32 {2378fn makeString(self: *MachO, bytes: []const u8) !u32 {
2413 if (self.string_table_directory.get(bytes)) |offset| {2379 if (self.string_table_directory.get(bytes)) |offset| {
2414 log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });2380 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;...@@ -8,12 +8,13 @@ const macho = std.macho;
8const mem = std.mem;8const mem = std.mem;
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Arch = std.Target.Cpu.Arch;
11const Object = @import("Object.zig");12const Object = @import("Object.zig");
1213
13usingnamespace @import("commands.zig");14usingnamespace @import("commands.zig");
1415
15allocator: *Allocator,16allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,17arch: ?Arch = null,
17file: ?fs.File = null,18file: ?fs.File = null,
18header: ?ar_hdr = null,19header: ?ar_hdr = null,
19name: ?[]const u8 = null,20name: ?[]const u8 = null,
...@@ -85,10 +86,36 @@ const ar_hdr = extern struct {...@@ -85,10 +86,36 @@ const ar_hdr = extern struct {
85 }86 }
86};87};
8788
88pub fn init(allocator: *Allocator) Archive {89pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
89 return .{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.* = .{
90 .allocator = allocator,103 .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,
91 };116 };
117
118 return archive;
92}119}
93120
94pub fn deinit(self: *Archive) void {121pub fn deinit(self: *Archive) void {
...@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {...@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {
116 const magic = try reader.readBytesNoEof(SARMAG);143 const magic = try reader.readBytesNoEof(SARMAG);
117144
118 if (!mem.eql(u8, &magic, ARMAG)) {145 if (!mem.eql(u8, &magic, ARMAG)) {
119 log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });146 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
120 return error.MalformedArchive;147 return error.NotArchive;
121 }148 }
122149
123 self.header = try reader.readStruct(ar_hdr);150 self.header = try reader.readStruct(ar_hdr);
124151
125 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {152 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
126 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });153 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
127 return error.MalformedArchive;154 return error.NotArchive;
128 }155 }
129156
130 var embedded_name = try parseName(self.allocator, self.header.?, reader);157 var embedded_name = try parseName(self.allocator, self.header.?, reader);
...@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {...@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
222 var object = try self.allocator.create(Object);249 var object = try self.allocator.create(Object);
223 errdefer self.allocator.destroy(object);250 errdefer self.allocator.destroy(object);
224251
225 object.* = Object.init(self.allocator);252 object.* = .{
226 object.arch = self.arch.?;253 .allocator = self.allocator,
227 object.file = try fs.cwd().openFile(self.name.?, .{});254 .arch = self.arch.?,
228 object.name = name;255 .file = try fs.cwd().openFile(self.name.?, .{}),
229 object.file_offset = @intCast(u32, try reader.context.getPos());256 .name = name,
257 .file_offset = @intCast(u32, try reader.context.getPos()),
258 };
230 try object.parse();259 try object.parse();
231
232 try reader.context.seekTo(0);260 try reader.context.seekTo(0);
233261
234 return object;262 return object;
235}263}
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");...@@ -19,7 +19,6 @@ const MachO = @import("../MachO.zig");
19const SrcFn = MachO.SrcFn;19const SrcFn = MachO.SrcFn;
20const TextBlock = MachO.TextBlock;20const TextBlock = MachO.TextBlock;
21const padToIdeal = MachO.padToIdeal;21const padToIdeal = MachO.padToIdeal;
22const makeStaticString = MachO.makeStaticString;
2322
24usingnamespace @import("commands.zig");23usingnamespace @import("commands.zig");
2524
...@@ -212,18 +211,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -212,18 +211,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
212 log.debug("found dSym __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });211 log.debug("found dSym __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
213212
214 try self.load_commands.append(allocator, .{213 try self.load_commands.append(allocator, .{
215 .Segment = SegmentCommand.empty(.{214 .Segment = SegmentCommand.empty("__DWARF", .{
216 .cmd = macho.LC_SEGMENT_64,
217 .cmdsize = @sizeOf(macho.segment_command_64),
218 .segname = makeStaticString("__DWARF"),
219 .vmaddr = vmaddr,215 .vmaddr = vmaddr,
220 .vmsize = needed_size,216 .vmsize = needed_size,
221 .fileoff = off,217 .fileoff = off,
222 .filesize = needed_size,218 .filesize = needed_size,
223 .maxprot = 0,
224 .initprot = 0,
225 .nsects = 0,
226 .flags = 0,
227 }),219 }),
228 });220 });
229 self.header_dirty = true;221 self.header_dirty = true;
...@@ -234,19 +226,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -234,19 +226,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
234 self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len);226 self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len);
235 assert(self.debug_string_table.items.len == 0);227 assert(self.debug_string_table.items.len == 0);
236228
237 try dwarf_segment.addSection(allocator, .{229 try dwarf_segment.addSection(allocator, "__debug_str", .{
238 .sectname = makeStaticString("__debug_str"),
239 .segname = makeStaticString("__DWARF"),
240 .addr = dwarf_segment.inner.vmaddr,230 .addr = dwarf_segment.inner.vmaddr,
241 .size = @intCast(u32, self.debug_string_table.items.len),231 .size = @intCast(u32, self.debug_string_table.items.len),
242 .offset = @intCast(u32, dwarf_segment.inner.fileoff),232 .offset = @intCast(u32, dwarf_segment.inner.fileoff),
243 .@"align" = 1,233 .@"align" = 1,
244 .reloff = 0,
245 .nreloc = 0,
246 .flags = macho.S_REGULAR,
247 .reserved1 = 0,
248 .reserved2 = 0,
249 .reserved3 = 0,
250 });234 });
251 self.header_dirty = true;235 self.header_dirty = true;
252 self.load_commands_dirty = true;236 self.load_commands_dirty = true;
...@@ -262,19 +246,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -262,19 +246,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
262246
263 log.debug("found dSym __debug_info free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });247 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, .{249 try dwarf_segment.addSection(allocator, "__debug_info", .{
266 .sectname = makeStaticString("__debug_info"),
267 .segname = makeStaticString("__DWARF"),
268 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,250 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
269 .size = file_size_hint,251 .size = file_size_hint,
270 .offset = @intCast(u32, off),252 .offset = @intCast(u32, off),
271 .@"align" = p_align,253 .@"align" = p_align,
272 .reloff = 0,
273 .nreloc = 0,
274 .flags = macho.S_REGULAR,
275 .reserved1 = 0,
276 .reserved2 = 0,
277 .reserved3 = 0,
278 });254 });
279 self.header_dirty = true;255 self.header_dirty = true;
280 self.load_commands_dirty = true;256 self.load_commands_dirty = true;
...@@ -290,19 +266,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -290,19 +266,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
290266
291 log.debug("found dSym __debug_abbrev free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });267 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, .{269 try dwarf_segment.addSection(allocator, "__debug_abbrev", .{
294 .sectname = makeStaticString("__debug_abbrev"),
295 .segname = makeStaticString("__DWARF"),
296 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,270 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
297 .size = file_size_hint,271 .size = file_size_hint,
298 .offset = @intCast(u32, off),272 .offset = @intCast(u32, off),
299 .@"align" = p_align,273 .@"align" = p_align,
300 .reloff = 0,
301 .nreloc = 0,
302 .flags = macho.S_REGULAR,
303 .reserved1 = 0,
304 .reserved2 = 0,
305 .reserved3 = 0,
306 });274 });
307 self.header_dirty = true;275 self.header_dirty = true;
308 self.load_commands_dirty = true;276 self.load_commands_dirty = true;
...@@ -318,19 +286,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -318,19 +286,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
318286
319 log.debug("found dSym __debug_aranges free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });287 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, .{289 try dwarf_segment.addSection(allocator, "__debug_aranges", .{
322 .sectname = makeStaticString("__debug_aranges"),
323 .segname = makeStaticString("__DWARF"),
324 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,290 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
325 .size = file_size_hint,291 .size = file_size_hint,
326 .offset = @intCast(u32, off),292 .offset = @intCast(u32, off),
327 .@"align" = p_align,293 .@"align" = p_align,
328 .reloff = 0,
329 .nreloc = 0,
330 .flags = macho.S_REGULAR,
331 .reserved1 = 0,
332 .reserved2 = 0,
333 .reserved3 = 0,
334 });294 });
335 self.header_dirty = true;295 self.header_dirty = true;
336 self.load_commands_dirty = true;296 self.load_commands_dirty = true;
...@@ -346,19 +306,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void...@@ -346,19 +306,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void
346306
347 log.debug("found dSym __debug_line free space 0x{x} to 0x{x}", .{ off, off + file_size_hint });307 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, .{309 try dwarf_segment.addSection(allocator, "__debug_line", .{
350 .sectname = makeStaticString("__debug_line"),
351 .segname = makeStaticString("__DWARF"),
352 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,310 .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff,
353 .size = file_size_hint,311 .size = file_size_hint,
354 .offset = @intCast(u32, off),312 .offset = @intCast(u32, off),
355 .@"align" = p_align,313 .@"align" = p_align,
356 .reloff = 0,
357 .nreloc = 0,
358 .flags = macho.S_REGULAR,
359 .reserved1 = 0,
360 .reserved2 = 0,
361 .reserved3 = 0,
362 });314 });
363 self.header_dirty = true;315 self.header_dirty = true;
364 self.load_commands_dirty = true;316 self.load_commands_dirty = true;
...@@ -692,14 +644,10 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {...@@ -692,14 +644,10 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void {
692}644}
693645
694fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {646fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand {
695 var cmd = SegmentCommand.empty(.{647 var cmd = SegmentCommand.empty("", .{
696 .cmd = macho.LC_SEGMENT_64,
697 .cmdsize = base_cmd.inner.cmdsize,648 .cmdsize = base_cmd.inner.cmdsize,
698 .segname = undefined,
699 .vmaddr = base_cmd.inner.vmaddr,649 .vmaddr = base_cmd.inner.vmaddr,
700 .vmsize = base_cmd.inner.vmsize,650 .vmsize = base_cmd.inner.vmsize,
701 .fileoff = 0,
702 .filesize = 0,
703 .maxprot = base_cmd.inner.maxprot,651 .maxprot = base_cmd.inner.maxprot,
704 .initprot = base_cmd.inner.initprot,652 .initprot = base_cmd.inner.initprot,
705 .nsects = base_cmd.inner.nsects,653 .nsects = base_cmd.inner.nsects,
src/link/MachO/Dylib.zig+305-21
...@@ -3,20 +3,26 @@ const Dylib = @This();...@@ -3,20 +3,26 @@ const Dylib = @This();
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const fs = std.fs;5const fs = std.fs;
6const fmt = std.fmt;
6const log = std.log.scoped(.dylib);7const log = std.log.scoped(.dylib);
7const macho = std.macho;8const macho = std.macho;
9const math = std.math;
8const mem = std.mem;10const mem = std.mem;
911
10const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
13const Arch = std.Target.Cpu.Arch;
11const Symbol = @import("Symbol.zig");14const Symbol = @import("Symbol.zig");
15const LibStub = @import("../tapi.zig").LibStub;
1216
13usingnamespace @import("commands.zig");17usingnamespace @import("commands.zig");
1418
15allocator: *Allocator,19allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,20
21arch: ?Arch = null,
17header: ?macho.mach_header_64 = null,22header: ?macho.mach_header_64 = null,
18file: ?fs.File = null,23file: ?fs.File = null,
19name: ?[]const u8 = null,24name: ?[]const u8 = null,
25syslibroot: ?[]const u8 = null,
2026
21ordinal: ?u16 = null,27ordinal: ?u16 = null,
2228
...@@ -33,19 +39,139 @@ id: ?Id = null,...@@ -33,19 +39,139 @@ id: ?Id = null,
33/// a symbol is referenced by an object file.39/// a symbol is referenced by an object file.
34symbols: std.StringArrayHashMapUnmanaged(void) = .{},40symbols: std.StringArrayHashMapUnmanaged(void) = .{},
3541
42// TODO add parsing re-exported libs from binary dylibs
43dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{},
44
36pub const Id = struct {45pub const Id = struct {
37 name: []const u8,46 name: []const u8,
38 timestamp: u32,47 timestamp: u32,
39 current_version: u32,48 current_version: u32,
40 compatibility_version: u32,49 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
42 pub fn deinit(id: *Id, allocator: *Allocator) void {60 pub fn deinit(id: *Id, allocator: *Allocator) void {
43 allocator.free(id.name);61 allocator.free(id.name);
44 }62 }
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 }
45};117};
46118
47pub fn init(allocator: *Allocator) Dylib {119pub const Error = error{
48 return .{ .allocator = allocator };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();
49}175}
50176
51pub fn deinit(self: *Dylib) void {177pub fn deinit(self: *Dylib) void {
...@@ -59,6 +185,11 @@ pub fn deinit(self: *Dylib) void {...@@ -59,6 +185,11 @@ pub fn deinit(self: *Dylib) void {
59 }185 }
60 self.symbols.deinit(self.allocator);186 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
62 if (self.name) |name| {193 if (self.name) |name| {
63 self.allocator.free(name);194 self.allocator.free(name);
64 }195 }
...@@ -81,8 +212,8 @@ pub fn parse(self: *Dylib) !void {...@@ -81,8 +212,8 @@ pub fn parse(self: *Dylib) !void {
81 self.header = try reader.readStruct(macho.mach_header_64);212 self.header = try reader.readStruct(macho.mach_header_64);
82213
83 if (self.header.?.filetype != macho.MH_DYLIB) {214 if (self.header.?.filetype != macho.MH_DYLIB) {
84 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });215 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
85 return error.MalformedDylib;216 return error.NotDylib;
86 }217 }
87218
88 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {219 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
...@@ -103,7 +234,7 @@ pub fn parse(self: *Dylib) !void {...@@ -103,7 +234,7 @@ pub fn parse(self: *Dylib) !void {
103 try self.parseSymbols();234 try self.parseSymbols();
104}235}
105236
106pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {237fn readLoadCommands(self: *Dylib, reader: anytype) !void {
107 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);238 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
108239
109 var i: u16 = 0;240 var i: u16 = 0;
...@@ -127,15 +258,10 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {...@@ -127,15 +258,10 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
127 }258 }
128}259}
129260
130pub fn parseId(self: *Dylib) !void {261fn parseId(self: *Dylib) !void {
131 const index = self.id_cmd_index orelse {262 const index = self.id_cmd_index orelse {
132 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});263 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
133 self.id = .{264 self.id = Id.default(try self.allocator.dupe(u8, self.name.?));
134 .name = try self.allocator.dupe(u8, self.name.?),
135 .timestamp = 2,
136 .current_version = 0,
137 .compatibility_version = 0,
138 };
139 return;265 return;
140 };266 };
141 const id_cmd = self.load_commands.items[index].Dylib;267 const id_cmd = self.load_commands.items[index].Dylib;
...@@ -153,7 +279,7 @@ pub fn parseId(self: *Dylib) !void {...@@ -153,7 +279,7 @@ pub fn parseId(self: *Dylib) !void {
153 };279 };
154}280}
155281
156pub fn parseSymbols(self: *Dylib) !void {282fn parseSymbols(self: *Dylib) !void {
157 const index = self.symtab_cmd_index orelse return;283 const index = self.symtab_cmd_index orelse return;
158 const symtab_cmd = self.load_commands.items[index].Symtab;284 const symtab_cmd = self.load_commands.items[index].Symtab;
159285
...@@ -176,13 +302,171 @@ pub fn parseSymbols(self: *Dylib) !void {...@@ -176,13 +302,171 @@ pub fn parseSymbols(self: *Dylib) !void {
176 }302 }
177}303}
178304
179pub fn isDylib(file: fs.File) !bool {305fn hasTarget(targets: []const []const u8, target: []const u8) bool {
180 const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {306 for (targets) |t| {
181 error.EndOfStream => return false,307 if (mem.eql(u8, t, target)) return true;
182 else => |e| return e,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,
183 };344 };
184 try file.seekTo(0);345
185 return header.filetype == macho.MH_DYLIB;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 }
186}470}
187471
188pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {472pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
...@@ -197,7 +481,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {...@@ -197,7 +481,7 @@ pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
197 .@"type" = .proxy,481 .@"type" = .proxy,
198 .name = name,482 .name = name,
199 },483 },
200 .file = .{ .dylib = self },484 .file = self,
201 };485 };
202486
203 return &proxy.base;487 return &proxy.base;
src/link/MachO/Object.zig+37-15
...@@ -11,6 +11,7 @@ const mem = std.mem;...@@ -11,6 +11,7 @@ const mem = std.mem;
11const reloc = @import("reloc.zig");11const reloc = @import("reloc.zig");
1212
13const Allocator = mem.Allocator;13const Allocator = mem.Allocator;
14const Arch = std.Target.Cpu.Arch;
14const Relocation = reloc.Relocation;15const Relocation = reloc.Relocation;
15const Symbol = @import("Symbol.zig");16const Symbol = @import("Symbol.zig");
16const parseName = @import("Zld.zig").parseName;17const parseName = @import("Zld.zig").parseName;
...@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;...@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;
18usingnamespace @import("commands.zig");19usingnamespace @import("commands.zig");
1920
20allocator: *Allocator,21allocator: *Allocator,
21arch: ?std.Target.Cpu.Arch = null,22arch: ?Arch = null,
22header: ?macho.mach_header_64 = null,23header: ?macho.mach_header_64 = null,
23file: ?fs.File = null,24file: ?fs.File = null,
24file_offset: ?u32 = null,25file_offset: ?u32 = null,
...@@ -173,10 +174,36 @@ const DebugInfo = struct {...@@ -173,10 +174,36 @@ const DebugInfo = struct {
173 }174 }
174};175};
175176
176pub fn init(allocator: *Allocator) Object {177pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
177 return .{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.* = .{
178 .allocator = allocator,191 .allocator = allocator,
192 .arch = arch,
193 .name = name,
194 .file = file,
179 };195 };
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;
180}207}
181208
182pub fn deinit(self: *Object) void {209pub fn deinit(self: *Object) void {
...@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {...@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {
223 self.header = try reader.readStruct(macho.mach_header_64);250 self.header = try reader.readStruct(macho.mach_header_64);
224251
225 if (self.header.?.filetype != macho.MH_OBJECT) {252 if (self.header.?.filetype != macho.MH_OBJECT) {
226 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype });253 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
227 return error.MalformedObject;254 macho.MH_OBJECT,
255 self.header.?.filetype,
256 });
257
258 return error.NotObject;
228 }259 }
229260
230 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {261 const this_arch: Arch = switch (self.header.?.cputype) {
231 macho.CPU_TYPE_ARM64 => .aarch64,262 macho.CPU_TYPE_ARM64 => .aarch64,
232 macho.CPU_TYPE_X86_64 => .x86_64,263 macho.CPU_TYPE_X86_64 => .x86_64,
233 else => |value| {264 else => |value| {
...@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {...@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {
533 try self.data_in_code_entries.append(self.allocator, dice);564 try self.data_in_code_entries.append(self.allocator, dice);
534 }565 }
535}566}
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;...@@ -7,7 +7,6 @@ const mem = std.mem;
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const Dylib = @import("Dylib.zig");8const Dylib = @import("Dylib.zig");
9const Object = @import("Object.zig");9const Object = @import("Object.zig");
10const Stub = @import("Stub.zig");
1110
12pub const Type = enum {11pub const Type = enum {
13 regular,12 regular,
...@@ -85,21 +84,26 @@ pub const Regular = struct {...@@ -85,21 +84,26 @@ pub const Regular = struct {
85pub const Proxy = struct {84pub const Proxy = struct {
86 base: Symbol,85 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.
89 /// null means self-reference.95 /// null means self-reference.
90 file: ?union(enum) {96 file: ?*Dylib = null,
91 dylib: *Dylib,
92 stub: *Stub,
93 } = null,
9497
95 pub const base_type: Symbol.Type = .proxy;98 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
97 pub fn dylibOrdinal(proxy: *Proxy) u16 {104 pub fn dylibOrdinal(proxy: *Proxy) u16 {
98 const file = proxy.file orelse return 0;105 const dylib = proxy.file orelse return 0;
99 return switch (file) {106 return dylib.ordinal.?;
100 .dylib => |dylib| dylib.ordinal.?,
101 .stub => |stub| stub.ordinal.?,
102 };
103 }107 }
104};108};
105109
...@@ -129,6 +133,10 @@ pub const Tentative = struct {...@@ -129,6 +133,10 @@ pub const Tentative = struct {
129133
130pub fn deinit(base: *Symbol, allocator: *Allocator) void {134pub fn deinit(base: *Symbol, allocator: *Allocator) void {
131 allocator.free(base.name);135 allocator.free(base.name);
136 switch (base.@"type") {
137 .proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator),
138 else => {},
139 }
132}140}
133141
134pub fn cast(base: *Symbol, comptime T: type) ?*T {142pub fn cast(base: *Symbol, comptime T: type) ?*T {
src/link/MachO/Zld.zig+462-805
...@@ -17,7 +17,6 @@ const Archive = @import("Archive.zig");...@@ -17,7 +17,6 @@ const Archive = @import("Archive.zig");
17const CodeSignature = @import("CodeSignature.zig");17const CodeSignature = @import("CodeSignature.zig");
18const Dylib = @import("Dylib.zig");18const Dylib = @import("Dylib.zig");
19const Object = @import("Object.zig");19const Object = @import("Object.zig");
20const Stub = @import("Stub.zig");
21const Symbol = @import("Symbol.zig");20const Symbol = @import("Symbol.zig");
22const Trie = @import("Trie.zig");21const Trie = @import("Trie.zig");
2322
...@@ -33,14 +32,14 @@ out_path: ?[]const u8 = null,...@@ -33,14 +32,14 @@ out_path: ?[]const u8 = null,
3332
34// TODO these args will become obselete once Zld is coalesced with incremental33// TODO these args will become obselete once Zld is coalesced with incremental
35// linker.34// linker.
35syslibroot: ?[]const u8 = null,
36stack_size: u64 = 0,36stack_size: u64 = 0,
3737
38objects: std.ArrayListUnmanaged(*Object) = .{},38objects: std.ArrayListUnmanaged(*Object) = .{},
39archives: std.ArrayListUnmanaged(*Archive) = .{},39archives: std.ArrayListUnmanaged(*Archive) = .{},
40dylibs: std.ArrayListUnmanaged(*Dylib) = .{},40dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
41lib_stubs: std.ArrayListUnmanaged(*Stub) = .{},
4241
43libsystem_stub_index: ?u16 = null,42libsystem_dylib_index: ?u16 = null,
44next_dylib_ordinal: u16 = 1,43next_dylib_ordinal: u16 = 1,
4544
46load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},45load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
...@@ -73,12 +72,21 @@ gcc_except_tab_section_index: ?u16 = null,...@@ -73,12 +72,21 @@ gcc_except_tab_section_index: ?u16 = null,
73unwind_info_section_index: ?u16 = null,72unwind_info_section_index: ?u16 = null,
74eh_frame_section_index: ?u16 = null,73eh_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
76// __DATA_CONST segment sections80// __DATA_CONST segment sections
77got_section_index: ?u16 = null,81got_section_index: ?u16 = null,
78mod_init_func_section_index: ?u16 = null,82mod_init_func_section_index: ?u16 = null,
79mod_term_func_section_index: ?u16 = null,83mod_term_func_section_index: ?u16 = null,
80data_const_section_index: ?u16 = null,84data_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
82// __DATA segment sections90// __DATA segment sections
83tlv_section_index: ?u16 = null,91tlv_section_index: ?u16 = null,
84tlv_data_section_index: ?u16 = null,92tlv_data_section_index: ?u16 = null,
...@@ -88,6 +96,11 @@ data_section_index: ?u16 = null,...@@ -88,6 +96,11 @@ data_section_index: ?u16 = null,
88bss_section_index: ?u16 = null,96bss_section_index: ?u16 = null,
89common_section_index: ?u16 = null,97common_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
91globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},104globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
92imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},105imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
93unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},106unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
...@@ -120,10 +133,6 @@ const TlvOffset = struct {...@@ -120,10 +133,6 @@ const TlvOffset = struct {
120/// Default path to dyld133/// Default path to dyld
121const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";134const 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
127pub fn init(allocator: *Allocator) Zld {136pub fn init(allocator: *Allocator) Zld {
128 return .{ .allocator = allocator };137 return .{ .allocator = allocator };
129}138}
...@@ -157,12 +166,6 @@ pub fn deinit(self: *Zld) void {...@@ -157,12 +166,6 @@ pub fn deinit(self: *Zld) void {
157 }166 }
158 self.dylibs.deinit(self.allocator);167 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
166 for (self.imports.values()) |proxy| {169 for (self.imports.values()) |proxy| {
167 proxy.deinit(self.allocator);170 proxy.deinit(self.allocator);
168 self.allocator.destroy(proxy);171 self.allocator.destroy(proxy);
...@@ -235,7 +238,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -235,7 +238,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
235 });238 });
236239
237 try self.populateMetadata();240 try self.populateMetadata();
238 try self.addRpaths(args.rpaths);
239 try self.parseInputFiles(files);241 try self.parseInputFiles(files);
240 try self.parseLibs(args.libs);242 try self.parseLibs(args.libs);
241 try self.parseLibSystem(args.libc_stub_path);243 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...@@ -243,217 +245,92 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
243 try self.resolveStubsAndGotEntries();245 try self.resolveStubsAndGotEntries();
244 try self.updateMetadata();246 try self.updateMetadata();
245 try self.sortSections();247 try self.sortSections();
248 try self.addRpaths(args.rpaths);
249 try self.addDataInCodeLC();
250 try self.addCodeSignatureLC();
246 try self.allocateTextSegment();251 try self.allocateTextSegment();
247 try self.allocateDataConstSegment();252 try self.allocateDataConstSegment();
248 try self.allocateDataSegment();253 try self.allocateDataSegment();
249 self.allocateLinkeditSegment();254 self.allocateLinkeditSegment();
250 try self.allocateSymbols();255 try self.allocateSymbols();
251 try self.allocateTentativeSymbols();256 try self.allocateTentativeSymbols();
257 try self.allocateProxyBindAddresses();
252 try self.flush();258 try self.flush();
253}259}
254260
255fn parseInputFiles(self: *Zld, files: []const []const u8) !void {261fn 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).
273 for (files) |file_name| {262 for (files) |file_name| {
274 const file = try fs.cwd().openFile(file_name, .{});
275 const full_path = full_path: {263 const full_path = full_path: {
276 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;264 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
277 const path = try std.fs.realpath(file_name, &buffer);265 const path = try std.fs.realpath(file_name, &buffer);
278 break :full_path try self.allocator.dupe(u8, path);266 break :full_path try self.allocator.dupe(u8, path);
279 };267 };
280268
281 try_object: {269 if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
282 if (!(try Object.isObject(file))) break :try_object;270 try self.objects.append(self.allocator, 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 });
298 continue;271 continue;
299 }272 }
300273
301 try_dylib: {274 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
302 if (!(try Dylib.isDylib(file))) break :try_dylib;275 try self.archives.append(self.allocator, archive);
303 try classified.append(.{
304 .kind = .dylib,
305 .origin = .{ .file = file },
306 .name = full_path,
307 });
308 continue;276 continue;
309 }277 }
310278
311 try_stub: {279 if (try Dylib.createAndParseFromPath(
312 var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch {280 self.allocator,
313 break :try_stub;281 self.arch.?,
314 };282 full_path,
315 try classified.append(.{283 self.syslibroot,
316 .kind = .stub,284 )) |dylibs| {
317 .origin = .{ .stub = lib_stub },285 defer self.allocator.free(dylibs);
318 .name = full_path,286 try self.dylibs.appendSlice(self.allocator, dylibs);
319 });
320 file.close();
321 continue;287 continue;
322 }288 }
323289
324 file.close();
325 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});290 log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
326 }291 }
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 }
381}292}
382293
383fn parseLibs(self: *Zld, libs: []const []const u8) !void {294fn parseLibs(self: *Zld, libs: []const []const u8) !void {
384 for (libs) |lib| {295 for (libs) |lib| {
385 const file = try fs.cwd().openFile(lib, .{});296 if (try Dylib.createAndParseFromPath(
386297 self.allocator,
387 if (try Dylib.isDylib(file)) {298 self.arch.?,
388 const dylib = try self.allocator.create(Dylib);299 lib,
389 errdefer self.allocator.destroy(dylib);300 self.syslibroot,
390301 )) |dylibs| {
391 dylib.* = Dylib.init(self.allocator);302 defer self.allocator.free(dylibs);
392 dylib.arch = self.arch.?;303 try self.dylibs.appendSlice(self.allocator, dylibs);
393 dylib.name = try self.allocator.dupe(u8, lib);304 continue;
394 dylib.file = file;305 }
395306
396 try dylib.parse();307 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
397 try self.dylibs.append(self.allocator, dylib);308 try self.archives.append(self.allocator, archive);
398 } else {309 continue;
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 }
431 }310 }
311
312 log.warn("unknown filetype for a library: '{s}'", .{lib});
432 }313 }
433}314}
434315
435fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
436 const file = try fs.cwd().openFile(libc_stub_path, .{});317 const dylibs = (try Dylib.createAndParseFromPath(
437 defer file.close();318 self.allocator,
438319 self.arch.?,
439 var lib_stub = try Stub.LibStub.loadFromFile(self.allocator, file);320 libc_stub_path,
440321 self.syslibroot,
441 const stub = try self.allocator.create(Stub);322 )) orelse return error.FailedToParseLibSystem;
442 errdefer self.allocator.destroy(stub);323 defer self.allocator.free(dylibs);
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;
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);328 self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
452 try self.lib_stubs.append(self.allocator, stub);329 try self.dylibs.append(self.allocator, dylib);
453330
454 // Add LC_LOAD_DYLIB load command.331 // Add LC_LOAD_DYLIB load command.
455 stub.ordinal = self.next_dylib_ordinal;332 dylib.ordinal = self.next_dylib_ordinal;
456 const dylib_id = stub.id orelse unreachable;333 const dylib_id = dylib.id orelse unreachable;
457 var dylib_cmd = try createLoadDylibCommand(334 var dylib_cmd = try createLoadDylibCommand(
458 self.allocator,335 self.allocator,
459 dylib_id.name,336 dylib_id.name,
...@@ -501,428 +378,22 @@ fn mapAndUpdateSections(...@@ -501,428 +378,22 @@ fn mapAndUpdateSections(
501378
502fn updateMetadata(self: *Zld) !void {379fn updateMetadata(self: *Zld) !void {
503 for (self.objects.items) |object| {380 for (self.objects.items) |object| {
504 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;381 // Find ideal section alignment and update section mappings
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
920 for (object.sections.items) |sect, sect_id| {382 for (object.sections.items) |sect, sect_id| {
921 if (self.getMatchingSection(sect)) |res| {383 const match = (try self.getMatchingSection(sect)) orelse {
922 try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect);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 });
923 continue;390 continue;
924 }391 };
925 log.debug("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() });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);
926 }397 }
927 }398 }
928399
...@@ -932,19 +403,8 @@ fn updateMetadata(self: *Zld) !void {...@@ -932,19 +403,8 @@ fn updateMetadata(self: *Zld) !void {
932 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;403 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
933 const common_section_index = self.common_section_index orelse ind: {404 const common_section_index = self.common_section_index orelse ind: {
934 self.common_section_index = @intCast(u16, data_seg.sections.items.len);405 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
935 try data_seg.addSection(self.allocator, .{406 try data_seg.addSection(self.allocator, "__common", .{
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,
944 .flags = macho.S_ZEROFILL,407 .flags = macho.S_ZEROFILL,
945 .reserved1 = 0,
946 .reserved2 = 0,
947 .reserved3 = 0,
948 });408 });
949 break :ind self.common_section_index.?;409 break :ind self.common_section_index.?;
950 };410 };
...@@ -1018,31 +478,116 @@ const MatchingSection = struct {...@@ -1018,31 +478,116 @@ const MatchingSection = struct {
1018 sect: u16,478 sect: u16,
1019};479};
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;
1022 const segname = sect.segname();485 const segname = sect.segname();
1023 const sectname = sect.sectname();486 const sectname = sect.sectname();
1024487
1025 const res: ?MatchingSection = blk: {488 const res: ?MatchingSection = blk: {
1026 switch (sect.sectionType()) {489 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
1028 break :blk .{496 break :blk .{
1029 .seg = self.text_segment_cmd_index.?,497 .seg = self.text_segment_cmd_index.?,
1030 .sect = self.text_const_section_index.?,498 .sect = self.text_const_section_index.?,
1031 };499 };
1032 },500 },
1033 macho.S_CSTRING_LITERALS => {501 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
1034 break :blk .{547 break :blk .{
1035 .seg = self.text_segment_cmd_index.?,548 .seg = self.text_segment_cmd_index.?,
1036 .sect = self.cstring_section_index.?,549 .sect = self.cstring_section_index.?,
1037 };550 };
1038 },551 },
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 },
1039 macho.S_MOD_INIT_FUNC_POINTERS => {570 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
1040 break :blk .{578 break :blk .{
1041 .seg = self.data_const_segment_cmd_index.?,579 .seg = self.data_const_segment_cmd_index.?,
1042 .sect = self.mod_init_func_section_index.?,580 .sect = self.mod_init_func_section_index.?,
1043 };581 };
1044 },582 },
1045 macho.S_MOD_TERM_FUNC_POINTERS => {583 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
1046 break :blk .{591 break :blk .{
1047 .seg = self.data_const_segment_cmd_index.?,592 .seg = self.data_const_segment_cmd_index.?,
1048 .sect = self.mod_term_func_section_index.?,593 .sect = self.mod_term_func_section_index.?,
...@@ -1050,11 +595,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1050,11 +595,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1050 },595 },
1051 macho.S_ZEROFILL => {596 macho.S_ZEROFILL => {
1052 if (mem.eql(u8, sectname, "__common")) {597 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
1053 break :blk .{605 break :blk .{
1054 .seg = self.data_segment_cmd_index.?,606 .seg = self.data_segment_cmd_index.?,
1055 .sect = self.common_section_index.?,607 .sect = self.common_section_index.?,
1056 };608 };
1057 } else {609 } 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
1058 break :blk .{617 break :blk .{
1059 .seg = self.data_segment_cmd_index.?,618 .seg = self.data_segment_cmd_index.?,
1060 .sect = self.bss_section_index.?,619 .sect = self.bss_section_index.?,
...@@ -1062,18 +621,39 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1062,18 +621,39 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1062 }621 }
1063 },622 },
1064 macho.S_THREAD_LOCAL_VARIABLES => {623 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
1065 break :blk .{631 break :blk .{
1066 .seg = self.data_segment_cmd_index.?,632 .seg = self.data_segment_cmd_index.?,
1067 .sect = self.tlv_section_index.?,633 .sect = self.tlv_section_index.?,
1068 };634 };
1069 },635 },
1070 macho.S_THREAD_LOCAL_REGULAR => {636 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
1071 break :blk .{644 break :blk .{
1072 .seg = self.data_segment_cmd_index.?,645 .seg = self.data_segment_cmd_index.?,
1073 .sect = self.tlv_data_section_index.?,646 .sect = self.tlv_data_section_index.?,
1074 };647 };
1075 },648 },
1076 macho.S_THREAD_LOCAL_ZEROFILL => {649 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
1077 break :blk .{657 break :blk .{
1078 .seg = self.data_segment_cmd_index.?,658 .seg = self.data_segment_cmd_index.?,
1079 .sect = self.tlv_bss_section_index.?,659 .sect = self.tlv_bss_section_index.?,
...@@ -1081,12 +661,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1081,12 +661,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1081 },661 },
1082 macho.S_COALESCED => {662 macho.S_COALESCED => {
1083 if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {663 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
1084 break :blk .{671 break :blk .{
1085 .seg = self.text_segment_cmd_index.?,672 .seg = self.text_segment_cmd_index.?,
1086 .sect = self.eh_frame_section_index.?,673 .sect = self.eh_frame_section_index.?,
1087 };674 };
1088 }675 }
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
1090 break :blk .{683 break :blk .{
1091 .seg = self.data_const_segment_cmd_index.?,684 .seg = self.data_const_segment_cmd_index.?,
1092 .sect = self.data_const_section_index.?,685 .sect = self.data_const_section_index.?,
...@@ -1094,6 +687,13 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1094,6 +687,13 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1094 },687 },
1095 macho.S_REGULAR => {688 macho.S_REGULAR => {
1096 if (sect.isCode()) {689 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
1097 break :blk .{697 break :blk .{
1098 .seg = self.text_segment_cmd_index.?,698 .seg = self.text_segment_cmd_index.?,
1099 .sect = self.text_section_index.?,699 .sect = self.text_section_index.?,
...@@ -1101,21 +701,51 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1101,21 +701,51 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1101 }701 }
1102 if (sect.isDebug()) {702 if (sect.isDebug()) {
1103 // TODO debug attributes703 // 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 }
1104 break :blk null;709 break :blk null;
1105 }710 }
1106711
1107 if (mem.eql(u8, segname, "__TEXT")) {712 if (mem.eql(u8, segname, "__TEXT")) {
1108 if (mem.eql(u8, sectname, "__ustring")) {713 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
1109 break :blk .{719 break :blk .{
1110 .seg = self.text_segment_cmd_index.?,720 .seg = self.text_segment_cmd_index.?,
1111 .sect = self.ustring_section_index.?,721 .sect = self.ustring_section_index.?,
1112 };722 };
1113 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {723 } 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
1114 break :blk .{729 break :blk .{
1115 .seg = self.text_segment_cmd_index.?,730 .seg = self.text_segment_cmd_index.?,
1116 .sect = self.gcc_except_tab_section_index.?,731 .sect = self.gcc_except_tab_section_index.?,
1117 };732 };
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 };
1118 } else {743 } 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
1119 break :blk .{749 break :blk .{
1120 .seg = self.text_segment_cmd_index.?,750 .seg = self.text_segment_cmd_index.?,
1121 .sect = self.text_const_section_index.?,751 .sect = self.text_const_section_index.?,
...@@ -1124,6 +754,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1124,6 +754,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1124 }754 }
1125755
1126 if (mem.eql(u8, segname, "__DATA_CONST")) {756 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
1127 break :blk .{762 break :blk .{
1128 .seg = self.data_const_segment_cmd_index.?,763 .seg = self.data_const_segment_cmd_index.?,
1129 .sect = self.data_const_section_index.?,764 .sect = self.data_const_section_index.?,
...@@ -1132,15 +767,92 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {...@@ -1132,15 +767,92 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection {
1132767
1133 if (mem.eql(u8, segname, "__DATA")) {768 if (mem.eql(u8, segname, "__DATA")) {
1134 if (mem.eql(u8, sectname, "__const")) {769 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
1135 break :blk .{775 break :blk .{
1136 .seg = self.data_const_segment_cmd_index.?,776 .seg = self.data_const_segment_cmd_index.?,
1137 .sect = self.data_const_section_index.?,777 .sect = self.data_const_section_index.?,
1138 };778 };
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 };
1139 }849 }
1140 break :blk .{850 }
1141 .seg = self.data_segment_cmd_index.?,851
1142 .sect = self.data_section_index.?,852 if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) {
1143 };853 log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{
854 sect.flags(), segname, sectname,
855 });
1144 }856 }
1145857
1146 break :blk null;858 break :blk null;
...@@ -1175,6 +887,9 @@ fn sortSections(self: *Zld) !void {...@@ -1175,6 +887,9 @@ fn sortSections(self: *Zld) !void {
1175 &self.cstring_section_index,887 &self.cstring_section_index,
1176 &self.ustring_section_index,888 &self.ustring_section_index,
1177 &self.text_const_section_index,889 &self.text_const_section_index,
890 &self.objc_methname_section_index,
891 &self.objc_methtype_section_index,
892 &self.objc_classname_section_index,
1178 &self.eh_frame_section_index,893 &self.eh_frame_section_index,
1179 };894 };
1180 for (indices) |maybe_index| {895 for (indices) |maybe_index| {
...@@ -1200,6 +915,9 @@ fn sortSections(self: *Zld) !void {...@@ -1200,6 +915,9 @@ fn sortSections(self: *Zld) !void {
1200 &self.mod_init_func_section_index,915 &self.mod_init_func_section_index,
1201 &self.mod_term_func_section_index,916 &self.mod_term_func_section_index,
1202 &self.data_const_section_index,917 &self.data_const_section_index,
918 &self.objc_cfstring_section_index,
919 &self.objc_classlist_section_index,
920 &self.objc_imageinfo_section_index,
1203 };921 };
1204 for (indices) |maybe_index| {922 for (indices) |maybe_index| {
1205 const new_index: u16 = if (maybe_index.*) |index| blk: {923 const new_index: u16 = if (maybe_index.*) |index| blk: {
...@@ -1222,6 +940,10 @@ fn sortSections(self: *Zld) !void {...@@ -1222,6 +940,10 @@ fn sortSections(self: *Zld) !void {
1222 // __DATA segment940 // __DATA segment
1223 const indices = &[_]*?u16{941 const indices = &[_]*?u16{
1224 &self.la_symbol_ptr_section_index,942 &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,
1225 &self.data_section_index,947 &self.data_section_index,
1226 &self.tlv_section_index,948 &self.tlv_section_index,
1227 &self.tlv_data_section_index,949 &self.tlv_data_section_index,
...@@ -1487,6 +1209,31 @@ fn allocateTentativeSymbols(self: *Zld) !void {...@@ -1487,6 +1209,31 @@ fn allocateTentativeSymbols(self: *Zld) !void {
1487 }1209 }
1488}1210}
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
1490fn writeStubHelperCommon(self: *Zld) !void {1237fn writeStubHelperCommon(self: *Zld) !void {
1491 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1238 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1492 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];1239 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
...@@ -1893,25 +1640,16 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1893,25 +1640,16 @@ fn resolveSymbols(self: *Zld) !void {
1893 }1640 }
1894 self.unresolved.clearRetainingCapacity();1641 self.unresolved.clearRetainingCapacity();
18951642
1896 var referenced = std.AutoHashMap(union(enum) {1643 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
1897 dylib: *Dylib,
1898 stub: *Stub,
1899 }, void).init(self.allocator);
1900 defer referenced.deinit();1644 defer referenced.deinit();
19011645
1902 loop: while (unresolved.popOrNull()) |undef| {1646 loop: while (unresolved.popOrNull()) |undef| {
1903 const proxy = self.imports.get(undef.name) orelse outer: {1647 const proxy = self.imports.get(undef.name) orelse outer: {
1904 const proxy = inner: {1648 const proxy = inner: {
1905 for (self.dylibs.items) |dylib| {1649 for (self.dylibs.items) |dylib, i| {
1906 const proxy = (try dylib.createProxy(undef.name)) orelse continue;1650 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
1907 try referenced.put(.{ .dylib = dylib }, {});1651 if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately.
1908 break :inner proxy;1652 try referenced.put(dylib, {});
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 }, {});
1915 }1653 }
1916 break :inner proxy;1654 break :inner proxy;
1917 }1655 }
...@@ -1944,33 +1682,17 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1944,33 +1682,17 @@ fn resolveSymbols(self: *Zld) !void {
19441682
1945 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.1683 // Add LC_LOAD_DYLIB load command for each referenced dylib/stub.
1946 var it = referenced.iterator();1684 var it = referenced.iterator();
1947 while (it.next()) |key| {1685 while (it.next()) |entry| {
1948 var dylib_cmd = blk: {1686 const dylib = entry.key_ptr.*;
1949 switch (key.key_ptr.*) {1687 dylib.ordinal = self.next_dylib_ordinal;
1950 .dylib => |dylib| {1688 const dylib_id = dylib.id orelse unreachable;
1951 dylib.ordinal = self.next_dylib_ordinal;1689 var dylib_cmd = try createLoadDylibCommand(
1952 const dylib_id = dylib.id orelse unreachable;1690 self.allocator,
1953 break :blk try createLoadDylibCommand(1691 dylib_id.name,
1954 self.allocator,1692 dylib_id.timestamp,
1955 dylib_id.name,1693 dylib_id.current_version,
1956 dylib_id.timestamp,1694 dylib_id.compatibility_version,
1957 dylib_id.current_version,1695 );
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 };
1974 errdefer dylib_cmd.deinit(self.allocator);1696 errdefer dylib_cmd.deinit(self.allocator);
1975 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });1697 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
1976 self.next_dylib_ordinal += 1;1698 self.next_dylib_ordinal += 1;
...@@ -1988,8 +1710,8 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1988,8 +1710,8 @@ fn resolveSymbols(self: *Zld) !void {
1988 }1710 }
19891711
1990 // Finally put dyld_stub_binder as an Import1712 // Finally put dyld_stub_binder as an Import
1991 const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?];1713 const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?];
1992 const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse {1714 const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse {
1993 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});1715 log.err("undefined reference to symbol 'dyld_stub_binder'", .{});
1994 return error.UndefinedSymbolReference;1716 return error.UndefinedSymbolReference;
1995 };1717 };
...@@ -2004,6 +1726,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {...@@ -2004,6 +1726,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
2004 const relocs = sect.relocs orelse continue;1726 const relocs = sect.relocs orelse continue;
2005 for (relocs) |rel| {1727 for (relocs) |rel| {
2006 switch (rel.@"type") {1728 switch (rel.@"type") {
1729 .unsigned => continue,
2007 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {1730 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
2008 const sym = rel.target.symbol.getTopmostAlias();1731 const sym = rel.target.symbol.getTopmostAlias();
2009 if (sym.got_index != null) continue;1732 if (sym.got_index != null) continue;
...@@ -2089,29 +1812,52 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -2089,29 +1812,52 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
2089 args.source_target_sect_addr = source_sect.inner.addr;1812 args.source_target_sect_addr = source_sect.inner.addr;
2090 }1813 }
20911814
2092 rebases: {1815 const flags = @truncate(u8, target_sect.flags & 0xff);
2093 var hit: bool = false;1816 const should_rebase = rebase: {
2094 if (target_map.segment_id == self.data_segment_cmd_index.?) {1817 if (!unsigned.is_64bit) break :rebase false;
2095 if (self.data_section_index) |index| {1818
2096 if (index == target_map.section_id) hit = true;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 }
2097 }1831 }
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;
2098 }1840 }
2099 if (target_map.segment_id == self.data_const_segment_cmd_index.?) {1841 if (rel.target == .symbol) {
2100 if (self.data_const_section_index) |index| {1842 const final = rel.target.symbol.getTopmostAlias();
2101 if (index == target_map.section_id) hit = true;1843 if (final.cast(Symbol.Proxy)) |_| {
1844 break :rebase false;
2102 }1845 }
2103 }1846 }
21041847
2105 if (!hit) break :rebases;1848 break :rebase true;
1849 };
21061850
1851 if (should_rebase) {
2107 try self.local_rebases.append(self.allocator, .{1852 try self.local_rebases.append(self.allocator, .{
2108 .offset = source_addr - target_seg.inner.vmaddr,1853 .offset = source_addr - target_seg.inner.vmaddr,
2109 .segment_id = target_map.segment_id,1854 .segment_id = target_map.segment_id,
2110 });1855 });
2111 }1856 }
1857
2112 // TLV is handled via a separate offset mechanism.1858 // TLV is handled via a separate offset mechanism.
2113 // Calculate the offset to the initializer.1859 // 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: {
2115 // TODO we don't want to save offset to tlv_bootstrap1861 // TODO we don't want to save offset to tlv_bootstrap
2116 if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv;1862 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...@@ -2208,7 +1954,13 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T
2208 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1954 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2209 const stubs = segment.sections.items[self.stubs_section_index.?];1955 const stubs = segment.sections.items[self.stubs_section_index.?];
2210 const stubs_index = proxy.base.stubs_index orelse {1956 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 );
2212 log.err("this is an internal linker error", .{});1964 log.err("this is an internal linker error", .{});
2213 return error.FailedToResolveRelocationTarget;1965 return error.FailedToResolveRelocationTarget;
2214 };1966 };
...@@ -2240,18 +1992,8 @@ fn populateMetadata(self: *Zld) !void {...@@ -2240,18 +1992,8 @@ fn populateMetadata(self: *Zld) !void {
2240 if (self.pagezero_segment_cmd_index == null) {1992 if (self.pagezero_segment_cmd_index == null) {
2241 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1993 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
2242 try self.load_commands.append(self.allocator, .{1994 try self.load_commands.append(self.allocator, .{
2243 .Segment = SegmentCommand.empty(.{1995 .Segment = SegmentCommand.empty("__PAGEZERO", .{
2244 .cmd = macho.LC_SEGMENT_64,
2245 .cmdsize = @sizeOf(macho.segment_command_64),
2246 .segname = makeStaticString("__PAGEZERO"),
2247 .vmaddr = 0,
2248 .vmsize = 0x100000000, // size always set to 4GB1996 .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,
2255 }),1997 }),
2256 });1998 });
2257 }1999 }
...@@ -2259,18 +2001,10 @@ fn populateMetadata(self: *Zld) !void {...@@ -2259,18 +2001,10 @@ fn populateMetadata(self: *Zld) !void {
2259 if (self.text_segment_cmd_index == null) {2001 if (self.text_segment_cmd_index == null) {
2260 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);2002 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
2261 try self.load_commands.append(self.allocator, .{2003 try self.load_commands.append(self.allocator, .{
2262 .Segment = SegmentCommand.empty(.{2004 .Segment = SegmentCommand.empty("__TEXT", .{
2263 .cmd = macho.LC_SEGMENT_64,
2264 .cmdsize = @sizeOf(macho.segment_command_64),
2265 .segname = makeStaticString("__TEXT"),
2266 .vmaddr = 0x100000000, // always starts at 4GB2005 .vmaddr = 0x100000000, // always starts at 4GB
2267 .vmsize = 0,
2268 .fileoff = 0,
2269 .filesize = 0,
2270 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,2006 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
2271 .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,2007 .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
2272 .nsects = 0,
2273 .flags = 0,
2274 }),2008 }),
2275 });2009 });
2276 }2010 }
...@@ -2283,19 +2017,9 @@ fn populateMetadata(self: *Zld) !void {...@@ -2283,19 +2017,9 @@ fn populateMetadata(self: *Zld) !void {
2283 .aarch64 => 2,2017 .aarch64 => 2,
2284 else => unreachable, // unhandled architecture type2018 else => unreachable, // unhandled architecture type
2285 };2019 };
2286 try text_seg.addSection(self.allocator, .{2020 try text_seg.addSection(self.allocator, "__text", .{
2287 .sectname = makeStaticString("__text"),
2288 .segname = makeStaticString("__TEXT"),
2289 .addr = 0,
2290 .size = 0,
2291 .offset = 0,
2292 .@"align" = alignment,2021 .@"align" = alignment,
2293 .reloff = 0,
2294 .nreloc = 0,
2295 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2022 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2296 .reserved1 = 0,
2297 .reserved2 = 0,
2298 .reserved3 = 0,
2299 });2023 });
2300 }2024 }
23012025
...@@ -2312,19 +2036,10 @@ fn populateMetadata(self: *Zld) !void {...@@ -2312,19 +2036,10 @@ fn populateMetadata(self: *Zld) !void {
2312 .aarch64 => 3 * @sizeOf(u32),2036 .aarch64 => 3 * @sizeOf(u32),
2313 else => unreachable, // unhandled architecture type2037 else => unreachable, // unhandled architecture type
2314 };2038 };
2315 try text_seg.addSection(self.allocator, .{2039 try text_seg.addSection(self.allocator, "__stubs", .{
2316 .sectname = makeStaticString("__stubs"),
2317 .segname = makeStaticString("__TEXT"),
2318 .addr = 0,
2319 .size = 0,
2320 .offset = 0,
2321 .@"align" = alignment,2040 .@"align" = alignment,
2322 .reloff = 0,
2323 .nreloc = 0,
2324 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2041 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2325 .reserved1 = 0,
2326 .reserved2 = stub_size,2042 .reserved2 = stub_size,
2327 .reserved3 = 0,
2328 });2043 });
2329 }2044 }
23302045
...@@ -2341,37 +2056,19 @@ fn populateMetadata(self: *Zld) !void {...@@ -2341,37 +2056,19 @@ fn populateMetadata(self: *Zld) !void {
2341 .aarch64 => 6 * @sizeOf(u32),2056 .aarch64 => 6 * @sizeOf(u32),
2342 else => unreachable,2057 else => unreachable,
2343 };2058 };
2344 try text_seg.addSection(self.allocator, .{2059 try text_seg.addSection(self.allocator, "__stub_helper", .{
2345 .sectname = makeStaticString("__stub_helper"),
2346 .segname = makeStaticString("__TEXT"),
2347 .addr = 0,
2348 .size = stub_helper_size,2060 .size = stub_helper_size,
2349 .offset = 0,
2350 .@"align" = alignment,2061 .@"align" = alignment,
2351 .reloff = 0,
2352 .nreloc = 0,
2353 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2062 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2354 .reserved1 = 0,
2355 .reserved2 = 0,
2356 .reserved3 = 0,
2357 });2063 });
2358 }2064 }
23592065
2360 if (self.data_const_segment_cmd_index == null) {2066 if (self.data_const_segment_cmd_index == null) {
2361 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);2067 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
2362 try self.load_commands.append(self.allocator, .{2068 try self.load_commands.append(self.allocator, .{
2363 .Segment = SegmentCommand.empty(.{2069 .Segment = SegmentCommand.empty("__DATA_CONST", .{
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,
2371 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,2070 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2372 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,2071 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2373 .nsects = 0,
2374 .flags = 0,
2375 }),2072 }),
2376 });2073 });
2377 }2074 }
...@@ -2379,37 +2076,18 @@ fn populateMetadata(self: *Zld) !void {...@@ -2379,37 +2076,18 @@ fn populateMetadata(self: *Zld) !void {
2379 if (self.got_section_index == null) {2076 if (self.got_section_index == null) {
2380 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2077 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2381 self.got_section_index = @intCast(u16, data_const_seg.sections.items.len);2078 self.got_section_index = @intCast(u16, data_const_seg.sections.items.len);
2382 try data_const_seg.addSection(self.allocator, .{2079 try data_const_seg.addSection(self.allocator, "__got", .{
2383 .sectname = makeStaticString("__got"),
2384 .segname = makeStaticString("__DATA_CONST"),
2385 .addr = 0,
2386 .size = 0,
2387 .offset = 0,
2388 .@"align" = 3, // 2^3 = @sizeOf(u64)2080 .@"align" = 3, // 2^3 = @sizeOf(u64)
2389 .reloff = 0,
2390 .nreloc = 0,
2391 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,2081 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
2392 .reserved1 = 0,
2393 .reserved2 = 0,
2394 .reserved3 = 0,
2395 });2082 });
2396 }2083 }
23972084
2398 if (self.data_segment_cmd_index == null) {2085 if (self.data_segment_cmd_index == null) {
2399 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);2086 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
2400 try self.load_commands.append(self.allocator, .{2087 try self.load_commands.append(self.allocator, .{
2401 .Segment = SegmentCommand.empty(.{2088 .Segment = SegmentCommand.empty("__DATA", .{
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,
2409 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,2089 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2410 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,2090 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
2411 .nsects = 0,
2412 .flags = 0,
2413 }),2091 }),
2414 });2092 });
2415 }2093 }
...@@ -2417,56 +2095,26 @@ fn populateMetadata(self: *Zld) !void {...@@ -2417,56 +2095,26 @@ fn populateMetadata(self: *Zld) !void {
2417 if (self.la_symbol_ptr_section_index == null) {2095 if (self.la_symbol_ptr_section_index == null) {
2418 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;2096 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2419 self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len);2097 self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len);
2420 try data_seg.addSection(self.allocator, .{2098 try data_seg.addSection(self.allocator, "__la_symbol_ptr", .{
2421 .sectname = makeStaticString("__la_symbol_ptr"),
2422 .segname = makeStaticString("__DATA"),
2423 .addr = 0,
2424 .size = 0,
2425 .offset = 0,
2426 .@"align" = 3, // 2^3 = @sizeOf(u64)2099 .@"align" = 3, // 2^3 = @sizeOf(u64)
2427 .reloff = 0,
2428 .nreloc = 0,
2429 .flags = macho.S_LAZY_SYMBOL_POINTERS,2100 .flags = macho.S_LAZY_SYMBOL_POINTERS,
2430 .reserved1 = 0,
2431 .reserved2 = 0,
2432 .reserved3 = 0,
2433 });2101 });
2434 }2102 }
24352103
2436 if (self.data_section_index == null) {2104 if (self.data_section_index == null) {
2437 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;2105 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2438 self.data_section_index = @intCast(u16, data_seg.sections.items.len);2106 self.data_section_index = @intCast(u16, data_seg.sections.items.len);
2439 try data_seg.addSection(self.allocator, .{2107 try data_seg.addSection(self.allocator, "__data", .{
2440 .sectname = makeStaticString("__data"),
2441 .segname = makeStaticString("__DATA"),
2442 .addr = 0,
2443 .size = 0,
2444 .offset = 0,
2445 .@"align" = 3, // 2^3 = @sizeOf(u64)2108 .@"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,
2452 });2109 });
2453 }2110 }
24542111
2455 if (self.linkedit_segment_cmd_index == null) {2112 if (self.linkedit_segment_cmd_index == null) {
2456 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);2113 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
2457 try self.load_commands.append(self.allocator, .{2114 try self.load_commands.append(self.allocator, .{
2458 .Segment = SegmentCommand.empty(.{2115 .Segment = SegmentCommand.empty("__LINKEDIT", .{
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,
2466 .maxprot = macho.VM_PROT_READ,2116 .maxprot = macho.VM_PROT_READ,
2467 .initprot = macho.VM_PROT_READ,2117 .initprot = macho.VM_PROT_READ,
2468 .nsects = 0,
2469 .flags = 0,
2470 }),2118 }),
2471 });2119 });
2472 }2120 }
...@@ -2585,24 +2233,28 @@ fn populateMetadata(self: *Zld) !void {...@@ -2585,24 +2233,28 @@ fn populateMetadata(self: *Zld) !void {
2585 std.crypto.random.bytes(&uuid_cmd.uuid);2233 std.crypto.random.bytes(&uuid_cmd.uuid);
2586 try self.load_commands.append(self.allocator, .{ .Uuid = uuid_cmd });2234 try self.load_commands.append(self.allocator, .{ .Uuid = uuid_cmd });
2587 }2235 }
2236}
25882237
2589 if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) {2238fn addDataInCodeLC(self: *Zld) !void {
2590 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);2239 if (self.data_in_code_cmd_index == null) {
2240 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
2591 try self.load_commands.append(self.allocator, .{2241 try self.load_commands.append(self.allocator, .{
2592 .LinkeditData = .{2242 .LinkeditData = .{
2593 .cmd = macho.LC_CODE_SIGNATURE,2243 .cmd = macho.LC_DATA_IN_CODE,
2594 .cmdsize = @sizeOf(macho.linkedit_data_command),2244 .cmdsize = @sizeOf(macho.linkedit_data_command),
2595 .dataoff = 0,2245 .dataoff = 0,
2596 .datasize = 0,2246 .datasize = 0,
2597 },2247 },
2598 });2248 });
2599 }2249 }
2250}
26002251
2601 if (self.data_in_code_cmd_index == null and self.arch.? == .x86_64) {2252fn addCodeSignatureLC(self: *Zld) !void {
2602 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);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);
2603 try self.load_commands.append(self.allocator, .{2255 try self.load_commands.append(self.allocator, .{
2604 .LinkeditData = .{2256 .LinkeditData = .{
2605 .cmd = macho.LC_DATA_IN_CODE,2257 .cmd = macho.LC_CODE_SIGNATURE,
2606 .cmdsize = @sizeOf(macho.linkedit_data_command),2258 .cmdsize = @sizeOf(macho.linkedit_data_command),
2607 .dataoff = 0,2259 .dataoff = 0,
2608 .datasize = 0,2260 .datasize = 0,
...@@ -2698,9 +2350,7 @@ fn flush(self: *Zld) !void {...@@ -2698,9 +2350,7 @@ fn flush(self: *Zld) !void {
2698 try self.writeBindInfoTable();2350 try self.writeBindInfoTable();
2699 try self.writeLazyBindInfoTable();2351 try self.writeLazyBindInfoTable();
2700 try self.writeExportInfo();2352 try self.writeExportInfo();
2701 if (self.arch.? == .x86_64) {2353 try self.writeDataInCode();
2702 try self.writeDataInCode();
2703 }
27042354
2705 {2355 {
2706 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2356 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
...@@ -2862,6 +2512,20 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2862,6 +2512,20 @@ fn writeBindInfoTable(self: *Zld) !void {
2862 }2512 }
2863 }2513 }
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
2865 if (self.tlv_section_index) |idx| {2529 if (self.tlv_section_index) |idx| {
2866 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;2530 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2867 const sect = seg.sections.items[idx];2531 const sect = seg.sections.items[idx];
...@@ -3469,13 +3133,6 @@ fn writeHeader(self: *Zld) !void {...@@ -3469,13 +3133,6 @@ fn writeHeader(self: *Zld) !void {
3469 try self.file.?.pwriteAll(mem.asBytes(&header), 0);3133 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
3470}3134}
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
3479fn makeString(self: *Zld, bytes: []const u8) !u32 {3136fn makeString(self: *Zld, bytes: []const u8) !u32 {
3480 if (self.strtab_dir.get(bytes)) |offset| {3137 if (self.strtab_dir.get(bytes)) |offset| {
3481 log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });3138 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;...@@ -9,7 +9,6 @@ const assert = std.debug.assert;
99
10const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
11const MachO = @import("../MachO.zig");11const MachO = @import("../MachO.zig");
12const makeStaticString = MachO.makeStaticString;
13const padToIdeal = MachO.padToIdeal;12const padToIdeal = MachO.padToIdeal;
1413
15pub const LoadCommand = union(enum) {14pub const LoadCommand = union(enum) {
...@@ -187,11 +186,70 @@ pub const SegmentCommand = struct {...@@ -187,11 +186,70 @@ pub const SegmentCommand = struct {
187 inner: macho.segment_command_64,186 inner: macho.segment_command_64,
188 sections: std.ArrayListUnmanaged(macho.section_64) = .{},187 sections: std.ArrayListUnmanaged(macho.section_64) = .{},
189188
190 pub fn empty(inner: macho.segment_command_64) SegmentCommand {189 const SegmentOptions = struct {
191 return .{ .inner = inner };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 };
192 }217 }
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);
195 try self.sections.append(alloc, section);253 try self.sections.append(alloc, section);
196 self.inner.cmdsize += @sizeOf(macho.section_64);254 self.inner.cmdsize += @sizeOf(macho.section_64);
197 self.inner.nsects += 1;255 self.inner.nsects += 1;
...@@ -338,6 +396,13 @@ pub fn createLoadDylibCommand(...@@ -338,6 +396,13 @@ pub fn createLoadDylibCommand(
338 return dylib_cmd;396 return dylib_cmd;
339}397}
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
341fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {406fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void {
342 var stream = io.fixedBufferStream(buffer);407 var stream = io.fixedBufferStream(buffer);
343 var given = try LoadCommand.read(allocator, stream.reader());408 var given = try LoadCommand.read(allocator, stream.reader());
src/link/tapi.zig+9-2
...@@ -26,6 +26,11 @@ pub const LibStub = struct {...@@ -26,6 +26,11 @@ pub const LibStub = struct {
26 float: f64,26 float: f64,
27 int: u64,27 int: u64,
28 },28 },
29 compatibility_version: ?union(enum) {
30 string: []const u8,
31 float: f64,
32 int: u64,
33 },
29 reexported_libraries: ?[]const struct {34 reexported_libraries: ?[]const struct {
30 targets: []const []const u8,35 targets: []const []const u8,
31 libraries: []const []const u8,36 libraries: []const []const u8,
...@@ -36,11 +41,13 @@ pub const LibStub = struct {...@@ -36,11 +41,13 @@ pub const LibStub = struct {
36 },41 },
37 exports: ?[]const struct {42 exports: ?[]const struct {
38 targets: []const []const u8,43 targets: []const []const u8,
39 symbols: []const []const u8,44 symbols: ?[]const []const u8,
45 objc_classes: ?[]const []const u8,
40 },46 },
41 reexports: ?[]const struct {47 reexports: ?[]const struct {
42 targets: []const []const u8,48 targets: []const []const u8,
43 symbols: []const []const u8,49 symbols: ?[]const []const u8,
50 objc_classes: ?[]const []const u8,
44 },51 },
45 allowable_clients: ?[]const struct {52 allowable_clients: ?[]const struct {
46 targets: []const []const u8,53 targets: []const []const u8,
src/link/tapi/parse.zig+1-6
...@@ -42,7 +42,7 @@ pub const Node = struct {...@@ -42,7 +42,7 @@ pub const Node = struct {
42 .doc => @fieldParentPtr(Node.Doc, "base", self).deinit(allocator),42 .doc => @fieldParentPtr(Node.Doc, "base", self).deinit(allocator),
43 .map => @fieldParentPtr(Node.Map, "base", self).deinit(allocator),43 .map => @fieldParentPtr(Node.Map, "base", self).deinit(allocator),
44 .list => @fieldParentPtr(Node.List, "base", self).deinit(allocator),44 .list => @fieldParentPtr(Node.List, "base", self).deinit(allocator),
45 .value => @fieldParentPtr(Node.Value, "base", self).deinit(allocator),45 .value => {},
46 }46 }
47 }47 }
4848
...@@ -180,11 +180,6 @@ pub const Node = struct {...@@ -180,11 +180,6 @@ pub const Node = struct {
180180
181 pub const base_tag: Node.Tag = .value;181 pub const base_tag: Node.Tag = .value;
182182
183 pub fn deinit(self: *Value, allocator: *Allocator) void {
184 _ = self;
185 _ = allocator;
186 }
187
188 pub fn format(183 pub fn format(
189 self: *const Value,184 self: *const Value,
190 comptime fmt: []const u8,185 comptime fmt: []const u8,
src/main.zig+3-2
...@@ -290,6 +290,7 @@ const usage_build_generic =...@@ -290,6 +290,7 @@ const usage_build_generic =
290 \\ .c C source code (requires LLVM extensions)290 \\ .c C source code (requires LLVM extensions)
291 \\ .cpp C++ source code (requires LLVM extensions)291 \\ .cpp C++ source code (requires LLVM extensions)
292 \\ Other C++ extensions: .C .cc .cxx292 \\ Other C++ extensions: .C .cc .cxx
293 \\ .m Objective-C source code (requires LLVM extensions)
293 \\294 \\
294 \\General Options:295 \\General Options:
295 \\ -h, --help Print this help and exit296 \\ -h, --help Print this help and exit
...@@ -1072,7 +1073,7 @@ fn buildOutputType(...@@ -1072,7 +1073,7 @@ fn buildOutputType(
1072 .object, .static_library, .shared_library => {1073 .object, .static_library, .shared_library => {
1073 try link_objects.append(arg);1074 try link_objects.append(arg);
1074 },1075 },
1075 .assembly, .c, .cpp, .h, .ll, .bc => {1076 .assembly, .c, .cpp, .h, .ll, .bc, .m => {
1076 try c_source_files.append(.{1077 try c_source_files.append(.{
1077 .src_path = arg,1078 .src_path = arg,
1078 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),1079 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
...@@ -1135,7 +1136,7 @@ fn buildOutputType(...@@ -1135,7 +1136,7 @@ fn buildOutputType(
1135 .positional => {1136 .positional => {
1136 const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg));1137 const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg));
1137 switch (file_ext) {1138 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 }),
1139 .unknown, .shared_library, .object, .static_library => {1140 .unknown, .shared_library, .object, .static_library => {
1140 try link_objects.append(it.only_arg);1141 try link_objects.append(it.only_arg);
1141 },1142 },