| author | |
| committer | |
| log | 4dc1907a88c950daa8273ed4db1b46f7537e20fc |
| tree | 9d570940f442e5fb4761141349e3ddcbcbb6c174 |
| parent | a25b780aad5df41bc97ce8ffc700917208be820b |
4 files changed, 120 insertions(+), 147 deletions(-)
test/link.zig-4| ... | @@ -135,10 +135,6 @@ pub const cases = [_]Case{ | ... | @@ -135,10 +135,6 @@ pub const cases = [_]Case{ |
| 135 | .build_root = "test/link/macho/stack_size", | 135 | .build_root = "test/link/macho/stack_size", |
| 136 | .import = @import("link/macho/stack_size/build.zig"), | 136 | .import = @import("link/macho/stack_size/build.zig"), |
| 137 | }, | 137 | }, |
| 138 | .{ | ||
| 139 | .build_root = "test/link/macho/strict_validation", | ||
| 140 | .import = @import("link/macho/strict_validation/build.zig"), | ||
| 141 | }, | ||
| 142 | .{ | 138 | .{ |
| 143 | .build_root = "test/link/macho/tbdv3", | 139 | .build_root = "test/link/macho/tbdv3", |
| 144 | .import = @import("link/macho/tbdv3/build.zig"), | 140 | .import = @import("link/macho/tbdv3/build.zig"), |
test/link/macho.zig+120| ... | @@ -23,6 +23,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -23,6 +23,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 23 | macho_step.dependOn(testHelloC(b, .{ .target = default_target })); | 23 | macho_step.dependOn(testHelloC(b, .{ .target = default_target })); |
| 24 | macho_step.dependOn(testHelloZig(b, .{ .target = default_target })); | 24 | macho_step.dependOn(testHelloZig(b, .{ .target = default_target })); |
| 25 | macho_step.dependOn(testLargeBss(b, .{ .target = default_target })); | 25 | macho_step.dependOn(testLargeBss(b, .{ .target = default_target })); |
| 26 | macho_step.dependOn(testLayout(b, .{ .target = default_target })); | ||
| 26 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); | 27 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); |
| 27 | macho_step.dependOn(testRelocatable(b, .{ .target = default_target })); | 28 | macho_step.dependOn(testRelocatable(b, .{ .target = default_target })); |
| 28 | macho_step.dependOn(testRelocatableZig(b, .{ .target = default_target })); | 29 | macho_step.dependOn(testRelocatableZig(b, .{ .target = default_target })); |
| ... | @@ -612,6 +613,125 @@ fn testLargeBss(b: *Build, opts: Options) *Step { | ... | @@ -612,6 +613,125 @@ fn testLargeBss(b: *Build, opts: Options) *Step { |
| 612 | return test_step; | 613 | return test_step; |
| 613 | } | 614 | } |
| 614 | 615 | ||
| 616 | fn testLayout(b: *Build, opts: Options) *Step { | ||
| 617 | const test_step = addTestStep(b, "macho-layout", opts); | ||
| 618 | |||
| 619 | const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = | ||
| 620 | \\#include <stdio.h> | ||
| 621 | \\int main() { | ||
| 622 | \\ printf("Hello world!"); | ||
| 623 | \\ return 0; | ||
| 624 | \\} | ||
| 625 | }); | ||
| 626 | |||
| 627 | const check = exe.checkObject(); | ||
| 628 | check.checkInHeaders(); | ||
| 629 | check.checkExact("cmd SEGMENT_64"); | ||
| 630 | check.checkExact("segname __LINKEDIT"); | ||
| 631 | check.checkExtract("fileoff {fileoff}"); | ||
| 632 | check.checkExtract("filesz {filesz}"); | ||
| 633 | check.checkInHeaders(); | ||
| 634 | check.checkExact("cmd DYLD_INFO_ONLY"); | ||
| 635 | check.checkExtract("rebaseoff {rebaseoff}"); | ||
| 636 | check.checkExtract("rebasesize {rebasesize}"); | ||
| 637 | check.checkExtract("bindoff {bindoff}"); | ||
| 638 | check.checkExtract("bindsize {bindsize}"); | ||
| 639 | check.checkExtract("lazybindoff {lazybindoff}"); | ||
| 640 | check.checkExtract("lazybindsize {lazybindsize}"); | ||
| 641 | check.checkExtract("exportoff {exportoff}"); | ||
| 642 | check.checkExtract("exportsize {exportsize}"); | ||
| 643 | check.checkInHeaders(); | ||
| 644 | check.checkExact("cmd FUNCTION_STARTS"); | ||
| 645 | check.checkExtract("dataoff {fstartoff}"); | ||
| 646 | check.checkExtract("datasize {fstartsize}"); | ||
| 647 | check.checkInHeaders(); | ||
| 648 | check.checkExact("cmd DATA_IN_CODE"); | ||
| 649 | check.checkExtract("dataoff {diceoff}"); | ||
| 650 | check.checkExtract("datasize {dicesize}"); | ||
| 651 | check.checkInHeaders(); | ||
| 652 | check.checkExact("cmd SYMTAB"); | ||
| 653 | check.checkExtract("symoff {symoff}"); | ||
| 654 | check.checkExtract("nsyms {symnsyms}"); | ||
| 655 | check.checkExtract("stroff {stroff}"); | ||
| 656 | check.checkExtract("strsize {strsize}"); | ||
| 657 | check.checkInHeaders(); | ||
| 658 | check.checkExact("cmd DYSYMTAB"); | ||
| 659 | check.checkExtract("indirectsymoff {dysymoff}"); | ||
| 660 | check.checkExtract("nindirectsyms {dysymnsyms}"); | ||
| 661 | |||
| 662 | switch (opts.target.result.cpu.arch) { | ||
| 663 | .aarch64 => { | ||
| 664 | check.checkInHeaders(); | ||
| 665 | check.checkExact("cmd CODE_SIGNATURE"); | ||
| 666 | check.checkExtract("dataoff {codesigoff}"); | ||
| 667 | check.checkExtract("datasize {codesigsize}"); | ||
| 668 | }, | ||
| 669 | .x86_64 => {}, | ||
| 670 | else => unreachable, | ||
| 671 | } | ||
| 672 | |||
| 673 | // DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export, | ||
| 674 | // and there are no gaps between them | ||
| 675 | check.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .eq, .value = .{ .variable = "bindoff" } }); | ||
| 676 | check.checkComputeCompare("bindoff bindsize +", .{ .op = .eq, .value = .{ .variable = "lazybindoff" } }); | ||
| 677 | check.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .eq, .value = .{ .variable = "exportoff" } }); | ||
| 678 | |||
| 679 | // FUNCTION_STARTS directly follows DYLD_INFO_ONLY (no gap) | ||
| 680 | check.checkComputeCompare("exportoff exportsize +", .{ .op = .eq, .value = .{ .variable = "fstartoff" } }); | ||
| 681 | |||
| 682 | // DATA_IN_CODE directly follows FUNCTION_STARTS (no gap) | ||
| 683 | check.checkComputeCompare("fstartoff fstartsize +", .{ .op = .eq, .value = .{ .variable = "diceoff" } }); | ||
| 684 | |||
| 685 | // SYMTAB directly follows DATA_IN_CODE (no gap) | ||
| 686 | check.checkComputeCompare("diceoff dicesize +", .{ .op = .eq, .value = .{ .variable = "symoff" } }); | ||
| 687 | |||
| 688 | // DYSYMTAB directly follows SYMTAB (no gap) | ||
| 689 | check.checkComputeCompare("symnsyms 16 symoff * +", .{ .op = .eq, .value = .{ .variable = "dysymoff" } }); | ||
| 690 | |||
| 691 | // STRTAB follows DYSYMTAB with possible gap | ||
| 692 | check.checkComputeCompare("dysymnsyms 4 dysymoff * +", .{ .op = .lte, .value = .{ .variable = "stroff" } }); | ||
| 693 | |||
| 694 | // all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned | ||
| 695 | check.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 696 | check.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 697 | check.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 698 | check.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 699 | check.checkComputeCompare("fstartoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 700 | check.checkComputeCompare("diceoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 701 | check.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 702 | check.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 703 | check.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 704 | |||
| 705 | switch (opts.target.result.cpu.arch) { | ||
| 706 | .aarch64 => { | ||
| 707 | // LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data | ||
| 708 | check.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{ | ||
| 709 | .op = .eq, | ||
| 710 | .value = .{ .literal = 0 }, | ||
| 711 | }); | ||
| 712 | |||
| 713 | // CODE_SIGNATURE data offset is 16-bytes aligned | ||
| 714 | check.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 715 | }, | ||
| 716 | .x86_64 => { | ||
| 717 | // LINKEDIT segment does not extend beyond, or does not include, strtab data | ||
| 718 | check.checkComputeCompare("fileoff filesz stroff strsize + - -", .{ | ||
| 719 | .op = .eq, | ||
| 720 | .value = .{ .literal = 0 }, | ||
| 721 | }); | ||
| 722 | }, | ||
| 723 | else => unreachable, | ||
| 724 | } | ||
| 725 | |||
| 726 | test_step.dependOn(&check.step); | ||
| 727 | |||
| 728 | const run = addRunArtifact(exe); | ||
| 729 | run.expectStdOutEqual("Hello world!"); | ||
| 730 | test_step.dependOn(&run.step); | ||
| 731 | |||
| 732 | return test_step; | ||
| 733 | } | ||
| 734 | |||
| 615 | fn testMhExecuteHeader(b: *Build, opts: Options) *Step { | 735 | fn testMhExecuteHeader(b: *Build, opts: Options) *Step { |
| 616 | const test_step = addTestStep(b, "macho-mh-execute-header", opts); | 736 | const test_step = addTestStep(b, "macho-mh-execute-header", opts); |
| 617 | 737 |
test/link/macho/strict_validation/build.zig deleted-137| ... | @@ -1,137 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | pub const requires_symlinks = true; | ||
| 5 | |||
| 6 | pub fn build(b: *std.Build) void { | ||
| 7 | const test_step = b.step("test", "Test it"); | ||
| 8 | b.default_step = test_step; | ||
| 9 | |||
| 10 | add(b, test_step, .Debug); | ||
| 11 | add(b, test_step, .ReleaseFast); | ||
| 12 | add(b, test_step, .ReleaseSmall); | ||
| 13 | add(b, test_step, .ReleaseSafe); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void { | ||
| 17 | const target = b.resolveTargetQuery(.{ .os_tag = .macos }); | ||
| 18 | |||
| 19 | const exe = b.addExecutable(.{ | ||
| 20 | .name = "main", | ||
| 21 | .root_source_file = .{ .path = "main.zig" }, | ||
| 22 | .optimize = optimize, | ||
| 23 | .target = target, | ||
| 24 | }); | ||
| 25 | exe.linkLibC(); | ||
| 26 | |||
| 27 | const check_exe = exe.checkObject(); | ||
| 28 | |||
| 29 | check_exe.checkInHeaders(); | ||
| 30 | check_exe.checkExact("cmd SEGMENT_64"); | ||
| 31 | check_exe.checkExact("segname __LINKEDIT"); | ||
| 32 | check_exe.checkExtract("fileoff {fileoff}"); | ||
| 33 | check_exe.checkExtract("filesz {filesz}"); | ||
| 34 | |||
| 35 | check_exe.checkInHeaders(); | ||
| 36 | check_exe.checkExact("cmd DYLD_INFO_ONLY"); | ||
| 37 | check_exe.checkExtract("rebaseoff {rebaseoff}"); | ||
| 38 | check_exe.checkExtract("rebasesize {rebasesize}"); | ||
| 39 | check_exe.checkExtract("bindoff {bindoff}"); | ||
| 40 | check_exe.checkExtract("bindsize {bindsize}"); | ||
| 41 | check_exe.checkExtract("lazybindoff {lazybindoff}"); | ||
| 42 | check_exe.checkExtract("lazybindsize {lazybindsize}"); | ||
| 43 | check_exe.checkExtract("exportoff {exportoff}"); | ||
| 44 | check_exe.checkExtract("exportsize {exportsize}"); | ||
| 45 | |||
| 46 | check_exe.checkInHeaders(); | ||
| 47 | check_exe.checkExact("cmd FUNCTION_STARTS"); | ||
| 48 | check_exe.checkExtract("dataoff {fstartoff}"); | ||
| 49 | check_exe.checkExtract("datasize {fstartsize}"); | ||
| 50 | |||
| 51 | check_exe.checkInHeaders(); | ||
| 52 | check_exe.checkExact("cmd DATA_IN_CODE"); | ||
| 53 | check_exe.checkExtract("dataoff {diceoff}"); | ||
| 54 | check_exe.checkExtract("datasize {dicesize}"); | ||
| 55 | |||
| 56 | check_exe.checkInHeaders(); | ||
| 57 | check_exe.checkExact("cmd SYMTAB"); | ||
| 58 | check_exe.checkExtract("symoff {symoff}"); | ||
| 59 | check_exe.checkExtract("nsyms {symnsyms}"); | ||
| 60 | check_exe.checkExtract("stroff {stroff}"); | ||
| 61 | check_exe.checkExtract("strsize {strsize}"); | ||
| 62 | |||
| 63 | check_exe.checkInHeaders(); | ||
| 64 | check_exe.checkExact("cmd DYSYMTAB"); | ||
| 65 | check_exe.checkExtract("indirectsymoff {dysymoff}"); | ||
| 66 | check_exe.checkExtract("nindirectsyms {dysymnsyms}"); | ||
| 67 | |||
| 68 | switch (builtin.cpu.arch) { | ||
| 69 | .aarch64 => { | ||
| 70 | check_exe.checkInHeaders(); | ||
| 71 | check_exe.checkExact("cmd CODE_SIGNATURE"); | ||
| 72 | check_exe.checkExtract("dataoff {codesigoff}"); | ||
| 73 | check_exe.checkExtract("datasize {codesigsize}"); | ||
| 74 | }, | ||
| 75 | .x86_64 => {}, | ||
| 76 | else => unreachable, | ||
| 77 | } | ||
| 78 | |||
| 79 | // DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export, | ||
| 80 | // and there are no gaps between them | ||
| 81 | check_exe.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .eq, .value = .{ .variable = "bindoff" } }); | ||
| 82 | check_exe.checkComputeCompare("bindoff bindsize +", .{ .op = .eq, .value = .{ .variable = "lazybindoff" } }); | ||
| 83 | check_exe.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .eq, .value = .{ .variable = "exportoff" } }); | ||
| 84 | |||
| 85 | // FUNCTION_STARTS directly follows DYLD_INFO_ONLY (no gap) | ||
| 86 | check_exe.checkComputeCompare("exportoff exportsize +", .{ .op = .eq, .value = .{ .variable = "fstartoff" } }); | ||
| 87 | |||
| 88 | // DATA_IN_CODE directly follows FUNCTION_STARTS (no gap) | ||
| 89 | check_exe.checkComputeCompare("fstartoff fstartsize +", .{ .op = .eq, .value = .{ .variable = "diceoff" } }); | ||
| 90 | |||
| 91 | // SYMTAB directly follows DATA_IN_CODE (no gap) | ||
| 92 | check_exe.checkComputeCompare("diceoff dicesize +", .{ .op = .eq, .value = .{ .variable = "symoff" } }); | ||
| 93 | |||
| 94 | // DYSYMTAB directly follows SYMTAB (no gap) | ||
| 95 | check_exe.checkComputeCompare("symnsyms 16 symoff * +", .{ .op = .eq, .value = .{ .variable = "dysymoff" } }); | ||
| 96 | |||
| 97 | // STRTAB follows DYSYMTAB with possible gap | ||
| 98 | check_exe.checkComputeCompare("dysymnsyms 4 dysymoff * +", .{ .op = .lte, .value = .{ .variable = "stroff" } }); | ||
| 99 | |||
| 100 | // all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned | ||
| 101 | check_exe.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 102 | check_exe.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 103 | check_exe.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 104 | check_exe.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 105 | check_exe.checkComputeCompare("fstartoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 106 | check_exe.checkComputeCompare("diceoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 107 | check_exe.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 108 | check_exe.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 109 | check_exe.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 110 | |||
| 111 | switch (builtin.cpu.arch) { | ||
| 112 | .aarch64 => { | ||
| 113 | // LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data | ||
| 114 | check_exe.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{ | ||
| 115 | .op = .eq, | ||
| 116 | .value = .{ .literal = 0 }, | ||
| 117 | }); | ||
| 118 | |||
| 119 | // CODE_SIGNATURE data offset is 16-bytes aligned | ||
| 120 | check_exe.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 121 | }, | ||
| 122 | .x86_64 => { | ||
| 123 | // LINKEDIT segment does not extend beyond, or does not include, strtab data | ||
| 124 | check_exe.checkComputeCompare("fileoff filesz stroff strsize + - -", .{ | ||
| 125 | .op = .eq, | ||
| 126 | .value = .{ .literal = 0 }, | ||
| 127 | }); | ||
| 128 | }, | ||
| 129 | else => unreachable, | ||
| 130 | } | ||
| 131 | test_step.dependOn(&check_exe.step); | ||
| 132 | |||
| 133 | const run = b.addRunArtifact(exe); | ||
| 134 | run.skip_foreign_checks = true; | ||
| 135 | run.expectStdOutEqual("Hello!\n"); | ||
| 136 | test_step.dependOn(&run.step); | ||
| 137 | } | ||
test/link/macho/strict_validation/main.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub fn main() !void { | ||
| 4 | const stdout = std.io.getStdOut().writer(); | ||
| 5 | try stdout.writeAll("Hello!\n"); | ||
| 6 | } | ||