| author | |
| committer | |
| log | bb62d5105ca02a8b1c959ccf79b9f2861505a150 |
| tree | d033a5e45e7d79982e7075d8ade9cecf50c8ad06 |
| parent | f211c1559ab8c25a52d45e495ef42d4937e98e97 |
| parent | 22b39f034b495176784f7ca295cf61c285958abe |
| signature |
macho+zld: write code signature padding before committing load commands6 files changed, 262 insertions(+), 50 deletions(-)
lib/std/build/CheckObjectStep.zig+102-9| ... | @@ -126,22 +126,28 @@ const Action = struct { | ... | @@ -126,22 +126,28 @@ const Action = struct { |
| 126 | /// its reduced, computed value compares using `op` with the expected value, either | 126 | /// its reduced, computed value compares using `op` with the expected value, either |
| 127 | /// a literal or another extracted variable. | 127 | /// a literal or another extracted variable. |
| 128 | fn computeCmp(act: Action, gpa: Allocator, global_vars: anytype) !bool { | 128 | fn computeCmp(act: Action, gpa: Allocator, global_vars: anytype) !bool { |
| 129 | var op_stack = std.ArrayList(enum { add }).init(gpa); | 129 | var op_stack = std.ArrayList(enum { add, sub, mod }).init(gpa); |
| 130 | var values = std.ArrayList(u64).init(gpa); | 130 | var values = std.ArrayList(u64).init(gpa); |
| 131 | 131 | ||
| 132 | var it = mem.tokenize(u8, act.phrase, " "); | 132 | var it = mem.tokenize(u8, act.phrase, " "); |
| 133 | while (it.next()) |next| { | 133 | while (it.next()) |next| { |
| 134 | if (mem.eql(u8, next, "+")) { | 134 | if (mem.eql(u8, next, "+")) { |
| 135 | try op_stack.append(.add); | 135 | try op_stack.append(.add); |
| 136 | } else if (mem.eql(u8, next, "-")) { | ||
| 137 | try op_stack.append(.sub); | ||
| 138 | } else if (mem.eql(u8, next, "%")) { | ||
| 139 | try op_stack.append(.mod); | ||
| 136 | } else { | 140 | } else { |
| 137 | const val = global_vars.get(next) orelse { | 141 | const val = std.fmt.parseInt(u64, next, 0) catch blk: { |
| 138 | std.debug.print( | 142 | break :blk global_vars.get(next) orelse { |
| 139 | \\ | 143 | std.debug.print( |
| 140 | \\========= Variable was not extracted: =========== | 144 | \\ |
| 141 | \\{s} | 145 | \\========= Variable was not extracted: =========== |
| 142 | \\ | 146 | \\{s} |
| 143 | , .{next}); | 147 | \\ |
| 144 | return error.UnknownVariable; | 148 | , .{next}); |
| 149 | return error.UnknownVariable; | ||
| 150 | }; | ||
| 145 | }; | 151 | }; |
| 146 | try values.append(val); | 152 | try values.append(val); |
| 147 | } | 153 | } |
| ... | @@ -155,7 +161,14 @@ const Action = struct { | ... | @@ -155,7 +161,14 @@ const Action = struct { |
| 155 | .add => { | 161 | .add => { |
| 156 | reduced += other; | 162 | reduced += other; |
| 157 | }, | 163 | }, |
| 164 | .sub => { | ||
| 165 | reduced -= other; | ||
| 166 | }, | ||
| 167 | .mod => { | ||
| 168 | reduced %= other; | ||
| 169 | }, | ||
| 158 | } | 170 | } |
| 171 | op_i += 1; | ||
| 159 | } | 172 | } |
| 160 | 173 | ||
| 161 | const exp_value = switch (act.expected.?.value) { | 174 | const exp_value = switch (act.expected.?.value) { |
| ... | @@ -577,6 +590,86 @@ const MachODumper = struct { | ... | @@ -577,6 +590,86 @@ const MachODumper = struct { |
| 577 | try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)}); | 590 | try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)}); |
| 578 | }, | 591 | }, |
| 579 | 592 | ||
| 593 | .DATA_IN_CODE, | ||
| 594 | .FUNCTION_STARTS, | ||
| 595 | .CODE_SIGNATURE, | ||
| 596 | => { | ||
| 597 | const llc = lc.cast(macho.linkedit_data_command).?; | ||
| 598 | try writer.writeByte('\n'); | ||
| 599 | try writer.print( | ||
| 600 | \\dataoff {x} | ||
| 601 | \\datasize {x} | ||
| 602 | , .{ llc.dataoff, llc.datasize }); | ||
| 603 | }, | ||
| 604 | |||
| 605 | .DYLD_INFO_ONLY => { | ||
| 606 | const dlc = lc.cast(macho.dyld_info_command).?; | ||
| 607 | try writer.writeByte('\n'); | ||
| 608 | try writer.print( | ||
| 609 | \\rebaseoff {x} | ||
| 610 | \\rebasesize {x} | ||
| 611 | \\bindoff {x} | ||
| 612 | \\bindsize {x} | ||
| 613 | \\weakbindoff {x} | ||
| 614 | \\weakbindsize {x} | ||
| 615 | \\lazybindoff {x} | ||
| 616 | \\lazybindsize {x} | ||
| 617 | \\exportoff {x} | ||
| 618 | \\exportsize {x} | ||
| 619 | , .{ | ||
| 620 | dlc.rebase_off, | ||
| 621 | dlc.rebase_size, | ||
| 622 | dlc.bind_off, | ||
| 623 | dlc.bind_size, | ||
| 624 | dlc.weak_bind_off, | ||
| 625 | dlc.weak_bind_size, | ||
| 626 | dlc.lazy_bind_off, | ||
| 627 | dlc.lazy_bind_size, | ||
| 628 | dlc.export_off, | ||
| 629 | dlc.export_size, | ||
| 630 | }); | ||
| 631 | }, | ||
| 632 | |||
| 633 | .SYMTAB => { | ||
| 634 | const slc = lc.cast(macho.symtab_command).?; | ||
| 635 | try writer.writeByte('\n'); | ||
| 636 | try writer.print( | ||
| 637 | \\symoff {x} | ||
| 638 | \\nsyms {x} | ||
| 639 | \\stroff {x} | ||
| 640 | \\strsize {x} | ||
| 641 | , .{ | ||
| 642 | slc.symoff, | ||
| 643 | slc.nsyms, | ||
| 644 | slc.stroff, | ||
| 645 | slc.strsize, | ||
| 646 | }); | ||
| 647 | }, | ||
| 648 | |||
| 649 | .DYSYMTAB => { | ||
| 650 | const dlc = lc.cast(macho.dysymtab_command).?; | ||
| 651 | try writer.writeByte('\n'); | ||
| 652 | try writer.print( | ||
| 653 | \\ilocalsym {x} | ||
| 654 | \\nlocalsym {x} | ||
| 655 | \\iextdefsym {x} | ||
| 656 | \\nextdefsym {x} | ||
| 657 | \\iundefsym {x} | ||
| 658 | \\nundefsym {x} | ||
| 659 | \\indirectsymoff {x} | ||
| 660 | \\nindirectsyms {x} | ||
| 661 | , .{ | ||
| 662 | dlc.ilocalsym, | ||
| 663 | dlc.nlocalsym, | ||
| 664 | dlc.iextdefsym, | ||
| 665 | dlc.nextdefsym, | ||
| 666 | dlc.iundefsym, | ||
| 667 | dlc.nundefsym, | ||
| 668 | dlc.indirectsymoff, | ||
| 669 | dlc.nindirectsyms, | ||
| 670 | }); | ||
| 671 | }, | ||
| 672 | |||
| 580 | else => {}, | 673 | else => {}, |
| 581 | } | 674 | } |
| 582 | } | 675 | } |
src/link/MachO.zig+25-21| ... | @@ -558,6 +558,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -558,6 +558,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 558 | 558 | ||
| 559 | try self.writeLinkeditSegmentData(); | 559 | try self.writeLinkeditSegmentData(); |
| 560 | 560 | ||
| 561 | const target = self.base.options.target; | ||
| 562 | const requires_codesig = blk: { | ||
| 563 | if (self.base.options.entitlements) |_| break :blk true; | ||
| 564 | if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator)) | ||
| 565 | break :blk true; | ||
| 566 | break :blk false; | ||
| 567 | }; | ||
| 568 | var codesig: ?CodeSignature = if (requires_codesig) blk: { | ||
| 569 | // Preallocate space for the code signature. | ||
| 570 | // We need to do this at this stage so that we have the load commands with proper values | ||
| 571 | // written out to the file. | ||
| 572 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment | ||
| 573 | // where the code signature goes into. | ||
| 574 | var codesig = CodeSignature.init(self.page_size); | ||
| 575 | codesig.code_directory.ident = self.base.options.emit.?.sub_path; | ||
| 576 | if (self.base.options.entitlements) |path| { | ||
| 577 | try codesig.addEntitlements(self.base.allocator, path); | ||
| 578 | } | ||
| 579 | try self.writeCodeSignaturePadding(&codesig); | ||
| 580 | break :blk codesig; | ||
| 581 | } else null; | ||
| 582 | defer if (codesig) |*csig| csig.deinit(self.base.allocator); | ||
| 583 | |||
| 561 | // Write load commands | 584 | // Write load commands |
| 562 | var lc_buffer = std.ArrayList(u8).init(arena); | 585 | var lc_buffer = std.ArrayList(u8).init(arena); |
| 563 | const lc_writer = lc_buffer.writer(); | 586 | const lc_writer = lc_buffer.writer(); |
| ... | @@ -606,28 +629,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -606,28 +629,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 606 | 629 | ||
| 607 | try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer); | 630 | try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer); |
| 608 | 631 | ||
| 609 | const target = self.base.options.target; | 632 | if (requires_codesig) { |
| 610 | const requires_codesig = blk: { | ||
| 611 | if (self.base.options.entitlements) |_| break :blk true; | ||
| 612 | if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator)) | ||
| 613 | break :blk true; | ||
| 614 | break :blk false; | ||
| 615 | }; | ||
| 616 | var codesig: ?CodeSignature = if (requires_codesig) blk: { | ||
| 617 | // Preallocate space for the code signature. | ||
| 618 | // We need to do this at this stage so that we have the load commands with proper values | ||
| 619 | // written out to the file. | ||
| 620 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment | ||
| 621 | // where the code signature goes into. | ||
| 622 | var codesig = CodeSignature.init(self.page_size); | ||
| 623 | codesig.code_directory.ident = self.base.options.emit.?.sub_path; | ||
| 624 | if (self.base.options.entitlements) |path| { | ||
| 625 | try codesig.addEntitlements(arena, path); | ||
| 626 | } | ||
| 627 | try self.writeCodeSignaturePadding(&codesig); | ||
| 628 | try lc_writer.writeStruct(self.codesig_cmd); | 633 | try lc_writer.writeStruct(self.codesig_cmd); |
| 629 | break :blk codesig; | 634 | } |
| 630 | } else null; | ||
| 631 | 635 | ||
| 632 | try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); | 636 | try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); |
| 633 | 637 |
src/link/MachO/zld.zig+24-20| ... | @@ -4100,6 +4100,28 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -4100,6 +4100,28 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4100 | } | 4100 | } |
| 4101 | } | 4101 | } |
| 4102 | 4102 | ||
| 4103 | // Write code signature padding if required | ||
| 4104 | const requires_codesig = blk: { | ||
| 4105 | if (options.entitlements) |_| break :blk true; | ||
| 4106 | if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true; | ||
| 4107 | break :blk false; | ||
| 4108 | }; | ||
| 4109 | var codesig: ?CodeSignature = if (requires_codesig) blk: { | ||
| 4110 | // Preallocate space for the code signature. | ||
| 4111 | // We need to do this at this stage so that we have the load commands with proper values | ||
| 4112 | // written out to the file. | ||
| 4113 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment | ||
| 4114 | // where the code signature goes into. | ||
| 4115 | var codesig = CodeSignature.init(page_size); | ||
| 4116 | codesig.code_directory.ident = fs.path.basename(full_out_path); | ||
| 4117 | if (options.entitlements) |path| { | ||
| 4118 | try codesig.addEntitlements(zld.gpa, path); | ||
| 4119 | } | ||
| 4120 | try zld.writeCodeSignaturePadding(&codesig); | ||
| 4121 | break :blk codesig; | ||
| 4122 | } else null; | ||
| 4123 | defer if (codesig) |*csig| csig.deinit(zld.gpa); | ||
| 4124 | |||
| 4103 | // Write load commands | 4125 | // Write load commands |
| 4104 | var lc_buffer = std.ArrayList(u8).init(arena); | 4126 | var lc_buffer = std.ArrayList(u8).init(arena); |
| 4105 | const lc_writer = lc_buffer.writer(); | 4127 | const lc_writer = lc_buffer.writer(); |
| ... | @@ -4142,29 +4164,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -4142,29 +4164,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 4142 | 4164 | ||
| 4143 | try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer); | 4165 | try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer); |
| 4144 | 4166 | ||
| 4145 | const requires_codesig = blk: { | ||
| 4146 | if (options.entitlements) |_| break :blk true; | ||
| 4147 | if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true; | ||
| 4148 | break :blk false; | ||
| 4149 | }; | ||
| 4150 | var codesig_cmd_offset: ?u32 = null; | 4167 | var codesig_cmd_offset: ?u32 = null; |
| 4151 | var codesig: ?CodeSignature = if (requires_codesig) blk: { | 4168 | if (requires_codesig) { |
| 4152 | // Preallocate space for the code signature. | ||
| 4153 | // We need to do this at this stage so that we have the load commands with proper values | ||
| 4154 | // written out to the file. | ||
| 4155 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment | ||
| 4156 | // where the code signature goes into. | ||
| 4157 | var codesig = CodeSignature.init(page_size); | ||
| 4158 | codesig.code_directory.ident = fs.path.basename(full_out_path); | ||
| 4159 | if (options.entitlements) |path| { | ||
| 4160 | try codesig.addEntitlements(gpa, path); | ||
| 4161 | } | ||
| 4162 | try zld.writeCodeSignaturePadding(&codesig); | ||
| 4163 | codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len); | 4169 | codesig_cmd_offset = @sizeOf(macho.mach_header_64) + @intCast(u32, lc_buffer.items.len); |
| 4164 | try lc_writer.writeStruct(zld.codesig_cmd); | 4170 | try lc_writer.writeStruct(zld.codesig_cmd); |
| 4165 | break :blk codesig; | 4171 | } |
| 4166 | } else null; | ||
| 4167 | defer if (codesig) |*csig| csig.deinit(gpa); | ||
| 4168 | 4172 | ||
| 4169 | const ncmds = load_commands.calcNumOfLCs(lc_buffer.items); | 4173 | const ncmds = load_commands.calcNumOfLCs(lc_buffer.items); |
| 4170 | try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); | 4174 | try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64)); |
test/link.zig+5| ... | @@ -165,6 +165,11 @@ fn addMachOCases(cases: *tests.StandaloneContext) void { | ... | @@ -165,6 +165,11 @@ fn addMachOCases(cases: *tests.StandaloneContext) void { |
| 165 | .requires_symlinks = true, | 165 | .requires_symlinks = true, |
| 166 | }); | 166 | }); |
| 167 | 167 | ||
| 168 | cases.addBuildFile("test/link/macho/strict_validation/build.zig", .{ | ||
| 169 | .build_modes = true, | ||
| 170 | .requires_symlinks = true, | ||
| 171 | }); | ||
| 172 | |||
| 168 | cases.addBuildFile("test/link/macho/tls/build.zig", .{ | 173 | cases.addBuildFile("test/link/macho/tls/build.zig", .{ |
| 169 | .build_modes = true, | 174 | .build_modes = true, |
| 170 | .requires_symlinks = true, | 175 | .requires_symlinks = true, |
test/link/macho/strict_validation/build.zig created+100| ... | @@ -0,0 +1,100 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const Builder = std.build.Builder; | ||
| 4 | const LibExeObjectStep = std.build.LibExeObjStep; | ||
| 5 | |||
| 6 | pub fn build(b: *Builder) void { | ||
| 7 | const mode = b.standardReleaseOptions(); | ||
| 8 | const target: std.zig.CrossTarget = .{ .os_tag = .macos }; | ||
| 9 | |||
| 10 | const test_step = b.step("test", "Test"); | ||
| 11 | test_step.dependOn(b.getInstallStep()); | ||
| 12 | |||
| 13 | const exe = b.addExecutable("main", "main.zig"); | ||
| 14 | exe.setBuildMode(mode); | ||
| 15 | exe.setTarget(target); | ||
| 16 | exe.linkLibC(); | ||
| 17 | |||
| 18 | const check_exe = exe.checkObject(.macho); | ||
| 19 | |||
| 20 | check_exe.checkStart("cmd SEGMENT_64"); | ||
| 21 | check_exe.checkNext("segname __LINKEDIT"); | ||
| 22 | check_exe.checkNext("fileoff {fileoff}"); | ||
| 23 | check_exe.checkNext("filesz {filesz}"); | ||
| 24 | |||
| 25 | check_exe.checkStart("cmd DYLD_INFO_ONLY"); | ||
| 26 | check_exe.checkNext("rebaseoff {rebaseoff}"); | ||
| 27 | check_exe.checkNext("rebasesize {rebasesize}"); | ||
| 28 | check_exe.checkNext("bindoff {bindoff}"); | ||
| 29 | check_exe.checkNext("bindsize {bindsize}"); | ||
| 30 | check_exe.checkNext("lazybindoff {lazybindoff}"); | ||
| 31 | check_exe.checkNext("lazybindsize {lazybindsize}"); | ||
| 32 | check_exe.checkNext("exportoff {exportoff}"); | ||
| 33 | check_exe.checkNext("exportsize {exportsize}"); | ||
| 34 | |||
| 35 | check_exe.checkStart("cmd SYMTAB"); | ||
| 36 | check_exe.checkNext("symoff {symoff}"); | ||
| 37 | check_exe.checkNext("stroff {stroff}"); | ||
| 38 | check_exe.checkNext("strsize {strsize}"); | ||
| 39 | |||
| 40 | check_exe.checkStart("cmd DYSYMTAB"); | ||
| 41 | check_exe.checkNext("indirectsymoff {dysymoff}"); | ||
| 42 | |||
| 43 | switch (builtin.cpu.arch) { | ||
| 44 | .aarch64 => { | ||
| 45 | check_exe.checkStart("cmd CODE_SIGNATURE"); | ||
| 46 | check_exe.checkNext("dataoff {codesigoff}"); | ||
| 47 | check_exe.checkNext("datasize {codesigsize}"); | ||
| 48 | }, | ||
| 49 | .x86_64 => {}, | ||
| 50 | else => unreachable, | ||
| 51 | } | ||
| 52 | |||
| 53 | // Next check: DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export | ||
| 54 | check_exe.checkComputeCompare("rebaseoff ", .{ .op = .lt, .value = .{ .variable = "bindoff" } }); | ||
| 55 | check_exe.checkComputeCompare("bindoff", .{ .op = .lt, .value = .{ .variable = "lazybindoff" } }); | ||
| 56 | check_exe.checkComputeCompare("lazybindoff", .{ .op = .lt, .value = .{ .variable = "exportoff" } }); | ||
| 57 | |||
| 58 | // Next check: DYLD_INFO_ONLY subsections do not overlap | ||
| 59 | check_exe.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .lte, .value = .{ .variable = "bindoff" } }); | ||
| 60 | check_exe.checkComputeCompare("bindoff bindsize +", .{ .op = .lte, .value = .{ .variable = "lazybindoff" } }); | ||
| 61 | check_exe.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .lte, .value = .{ .variable = "exportoff" } }); | ||
| 62 | |||
| 63 | // Next check: we maintain order: symtab < dysymtab < strtab | ||
| 64 | check_exe.checkComputeCompare("symoff", .{ .op = .lt, .value = .{ .variable = "dysymoff" } }); | ||
| 65 | check_exe.checkComputeCompare("dysymoff", .{ .op = .lt, .value = .{ .variable = "stroff" } }); | ||
| 66 | |||
| 67 | // Next check: all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned | ||
| 68 | check_exe.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 69 | check_exe.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 70 | check_exe.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 71 | check_exe.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 72 | check_exe.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 73 | check_exe.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 74 | check_exe.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 75 | |||
| 76 | switch (builtin.cpu.arch) { | ||
| 77 | .aarch64 => { | ||
| 78 | // Next check: LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data | ||
| 79 | check_exe.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{ | ||
| 80 | .op = .eq, | ||
| 81 | .value = .{ .literal = 0 }, | ||
| 82 | }); | ||
| 83 | |||
| 84 | // Next check: CODE_SIGNATURE data offset is 16-bytes aligned | ||
| 85 | check_exe.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } }); | ||
| 86 | }, | ||
| 87 | .x86_64 => { | ||
| 88 | // Next check: LINKEDIT segment does not extend beyond, or does not include, strtab data | ||
| 89 | check_exe.checkComputeCompare("fileoff filesz stroff strsize + - -", .{ | ||
| 90 | .op = .eq, | ||
| 91 | .value = .{ .literal = 0 }, | ||
| 92 | }); | ||
| 93 | }, | ||
| 94 | else => unreachable, | ||
| 95 | } | ||
| 96 | |||
| 97 | const run = check_exe.runAndCompare(); | ||
| 98 | run.expectStdOutEqual("Hello!\n"); | ||
| 99 | test_step.dependOn(&run.step); | ||
| 100 | } | ||
test/link/macho/strict_validation/main.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 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 | } | ||