| author | |
| committer | |
| log | 2cb6db22193acc802ff38f1cc4576ac1ee3f94fa |
| tree | ea09230231a0fe10760b342537f46b024f607d0a |
| parent | 550ebcce9abe9db9453509b38820756a1fff8391 |
Support more operators when running simple arithmetic tests, and
allow for int literals in the program spec.4 files changed, 213 insertions(+), 9 deletions(-)
lib/std/build/CheckObjectStep.zig+102-9| ... | ... | @@ -126,22 +126,28 @@ const Action = struct { |
| 126 | 126 | /// its reduced, computed value compares using `op` with the expected value, either |
| 127 | 127 | /// a literal or another extracted variable. |
| 128 | 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 | 130 | var values = std.ArrayList(u64).init(gpa); |
| 131 | 131 | |
| 132 | 132 | var it = mem.tokenize(u8, act.phrase, " "); |
| 133 | 133 | while (it.next()) |next| { |
| 134 | 134 | if (mem.eql(u8, next, "+")) { |
| 135 | 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 | 140 | } else { |
| 137 | const val = global_vars.get(next) orelse { | |
| 138 | std.debug.print( | |
| 139 | \\ | |
| 140 | \\========= Variable was not extracted: =========== | |
| 141 | \\{s} | |
| 142 | \\ | |
| 143 | , .{next}); | |
| 144 | return error.UnknownVariable; | |
| 141 | const val = std.fmt.parseInt(u64, next, 0) catch blk: { | |
| 142 | break :blk global_vars.get(next) orelse { | |
| 143 | std.debug.print( | |
| 144 | \\ | |
| 145 | \\========= Variable was not extracted: =========== | |
| 146 | \\{s} | |
| 147 | \\ | |
| 148 | , .{next}); | |
| 149 | return error.UnknownVariable; | |
| 150 | }; | |
| 145 | 151 | }; |
| 146 | 152 | try values.append(val); |
| 147 | 153 | } |
| ... | ... | @@ -155,7 +161,14 @@ const Action = struct { |
| 155 | 161 | .add => { |
| 156 | 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 | 174 | const exp_value = switch (act.expected.?.value) { |
| ... | ... | @@ -577,6 +590,86 @@ const MachODumper = struct { |
| 577 | 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 | 673 | else => {}, |
| 581 | 674 | } |
| 582 | 675 | } |
test/link.zig+5| ... | ... | @@ -165,6 +165,11 @@ fn addMachOCases(cases: *tests.StandaloneContext) void { |
| 165 | 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 | 173 | cases.addBuildFile("test/link/macho/tls/build.zig", .{ |
| 169 | 174 | .build_modes = true, |
| 170 | 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 | } |