diff options
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/build.zig | 15 | ||||
| -rw-r--r-- | lib/std/build/CheckObjectStep.zig | 219 |
2 files changed, 152 insertions, 82 deletions
diff --git a/lib/std/build.zig b/lib/std/build.zig index 0b49087747..968ee043bf 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1593,6 +1593,14 @@ pub const LibExeObjStep = struct { /// search strategy. search_strategy: ?enum { paths_first, dylibs_first } = null, + /// (Darwin) Set size of the padding between the end of load commands + /// and start of `__TEXT,__text` section. + headerpad_size: ?u32 = null, + + /// (Darwin) Automatically Set size of the padding between the end of load commands + /// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN. + headerpad_max_install_names: bool = false, + /// Position Independent Code force_pic: ?bool = null, @@ -2661,6 +2669,13 @@ pub const LibExeObjStep = struct { .paths_first => try zig_args.append("-search_paths_first"), .dylibs_first => try zig_args.append("-search_dylibs_first"), }; + if (self.headerpad_size) |headerpad_size| { + const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{headerpad_size}); + try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size }); + } + if (self.headerpad_max_install_names) { + try zig_args.append("-headerpad_max_install_names"); + } if (self.bundle_compiler_rt) |x| { if (x) { diff --git a/lib/std/build/CheckObjectStep.zig b/lib/std/build/CheckObjectStep.zig index 65a57f8832..375e183231 100644 --- a/lib/std/build/CheckObjectStep.zig +++ b/lib/std/build/CheckObjectStep.zig @@ -3,6 +3,7 @@ const assert = std.debug.assert; const build = std.build; const fs = std.fs; const macho = std.macho; +const math = std.math; const mem = std.mem; const testing = std.testing; @@ -36,20 +37,24 @@ pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Targe return self; } -const Action = union(enum) { - match: MatchAction, - compute_eq: ComputeEqAction, -}; - -/// MatchAction is the main building block of standard matchers with optional eat-all token `{*}` +/// There two types of actions currently suported: +/// * `.match` - is the main building block of standard matchers with optional eat-all token `{*}` /// and extractors by name such as `{n_value}`. Please note this action is very simplistic in nature /// i.e., it won't really handle edge cases/nontrivial examples. But given that we do want to use /// it mainly to test the output of our object format parser-dumpers when testing the linkers, etc. /// it should be plenty useful in its current form. -const MatchAction = struct { - needle: []const u8, +/// * `.compute_cmp` - can be used to perform an operation on the extracted global variables +/// using the MatchAction. It currently only supports an addition. The operation is required +/// to be specified in Reverse Polish Notation to ease in operator-precedence parsing (well, +/// to avoid any parsing really). +/// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively +/// they could then be added with this simple program `vmaddr entryoff +`. +const Action = struct { + tag: enum { match, compute_cmp }, + phrase: []const u8, + expected: ?ComputeCompareExpected = null, - /// Will return true if the `needle` was found in the `haystack`. + /// Will return true if the `phrase` was found in the `haystack`. /// Some examples include: /// /// LC 0 => will match in its entirety @@ -57,9 +62,11 @@ const MatchAction = struct { /// and save under `vmaddr` global name (see `global_vars` param) /// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib` /// in that order with other letters in between - fn match(act: MatchAction, haystack: []const u8, global_vars: anytype) !bool { + fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool { + assert(act.tag == .match); + var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); - var needle_it = mem.tokenize(u8, mem.trim(u8, act.needle, " "), " "); + var needle_it = mem.tokenize(u8, mem.trim(u8, act.phrase, " "), " "); while (needle_it.next()) |needle_tok| { const hay_tok = hay_it.next() orelse return false; @@ -93,22 +100,80 @@ const MatchAction = struct { return true; } -}; -/// ComputeEqAction can be used to perform an operation on the extracted global variables -/// using the MatchAction. It currently only supports an addition. The operation is required -/// to be specified in Reverse Polish Notation to ease in operator-precedence parsing (well, -/// to avoid any parsing really). -/// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively -/// they could then be added with this simple program `vmaddr entryoff +`. -const ComputeEqAction = struct { - expected: []const u8, - var_stack: std.ArrayList([]const u8), - op_stack: std.ArrayList(Op), + /// Will return true if the `phrase` is correctly parsed into an RPN program and + /// its reduced, computed value compares using `op` with the expected value, either + /// a literal or another extracted variable. + fn computeCmp(act: Action, gpa: Allocator, global_vars: anytype) !bool { + var op_stack = std.ArrayList(enum { add }).init(gpa); + var values = std.ArrayList(u64).init(gpa); + + var it = mem.tokenize(u8, act.phrase, " "); + while (it.next()) |next| { + if (mem.eql(u8, next, "+")) { + try op_stack.append(.add); + } else { + const val = global_vars.get(next) orelse { + std.debug.print( + \\ + \\========= Variable was not extracted: =========== + \\{s} + \\ + , .{next}); + return error.UnknownVariable; + }; + try values.append(val); + } + } - const Op = enum { - add, - }; + var op_i: usize = 1; + var reduced: u64 = values.items[0]; + for (op_stack.items) |op| { + const other = values.items[op_i]; + switch (op) { + .add => { + reduced += other; + }, + } + } + + const exp_value = switch (act.expected.?.value) { + .variable => |name| global_vars.get(name) orelse { + std.debug.print( + \\ + \\========= Variable was not extracted: =========== + \\{s} + \\ + , .{name}); + return error.UnknownVariable; + }, + .literal => |x| x, + }; + return math.compare(reduced, act.expected.?.op, exp_value); + } +}; + +const ComputeCompareExpected = struct { + op: math.CompareOperator, + value: union(enum) { + variable: []const u8, + literal: u64, + }, + + pub fn format( + value: @This(), + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + try writer.print("{s} ", .{@tagName(value.op)}); + switch (value.value) { + .variable => |name| try writer.writeAll(name), + .literal => |x| try writer.print("{x}", .{x}), + } + } }; const Check = struct { @@ -122,15 +187,18 @@ const Check = struct { }; } - fn match(self: *Check, needle: []const u8) void { + fn match(self: *Check, phrase: []const u8) void { self.actions.append(.{ - .match = .{ .needle = self.builder.dupe(needle) }, + .tag = .match, + .phrase = self.builder.dupe(phrase), }) catch unreachable; } - fn computeEq(self: *Check, act: ComputeEqAction) void { + fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void { self.actions.append(.{ - .compute_eq = act, + .tag = .compute_cmp, + .phrase = self.builder.dupe(phrase), + .expected = expected, }) catch unreachable; } }; @@ -165,25 +233,13 @@ pub fn checkInSymtab(self: *CheckObjectStep) void { /// Creates a new standalone, singular check which allows running simple binary operations /// on the extracted variables. It will then compare the reduced program with the value of /// the expected variable. -pub fn checkComputeEq(self: *CheckObjectStep, program: []const u8, expected: []const u8) void { - const gpa = self.builder.allocator; - var ca = ComputeEqAction{ - .expected = expected, - .var_stack = std.ArrayList([]const u8).init(gpa), - .op_stack = std.ArrayList(ComputeEqAction.Op).init(gpa), - }; - - var it = mem.tokenize(u8, program, " "); - while (it.next()) |next| { - if (mem.eql(u8, next, "+")) { - ca.op_stack.append(.add) catch unreachable; - } else { - ca.var_stack.append(self.builder.dupe(next)) catch unreachable; - } - } - +pub fn checkComputeCompare( + self: *CheckObjectStep, + program: []const u8, + expected: ComputeCompareExpected, +) void { var new_check = Check.create(self.builder); - new_check.computeEq(ca); + new_check.computeCmp(program, expected); self.checks.append(new_check) catch unreachable; } @@ -210,10 +266,10 @@ fn make(step: *Step) !void { for (self.checks.items) |chk| { var it = mem.tokenize(u8, output, "\r\n"); for (chk.actions.items) |act| { - switch (act) { - .match => |match_act| { + switch (act.tag) { + .match => { while (it.next()) |line| { - if (try match_act.match(line, &vars)) break; + if (try act.match(line, &vars)) break; } else { std.debug.print( \\ @@ -222,51 +278,33 @@ fn make(step: *Step) !void { \\========= But parsed file does not contain it: ======= \\{s} \\ - , .{ match_act.needle, output }); + , .{ act.phrase, output }); return error.TestFailed; } }, - .compute_eq => |c_eq| { - var values = std.ArrayList(u64).init(gpa); - try values.ensureTotalCapacity(c_eq.var_stack.items.len); - for (c_eq.var_stack.items) |vv| { - const val = vars.get(vv) orelse { + .compute_cmp => { + const res = act.computeCmp(gpa, vars) catch |err| switch (err) { + error.UnknownVariable => { std.debug.print( - \\ - \\========= Variable was not extracted: =========== - \\{s} \\========= From parsed file: ===================== \\{s} \\ - , .{ vv, output }); + , .{output}); return error.TestFailed; - }; - values.appendAssumeCapacity(val); - } - - var op_i: usize = 1; - var reduced: u64 = values.items[0]; - for (c_eq.op_stack.items) |op| { - const other = values.items[op_i]; - switch (op) { - .add => { - reduced += other; - }, - } - } - - const expected = vars.get(c_eq.expected) orelse { + }, + else => |e| return e, + }; + if (!res) { std.debug.print( \\ - \\========= Variable was not extracted: =========== - \\{s} - \\========= From parsed file: ===================== + \\========= Comparison failed for action: =========== + \\{s} {s} + \\========= From parsed file: ======================= \\{s} \\ - , .{ c_eq.expected, output }); + , .{ act.phrase, act.expected.?, output }); return error.TestFailed; - }; - try testing.expectEqual(reduced, expected); + } }, } } @@ -349,6 +387,23 @@ const MachODumper = struct { seg.fileoff, seg.filesize, }); + + for (lc.segment.sections.items) |sect| { + try writer.writeByte('\n'); + try writer.print( + \\sectname {s} + \\addr {x} + \\size {x} + \\offset {x} + \\align {x} + , .{ + sect.sectName(), + sect.addr, + sect.size, + sect.offset, + sect.@"align", + }); + } }, .ID_DYLIB, |
