| author | |
| committer | |
| log | 350ead9cb2ce87485569fbf630f2906864f35a6b |
| tree | 8c0f8fe31061a60db637ffc9120f800a0379beb1 |
| parent | 8216ce67895f5605d1720df4e5e6636395f2fc92 |
| parent | ddd2cd73307c06906a8d120b41fd5ab8864797a1 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
zig ld: link Obj-C, link frameworks, improve linker's implementation14 files changed, 1105 insertions(+), 1256 deletions(-)
CMakeLists.txt-1| ... | ... | @@ -579,7 +579,6 @@ set(ZIG_STAGE2_SOURCES |
| 579 | 579 | "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig" |
| 580 | 580 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig" |
| 581 | 581 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" |
| 582 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Stub.zig" | |
| 583 | 582 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig" |
| 584 | 583 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" |
| 585 | 584 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig" |
src/Compilation.zig+10-2| ... | ... | @@ -2857,7 +2857,7 @@ pub fn addCCArgs( |
| 2857 | 2857 | try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); |
| 2858 | 2858 | |
| 2859 | 2859 | switch (ext) { |
| 2860 | .c, .cpp, .h => { | |
| 2860 | .c, .cpp, .m, .h => { | |
| 2861 | 2861 | try argv.appendSlice(&[_][]const u8{ |
| 2862 | 2862 | "-nostdinc", |
| 2863 | 2863 | "-fno-spell-checking", |
| ... | ... | @@ -3148,6 +3148,7 @@ pub const FileExt = enum { |
| 3148 | 3148 | c, |
| 3149 | 3149 | cpp, |
| 3150 | 3150 | h, |
| 3151 | m, | |
| 3151 | 3152 | ll, |
| 3152 | 3153 | bc, |
| 3153 | 3154 | assembly, |
| ... | ... | @@ -3159,7 +3160,7 @@ pub const FileExt = enum { |
| 3159 | 3160 | |
| 3160 | 3161 | pub fn clangSupportsDepFile(ext: FileExt) bool { |
| 3161 | 3162 | return switch (ext) { |
| 3162 | .c, .cpp, .h => true, | |
| 3163 | .c, .cpp, .h, .m => true, | |
| 3163 | 3164 | |
| 3164 | 3165 | .ll, |
| 3165 | 3166 | .bc, |
| ... | ... | @@ -3193,6 +3194,10 @@ pub fn hasCppExt(filename: []const u8) bool { |
| 3193 | 3194 | mem.endsWith(u8, filename, ".cxx"); |
| 3194 | 3195 | } |
| 3195 | 3196 | |
| 3197 | pub fn hasObjCExt(filename: []const u8) bool { | |
| 3198 | return mem.endsWith(u8, filename, ".m"); | |
| 3199 | } | |
| 3200 | ||
| 3196 | 3201 | pub fn hasAsmExt(filename: []const u8) bool { |
| 3197 | 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 | 3234 | return .c; |
| 3230 | 3235 | } else if (hasCppExt(filename)) { |
| 3231 | 3236 | return .cpp; |
| 3237 | } else if (hasObjCExt(filename)) { | |
| 3238 | return .m; | |
| 3232 | 3239 | } else if (mem.endsWith(u8, filename, ".ll")) { |
| 3233 | 3240 | return .ll; |
| 3234 | 3241 | } else if (mem.endsWith(u8, filename, ".bc")) { |
| ... | ... | @@ -3252,6 +3259,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt { |
| 3252 | 3259 | |
| 3253 | 3260 | test "classifyFileExt" { |
| 3254 | 3261 | try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc")); |
| 3262 | try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m")); | |
| 3255 | 3263 | try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim")); |
| 3256 | 3264 | try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so")); |
| 3257 | 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 | 514 | } |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | fn 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 | ||
| 517 | 630 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 518 | 631 | const tracy = trace(@src()); |
| 519 | 632 | defer tracy.end(); |
| ... | ... | @@ -676,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 676 | 789 | zld.deinit(); |
| 677 | 790 | } |
| 678 | 791 | zld.arch = target.cpu.arch; |
| 792 | zld.syslibroot = self.base.options.syslibroot; | |
| 679 | 793 | zld.stack_size = stack_size; |
| 680 | 794 | |
| 681 | 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 | 814 | } |
| 701 | 815 | |
| 702 | 816 | // Shared and static libraries passed via `-l` flag. |
| 703 | var libs = std.ArrayList([]const u8).init(arena); | |
| 704 | 817 | var search_lib_names = std.ArrayList([]const u8).init(arena); |
| 705 | 818 | |
| 706 | 819 | const system_libs = self.base.options.system_libs.keys(); |
| ... | ... | @@ -716,84 +829,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 716 | 829 | try search_lib_names.append(link_lib); |
| 717 | 830 | } |
| 718 | 831 | |
| 719 | var search_lib_dirs = std.ArrayList([]const u8).init(arena); | |
| 720 | ||
| 721 | for (self.base.options.lib_dirs) |path| { | |
| 722 | if (fs.path.isAbsolute(path)) { | |
| 723 | var candidates = std.ArrayList([]const u8).init(arena); | |
| 724 | if (self.base.options.syslibroot) |syslibroot| { | |
| 725 | const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path }); | |
| 726 | try candidates.append(full_path); | |
| 727 | } | |
| 728 | try candidates.append(path); | |
| 729 | ||
| 730 | var found = false; | |
| 731 | for (candidates.items) |candidate| { | |
| 732 | // Verify that search path actually exists | |
| 733 | var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { | |
| 734 | error.FileNotFound => continue, | |
| 735 | else => |e| return e, | |
| 736 | }; | |
| 737 | defer tmp.close(); | |
| 738 | ||
| 739 | try search_lib_dirs.append(candidate); | |
| 740 | found = true; | |
| 741 | break; | |
| 742 | } | |
| 743 | ||
| 744 | if (!found) { | |
| 745 | log.warn("directory not found for '-L{s}'", .{path}); | |
| 746 | } | |
| 747 | } else { | |
| 748 | // Verify that search path actually exists | |
| 749 | var tmp = fs.cwd().openDir(path, .{}) catch |err| switch (err) { | |
| 750 | error.FileNotFound => { | |
| 751 | log.warn("directory not found for '-L{s}'", .{path}); | |
| 752 | continue; | |
| 753 | }, | |
| 754 | else => |e| return e, | |
| 755 | }; | |
| 756 | defer tmp.close(); | |
| 757 | ||
| 758 | try search_lib_dirs.append(path); | |
| 759 | } | |
| 760 | } | |
| 761 | ||
| 762 | // Assume ld64 default: -search_paths_first | |
| 763 | // Look in each directory for a dylib (next, tbd), and then for archive | |
| 764 | // TODO implement alternative: -search_dylibs_first | |
| 765 | const exts = &[_][]const u8{ "dylib", "tbd", "a" }; | |
| 766 | ||
| 767 | for (search_lib_names.items) |l_name| { | |
| 768 | var found = false; | |
| 769 | ||
| 770 | ext: for (exts) |ext| { | |
| 771 | const l_name_ext = try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ l_name, ext }); | |
| 772 | ||
| 773 | for (search_lib_dirs.items) |lib_dir| { | |
| 774 | const full_path = try fs.path.join(arena, &[_][]const u8{ lib_dir, l_name_ext }); | |
| 775 | ||
| 776 | // Check if the lib file exists. | |
| 777 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | |
| 778 | error.FileNotFound => continue, | |
| 779 | else => |e| return e, | |
| 780 | }; | |
| 781 | defer tmp.close(); | |
| 782 | ||
| 783 | try libs.append(full_path); | |
| 784 | found = true; | |
| 785 | break :ext; | |
| 786 | } | |
| 787 | } | |
| 788 | ||
| 789 | if (!found) { | |
| 790 | log.warn("library not found for '-l{s}'", .{l_name}); | |
| 791 | log.warn("Library search paths:", .{}); | |
| 792 | for (search_lib_dirs.items) |lib_dir| { | |
| 793 | log.warn(" {s}", .{lib_dir}); | |
| 794 | } | |
| 795 | } | |
| 796 | } | |
| 832 | var libs = std.ArrayList([]const u8).init(arena); | |
| 833 | try resolvePaths( | |
| 834 | arena, | |
| 835 | &libs, | |
| 836 | self.base.options.syslibroot, | |
| 837 | self.base.options.lib_dirs, | |
| 838 | search_lib_names.items, | |
| 839 | .lib, | |
| 840 | ); | |
| 797 | 841 | |
| 798 | 842 | // rpaths |
| 799 | 843 | var rpath_table = std.StringArrayHashMap(void).init(arena); |
| ... | ... | @@ -809,9 +853,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 809 | 853 | } |
| 810 | 854 | |
| 811 | 855 | // frameworks |
| 812 | for (self.base.options.frameworks) |framework| { | |
| 813 | log.warn("frameworks not yet supported for '-framework {s}'", .{framework}); | |
| 814 | } | |
| 856 | try resolvePaths( | |
| 857 | arena, | |
| 858 | &libs, | |
| 859 | self.base.options.syslibroot, | |
| 860 | self.base.options.framework_dirs, | |
| 861 | self.base.options.frameworks, | |
| 862 | .framework, | |
| 863 | ); | |
| 815 | 864 | |
| 816 | 865 | if (self.base.options.verbose_link) { |
| 817 | 866 | var argv = std.ArrayList([]const u8).init(arena); |
| ... | ... | @@ -1731,18 +1780,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1731 | 1780 | if (self.pagezero_segment_cmd_index == null) { |
| 1732 | 1781 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 1733 | 1782 | try self.load_commands.append(self.base.allocator, .{ |
| 1734 | .Segment = SegmentCommand.empty(.{ | |
| 1735 | .cmd = macho.LC_SEGMENT_64, | |
| 1736 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1737 | .segname = makeStaticString("__PAGEZERO"), | |
| 1738 | .vmaddr = 0, | |
| 1783 | .Segment = SegmentCommand.empty("__PAGEZERO", .{ | |
| 1739 | 1784 | .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 | 1787 | self.header_dirty = true; |
| ... | ... | @@ -1761,18 +1800,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1761 | 1800 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); |
| 1762 | 1801 | |
| 1763 | 1802 | try self.load_commands.append(self.base.allocator, .{ |
| 1764 | .Segment = SegmentCommand.empty(.{ | |
| 1765 | .cmd = macho.LC_SEGMENT_64, | |
| 1766 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1767 | .segname = makeStaticString("__TEXT"), | |
| 1803 | .Segment = SegmentCommand.empty("__TEXT", .{ | |
| 1768 | 1804 | .vmaddr = 0x100000000, // always starts at 4GB |
| 1769 | 1805 | .vmsize = needed_size, |
| 1770 | .fileoff = 0, | |
| 1771 | 1806 | .filesize = needed_size, |
| 1772 | 1807 | .maxprot = maxprot, |
| 1773 | 1808 | .initprot = initprot, |
| 1774 | .nsects = 0, | |
| 1775 | .flags = 0, | |
| 1776 | 1809 | }), |
| 1777 | 1810 | }); |
| 1778 | 1811 | self.header_dirty = true; |
| ... | ... | @@ -1793,19 +1826,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1793 | 1826 | |
| 1794 | 1827 | log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1795 | 1828 | |
| 1796 | try text_segment.addSection(self.base.allocator, .{ | |
| 1797 | .sectname = makeStaticString("__text"), | |
| 1798 | .segname = makeStaticString("__TEXT"), | |
| 1829 | try text_segment.addSection(self.base.allocator, "__text", .{ | |
| 1799 | 1830 | .addr = text_segment.inner.vmaddr + off, |
| 1800 | 1831 | .size = @intCast(u32, needed_size), |
| 1801 | 1832 | .offset = @intCast(u32, off), |
| 1802 | 1833 | .@"align" = alignment, |
| 1803 | .reloff = 0, | |
| 1804 | .nreloc = 0, | |
| 1805 | 1834 | .flags = flags, |
| 1806 | .reserved1 = 0, | |
| 1807 | .reserved2 = 0, | |
| 1808 | .reserved3 = 0, | |
| 1809 | 1835 | }); |
| 1810 | 1836 | self.header_dirty = true; |
| 1811 | 1837 | self.load_commands_dirty = true; |
| ... | ... | @@ -1831,19 +1857,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1831 | 1857 | |
| 1832 | 1858 | log.debug("found __stubs section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1833 | 1859 | |
| 1834 | try text_segment.addSection(self.base.allocator, .{ | |
| 1835 | .sectname = makeStaticString("__stubs"), | |
| 1836 | .segname = makeStaticString("__TEXT"), | |
| 1860 | try text_segment.addSection(self.base.allocator, "__stubs", .{ | |
| 1837 | 1861 | .addr = text_segment.inner.vmaddr + off, |
| 1838 | 1862 | .size = needed_size, |
| 1839 | 1863 | .offset = @intCast(u32, off), |
| 1840 | 1864 | .@"align" = alignment, |
| 1841 | .reloff = 0, | |
| 1842 | .nreloc = 0, | |
| 1843 | 1865 | .flags = flags, |
| 1844 | .reserved1 = 0, | |
| 1845 | 1866 | .reserved2 = stub_size, |
| 1846 | .reserved3 = 0, | |
| 1847 | 1867 | }); |
| 1848 | 1868 | self.header_dirty = true; |
| 1849 | 1869 | self.load_commands_dirty = true; |
| ... | ... | @@ -1864,19 +1884,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1864 | 1884 | |
| 1865 | 1885 | log.debug("found __stub_helper section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1866 | 1886 | |
| 1867 | try text_segment.addSection(self.base.allocator, .{ | |
| 1868 | .sectname = makeStaticString("__stub_helper"), | |
| 1869 | .segname = makeStaticString("__TEXT"), | |
| 1887 | try text_segment.addSection(self.base.allocator, "__stub_helper", .{ | |
| 1870 | 1888 | .addr = text_segment.inner.vmaddr + off, |
| 1871 | 1889 | .size = needed_size, |
| 1872 | 1890 | .offset = @intCast(u32, off), |
| 1873 | 1891 | .@"align" = alignment, |
| 1874 | .reloff = 0, | |
| 1875 | .nreloc = 0, | |
| 1876 | 1892 | .flags = flags, |
| 1877 | .reserved1 = 0, | |
| 1878 | .reserved2 = 0, | |
| 1879 | .reserved3 = 0, | |
| 1880 | 1893 | }); |
| 1881 | 1894 | self.header_dirty = true; |
| 1882 | 1895 | self.load_commands_dirty = true; |
| ... | ... | @@ -1893,18 +1906,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1893 | 1906 | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); |
| 1894 | 1907 | |
| 1895 | 1908 | try self.load_commands.append(self.base.allocator, .{ |
| 1896 | .Segment = SegmentCommand.empty(.{ | |
| 1897 | .cmd = macho.LC_SEGMENT_64, | |
| 1898 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1899 | .segname = makeStaticString("__DATA_CONST"), | |
| 1909 | .Segment = SegmentCommand.empty("__DATA_CONST", .{ | |
| 1900 | 1910 | .vmaddr = address_and_offset.address, |
| 1901 | 1911 | .vmsize = needed_size, |
| 1902 | 1912 | .fileoff = address_and_offset.offset, |
| 1903 | 1913 | .filesize = needed_size, |
| 1904 | 1914 | .maxprot = maxprot, |
| 1905 | 1915 | .initprot = initprot, |
| 1906 | .nsects = 0, | |
| 1907 | .flags = 0, | |
| 1908 | 1916 | }), |
| 1909 | 1917 | }); |
| 1910 | 1918 | self.header_dirty = true; |
| ... | ... | @@ -1921,19 +1929,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1921 | 1929 | |
| 1922 | 1930 | log.debug("found __got section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1923 | 1931 | |
| 1924 | try dc_segment.addSection(self.base.allocator, .{ | |
| 1925 | .sectname = makeStaticString("__got"), | |
| 1926 | .segname = makeStaticString("__DATA_CONST"), | |
| 1932 | try dc_segment.addSection(self.base.allocator, "__got", .{ | |
| 1927 | 1933 | .addr = dc_segment.inner.vmaddr + off - dc_segment.inner.fileoff, |
| 1928 | 1934 | .size = needed_size, |
| 1929 | 1935 | .offset = @intCast(u32, off), |
| 1930 | 1936 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 1931 | .reloff = 0, | |
| 1932 | .nreloc = 0, | |
| 1933 | 1937 | .flags = flags, |
| 1934 | .reserved1 = 0, | |
| 1935 | .reserved2 = 0, | |
| 1936 | .reserved3 = 0, | |
| 1937 | 1938 | }); |
| 1938 | 1939 | self.header_dirty = true; |
| 1939 | 1940 | self.load_commands_dirty = true; |
| ... | ... | @@ -1950,18 +1951,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1950 | 1951 | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); |
| 1951 | 1952 | |
| 1952 | 1953 | try self.load_commands.append(self.base.allocator, .{ |
| 1953 | .Segment = SegmentCommand.empty(.{ | |
| 1954 | .cmd = macho.LC_SEGMENT_64, | |
| 1955 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 1956 | .segname = makeStaticString("__DATA"), | |
| 1954 | .Segment = SegmentCommand.empty("__DATA", .{ | |
| 1957 | 1955 | .vmaddr = address_and_offset.address, |
| 1958 | 1956 | .vmsize = needed_size, |
| 1959 | 1957 | .fileoff = address_and_offset.offset, |
| 1960 | 1958 | .filesize = needed_size, |
| 1961 | 1959 | .maxprot = maxprot, |
| 1962 | 1960 | .initprot = initprot, |
| 1963 | .nsects = 0, | |
| 1964 | .flags = 0, | |
| 1965 | 1961 | }), |
| 1966 | 1962 | }); |
| 1967 | 1963 | self.header_dirty = true; |
| ... | ... | @@ -1978,19 +1974,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1978 | 1974 | |
| 1979 | 1975 | log.debug("found __la_symbol_ptr section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 1980 | 1976 | |
| 1981 | try data_segment.addSection(self.base.allocator, .{ | |
| 1982 | .sectname = makeStaticString("__la_symbol_ptr"), | |
| 1983 | .segname = makeStaticString("__DATA"), | |
| 1977 | try data_segment.addSection(self.base.allocator, "__la_symbol_ptr", .{ | |
| 1984 | 1978 | .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff, |
| 1985 | 1979 | .size = needed_size, |
| 1986 | 1980 | .offset = @intCast(u32, off), |
| 1987 | 1981 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 1988 | .reloff = 0, | |
| 1989 | .nreloc = 0, | |
| 1990 | 1982 | .flags = flags, |
| 1991 | .reserved1 = 0, | |
| 1992 | .reserved2 = 0, | |
| 1993 | .reserved3 = 0, | |
| 1994 | 1983 | }); |
| 1995 | 1984 | self.header_dirty = true; |
| 1996 | 1985 | self.load_commands_dirty = true; |
| ... | ... | @@ -1999,26 +1988,17 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1999 | 1988 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2000 | 1989 | self.data_section_index = @intCast(u16, data_segment.sections.items.len); |
| 2001 | 1990 | |
| 2002 | const flags = macho.S_REGULAR; | |
| 2003 | 1991 | const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 2004 | 1992 | const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null); |
| 2005 | 1993 | assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment. |
| 2006 | 1994 | |
| 2007 | 1995 | log.debug("found __data section free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 2008 | 1996 | |
| 2009 | try data_segment.addSection(self.base.allocator, .{ | |
| 2010 | .sectname = makeStaticString("__data"), | |
| 2011 | .segname = makeStaticString("__DATA"), | |
| 1997 | try data_segment.addSection(self.base.allocator, "__data", .{ | |
| 2012 | 1998 | .addr = data_segment.inner.vmaddr + off - data_segment.inner.fileoff, |
| 2013 | 1999 | .size = needed_size, |
| 2014 | 2000 | .offset = @intCast(u32, off), |
| 2015 | 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 | 2003 | self.header_dirty = true; |
| 2024 | 2004 | self.load_commands_dirty = true; |
| ... | ... | @@ -2033,18 +2013,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2033 | 2013 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset}); |
| 2034 | 2014 | |
| 2035 | 2015 | try self.load_commands.append(self.base.allocator, .{ |
| 2036 | .Segment = SegmentCommand.empty(.{ | |
| 2037 | .cmd = macho.LC_SEGMENT_64, | |
| 2038 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2039 | .segname = makeStaticString("__LINKEDIT"), | |
| 2016 | .Segment = SegmentCommand.empty("__LINKEDIT", .{ | |
| 2040 | 2017 | .vmaddr = address_and_offset.address, |
| 2041 | .vmsize = 0, | |
| 2042 | 2018 | .fileoff = address_and_offset.offset, |
| 2043 | .filesize = 0, | |
| 2044 | 2019 | .maxprot = maxprot, |
| 2045 | 2020 | .initprot = initprot, |
| 2046 | .nsects = 0, | |
| 2047 | .flags = 0, | |
| 2048 | 2021 | }), |
| 2049 | 2022 | }); |
| 2050 | 2023 | self.header_dirty = true; |
| ... | ... | @@ -2402,13 +2375,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 2402 | 2375 | return vaddr; |
| 2403 | 2376 | } |
| 2404 | 2377 | |
| 2405 | pub 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 | ||
| 2412 | 2378 | fn makeString(self: *MachO, bytes: []const u8) !u32 { |
| 2413 | 2379 | if (self.string_table_directory.get(bytes)) |offset| { |
| 2414 | 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 | 8 | const mem = std.mem; |
| 9 | 9 | |
| 10 | 10 | const Allocator = mem.Allocator; |
| 11 | const Arch = std.Target.Cpu.Arch; | |
| 11 | 12 | const Object = @import("Object.zig"); |
| 12 | 13 | |
| 13 | 14 | usingnamespace @import("commands.zig"); |
| 14 | 15 | |
| 15 | 16 | allocator: *Allocator, |
| 16 | arch: ?std.Target.Cpu.Arch = null, | |
| 17 | arch: ?Arch = null, | |
| 17 | 18 | file: ?fs.File = null, |
| 18 | 19 | header: ?ar_hdr = null, |
| 19 | 20 | name: ?[]const u8 = null, |
| ... | ... | @@ -85,10 +86,36 @@ const ar_hdr = extern struct { |
| 85 | 86 | } |
| 86 | 87 | }; |
| 87 | 88 | |
| 88 | pub fn init(allocator: *Allocator) Archive { | |
| 89 | return .{ | |
| 89 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive { | |
| 90 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | |
| 91 | error.FileNotFound => return null, | |
| 92 | else => |e| return e, | |
| 93 | }; | |
| 94 | errdefer file.close(); | |
| 95 | ||
| 96 | const archive = try allocator.create(Archive); | |
| 97 | errdefer allocator.destroy(archive); | |
| 98 | ||
| 99 | const name = try allocator.dupe(u8, path); | |
| 100 | errdefer allocator.free(name); | |
| 101 | ||
| 102 | archive.* = .{ | |
| 90 | 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 | } |
| 93 | 120 | |
| 94 | 121 | pub fn deinit(self: *Archive) void { |
| ... | ... | @@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void { |
| 116 | 143 | const magic = try reader.readBytesNoEof(SARMAG); |
| 117 | 144 | |
| 118 | 145 | if (!mem.eql(u8, &magic, ARMAG)) { |
| 119 | log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic }); | |
| 120 | return error.MalformedArchive; | |
| 146 | log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic }); | |
| 147 | return error.NotArchive; | |
| 121 | 148 | } |
| 122 | 149 | |
| 123 | 150 | self.header = try reader.readStruct(ar_hdr); |
| 124 | 151 | |
| 125 | 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 }); | |
| 127 | return error.MalformedArchive; | |
| 153 | log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag }); | |
| 154 | return error.NotArchive; | |
| 128 | 155 | } |
| 129 | 156 | |
| 130 | 157 | var embedded_name = try parseName(self.allocator, self.header.?, reader); |
| ... | ... | @@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 222 | 249 | var object = try self.allocator.create(Object); |
| 223 | 250 | errdefer self.allocator.destroy(object); |
| 224 | 251 | |
| 225 | object.* = Object.init(self.allocator); | |
| 226 | object.arch = self.arch.?; | |
| 227 | object.file = try fs.cwd().openFile(self.name.?, .{}); | |
| 228 | object.name = name; | |
| 229 | object.file_offset = @intCast(u32, try reader.context.getPos()); | |
| 252 | object.* = .{ | |
| 253 | .allocator = self.allocator, | |
| 254 | .arch = self.arch.?, | |
| 255 | .file = try fs.cwd().openFile(self.name.?, .{}), | |
| 256 | .name = name, | |
| 257 | .file_offset = @intCast(u32, try reader.context.getPos()), | |
| 258 | }; | |
| 230 | 259 | try object.parse(); |
| 231 | ||
| 232 | 260 | try reader.context.seekTo(0); |
| 233 | 261 | |
| 234 | 262 | return object; |
| 235 | 263 | } |
| 236 | ||
| 237 | pub 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 | 19 | const SrcFn = MachO.SrcFn; |
| 20 | 20 | const TextBlock = MachO.TextBlock; |
| 21 | 21 | const padToIdeal = MachO.padToIdeal; |
| 22 | const makeStaticString = MachO.makeStaticString; | |
| 23 | 22 | |
| 24 | 23 | usingnamespace @import("commands.zig"); |
| 25 | 24 | |
| ... | ... | @@ -212,18 +211,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 212 | 211 | log.debug("found dSym __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 213 | 212 | |
| 214 | 213 | try self.load_commands.append(allocator, .{ |
| 215 | .Segment = SegmentCommand.empty(.{ | |
| 216 | .cmd = macho.LC_SEGMENT_64, | |
| 217 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 218 | .segname = makeStaticString("__DWARF"), | |
| 214 | .Segment = SegmentCommand.empty("__DWARF", .{ | |
| 219 | 215 | .vmaddr = vmaddr, |
| 220 | 216 | .vmsize = needed_size, |
| 221 | 217 | .fileoff = off, |
| 222 | 218 | .filesize = needed_size, |
| 223 | .maxprot = 0, | |
| 224 | .initprot = 0, | |
| 225 | .nsects = 0, | |
| 226 | .flags = 0, | |
| 227 | 219 | }), |
| 228 | 220 | }); |
| 229 | 221 | self.header_dirty = true; |
| ... | ... | @@ -234,19 +226,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 234 | 226 | self.debug_str_section_index = @intCast(u16, dwarf_segment.sections.items.len); |
| 235 | 227 | assert(self.debug_string_table.items.len == 0); |
| 236 | 228 | |
| 237 | try dwarf_segment.addSection(allocator, .{ | |
| 238 | .sectname = makeStaticString("__debug_str"), | |
| 239 | .segname = makeStaticString("__DWARF"), | |
| 229 | try dwarf_segment.addSection(allocator, "__debug_str", .{ | |
| 240 | 230 | .addr = dwarf_segment.inner.vmaddr, |
| 241 | 231 | .size = @intCast(u32, self.debug_string_table.items.len), |
| 242 | 232 | .offset = @intCast(u32, dwarf_segment.inner.fileoff), |
| 243 | 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 | 235 | self.header_dirty = true; |
| 252 | 236 | self.load_commands_dirty = true; |
| ... | ... | @@ -262,19 +246,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 262 | 246 | |
| 263 | 247 | log.debug("found dSym __debug_info free space 0x{x} to 0x{x}", .{ off, off + file_size_hint }); |
| 264 | 248 | |
| 265 | try dwarf_segment.addSection(allocator, .{ | |
| 266 | .sectname = makeStaticString("__debug_info"), | |
| 267 | .segname = makeStaticString("__DWARF"), | |
| 249 | try dwarf_segment.addSection(allocator, "__debug_info", .{ | |
| 268 | 250 | .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff, |
| 269 | 251 | .size = file_size_hint, |
| 270 | 252 | .offset = @intCast(u32, off), |
| 271 | 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 | 255 | self.header_dirty = true; |
| 280 | 256 | self.load_commands_dirty = true; |
| ... | ... | @@ -290,19 +266,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 290 | 266 | |
| 291 | 267 | log.debug("found dSym __debug_abbrev free space 0x{x} to 0x{x}", .{ off, off + file_size_hint }); |
| 292 | 268 | |
| 293 | try dwarf_segment.addSection(allocator, .{ | |
| 294 | .sectname = makeStaticString("__debug_abbrev"), | |
| 295 | .segname = makeStaticString("__DWARF"), | |
| 269 | try dwarf_segment.addSection(allocator, "__debug_abbrev", .{ | |
| 296 | 270 | .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff, |
| 297 | 271 | .size = file_size_hint, |
| 298 | 272 | .offset = @intCast(u32, off), |
| 299 | 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 | 275 | self.header_dirty = true; |
| 308 | 276 | self.load_commands_dirty = true; |
| ... | ... | @@ -318,19 +286,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 318 | 286 | |
| 319 | 287 | log.debug("found dSym __debug_aranges free space 0x{x} to 0x{x}", .{ off, off + file_size_hint }); |
| 320 | 288 | |
| 321 | try dwarf_segment.addSection(allocator, .{ | |
| 322 | .sectname = makeStaticString("__debug_aranges"), | |
| 323 | .segname = makeStaticString("__DWARF"), | |
| 289 | try dwarf_segment.addSection(allocator, "__debug_aranges", .{ | |
| 324 | 290 | .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff, |
| 325 | 291 | .size = file_size_hint, |
| 326 | 292 | .offset = @intCast(u32, off), |
| 327 | 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 | 295 | self.header_dirty = true; |
| 336 | 296 | self.load_commands_dirty = true; |
| ... | ... | @@ -346,19 +306,11 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: *Allocator) !void |
| 346 | 306 | |
| 347 | 307 | log.debug("found dSym __debug_line free space 0x{x} to 0x{x}", .{ off, off + file_size_hint }); |
| 348 | 308 | |
| 349 | try dwarf_segment.addSection(allocator, .{ | |
| 350 | .sectname = makeStaticString("__debug_line"), | |
| 351 | .segname = makeStaticString("__DWARF"), | |
| 309 | try dwarf_segment.addSection(allocator, "__debug_line", .{ | |
| 352 | 310 | .addr = dwarf_segment.inner.vmaddr + off - dwarf_segment.inner.fileoff, |
| 353 | 311 | .size = file_size_hint, |
| 354 | 312 | .offset = @intCast(u32, off), |
| 355 | 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 | 315 | self.header_dirty = true; |
| 364 | 316 | self.load_commands_dirty = true; |
| ... | ... | @@ -692,14 +644,10 @@ pub fn deinit(self: *DebugSymbols, allocator: *Allocator) void { |
| 692 | 644 | } |
| 693 | 645 | |
| 694 | 646 | fn copySegmentCommand(self: *DebugSymbols, allocator: *Allocator, base_cmd: SegmentCommand) !SegmentCommand { |
| 695 | var cmd = SegmentCommand.empty(.{ | |
| 696 | .cmd = macho.LC_SEGMENT_64, | |
| 647 | var cmd = SegmentCommand.empty("", .{ | |
| 697 | 648 | .cmdsize = base_cmd.inner.cmdsize, |
| 698 | .segname = undefined, | |
| 699 | 649 | .vmaddr = base_cmd.inner.vmaddr, |
| 700 | 650 | .vmsize = base_cmd.inner.vmsize, |
| 701 | .fileoff = 0, | |
| 702 | .filesize = 0, | |
| 703 | 651 | .maxprot = base_cmd.inner.maxprot, |
| 704 | 652 | .initprot = base_cmd.inner.initprot, |
| 705 | 653 | .nsects = base_cmd.inner.nsects, |
src/link/MachO/Dylib.zig+305-21| ... | ... | @@ -3,20 +3,26 @@ const Dylib = @This(); |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const fs = std.fs; |
| 6 | const fmt = std.fmt; | |
| 6 | 7 | const log = std.log.scoped(.dylib); |
| 7 | 8 | const macho = std.macho; |
| 9 | const math = std.math; | |
| 8 | 10 | const mem = std.mem; |
| 9 | 11 | |
| 10 | 12 | const Allocator = mem.Allocator; |
| 13 | const Arch = std.Target.Cpu.Arch; | |
| 11 | 14 | const Symbol = @import("Symbol.zig"); |
| 15 | const LibStub = @import("../tapi.zig").LibStub; | |
| 12 | 16 | |
| 13 | 17 | usingnamespace @import("commands.zig"); |
| 14 | 18 | |
| 15 | 19 | allocator: *Allocator, |
| 16 | arch: ?std.Target.Cpu.Arch = null, | |
| 20 | ||
| 21 | arch: ?Arch = null, | |
| 17 | 22 | header: ?macho.mach_header_64 = null, |
| 18 | 23 | file: ?fs.File = null, |
| 19 | 24 | name: ?[]const u8 = null, |
| 25 | syslibroot: ?[]const u8 = null, | |
| 20 | 26 | |
| 21 | 27 | ordinal: ?u16 = null, |
| 22 | 28 | |
| ... | ... | @@ -33,19 +39,139 @@ id: ?Id = null, |
| 33 | 39 | /// a symbol is referenced by an object file. |
| 34 | 40 | symbols: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 35 | 41 | |
| 42 | // TODO add parsing re-exported libs from binary dylibs | |
| 43 | dependent_libs: std.StringArrayHashMapUnmanaged(void) = .{}, | |
| 44 | ||
| 36 | 45 | pub const Id = struct { |
| 37 | 46 | name: []const u8, |
| 38 | 47 | timestamp: u32, |
| 39 | 48 | current_version: u32, |
| 40 | 49 | compatibility_version: u32, |
| 41 | 50 | |
| 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 | 60 | pub fn deinit(id: *Id, allocator: *Allocator) void { |
| 43 | 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 | }; |
| 46 | 118 | |
| 47 | pub fn init(allocator: *Allocator) Dylib { | |
| 48 | return .{ .allocator = allocator }; | |
| 119 | pub const Error = error{ | |
| 120 | OutOfMemory, | |
| 121 | EmptyStubFile, | |
| 122 | MismatchedCpuArchitecture, | |
| 123 | UnsupportedCpuArchitecture, | |
| 124 | } || fs.File.OpenError || std.os.PReadError || Id.ParseError; | |
| 125 | ||
| 126 | pub 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 | } |
| 50 | 176 | |
| 51 | 177 | pub fn deinit(self: *Dylib) void { |
| ... | ... | @@ -59,6 +185,11 @@ pub fn deinit(self: *Dylib) void { |
| 59 | 185 | } |
| 60 | 186 | self.symbols.deinit(self.allocator); |
| 61 | 187 | |
| 188 | for (self.dependent_libs.keys()) |key| { | |
| 189 | self.allocator.free(key); | |
| 190 | } | |
| 191 | self.dependent_libs.deinit(self.allocator); | |
| 192 | ||
| 62 | 193 | if (self.name) |name| { |
| 63 | 194 | self.allocator.free(name); |
| 64 | 195 | } |
| ... | ... | @@ -81,8 +212,8 @@ pub fn parse(self: *Dylib) !void { |
| 81 | 212 | self.header = try reader.readStruct(macho.mach_header_64); |
| 82 | 213 | |
| 83 | 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 }); | |
| 85 | return error.MalformedDylib; | |
| 215 | log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype }); | |
| 216 | return error.NotDylib; | |
| 86 | 217 | } |
| 87 | 218 | |
| 88 | 219 | const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { |
| ... | ... | @@ -103,7 +234,7 @@ pub fn parse(self: *Dylib) !void { |
| 103 | 234 | try self.parseSymbols(); |
| 104 | 235 | } |
| 105 | 236 | |
| 106 | pub fn readLoadCommands(self: *Dylib, reader: anytype) !void { | |
| 237 | fn readLoadCommands(self: *Dylib, reader: anytype) !void { | |
| 107 | 238 | try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds); |
| 108 | 239 | |
| 109 | 240 | var i: u16 = 0; |
| ... | ... | @@ -127,15 +258,10 @@ pub fn readLoadCommands(self: *Dylib, reader: anytype) !void { |
| 127 | 258 | } |
| 128 | 259 | } |
| 129 | 260 | |
| 130 | pub fn parseId(self: *Dylib) !void { | |
| 261 | fn parseId(self: *Dylib) !void { | |
| 131 | 262 | const index = self.id_cmd_index orelse { |
| 132 | 263 | log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{}); |
| 133 | self.id = .{ | |
| 134 | .name = try self.allocator.dupe(u8, self.name.?), | |
| 135 | .timestamp = 2, | |
| 136 | .current_version = 0, | |
| 137 | .compatibility_version = 0, | |
| 138 | }; | |
| 264 | self.id = Id.default(try self.allocator.dupe(u8, self.name.?)); | |
| 139 | 265 | return; |
| 140 | 266 | }; |
| 141 | 267 | const id_cmd = self.load_commands.items[index].Dylib; |
| ... | ... | @@ -153,7 +279,7 @@ pub fn parseId(self: *Dylib) !void { |
| 153 | 279 | }; |
| 154 | 280 | } |
| 155 | 281 | |
| 156 | pub fn parseSymbols(self: *Dylib) !void { | |
| 282 | fn parseSymbols(self: *Dylib) !void { | |
| 157 | 283 | const index = self.symtab_cmd_index orelse return; |
| 158 | 284 | const symtab_cmd = self.load_commands.items[index].Symtab; |
| 159 | 285 | |
| ... | ... | @@ -176,13 +302,171 @@ pub fn parseSymbols(self: *Dylib) !void { |
| 176 | 302 | } |
| 177 | 303 | } |
| 178 | 304 | |
| 179 | pub fn isDylib(file: fs.File) !bool { | |
| 180 | const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) { | |
| 181 | error.EndOfStream => return false, | |
| 182 | else => |e| return e, | |
| 305 | fn hasTarget(targets: []const []const u8, target: []const u8) bool { | |
| 306 | for (targets) |t| { | |
| 307 | if (mem.eql(u8, t, target)) return true; | |
| 308 | } | |
| 309 | return false; | |
| 310 | } | |
| 311 | ||
| 312 | fn 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 | ||
| 324 | pub 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); | |
| 185 | return header.filetype == macho.MH_DYLIB; | |
| 345 | ||
| 346 | var umbrella_libs = std.StringHashMap(void).init(self.allocator); | |
| 347 | defer umbrella_libs.deinit(); | |
| 348 | ||
| 349 | for (lib_stub.inner) |stub, stub_index| { | |
| 350 | if (!hasTarget(stub.targets, target_string)) continue; | |
| 351 | ||
| 352 | if (stub_index > 0) { | |
| 353 | // TODO I thought that we could switch on presence of `parent-umbrella` map; | |
| 354 | // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib` | |
| 355 | // BUT does not feature a `parent-umbrella` map as the only sublib. Apple's bug perhaps? | |
| 356 | try umbrella_libs.put(stub.install_name, .{}); | |
| 357 | } | |
| 358 | ||
| 359 | if (stub.exports) |exports| { | |
| 360 | for (exports) |exp| { | |
| 361 | if (!hasTarget(exp.targets, target_string)) continue; | |
| 362 | ||
| 363 | if (exp.symbols) |symbols| { | |
| 364 | for (symbols) |sym_name| { | |
| 365 | if (self.symbols.contains(sym_name)) continue; | |
| 366 | try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {}); | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | if (exp.objc_classes) |classes| { | |
| 371 | for (classes) |sym_name| { | |
| 372 | try self.addObjCClassSymbols(sym_name); | |
| 373 | } | |
| 374 | } | |
| 375 | } | |
| 376 | } | |
| 377 | ||
| 378 | if (stub.reexports) |reexports| { | |
| 379 | for (reexports) |reexp| { | |
| 380 | if (!hasTarget(reexp.targets, target_string)) continue; | |
| 381 | ||
| 382 | if (reexp.symbols) |symbols| { | |
| 383 | for (symbols) |sym_name| { | |
| 384 | if (self.symbols.contains(sym_name)) continue; | |
| 385 | try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {}); | |
| 386 | } | |
| 387 | } | |
| 388 | ||
| 389 | if (reexp.objc_classes) |classes| { | |
| 390 | for (classes) |sym_name| { | |
| 391 | try self.addObjCClassSymbols(sym_name); | |
| 392 | } | |
| 393 | } | |
| 394 | } | |
| 395 | } | |
| 396 | ||
| 397 | if (stub.objc_classes) |classes| { | |
| 398 | for (classes) |sym_name| { | |
| 399 | try self.addObjCClassSymbols(sym_name); | |
| 400 | } | |
| 401 | } | |
| 402 | } | |
| 403 | ||
| 404 | log.debug("{s}", .{umbrella_lib.install_name}); | |
| 405 | ||
| 406 | // TODO track which libs were already parsed in different steps | |
| 407 | for (lib_stub.inner) |stub| { | |
| 408 | if (!hasTarget(stub.targets, target_string)) continue; | |
| 409 | ||
| 410 | if (stub.reexported_libraries) |reexports| { | |
| 411 | for (reexports) |reexp| { | |
| 412 | if (!hasTarget(reexp.targets, target_string)) continue; | |
| 413 | ||
| 414 | for (reexp.libraries) |lib| { | |
| 415 | if (umbrella_libs.contains(lib)) { | |
| 416 | log.debug(" | {s} <= {s}", .{ lib, umbrella_lib.install_name }); | |
| 417 | continue; | |
| 418 | } | |
| 419 | ||
| 420 | log.debug(" | {s}", .{lib}); | |
| 421 | try self.dependent_libs.put(self.allocator, try self.allocator.dupe(u8, lib), {}); | |
| 422 | } | |
| 423 | } | |
| 424 | } | |
| 425 | } | |
| 426 | } | |
| 427 | ||
| 428 | pub 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 | } |
| 187 | 471 | |
| 188 | 472 | 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 | 481 | .@"type" = .proxy, |
| 198 | 482 | .name = name, |
| 199 | 483 | }, |
| 200 | .file = .{ .dylib = self }, | |
| 484 | .file = self, | |
| 201 | 485 | }; |
| 202 | 486 | |
| 203 | 487 | return &proxy.base; |
src/link/MachO/Object.zig+37-15| ... | ... | @@ -11,6 +11,7 @@ const mem = std.mem; |
| 11 | 11 | const reloc = @import("reloc.zig"); |
| 12 | 12 | |
| 13 | 13 | const Allocator = mem.Allocator; |
| 14 | const Arch = std.Target.Cpu.Arch; | |
| 14 | 15 | const Relocation = reloc.Relocation; |
| 15 | 16 | const Symbol = @import("Symbol.zig"); |
| 16 | 17 | const parseName = @import("Zld.zig").parseName; |
| ... | ... | @@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName; |
| 18 | 19 | usingnamespace @import("commands.zig"); |
| 19 | 20 | |
| 20 | 21 | allocator: *Allocator, |
| 21 | arch: ?std.Target.Cpu.Arch = null, | |
| 22 | arch: ?Arch = null, | |
| 22 | 23 | header: ?macho.mach_header_64 = null, |
| 23 | 24 | file: ?fs.File = null, |
| 24 | 25 | file_offset: ?u32 = null, |
| ... | ... | @@ -173,10 +174,36 @@ const DebugInfo = struct { |
| 173 | 174 | } |
| 174 | 175 | }; |
| 175 | 176 | |
| 176 | pub fn init(allocator: *Allocator) Object { | |
| 177 | return .{ | |
| 177 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object { | |
| 178 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | |
| 179 | error.FileNotFound => return null, | |
| 180 | else => |e| return e, | |
| 181 | }; | |
| 182 | errdefer file.close(); | |
| 183 | ||
| 184 | const object = try allocator.create(Object); | |
| 185 | errdefer allocator.destroy(object); | |
| 186 | ||
| 187 | const name = try allocator.dupe(u8, path); | |
| 188 | errdefer allocator.free(name); | |
| 189 | ||
| 190 | object.* = .{ | |
| 178 | 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 | } |
| 181 | 208 | |
| 182 | 209 | pub fn deinit(self: *Object) void { |
| ... | ... | @@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void { |
| 223 | 250 | self.header = try reader.readStruct(macho.mach_header_64); |
| 224 | 251 | |
| 225 | 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 }); | |
| 227 | return error.MalformedObject; | |
| 253 | log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ | |
| 254 | macho.MH_OBJECT, | |
| 255 | self.header.?.filetype, | |
| 256 | }); | |
| 257 | ||
| 258 | return error.NotObject; | |
| 228 | 259 | } |
| 229 | 260 | |
| 230 | const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { | |
| 261 | const this_arch: Arch = switch (self.header.?.cputype) { | |
| 231 | 262 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 232 | 263 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 233 | 264 | else => |value| { |
| ... | ... | @@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void { |
| 533 | 564 | try self.data_in_code_entries.append(self.allocator, dice); |
| 534 | 565 | } |
| 535 | 566 | } |
| 536 | ||
| 537 | pub 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 @@ |
| 1 | const Stub = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const assert = std.debug.assert; | |
| 5 | const fs = std.fs; | |
| 6 | const log = std.log.scoped(.stub); | |
| 7 | const macho = std.macho; | |
| 8 | const mem = std.mem; | |
| 9 | ||
| 10 | const Allocator = mem.Allocator; | |
| 11 | const Symbol = @import("Symbol.zig"); | |
| 12 | pub const LibStub = @import("../tapi.zig").LibStub; | |
| 13 | ||
| 14 | allocator: *Allocator, | |
| 15 | arch: ?std.Target.Cpu.Arch = null, | |
| 16 | lib_stub: ?LibStub = null, | |
| 17 | name: ?[]const u8 = null, | |
| 18 | ||
| 19 | ordinal: ?u16 = null, | |
| 20 | ||
| 21 | id: ?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. | |
| 26 | symbols: std.StringArrayHashMapUnmanaged(void) = .{}, | |
| 27 | ||
| 28 | pub 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 | ||
| 39 | pub fn init(allocator: *Allocator) Stub { | |
| 40 | return .{ .allocator = allocator }; | |
| 41 | } | |
| 42 | ||
| 43 | pub 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 | ||
| 59 | pub 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 | ||
| 107 | fn 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 | ||
| 114 | pub 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 | const Allocator = mem.Allocator; |
| 8 | 8 | const Dylib = @import("Dylib.zig"); |
| 9 | 9 | const Object = @import("Object.zig"); |
| 10 | const Stub = @import("Stub.zig"); | |
| 11 | 10 | |
| 12 | 11 | pub const Type = enum { |
| 13 | 12 | regular, |
| ... | ... | @@ -85,21 +84,26 @@ pub const Regular = struct { |
| 85 | 84 | pub const Proxy = struct { |
| 86 | 85 | base: Symbol, |
| 87 | 86 | |
| 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 | 95 | /// null means self-reference. |
| 90 | file: ?union(enum) { | |
| 91 | dylib: *Dylib, | |
| 92 | stub: *Stub, | |
| 93 | } = null, | |
| 96 | file: ?*Dylib = null, | |
| 94 | 97 | |
| 95 | 98 | pub const base_type: Symbol.Type = .proxy; |
| 96 | 99 | |
| 100 | pub fn deinit(proxy: *Proxy, allocator: *Allocator) void { | |
| 101 | proxy.bind_info.deinit(allocator); | |
| 102 | } | |
| 103 | ||
| 97 | 104 | pub fn dylibOrdinal(proxy: *Proxy) u16 { |
| 98 | const file = proxy.file orelse return 0; | |
| 99 | return switch (file) { | |
| 100 | .dylib => |dylib| dylib.ordinal.?, | |
| 101 | .stub => |stub| stub.ordinal.?, | |
| 102 | }; | |
| 105 | const dylib = proxy.file orelse return 0; | |
| 106 | return dylib.ordinal.?; | |
| 103 | 107 | } |
| 104 | 108 | }; |
| 105 | 109 | |
| ... | ... | @@ -129,6 +133,10 @@ pub const Tentative = struct { |
| 129 | 133 | |
| 130 | 134 | pub fn deinit(base: *Symbol, allocator: *Allocator) void { |
| 131 | 135 | allocator.free(base.name); |
| 136 | switch (base.@"type") { | |
| 137 | .proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator), | |
| 138 | else => {}, | |
| 139 | } | |
| 132 | 140 | } |
| 133 | 141 | |
| 134 | 142 | pub 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 | 17 | const CodeSignature = @import("CodeSignature.zig"); |
| 18 | 18 | const Dylib = @import("Dylib.zig"); |
| 19 | 19 | const Object = @import("Object.zig"); |
| 20 | const Stub = @import("Stub.zig"); | |
| 21 | 20 | const Symbol = @import("Symbol.zig"); |
| 22 | 21 | const Trie = @import("Trie.zig"); |
| 23 | 22 | |
| ... | ... | @@ -33,14 +32,14 @@ out_path: ?[]const u8 = null, |
| 33 | 32 | |
| 34 | 33 | // TODO these args will become obselete once Zld is coalesced with incremental |
| 35 | 34 | // linker. |
| 35 | syslibroot: ?[]const u8 = null, | |
| 36 | 36 | stack_size: u64 = 0, |
| 37 | 37 | |
| 38 | 38 | objects: std.ArrayListUnmanaged(*Object) = .{}, |
| 39 | 39 | archives: std.ArrayListUnmanaged(*Archive) = .{}, |
| 40 | 40 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, |
| 41 | lib_stubs: std.ArrayListUnmanaged(*Stub) = .{}, | |
| 42 | 41 | |
| 43 | libsystem_stub_index: ?u16 = null, | |
| 42 | libsystem_dylib_index: ?u16 = null, | |
| 44 | 43 | next_dylib_ordinal: u16 = 1, |
| 45 | 44 | |
| 46 | 45 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| ... | ... | @@ -73,12 +72,21 @@ gcc_except_tab_section_index: ?u16 = null, |
| 73 | 72 | unwind_info_section_index: ?u16 = null, |
| 74 | 73 | eh_frame_section_index: ?u16 = null, |
| 75 | 74 | |
| 75 | objc_methlist_section_index: ?u16 = null, | |
| 76 | objc_methname_section_index: ?u16 = null, | |
| 77 | objc_methtype_section_index: ?u16 = null, | |
| 78 | objc_classname_section_index: ?u16 = null, | |
| 79 | ||
| 76 | 80 | // __DATA_CONST segment sections |
| 77 | 81 | got_section_index: ?u16 = null, |
| 78 | 82 | mod_init_func_section_index: ?u16 = null, |
| 79 | 83 | mod_term_func_section_index: ?u16 = null, |
| 80 | 84 | data_const_section_index: ?u16 = null, |
| 81 | 85 | |
| 86 | objc_cfstring_section_index: ?u16 = null, | |
| 87 | objc_classlist_section_index: ?u16 = null, | |
| 88 | objc_imageinfo_section_index: ?u16 = null, | |
| 89 | ||
| 82 | 90 | // __DATA segment sections |
| 83 | 91 | tlv_section_index: ?u16 = null, |
| 84 | 92 | tlv_data_section_index: ?u16 = null, |
| ... | ... | @@ -88,6 +96,11 @@ data_section_index: ?u16 = null, |
| 88 | 96 | bss_section_index: ?u16 = null, |
| 89 | 97 | common_section_index: ?u16 = null, |
| 90 | 98 | |
| 99 | objc_const_section_index: ?u16 = null, | |
| 100 | objc_selrefs_section_index: ?u16 = null, | |
| 101 | objc_classrefs_section_index: ?u16 = null, | |
| 102 | objc_data_section_index: ?u16 = null, | |
| 103 | ||
| 91 | 104 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 92 | 105 | imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 93 | 106 | unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| ... | ... | @@ -120,10 +133,6 @@ const TlvOffset = struct { |
| 120 | 133 | /// Default path to dyld |
| 121 | 134 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 122 | 135 | |
| 123 | const LIB_SYSTEM_NAME: [*:0]const u8 = "System"; | |
| 124 | /// TODO this should be inferred from included libSystem.tbd or similar. | |
| 125 | const LIB_SYSTEM_PATH: [*:0]const u8 = "/usr/lib/libSystem.B.dylib"; | |
| 126 | ||
| 127 | 136 | pub fn init(allocator: *Allocator) Zld { |
| 128 | 137 | return .{ .allocator = allocator }; |
| 129 | 138 | } |
| ... | ... | @@ -157,12 +166,6 @@ pub fn deinit(self: *Zld) void { |
| 157 | 166 | } |
| 158 | 167 | self.dylibs.deinit(self.allocator); |
| 159 | 168 | |
| 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 | 169 | for (self.imports.values()) |proxy| { |
| 167 | 170 | proxy.deinit(self.allocator); |
| 168 | 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 | 238 | }); |
| 236 | 239 | |
| 237 | 240 | try self.populateMetadata(); |
| 238 | try self.addRpaths(args.rpaths); | |
| 239 | 241 | try self.parseInputFiles(files); |
| 240 | 242 | try self.parseLibs(args.libs); |
| 241 | 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 | 245 | try self.resolveStubsAndGotEntries(); |
| 244 | 246 | try self.updateMetadata(); |
| 245 | 247 | try self.sortSections(); |
| 248 | try self.addRpaths(args.rpaths); | |
| 249 | try self.addDataInCodeLC(); | |
| 250 | try self.addCodeSignatureLC(); | |
| 246 | 251 | try self.allocateTextSegment(); |
| 247 | 252 | try self.allocateDataConstSegment(); |
| 248 | 253 | try self.allocateDataSegment(); |
| 249 | 254 | self.allocateLinkeditSegment(); |
| 250 | 255 | try self.allocateSymbols(); |
| 251 | 256 | try self.allocateTentativeSymbols(); |
| 257 | try self.allocateProxyBindAddresses(); | |
| 252 | 258 | try self.flush(); |
| 253 | 259 | } |
| 254 | 260 | |
| 255 | 261 | fn 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 | 262 | for (files) |file_name| { |
| 274 | const file = try fs.cwd().openFile(file_name, .{}); | |
| 275 | 263 | const full_path = full_path: { |
| 276 | 264 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 277 | 265 | const path = try std.fs.realpath(file_name, &buffer); |
| 278 | 266 | break :full_path try self.allocator.dupe(u8, path); |
| 279 | 267 | }; |
| 280 | 268 | |
| 281 | try_object: { | |
| 282 | if (!(try Object.isObject(file))) break :try_object; | |
| 283 | try classified.append(.{ | |
| 284 | .kind = .object, | |
| 285 | .origin = .{ .file = file }, | |
| 286 | .name = full_path, | |
| 287 | }); | |
| 288 | continue; | |
| 289 | } | |
| 290 | ||
| 291 | try_archive: { | |
| 292 | if (!(try Archive.isArchive(file))) break :try_archive; | |
| 293 | try classified.append(.{ | |
| 294 | .kind = .archive, | |
| 295 | .origin = .{ .file = file }, | |
| 296 | .name = full_path, | |
| 297 | }); | |
| 269 | if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| { | |
| 270 | try self.objects.append(self.allocator, object); | |
| 298 | 271 | continue; |
| 299 | 272 | } |
| 300 | 273 | |
| 301 | try_dylib: { | |
| 302 | if (!(try Dylib.isDylib(file))) break :try_dylib; | |
| 303 | try classified.append(.{ | |
| 304 | .kind = .dylib, | |
| 305 | .origin = .{ .file = file }, | |
| 306 | .name = full_path, | |
| 307 | }); | |
| 274 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| { | |
| 275 | try self.archives.append(self.allocator, archive); | |
| 308 | 276 | continue; |
| 309 | 277 | } |
| 310 | 278 | |
| 311 | try_stub: { | |
| 312 | var lib_stub = Stub.LibStub.loadFromFile(self.allocator, file) catch { | |
| 313 | break :try_stub; | |
| 314 | }; | |
| 315 | try classified.append(.{ | |
| 316 | .kind = .stub, | |
| 317 | .origin = .{ .stub = lib_stub }, | |
| 318 | .name = full_path, | |
| 319 | }); | |
| 320 | file.close(); | |
| 279 | if (try Dylib.createAndParseFromPath( | |
| 280 | self.allocator, | |
| 281 | self.arch.?, | |
| 282 | full_path, | |
| 283 | self.syslibroot, | |
| 284 | )) |dylibs| { | |
| 285 | defer self.allocator.free(dylibs); | |
| 286 | try self.dylibs.appendSlice(self.allocator, dylibs); | |
| 321 | 287 | continue; |
| 322 | 288 | } |
| 323 | 289 | |
| 324 | file.close(); | |
| 325 | 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 | } |
| 382 | 293 | |
| 383 | 294 | fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 384 | 295 | for (libs) |lib| { |
| 385 | const file = try fs.cwd().openFile(lib, .{}); | |
| 386 | ||
| 387 | if (try Dylib.isDylib(file)) { | |
| 388 | const dylib = try self.allocator.create(Dylib); | |
| 389 | errdefer self.allocator.destroy(dylib); | |
| 390 | ||
| 391 | dylib.* = Dylib.init(self.allocator); | |
| 392 | dylib.arch = self.arch.?; | |
| 393 | dylib.name = try self.allocator.dupe(u8, lib); | |
| 394 | dylib.file = file; | |
| 296 | if (try Dylib.createAndParseFromPath( | |
| 297 | self.allocator, | |
| 298 | self.arch.?, | |
| 299 | lib, | |
| 300 | self.syslibroot, | |
| 301 | )) |dylibs| { | |
| 302 | defer self.allocator.free(dylibs); | |
| 303 | try self.dylibs.appendSlice(self.allocator, dylibs); | |
| 304 | continue; | |
| 305 | } | |
| 395 | 306 | |
| 396 | try dylib.parse(); | |
| 397 | try self.dylibs.append(self.allocator, dylib); | |
| 398 | } else { | |
| 399 | // Try tbd stub file next. | |
| 400 | if (Stub.LibStub.loadFromFile(self.allocator, file)) |lib_stub| { | |
| 401 | const stub = try self.allocator.create(Stub); | |
| 402 | errdefer self.allocator.destroy(stub); | |
| 403 | ||
| 404 | stub.* = Stub.init(self.allocator); | |
| 405 | stub.arch = self.arch.?; | |
| 406 | stub.name = try self.allocator.dupe(u8, lib); | |
| 407 | stub.lib_stub = lib_stub; | |
| 408 | ||
| 409 | try stub.parse(); | |
| 410 | try self.lib_stubs.append(self.allocator, stub); | |
| 411 | } else |_| { | |
| 412 | // TODO this entire logic has to be cleaned up. | |
| 413 | try file.seekTo(0); | |
| 414 | ||
| 415 | if (try Archive.isArchive(file)) { | |
| 416 | const archive = try self.allocator.create(Archive); | |
| 417 | errdefer self.allocator.destroy(archive); | |
| 418 | ||
| 419 | archive.* = Archive.init(self.allocator); | |
| 420 | archive.arch = self.arch.?; | |
| 421 | archive.name = try self.allocator.dupe(u8, lib); | |
| 422 | archive.file = file; | |
| 423 | ||
| 424 | try archive.parse(); | |
| 425 | try self.archives.append(self.allocator, archive); | |
| 426 | } else { | |
| 427 | file.close(); | |
| 428 | log.warn("unknown filetype for a library: '{s}'", .{lib}); | |
| 429 | } | |
| 430 | } | |
| 307 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| { | |
| 308 | try self.archives.append(self.allocator, archive); | |
| 309 | continue; | |
| 431 | 310 | } |
| 311 | ||
| 312 | log.warn("unknown filetype for a library: '{s}'", .{lib}); | |
| 432 | 313 | } |
| 433 | 314 | } |
| 434 | 315 | |
| 435 | 316 | fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void { |
| 436 | const file = try fs.cwd().openFile(libc_stub_path, .{}); | |
| 437 | defer file.close(); | |
| 438 | ||
| 439 | var lib_stub = try Stub.LibStub.loadFromFile(self.allocator, file); | |
| 440 | ||
| 441 | const stub = try self.allocator.create(Stub); | |
| 442 | errdefer self.allocator.destroy(stub); | |
| 443 | ||
| 444 | stub.* = Stub.init(self.allocator); | |
| 445 | stub.arch = self.arch.?; | |
| 446 | stub.name = try self.allocator.dupe(u8, libc_stub_path); | |
| 447 | stub.lib_stub = lib_stub; | |
| 317 | const dylibs = (try Dylib.createAndParseFromPath( | |
| 318 | self.allocator, | |
| 319 | self.arch.?, | |
| 320 | libc_stub_path, | |
| 321 | self.syslibroot, | |
| 322 | )) orelse return error.FailedToParseLibSystem; | |
| 323 | defer self.allocator.free(dylibs); | |
| 448 | 324 | |
| 449 | try stub.parse(); | |
| 325 | assert(dylibs.len == 1); // More than one dylib output from parsing libSystem! | |
| 326 | const dylib = dylibs[0]; | |
| 450 | 327 | |
| 451 | self.libsystem_stub_index = @intCast(u16, self.lib_stubs.items.len); | |
| 452 | try self.lib_stubs.append(self.allocator, stub); | |
| 328 | self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len); | |
| 329 | try self.dylibs.append(self.allocator, dylib); | |
| 453 | 330 | |
| 454 | 331 | // Add LC_LOAD_DYLIB load command. |
| 455 | stub.ordinal = self.next_dylib_ordinal; | |
| 456 | const dylib_id = stub.id orelse unreachable; | |
| 332 | dylib.ordinal = self.next_dylib_ordinal; | |
| 333 | const dylib_id = dylib.id orelse unreachable; | |
| 457 | 334 | var dylib_cmd = try createLoadDylibCommand( |
| 458 | 335 | self.allocator, |
| 459 | 336 | dylib_id.name, |
| ... | ... | @@ -501,428 +378,22 @@ fn mapAndUpdateSections( |
| 501 | 378 | |
| 502 | 379 | fn updateMetadata(self: *Zld) !void { |
| 503 | 380 | for (self.objects.items) |object| { |
| 504 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | |
| 505 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | |
| 506 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | |
| 507 | ||
| 508 | // Create missing metadata | |
| 509 | for (object.sections.items) |sect| { | |
| 510 | const segname = sect.segname(); | |
| 511 | const sectname = sect.sectname(); | |
| 512 | ||
| 513 | switch (sect.sectionType()) { | |
| 514 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => { | |
| 515 | if (self.text_const_section_index != null) continue; | |
| 516 | ||
| 517 | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 518 | try text_seg.addSection(self.allocator, .{ | |
| 519 | .sectname = makeStaticString("__const"), | |
| 520 | .segname = makeStaticString("__TEXT"), | |
| 521 | .addr = 0, | |
| 522 | .size = 0, | |
| 523 | .offset = 0, | |
| 524 | .@"align" = 0, | |
| 525 | .reloff = 0, | |
| 526 | .nreloc = 0, | |
| 527 | .flags = macho.S_REGULAR, | |
| 528 | .reserved1 = 0, | |
| 529 | .reserved2 = 0, | |
| 530 | .reserved3 = 0, | |
| 531 | }); | |
| 532 | continue; | |
| 533 | }, | |
| 534 | macho.S_CSTRING_LITERALS => { | |
| 535 | if (self.cstring_section_index != null) continue; | |
| 536 | ||
| 537 | self.cstring_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 538 | try text_seg.addSection(self.allocator, .{ | |
| 539 | .sectname = makeStaticString("__cstring"), | |
| 540 | .segname = makeStaticString("__TEXT"), | |
| 541 | .addr = 0, | |
| 542 | .size = 0, | |
| 543 | .offset = 0, | |
| 544 | .@"align" = 0, | |
| 545 | .reloff = 0, | |
| 546 | .nreloc = 0, | |
| 547 | .flags = macho.S_CSTRING_LITERALS, | |
| 548 | .reserved1 = 0, | |
| 549 | .reserved2 = 0, | |
| 550 | .reserved3 = 0, | |
| 551 | }); | |
| 552 | continue; | |
| 553 | }, | |
| 554 | macho.S_MOD_INIT_FUNC_POINTERS => { | |
| 555 | if (self.mod_init_func_section_index != null) continue; | |
| 556 | ||
| 557 | self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len); | |
| 558 | try data_const_seg.addSection(self.allocator, .{ | |
| 559 | .sectname = makeStaticString("__mod_init_func"), | |
| 560 | .segname = makeStaticString("__DATA_CONST"), | |
| 561 | .addr = 0, | |
| 562 | .size = 0, | |
| 563 | .offset = 0, | |
| 564 | .@"align" = 0, | |
| 565 | .reloff = 0, | |
| 566 | .nreloc = 0, | |
| 567 | .flags = macho.S_MOD_INIT_FUNC_POINTERS, | |
| 568 | .reserved1 = 0, | |
| 569 | .reserved2 = 0, | |
| 570 | .reserved3 = 0, | |
| 571 | }); | |
| 572 | continue; | |
| 573 | }, | |
| 574 | macho.S_MOD_TERM_FUNC_POINTERS => { | |
| 575 | if (self.mod_term_func_section_index != null) continue; | |
| 576 | ||
| 577 | self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len); | |
| 578 | try data_const_seg.addSection(self.allocator, .{ | |
| 579 | .sectname = makeStaticString("__mod_term_func"), | |
| 580 | .segname = makeStaticString("__DATA_CONST"), | |
| 581 | .addr = 0, | |
| 582 | .size = 0, | |
| 583 | .offset = 0, | |
| 584 | .@"align" = 0, | |
| 585 | .reloff = 0, | |
| 586 | .nreloc = 0, | |
| 587 | .flags = macho.S_MOD_TERM_FUNC_POINTERS, | |
| 588 | .reserved1 = 0, | |
| 589 | .reserved2 = 0, | |
| 590 | .reserved3 = 0, | |
| 591 | }); | |
| 592 | continue; | |
| 593 | }, | |
| 594 | macho.S_ZEROFILL => { | |
| 595 | if (mem.eql(u8, sectname, "__common")) { | |
| 596 | if (self.common_section_index != null) continue; | |
| 597 | ||
| 598 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 599 | try data_seg.addSection(self.allocator, .{ | |
| 600 | .sectname = makeStaticString("__common"), | |
| 601 | .segname = makeStaticString("__DATA"), | |
| 602 | .addr = 0, | |
| 603 | .size = 0, | |
| 604 | .offset = 0, | |
| 605 | .@"align" = 0, | |
| 606 | .reloff = 0, | |
| 607 | .nreloc = 0, | |
| 608 | .flags = macho.S_ZEROFILL, | |
| 609 | .reserved1 = 0, | |
| 610 | .reserved2 = 0, | |
| 611 | .reserved3 = 0, | |
| 612 | }); | |
| 613 | } else { | |
| 614 | if (self.bss_section_index != null) continue; | |
| 615 | ||
| 616 | self.bss_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 617 | try data_seg.addSection(self.allocator, .{ | |
| 618 | .sectname = makeStaticString("__bss"), | |
| 619 | .segname = makeStaticString("__DATA"), | |
| 620 | .addr = 0, | |
| 621 | .size = 0, | |
| 622 | .offset = 0, | |
| 623 | .@"align" = 0, | |
| 624 | .reloff = 0, | |
| 625 | .nreloc = 0, | |
| 626 | .flags = macho.S_ZEROFILL, | |
| 627 | .reserved1 = 0, | |
| 628 | .reserved2 = 0, | |
| 629 | .reserved3 = 0, | |
| 630 | }); | |
| 631 | } | |
| 632 | continue; | |
| 633 | }, | |
| 634 | macho.S_THREAD_LOCAL_VARIABLES => { | |
| 635 | if (self.tlv_section_index != null) continue; | |
| 636 | ||
| 637 | self.tlv_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 638 | try data_seg.addSection(self.allocator, .{ | |
| 639 | .sectname = makeStaticString("__thread_vars"), | |
| 640 | .segname = makeStaticString("__DATA"), | |
| 641 | .addr = 0, | |
| 642 | .size = 0, | |
| 643 | .offset = 0, | |
| 644 | .@"align" = 0, | |
| 645 | .reloff = 0, | |
| 646 | .nreloc = 0, | |
| 647 | .flags = macho.S_THREAD_LOCAL_VARIABLES, | |
| 648 | .reserved1 = 0, | |
| 649 | .reserved2 = 0, | |
| 650 | .reserved3 = 0, | |
| 651 | }); | |
| 652 | continue; | |
| 653 | }, | |
| 654 | macho.S_THREAD_LOCAL_REGULAR => { | |
| 655 | if (self.tlv_data_section_index != null) continue; | |
| 656 | ||
| 657 | self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 658 | try data_seg.addSection(self.allocator, .{ | |
| 659 | .sectname = makeStaticString("__thread_data"), | |
| 660 | .segname = makeStaticString("__DATA"), | |
| 661 | .addr = 0, | |
| 662 | .size = 0, | |
| 663 | .offset = 0, | |
| 664 | .@"align" = 0, | |
| 665 | .reloff = 0, | |
| 666 | .nreloc = 0, | |
| 667 | .flags = macho.S_THREAD_LOCAL_REGULAR, | |
| 668 | .reserved1 = 0, | |
| 669 | .reserved2 = 0, | |
| 670 | .reserved3 = 0, | |
| 671 | }); | |
| 672 | continue; | |
| 673 | }, | |
| 674 | macho.S_THREAD_LOCAL_ZEROFILL => { | |
| 675 | if (self.tlv_bss_section_index != null) continue; | |
| 676 | ||
| 677 | self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 678 | try data_seg.addSection(self.allocator, .{ | |
| 679 | .sectname = makeStaticString("__thread_bss"), | |
| 680 | .segname = makeStaticString("__DATA"), | |
| 681 | .addr = 0, | |
| 682 | .size = 0, | |
| 683 | .offset = 0, | |
| 684 | .@"align" = 0, | |
| 685 | .reloff = 0, | |
| 686 | .nreloc = 0, | |
| 687 | .flags = macho.S_THREAD_LOCAL_ZEROFILL, | |
| 688 | .reserved1 = 0, | |
| 689 | .reserved2 = 0, | |
| 690 | .reserved3 = 0, | |
| 691 | }); | |
| 692 | continue; | |
| 693 | }, | |
| 694 | macho.S_COALESCED => { | |
| 695 | if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) { | |
| 696 | // TODO I believe __eh_frame is currently part of __unwind_info section | |
| 697 | // in the latest ld64 output. | |
| 698 | if (self.eh_frame_section_index != null) continue; | |
| 699 | ||
| 700 | self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 701 | try text_seg.addSection(self.allocator, .{ | |
| 702 | .sectname = makeStaticString("__eh_frame"), | |
| 703 | .segname = makeStaticString("__TEXT"), | |
| 704 | .addr = 0, | |
| 705 | .size = 0, | |
| 706 | .offset = 0, | |
| 707 | .@"align" = 0, | |
| 708 | .reloff = 0, | |
| 709 | .nreloc = 0, | |
| 710 | .flags = macho.S_REGULAR, | |
| 711 | .reserved1 = 0, | |
| 712 | .reserved2 = 0, | |
| 713 | .reserved3 = 0, | |
| 714 | }); | |
| 715 | continue; | |
| 716 | } | |
| 717 | ||
| 718 | // TODO audit this: is this the right mapping? | |
| 719 | if (self.data_const_section_index != null) continue; | |
| 720 | ||
| 721 | self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); | |
| 722 | try data_const_seg.addSection(self.allocator, .{ | |
| 723 | .sectname = makeStaticString("__const"), | |
| 724 | .segname = makeStaticString("__DATA_CONST"), | |
| 725 | .addr = 0, | |
| 726 | .size = 0, | |
| 727 | .offset = 0, | |
| 728 | .@"align" = 0, | |
| 729 | .reloff = 0, | |
| 730 | .nreloc = 0, | |
| 731 | .flags = macho.S_REGULAR, | |
| 732 | .reserved1 = 0, | |
| 733 | .reserved2 = 0, | |
| 734 | .reserved3 = 0, | |
| 735 | }); | |
| 736 | continue; | |
| 737 | }, | |
| 738 | macho.S_REGULAR => { | |
| 739 | if (sect.isCode()) { | |
| 740 | if (self.text_section_index != null) continue; | |
| 741 | ||
| 742 | self.text_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 743 | try text_seg.addSection(self.allocator, .{ | |
| 744 | .sectname = makeStaticString("__text"), | |
| 745 | .segname = makeStaticString("__TEXT"), | |
| 746 | .addr = 0, | |
| 747 | .size = 0, | |
| 748 | .offset = 0, | |
| 749 | .@"align" = 0, | |
| 750 | .reloff = 0, | |
| 751 | .nreloc = 0, | |
| 752 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | |
| 753 | .reserved1 = 0, | |
| 754 | .reserved2 = 0, | |
| 755 | .reserved3 = 0, | |
| 756 | }); | |
| 757 | continue; | |
| 758 | } | |
| 759 | ||
| 760 | if (sect.isDebug()) { | |
| 761 | if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { | |
| 762 | log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ | |
| 763 | sect.flags(), segname, sectname, | |
| 764 | }); | |
| 765 | } | |
| 766 | continue; | |
| 767 | } | |
| 768 | ||
| 769 | if (mem.eql(u8, segname, "__TEXT")) { | |
| 770 | if (mem.eql(u8, sectname, "__ustring")) { | |
| 771 | if (self.ustring_section_index != null) continue; | |
| 772 | ||
| 773 | self.ustring_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 774 | try text_seg.addSection(self.allocator, .{ | |
| 775 | .sectname = makeStaticString("__ustring"), | |
| 776 | .segname = makeStaticString("__TEXT"), | |
| 777 | .addr = 0, | |
| 778 | .size = 0, | |
| 779 | .offset = 0, | |
| 780 | .@"align" = 0, | |
| 781 | .reloff = 0, | |
| 782 | .nreloc = 0, | |
| 783 | .flags = macho.S_REGULAR, | |
| 784 | .reserved1 = 0, | |
| 785 | .reserved2 = 0, | |
| 786 | .reserved3 = 0, | |
| 787 | }); | |
| 788 | } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { | |
| 789 | if (self.gcc_except_tab_section_index != null) continue; | |
| 790 | ||
| 791 | self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 792 | try text_seg.addSection(self.allocator, .{ | |
| 793 | .sectname = makeStaticString("__gcc_except_tab"), | |
| 794 | .segname = makeStaticString("__TEXT"), | |
| 795 | .addr = 0, | |
| 796 | .size = 0, | |
| 797 | .offset = 0, | |
| 798 | .@"align" = 0, | |
| 799 | .reloff = 0, | |
| 800 | .nreloc = 0, | |
| 801 | .flags = macho.S_REGULAR, | |
| 802 | .reserved1 = 0, | |
| 803 | .reserved2 = 0, | |
| 804 | .reserved3 = 0, | |
| 805 | }); | |
| 806 | } else { | |
| 807 | if (self.text_const_section_index != null) continue; | |
| 808 | ||
| 809 | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); | |
| 810 | try text_seg.addSection(self.allocator, .{ | |
| 811 | .sectname = makeStaticString("__const"), | |
| 812 | .segname = makeStaticString("__TEXT"), | |
| 813 | .addr = 0, | |
| 814 | .size = 0, | |
| 815 | .offset = 0, | |
| 816 | .@"align" = 0, | |
| 817 | .reloff = 0, | |
| 818 | .nreloc = 0, | |
| 819 | .flags = macho.S_REGULAR, | |
| 820 | .reserved1 = 0, | |
| 821 | .reserved2 = 0, | |
| 822 | .reserved3 = 0, | |
| 823 | }); | |
| 824 | } | |
| 825 | continue; | |
| 826 | } | |
| 827 | ||
| 828 | if (mem.eql(u8, segname, "__DATA_CONST")) { | |
| 829 | if (self.data_const_section_index != null) continue; | |
| 830 | ||
| 831 | self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); | |
| 832 | try data_const_seg.addSection(self.allocator, .{ | |
| 833 | .sectname = makeStaticString("__const"), | |
| 834 | .segname = makeStaticString("__DATA_CONST"), | |
| 835 | .addr = 0, | |
| 836 | .size = 0, | |
| 837 | .offset = 0, | |
| 838 | .@"align" = 0, | |
| 839 | .reloff = 0, | |
| 840 | .nreloc = 0, | |
| 841 | .flags = macho.S_REGULAR, | |
| 842 | .reserved1 = 0, | |
| 843 | .reserved2 = 0, | |
| 844 | .reserved3 = 0, | |
| 845 | }); | |
| 846 | continue; | |
| 847 | } | |
| 848 | ||
| 849 | if (mem.eql(u8, segname, "__DATA")) { | |
| 850 | if (mem.eql(u8, sectname, "__const")) { | |
| 851 | if (self.data_const_section_index != null) continue; | |
| 852 | ||
| 853 | self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); | |
| 854 | try data_const_seg.addSection(self.allocator, .{ | |
| 855 | .sectname = makeStaticString("__const"), | |
| 856 | .segname = makeStaticString("__DATA_CONST"), | |
| 857 | .addr = 0, | |
| 858 | .size = 0, | |
| 859 | .offset = 0, | |
| 860 | .@"align" = 0, | |
| 861 | .reloff = 0, | |
| 862 | .nreloc = 0, | |
| 863 | .flags = macho.S_REGULAR, | |
| 864 | .reserved1 = 0, | |
| 865 | .reserved2 = 0, | |
| 866 | .reserved3 = 0, | |
| 867 | }); | |
| 868 | } else { | |
| 869 | if (self.data_section_index != null) continue; | |
| 870 | ||
| 871 | self.data_section_index = @intCast(u16, data_seg.sections.items.len); | |
| 872 | try data_seg.addSection(self.allocator, .{ | |
| 873 | .sectname = makeStaticString("__data"), | |
| 874 | .segname = makeStaticString("__DATA"), | |
| 875 | .addr = 0, | |
| 876 | .size = 0, | |
| 877 | .offset = 0, | |
| 878 | .@"align" = 0, | |
| 879 | .reloff = 0, | |
| 880 | .nreloc = 0, | |
| 881 | .flags = macho.S_REGULAR, | |
| 882 | .reserved1 = 0, | |
| 883 | .reserved2 = 0, | |
| 884 | .reserved3 = 0, | |
| 885 | }); | |
| 886 | } | |
| 887 | ||
| 888 | continue; | |
| 889 | } | |
| 890 | ||
| 891 | if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { | |
| 892 | log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{ | |
| 893 | sect.flags(), segname, sectname, | |
| 894 | }); | |
| 895 | continue; | |
| 896 | } | |
| 897 | }, | |
| 898 | else => {}, | |
| 899 | } | |
| 900 | ||
| 901 | log.err("{s}: unhandled section type 0x{x} for '{s},{s}'", .{ | |
| 902 | object.name.?, | |
| 903 | sect.flags(), | |
| 904 | segname, | |
| 905 | sectname, | |
| 906 | }); | |
| 907 | return error.UnhandledSection; | |
| 908 | } | |
| 909 | ||
| 910 | // Find ideal section alignment. | |
| 911 | for (object.sections.items) |sect| { | |
| 912 | if (self.getMatchingSection(sect)) |res| { | |
| 913 | const target_seg = &self.load_commands.items[res.seg].Segment; | |
| 914 | const target_sect = &target_seg.sections.items[res.sect]; | |
| 915 | target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align"); | |
| 916 | } | |
| 917 | } | |
| 918 | ||
| 919 | // Update section mappings | |
| 381 | // Find ideal section alignment and update section mappings | |
| 920 | 382 | for (object.sections.items) |sect, sect_id| { |
| 921 | if (self.getMatchingSection(sect)) |res| { | |
| 922 | try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect); | |
| 383 | const match = (try self.getMatchingSection(sect)) orelse { | |
| 384 | log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{ | |
| 385 | object.name.?, | |
| 386 | sect.flags(), | |
| 387 | sect.segname(), | |
| 388 | sect.sectname(), | |
| 389 | }); | |
| 923 | 390 | continue; |
| 924 | } | |
| 925 | log.debug("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() }); | |
| 391 | }; | |
| 392 | const target_seg = &self.load_commands.items[match.seg].Segment; | |
| 393 | const target_sect = &target_seg.sections.items[match.sect]; | |
| 394 | target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align"); | |
| 395 | ||
| 396 | try self.mapAndUpdateSections(object, @intCast(u16, sect_id), match.seg, match.sect); | |
| 926 | 397 | } |
| 927 | 398 | } |
| 928 | 399 | |
| ... | ... | @@ -932,19 +403,8 @@ fn updateMetadata(self: *Zld) !void { |
| 932 | 403 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 933 | 404 | const common_section_index = self.common_section_index orelse ind: { |
| 934 | 405 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); |
| 935 | try data_seg.addSection(self.allocator, .{ | |
| 936 | .sectname = makeStaticString("__common"), | |
| 937 | .segname = makeStaticString("__DATA"), | |
| 938 | .addr = 0, | |
| 939 | .size = 0, | |
| 940 | .offset = 0, | |
| 941 | .@"align" = 0, | |
| 942 | .reloff = 0, | |
| 943 | .nreloc = 0, | |
| 406 | try data_seg.addSection(self.allocator, "__common", .{ | |
| 944 | 407 | .flags = macho.S_ZEROFILL, |
| 945 | .reserved1 = 0, | |
| 946 | .reserved2 = 0, | |
| 947 | .reserved3 = 0, | |
| 948 | 408 | }); |
| 949 | 409 | break :ind self.common_section_index.?; |
| 950 | 410 | }; |
| ... | ... | @@ -1018,31 +478,116 @@ const MatchingSection = struct { |
| 1018 | 478 | sect: u16, |
| 1019 | 479 | }; |
| 1020 | 480 | |
| 1021 | fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { | |
| 481 | fn 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 | 485 | const segname = sect.segname(); |
| 1023 | 486 | const sectname = sect.sectname(); |
| 1024 | 487 | |
| 1025 | 488 | const res: ?MatchingSection = blk: { |
| 1026 | 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 | 496 | break :blk .{ |
| 1029 | 497 | .seg = self.text_segment_cmd_index.?, |
| 1030 | 498 | .sect = self.text_const_section_index.?, |
| 1031 | 499 | }; |
| 1032 | 500 | }, |
| 1033 | 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 | 547 | break :blk .{ |
| 1035 | 548 | .seg = self.text_segment_cmd_index.?, |
| 1036 | 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 | 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 | 578 | break :blk .{ |
| 1041 | 579 | .seg = self.data_const_segment_cmd_index.?, |
| 1042 | 580 | .sect = self.mod_init_func_section_index.?, |
| 1043 | 581 | }; |
| 1044 | 582 | }, |
| 1045 | 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 | 591 | break :blk .{ |
| 1047 | 592 | .seg = self.data_const_segment_cmd_index.?, |
| 1048 | 593 | .sect = self.mod_term_func_section_index.?, |
| ... | ... | @@ -1050,11 +595,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1050 | 595 | }, |
| 1051 | 596 | macho.S_ZEROFILL => { |
| 1052 | 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 | 605 | break :blk .{ |
| 1054 | 606 | .seg = self.data_segment_cmd_index.?, |
| 1055 | 607 | .sect = self.common_section_index.?, |
| 1056 | 608 | }; |
| 1057 | 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 | 617 | break :blk .{ |
| 1059 | 618 | .seg = self.data_segment_cmd_index.?, |
| 1060 | 619 | .sect = self.bss_section_index.?, |
| ... | ... | @@ -1062,18 +621,39 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1062 | 621 | } |
| 1063 | 622 | }, |
| 1064 | 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 | 631 | break :blk .{ |
| 1066 | 632 | .seg = self.data_segment_cmd_index.?, |
| 1067 | 633 | .sect = self.tlv_section_index.?, |
| 1068 | 634 | }; |
| 1069 | 635 | }, |
| 1070 | 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 | 644 | break :blk .{ |
| 1072 | 645 | .seg = self.data_segment_cmd_index.?, |
| 1073 | 646 | .sect = self.tlv_data_section_index.?, |
| 1074 | 647 | }; |
| 1075 | 648 | }, |
| 1076 | 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 | 657 | break :blk .{ |
| 1078 | 658 | .seg = self.data_segment_cmd_index.?, |
| 1079 | 659 | .sect = self.tlv_bss_section_index.?, |
| ... | ... | @@ -1081,12 +661,25 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1081 | 661 | }, |
| 1082 | 662 | macho.S_COALESCED => { |
| 1083 | 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 | 671 | break :blk .{ |
| 1085 | 672 | .seg = self.text_segment_cmd_index.?, |
| 1086 | 673 | .sect = self.eh_frame_section_index.?, |
| 1087 | 674 | }; |
| 1088 | 675 | } |
| 1089 | 676 | |
| 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 | 683 | break :blk .{ |
| 1091 | 684 | .seg = self.data_const_segment_cmd_index.?, |
| 1092 | 685 | .sect = self.data_const_section_index.?, |
| ... | ... | @@ -1094,6 +687,13 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1094 | 687 | }, |
| 1095 | 688 | macho.S_REGULAR => { |
| 1096 | 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 | 697 | break :blk .{ |
| 1098 | 698 | .seg = self.text_segment_cmd_index.?, |
| 1099 | 699 | .sect = self.text_section_index.?, |
| ... | ... | @@ -1101,21 +701,51 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1101 | 701 | } |
| 1102 | 702 | if (sect.isDebug()) { |
| 1103 | 703 | // 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 | 709 | break :blk null; |
| 1105 | 710 | } |
| 1106 | 711 | |
| 1107 | 712 | if (mem.eql(u8, segname, "__TEXT")) { |
| 1108 | 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 | 719 | break :blk .{ |
| 1110 | 720 | .seg = self.text_segment_cmd_index.?, |
| 1111 | 721 | .sect = self.ustring_section_index.?, |
| 1112 | 722 | }; |
| 1113 | 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 | 729 | break :blk .{ |
| 1115 | 730 | .seg = self.text_segment_cmd_index.?, |
| 1116 | 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 | 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 | 749 | break :blk .{ |
| 1120 | 750 | .seg = self.text_segment_cmd_index.?, |
| 1121 | 751 | .sect = self.text_const_section_index.?, |
| ... | ... | @@ -1124,6 +754,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1124 | 754 | } |
| 1125 | 755 | |
| 1126 | 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 | 762 | break :blk .{ |
| 1128 | 763 | .seg = self.data_const_segment_cmd_index.?, |
| 1129 | 764 | .sect = self.data_const_section_index.?, |
| ... | ... | @@ -1132,15 +767,92 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { |
| 1132 | 767 | |
| 1133 | 768 | if (mem.eql(u8, segname, "__DATA")) { |
| 1134 | 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 | 775 | break :blk .{ |
| 1136 | 776 | .seg = self.data_const_segment_cmd_index.?, |
| 1137 | 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 .{ | |
| 1141 | .seg = self.data_segment_cmd_index.?, | |
| 1142 | .sect = self.data_section_index.?, | |
| 1143 | }; | |
| 850 | } | |
| 851 | ||
| 852 | if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { | |
| 853 | log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{ | |
| 854 | sect.flags(), segname, sectname, | |
| 855 | }); | |
| 1144 | 856 | } |
| 1145 | 857 | |
| 1146 | 858 | break :blk null; |
| ... | ... | @@ -1175,6 +887,9 @@ fn sortSections(self: *Zld) !void { |
| 1175 | 887 | &self.cstring_section_index, |
| 1176 | 888 | &self.ustring_section_index, |
| 1177 | 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 | 893 | &self.eh_frame_section_index, |
| 1179 | 894 | }; |
| 1180 | 895 | for (indices) |maybe_index| { |
| ... | ... | @@ -1200,6 +915,9 @@ fn sortSections(self: *Zld) !void { |
| 1200 | 915 | &self.mod_init_func_section_index, |
| 1201 | 916 | &self.mod_term_func_section_index, |
| 1202 | 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 | 922 | for (indices) |maybe_index| { |
| 1205 | 923 | const new_index: u16 = if (maybe_index.*) |index| blk: { |
| ... | ... | @@ -1222,6 +940,10 @@ fn sortSections(self: *Zld) !void { |
| 1222 | 940 | // __DATA segment |
| 1223 | 941 | const indices = &[_]*?u16{ |
| 1224 | 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 | 947 | &self.data_section_index, |
| 1226 | 948 | &self.tlv_section_index, |
| 1227 | 949 | &self.tlv_data_section_index, |
| ... | ... | @@ -1487,6 +1209,31 @@ fn allocateTentativeSymbols(self: *Zld) !void { |
| 1487 | 1209 | } |
| 1488 | 1210 | } |
| 1489 | 1211 | |
| 1212 | fn 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 | ||
| 1490 | 1237 | fn writeStubHelperCommon(self: *Zld) !void { |
| 1491 | 1238 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1492 | 1239 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | ... | @@ -1893,25 +1640,16 @@ fn resolveSymbols(self: *Zld) !void { |
| 1893 | 1640 | } |
| 1894 | 1641 | self.unresolved.clearRetainingCapacity(); |
| 1895 | 1642 | |
| 1896 | var referenced = std.AutoHashMap(union(enum) { | |
| 1897 | dylib: *Dylib, | |
| 1898 | stub: *Stub, | |
| 1899 | }, void).init(self.allocator); | |
| 1643 | var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator); | |
| 1900 | 1644 | defer referenced.deinit(); |
| 1901 | 1645 | |
| 1902 | 1646 | loop: while (unresolved.popOrNull()) |undef| { |
| 1903 | 1647 | const proxy = self.imports.get(undef.name) orelse outer: { |
| 1904 | 1648 | const proxy = inner: { |
| 1905 | for (self.dylibs.items) |dylib| { | |
| 1649 | for (self.dylibs.items) |dylib, i| { | |
| 1906 | 1650 | const proxy = (try dylib.createProxy(undef.name)) orelse continue; |
| 1907 | try referenced.put(.{ .dylib = dylib }, {}); | |
| 1908 | break :inner proxy; | |
| 1909 | } | |
| 1910 | for (self.lib_stubs.items) |stub, i| { | |
| 1911 | const proxy = (try stub.createProxy(undef.name)) orelse continue; | |
| 1912 | if (self.libsystem_stub_index.? != @intCast(u16, i)) { | |
| 1913 | // LibSystem gets its load command separately. | |
| 1914 | try referenced.put(.{ .stub = stub }, {}); | |
| 1651 | if (self.libsystem_dylib_index.? != @intCast(u16, i)) { // LibSystem gets load command seperately. | |
| 1652 | try referenced.put(dylib, {}); | |
| 1915 | 1653 | } |
| 1916 | 1654 | break :inner proxy; |
| 1917 | 1655 | } |
| ... | ... | @@ -1944,33 +1682,17 @@ fn resolveSymbols(self: *Zld) !void { |
| 1944 | 1682 | |
| 1945 | 1683 | // Add LC_LOAD_DYLIB load command for each referenced dylib/stub. |
| 1946 | 1684 | var it = referenced.iterator(); |
| 1947 | while (it.next()) |key| { | |
| 1948 | var dylib_cmd = blk: { | |
| 1949 | switch (key.key_ptr.*) { | |
| 1950 | .dylib => |dylib| { | |
| 1951 | dylib.ordinal = self.next_dylib_ordinal; | |
| 1952 | const dylib_id = dylib.id orelse unreachable; | |
| 1953 | break :blk try createLoadDylibCommand( | |
| 1954 | self.allocator, | |
| 1955 | dylib_id.name, | |
| 1956 | dylib_id.timestamp, | |
| 1957 | dylib_id.current_version, | |
| 1958 | dylib_id.compatibility_version, | |
| 1959 | ); | |
| 1960 | }, | |
| 1961 | .stub => |stub| { | |
| 1962 | stub.ordinal = self.next_dylib_ordinal; | |
| 1963 | const dylib_id = stub.id orelse unreachable; | |
| 1964 | break :blk try createLoadDylibCommand( | |
| 1965 | self.allocator, | |
| 1966 | dylib_id.name, | |
| 1967 | dylib_id.timestamp, | |
| 1968 | dylib_id.current_version, | |
| 1969 | dylib_id.compatibility_version, | |
| 1970 | ); | |
| 1971 | }, | |
| 1972 | } | |
| 1973 | }; | |
| 1685 | while (it.next()) |entry| { | |
| 1686 | const dylib = entry.key_ptr.*; | |
| 1687 | dylib.ordinal = self.next_dylib_ordinal; | |
| 1688 | const dylib_id = dylib.id orelse unreachable; | |
| 1689 | var dylib_cmd = try createLoadDylibCommand( | |
| 1690 | self.allocator, | |
| 1691 | dylib_id.name, | |
| 1692 | dylib_id.timestamp, | |
| 1693 | dylib_id.current_version, | |
| 1694 | dylib_id.compatibility_version, | |
| 1695 | ); | |
| 1974 | 1696 | errdefer dylib_cmd.deinit(self.allocator); |
| 1975 | 1697 | try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); |
| 1976 | 1698 | self.next_dylib_ordinal += 1; |
| ... | ... | @@ -1988,8 +1710,8 @@ fn resolveSymbols(self: *Zld) !void { |
| 1988 | 1710 | } |
| 1989 | 1711 | |
| 1990 | 1712 | // Finally put dyld_stub_binder as an Import |
| 1991 | const libsystem_stub = self.lib_stubs.items[self.libsystem_stub_index.?]; | |
| 1992 | const proxy = (try libsystem_stub.createProxy("dyld_stub_binder")) orelse { | |
| 1713 | const libsystem_dylib = self.dylibs.items[self.libsystem_dylib_index.?]; | |
| 1714 | const proxy = (try libsystem_dylib.createProxy("dyld_stub_binder")) orelse { | |
| 1993 | 1715 | log.err("undefined reference to symbol 'dyld_stub_binder'", .{}); |
| 1994 | 1716 | return error.UndefinedSymbolReference; |
| 1995 | 1717 | }; |
| ... | ... | @@ -2004,6 +1726,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 2004 | 1726 | const relocs = sect.relocs orelse continue; |
| 2005 | 1727 | for (relocs) |rel| { |
| 2006 | 1728 | switch (rel.@"type") { |
| 1729 | .unsigned => continue, | |
| 2007 | 1730 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { |
| 2008 | 1731 | const sym = rel.target.symbol.getTopmostAlias(); |
| 2009 | 1732 | if (sym.got_index != null) continue; |
| ... | ... | @@ -2089,29 +1812,52 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 2089 | 1812 | args.source_target_sect_addr = source_sect.inner.addr; |
| 2090 | 1813 | } |
| 2091 | 1814 | |
| 2092 | rebases: { | |
| 2093 | var hit: bool = false; | |
| 2094 | if (target_map.segment_id == self.data_segment_cmd_index.?) { | |
| 2095 | if (self.data_section_index) |index| { | |
| 2096 | if (index == target_map.section_id) hit = true; | |
| 1815 | const flags = @truncate(u8, target_sect.flags & 0xff); | |
| 1816 | const should_rebase = rebase: { | |
| 1817 | if (!unsigned.is_64bit) break :rebase false; | |
| 1818 | ||
| 1819 | // TODO actually, a check similar to what dyld is doing, that is, verifying | |
| 1820 | // that the segment is writable should be enough here. | |
| 1821 | const is_right_segment = blk: { | |
| 1822 | if (self.data_segment_cmd_index) |idx| { | |
| 1823 | if (target_map.segment_id == idx) { | |
| 1824 | break :blk true; | |
| 1825 | } | |
| 1826 | } | |
| 1827 | if (self.data_const_segment_cmd_index) |idx| { | |
| 1828 | if (target_map.segment_id == idx) { | |
| 1829 | break :blk true; | |
| 1830 | } | |
| 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.?) { | |
| 2100 | if (self.data_const_section_index) |index| { | |
| 2101 | if (index == target_map.section_id) hit = true; | |
| 1841 | if (rel.target == .symbol) { | |
| 1842 | const final = rel.target.symbol.getTopmostAlias(); | |
| 1843 | if (final.cast(Symbol.Proxy)) |_| { | |
| 1844 | break :rebase false; | |
| 2102 | 1845 | } |
| 2103 | 1846 | } |
| 2104 | 1847 | |
| 2105 | if (!hit) break :rebases; | |
| 1848 | break :rebase true; | |
| 1849 | }; | |
| 2106 | 1850 | |
| 1851 | if (should_rebase) { | |
| 2107 | 1852 | try self.local_rebases.append(self.allocator, .{ |
| 2108 | 1853 | .offset = source_addr - target_seg.inner.vmaddr, |
| 2109 | 1854 | .segment_id = target_map.segment_id, |
| 2110 | 1855 | }); |
| 2111 | 1856 | } |
| 1857 | ||
| 2112 | 1858 | // TLV is handled via a separate offset mechanism. |
| 2113 | 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 | 1861 | // TODO we don't want to save offset to tlv_bootstrap |
| 2116 | 1862 | if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv; |
| 2117 | 1863 | |
| ... | ... | @@ -2208,7 +1954,13 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T |
| 2208 | 1954 | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2209 | 1955 | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| 2210 | 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 | 1964 | log.err("this is an internal linker error", .{}); |
| 2213 | 1965 | return error.FailedToResolveRelocationTarget; |
| 2214 | 1966 | }; |
| ... | ... | @@ -2240,18 +1992,8 @@ fn populateMetadata(self: *Zld) !void { |
| 2240 | 1992 | if (self.pagezero_segment_cmd_index == null) { |
| 2241 | 1993 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2242 | 1994 | try self.load_commands.append(self.allocator, .{ |
| 2243 | .Segment = SegmentCommand.empty(.{ | |
| 2244 | .cmd = macho.LC_SEGMENT_64, | |
| 2245 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2246 | .segname = makeStaticString("__PAGEZERO"), | |
| 2247 | .vmaddr = 0, | |
| 1995 | .Segment = SegmentCommand.empty("__PAGEZERO", .{ | |
| 2248 | 1996 | .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 | 2001 | if (self.text_segment_cmd_index == null) { |
| 2260 | 2002 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2261 | 2003 | try self.load_commands.append(self.allocator, .{ |
| 2262 | .Segment = SegmentCommand.empty(.{ | |
| 2263 | .cmd = macho.LC_SEGMENT_64, | |
| 2264 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2265 | .segname = makeStaticString("__TEXT"), | |
| 2004 | .Segment = SegmentCommand.empty("__TEXT", .{ | |
| 2266 | 2005 | .vmaddr = 0x100000000, // always starts at 4GB |
| 2267 | .vmsize = 0, | |
| 2268 | .fileoff = 0, | |
| 2269 | .filesize = 0, | |
| 2270 | 2006 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE, |
| 2271 | 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 | 2017 | .aarch64 => 2, |
| 2284 | 2018 | else => unreachable, // unhandled architecture type |
| 2285 | 2019 | }; |
| 2286 | try text_seg.addSection(self.allocator, .{ | |
| 2287 | .sectname = makeStaticString("__text"), | |
| 2288 | .segname = makeStaticString("__TEXT"), | |
| 2289 | .addr = 0, | |
| 2290 | .size = 0, | |
| 2291 | .offset = 0, | |
| 2020 | try text_seg.addSection(self.allocator, "__text", .{ | |
| 2292 | 2021 | .@"align" = alignment, |
| 2293 | .reloff = 0, | |
| 2294 | .nreloc = 0, | |
| 2295 | 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 | } |
| 2301 | 2025 | |
| ... | ... | @@ -2312,19 +2036,10 @@ fn populateMetadata(self: *Zld) !void { |
| 2312 | 2036 | .aarch64 => 3 * @sizeOf(u32), |
| 2313 | 2037 | else => unreachable, // unhandled architecture type |
| 2314 | 2038 | }; |
| 2315 | try text_seg.addSection(self.allocator, .{ | |
| 2316 | .sectname = makeStaticString("__stubs"), | |
| 2317 | .segname = makeStaticString("__TEXT"), | |
| 2318 | .addr = 0, | |
| 2319 | .size = 0, | |
| 2320 | .offset = 0, | |
| 2039 | try text_seg.addSection(self.allocator, "__stubs", .{ | |
| 2321 | 2040 | .@"align" = alignment, |
| 2322 | .reloff = 0, | |
| 2323 | .nreloc = 0, | |
| 2324 | 2041 | .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, |
| 2325 | .reserved1 = 0, | |
| 2326 | 2042 | .reserved2 = stub_size, |
| 2327 | .reserved3 = 0, | |
| 2328 | 2043 | }); |
| 2329 | 2044 | } |
| 2330 | 2045 | |
| ... | ... | @@ -2341,37 +2056,19 @@ fn populateMetadata(self: *Zld) !void { |
| 2341 | 2056 | .aarch64 => 6 * @sizeOf(u32), |
| 2342 | 2057 | else => unreachable, |
| 2343 | 2058 | }; |
| 2344 | try text_seg.addSection(self.allocator, .{ | |
| 2345 | .sectname = makeStaticString("__stub_helper"), | |
| 2346 | .segname = makeStaticString("__TEXT"), | |
| 2347 | .addr = 0, | |
| 2059 | try text_seg.addSection(self.allocator, "__stub_helper", .{ | |
| 2348 | 2060 | .size = stub_helper_size, |
| 2349 | .offset = 0, | |
| 2350 | 2061 | .@"align" = alignment, |
| 2351 | .reloff = 0, | |
| 2352 | .nreloc = 0, | |
| 2353 | 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 | } |
| 2359 | 2065 | |
| 2360 | 2066 | if (self.data_const_segment_cmd_index == null) { |
| 2361 | 2067 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2362 | 2068 | try self.load_commands.append(self.allocator, .{ |
| 2363 | .Segment = SegmentCommand.empty(.{ | |
| 2364 | .cmd = macho.LC_SEGMENT_64, | |
| 2365 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2366 | .segname = makeStaticString("__DATA_CONST"), | |
| 2367 | .vmaddr = 0, | |
| 2368 | .vmsize = 0, | |
| 2369 | .fileoff = 0, | |
| 2370 | .filesize = 0, | |
| 2069 | .Segment = SegmentCommand.empty("__DATA_CONST", .{ | |
| 2371 | 2070 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| 2372 | 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 | 2076 | if (self.got_section_index == null) { |
| 2380 | 2077 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2381 | 2078 | self.got_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 2382 | try data_const_seg.addSection(self.allocator, .{ | |
| 2383 | .sectname = makeStaticString("__got"), | |
| 2384 | .segname = makeStaticString("__DATA_CONST"), | |
| 2385 | .addr = 0, | |
| 2386 | .size = 0, | |
| 2387 | .offset = 0, | |
| 2079 | try data_const_seg.addSection(self.allocator, "__got", .{ | |
| 2388 | 2080 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 2389 | .reloff = 0, | |
| 2390 | .nreloc = 0, | |
| 2391 | 2081 | .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, |
| 2392 | .reserved1 = 0, | |
| 2393 | .reserved2 = 0, | |
| 2394 | .reserved3 = 0, | |
| 2395 | 2082 | }); |
| 2396 | 2083 | } |
| 2397 | 2084 | |
| 2398 | 2085 | if (self.data_segment_cmd_index == null) { |
| 2399 | 2086 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2400 | 2087 | try self.load_commands.append(self.allocator, .{ |
| 2401 | .Segment = SegmentCommand.empty(.{ | |
| 2402 | .cmd = macho.LC_SEGMENT_64, | |
| 2403 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2404 | .segname = makeStaticString("__DATA"), | |
| 2405 | .vmaddr = 0, | |
| 2406 | .vmsize = 0, | |
| 2407 | .fileoff = 0, | |
| 2408 | .filesize = 0, | |
| 2088 | .Segment = SegmentCommand.empty("__DATA", .{ | |
| 2409 | 2089 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| 2410 | 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 | 2095 | if (self.la_symbol_ptr_section_index == null) { |
| 2418 | 2096 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2419 | 2097 | self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len); |
| 2420 | try data_seg.addSection(self.allocator, .{ | |
| 2421 | .sectname = makeStaticString("__la_symbol_ptr"), | |
| 2422 | .segname = makeStaticString("__DATA"), | |
| 2423 | .addr = 0, | |
| 2424 | .size = 0, | |
| 2425 | .offset = 0, | |
| 2098 | try data_seg.addSection(self.allocator, "__la_symbol_ptr", .{ | |
| 2426 | 2099 | .@"align" = 3, // 2^3 = @sizeOf(u64) |
| 2427 | .reloff = 0, | |
| 2428 | .nreloc = 0, | |
| 2429 | 2100 | .flags = macho.S_LAZY_SYMBOL_POINTERS, |
| 2430 | .reserved1 = 0, | |
| 2431 | .reserved2 = 0, | |
| 2432 | .reserved3 = 0, | |
| 2433 | 2101 | }); |
| 2434 | 2102 | } |
| 2435 | 2103 | |
| 2436 | 2104 | if (self.data_section_index == null) { |
| 2437 | 2105 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2438 | 2106 | self.data_section_index = @intCast(u16, data_seg.sections.items.len); |
| 2439 | try data_seg.addSection(self.allocator, .{ | |
| 2440 | .sectname = makeStaticString("__data"), | |
| 2441 | .segname = makeStaticString("__DATA"), | |
| 2442 | .addr = 0, | |
| 2443 | .size = 0, | |
| 2444 | .offset = 0, | |
| 2107 | try data_seg.addSection(self.allocator, "__data", .{ | |
| 2445 | 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 | } |
| 2454 | 2111 | |
| 2455 | 2112 | if (self.linkedit_segment_cmd_index == null) { |
| 2456 | 2113 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2457 | 2114 | try self.load_commands.append(self.allocator, .{ |
| 2458 | .Segment = SegmentCommand.empty(.{ | |
| 2459 | .cmd = macho.LC_SEGMENT_64, | |
| 2460 | .cmdsize = @sizeOf(macho.segment_command_64), | |
| 2461 | .segname = makeStaticString("__LINKEDIT"), | |
| 2462 | .vmaddr = 0, | |
| 2463 | .vmsize = 0, | |
| 2464 | .fileoff = 0, | |
| 2465 | .filesize = 0, | |
| 2115 | .Segment = SegmentCommand.empty("__LINKEDIT", .{ | |
| 2466 | 2116 | .maxprot = macho.VM_PROT_READ, |
| 2467 | 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 | 2233 | std.crypto.random.bytes(&uuid_cmd.uuid); |
| 2586 | 2234 | try self.load_commands.append(self.allocator, .{ .Uuid = uuid_cmd }); |
| 2587 | 2235 | } |
| 2236 | } | |
| 2588 | 2237 | |
| 2589 | if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) { | |
| 2590 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 2238 | fn addDataInCodeLC(self: *Zld) !void { | |
| 2239 | if (self.data_in_code_cmd_index == null) { | |
| 2240 | self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 2591 | 2241 | try self.load_commands.append(self.allocator, .{ |
| 2592 | 2242 | .LinkeditData = .{ |
| 2593 | .cmd = macho.LC_CODE_SIGNATURE, | |
| 2243 | .cmd = macho.LC_DATA_IN_CODE, | |
| 2594 | 2244 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 2595 | 2245 | .dataoff = 0, |
| 2596 | 2246 | .datasize = 0, |
| 2597 | 2247 | }, |
| 2598 | 2248 | }); |
| 2599 | 2249 | } |
| 2250 | } | |
| 2600 | 2251 | |
| 2601 | if (self.data_in_code_cmd_index == null and self.arch.? == .x86_64) { | |
| 2602 | self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 2252 | fn addCodeSignatureLC(self: *Zld) !void { | |
| 2253 | if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) { | |
| 2254 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 2603 | 2255 | try self.load_commands.append(self.allocator, .{ |
| 2604 | 2256 | .LinkeditData = .{ |
| 2605 | .cmd = macho.LC_DATA_IN_CODE, | |
| 2257 | .cmd = macho.LC_CODE_SIGNATURE, | |
| 2606 | 2258 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 2607 | 2259 | .dataoff = 0, |
| 2608 | 2260 | .datasize = 0, |
| ... | ... | @@ -2698,9 +2350,7 @@ fn flush(self: *Zld) !void { |
| 2698 | 2350 | try self.writeBindInfoTable(); |
| 2699 | 2351 | try self.writeLazyBindInfoTable(); |
| 2700 | 2352 | try self.writeExportInfo(); |
| 2701 | if (self.arch.? == .x86_64) { | |
| 2702 | try self.writeDataInCode(); | |
| 2703 | } | |
| 2353 | try self.writeDataInCode(); | |
| 2704 | 2354 | |
| 2705 | 2355 | { |
| 2706 | 2356 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| ... | ... | @@ -2862,6 +2512,20 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2862 | 2512 | } |
| 2863 | 2513 | } |
| 2864 | 2514 | |
| 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 | 2529 | if (self.tlv_section_index) |idx| { |
| 2866 | 2530 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2867 | 2531 | const sect = seg.sections.items[idx]; |
| ... | ... | @@ -3469,13 +3133,6 @@ fn writeHeader(self: *Zld) !void { |
| 3469 | 3133 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); |
| 3470 | 3134 | } |
| 3471 | 3135 | |
| 3472 | pub 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 | ||
| 3479 | 3136 | fn makeString(self: *Zld, bytes: []const u8) !u32 { |
| 3480 | 3137 | if (self.strtab_dir.get(bytes)) |offset| { |
| 3481 | 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 | 9 | |
| 10 | 10 | const Allocator = std.mem.Allocator; |
| 11 | 11 | const MachO = @import("../MachO.zig"); |
| 12 | const makeStaticString = MachO.makeStaticString; | |
| 13 | 12 | const padToIdeal = MachO.padToIdeal; |
| 14 | 13 | |
| 15 | 14 | pub const LoadCommand = union(enum) { |
| ... | ... | @@ -187,11 +186,70 @@ pub const SegmentCommand = struct { |
| 187 | 186 | inner: macho.segment_command_64, |
| 188 | 187 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, |
| 189 | 188 | |
| 190 | pub fn empty(inner: macho.segment_command_64) SegmentCommand { | |
| 191 | return .{ .inner = inner }; | |
| 189 | const SegmentOptions = struct { | |
| 190 | cmdsize: u32 = @sizeOf(macho.segment_command_64), | |
| 191 | vmaddr: u64 = 0, | |
| 192 | vmsize: u64 = 0, | |
| 193 | fileoff: u64 = 0, | |
| 194 | filesize: u64 = 0, | |
| 195 | maxprot: macho.vm_prot_t = macho.VM_PROT_NONE, | |
| 196 | initprot: macho.vm_prot_t = macho.VM_PROT_NONE, | |
| 197 | nsects: u32 = 0, | |
| 198 | flags: u32 = 0, | |
| 199 | }; | |
| 200 | ||
| 201 | pub fn empty(comptime segname: []const u8, opts: SegmentOptions) SegmentCommand { | |
| 202 | return .{ | |
| 203 | .inner = .{ | |
| 204 | .cmd = macho.LC_SEGMENT_64, | |
| 205 | .cmdsize = opts.cmdsize, | |
| 206 | .segname = makeStaticString(segname), | |
| 207 | .vmaddr = opts.vmaddr, | |
| 208 | .vmsize = opts.vmsize, | |
| 209 | .fileoff = opts.fileoff, | |
| 210 | .filesize = opts.filesize, | |
| 211 | .maxprot = opts.maxprot, | |
| 212 | .initprot = opts.initprot, | |
| 213 | .nsects = opts.nsects, | |
| 214 | .flags = opts.flags, | |
| 215 | }, | |
| 216 | }; | |
| 192 | 217 | } |
| 193 | 218 | |
| 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 | 253 | try self.sections.append(alloc, section); |
| 196 | 254 | self.inner.cmdsize += @sizeOf(macho.section_64); |
| 197 | 255 | self.inner.nsects += 1; |
| ... | ... | @@ -338,6 +396,13 @@ pub fn createLoadDylibCommand( |
| 338 | 396 | return dylib_cmd; |
| 339 | 397 | } |
| 340 | 398 | |
| 399 | fn 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 | ||
| 341 | 406 | fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void { |
| 342 | 407 | var stream = io.fixedBufferStream(buffer); |
| 343 | 408 | var given = try LoadCommand.read(allocator, stream.reader()); |
src/link/tapi.zig+9-2| ... | ... | @@ -26,6 +26,11 @@ pub const LibStub = struct { |
| 26 | 26 | float: f64, |
| 27 | 27 | int: u64, |
| 28 | 28 | }, |
| 29 | compatibility_version: ?union(enum) { | |
| 30 | string: []const u8, | |
| 31 | float: f64, | |
| 32 | int: u64, | |
| 33 | }, | |
| 29 | 34 | reexported_libraries: ?[]const struct { |
| 30 | 35 | targets: []const []const u8, |
| 31 | 36 | libraries: []const []const u8, |
| ... | ... | @@ -36,11 +41,13 @@ pub const LibStub = struct { |
| 36 | 41 | }, |
| 37 | 42 | exports: ?[]const struct { |
| 38 | 43 | targets: []const []const u8, |
| 39 | symbols: []const []const u8, | |
| 44 | symbols: ?[]const []const u8, | |
| 45 | objc_classes: ?[]const []const u8, | |
| 40 | 46 | }, |
| 41 | 47 | reexports: ?[]const struct { |
| 42 | 48 | targets: []const []const u8, |
| 43 | symbols: []const []const u8, | |
| 49 | symbols: ?[]const []const u8, | |
| 50 | objc_classes: ?[]const []const u8, | |
| 44 | 51 | }, |
| 45 | 52 | allowable_clients: ?[]const struct { |
| 46 | 53 | targets: []const []const u8, |
src/link/tapi/parse.zig+1-6| ... | ... | @@ -42,7 +42,7 @@ pub const Node = struct { |
| 42 | 42 | .doc => @fieldParentPtr(Node.Doc, "base", self).deinit(allocator), |
| 43 | 43 | .map => @fieldParentPtr(Node.Map, "base", self).deinit(allocator), |
| 44 | 44 | .list => @fieldParentPtr(Node.List, "base", self).deinit(allocator), |
| 45 | .value => @fieldParentPtr(Node.Value, "base", self).deinit(allocator), | |
| 45 | .value => {}, | |
| 46 | 46 | } |
| 47 | 47 | } |
| 48 | 48 | |
| ... | ... | @@ -180,11 +180,6 @@ pub const Node = struct { |
| 180 | 180 | |
| 181 | 181 | pub const base_tag: Node.Tag = .value; |
| 182 | 182 | |
| 183 | pub fn deinit(self: *Value, allocator: *Allocator) void { | |
| 184 | _ = self; | |
| 185 | _ = allocator; | |
| 186 | } | |
| 187 | ||
| 188 | 183 | pub fn format( |
| 189 | 184 | self: *const Value, |
| 190 | 185 | comptime fmt: []const u8, |
src/main.zig+3-2| ... | ... | @@ -290,6 +290,7 @@ const usage_build_generic = |
| 290 | 290 | \\ .c C source code (requires LLVM extensions) |
| 291 | 291 | \\ .cpp C++ source code (requires LLVM extensions) |
| 292 | 292 | \\ Other C++ extensions: .C .cc .cxx |
| 293 | \\ .m Objective-C source code (requires LLVM extensions) | |
| 293 | 294 | \\ |
| 294 | 295 | \\General Options: |
| 295 | 296 | \\ -h, --help Print this help and exit |
| ... | ... | @@ -1072,7 +1073,7 @@ fn buildOutputType( |
| 1072 | 1073 | .object, .static_library, .shared_library => { |
| 1073 | 1074 | try link_objects.append(arg); |
| 1074 | 1075 | }, |
| 1075 | .assembly, .c, .cpp, .h, .ll, .bc => { | |
| 1076 | .assembly, .c, .cpp, .h, .ll, .bc, .m => { | |
| 1076 | 1077 | try c_source_files.append(.{ |
| 1077 | 1078 | .src_path = arg, |
| 1078 | 1079 | .extra_flags = try arena.dupe([]const u8, extra_cflags.items), |
| ... | ... | @@ -1135,7 +1136,7 @@ fn buildOutputType( |
| 1135 | 1136 | .positional => { |
| 1136 | 1137 | const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg)); |
| 1137 | 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 | 1140 | .unknown, .shared_library, .object, .static_library => { |
| 1140 | 1141 | try link_objects.append(it.only_arg); |
| 1141 | 1142 | }, |