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