zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 30982e6b (98800B) - Raw


      1 //! Here we test our MachO linker for correctness and functionality.
      2 
      3 pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
      4     const macho_step = b.step("test-macho", "Run MachO tests");
      5 
      6     const x86_64_target = b.resolveTargetQuery(.{
      7         .cpu_arch = .x86_64,
      8         .os_tag = .macos,
      9     });
     10     const aarch64_target = b.resolveTargetQuery(.{
     11         .cpu_arch = .aarch64,
     12         .os_tag = .macos,
     13     });
     14 
     15     const default_target = switch (builtin.cpu.arch) {
     16         .x86_64, .aarch64 => b.resolveTargetQuery(.{
     17             .os_tag = .macos,
     18         }),
     19         else => aarch64_target,
     20     };
     21 
     22     // Exercise linker with self-hosted backend (no LLVM)
     23     macho_step.dependOn(testEmptyZig(b, .{ .use_llvm = false, .target = x86_64_target }));
     24     macho_step.dependOn(testHelloZig(b, .{ .use_llvm = false, .target = x86_64_target }));
     25     macho_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = x86_64_target }));
     26     macho_step.dependOn(testReexportsZig(b, .{ .use_llvm = false, .target = x86_64_target }));
     27     macho_step.dependOn(testRelocatableZig(b, .{ .use_llvm = false, .target = x86_64_target }));
     28     macho_step.dependOn(testTlsZig(b, .{ .use_llvm = false, .target = x86_64_target }));
     29     macho_step.dependOn(testUnresolvedError(b, .{ .use_llvm = false, .target = x86_64_target }));
     30 
     31     // Exercise linker with LLVM backend
     32     macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
     33     macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target }));
     34     macho_step.dependOn(testEmptyObject(b, .{ .target = default_target }));
     35     macho_step.dependOn(testEmptyZig(b, .{ .target = default_target }));
     36     macho_step.dependOn(testEntryPoint(b, .{ .target = default_target }));
     37     macho_step.dependOn(testHeaderWeakFlags(b, .{ .target = default_target }));
     38     macho_step.dependOn(testHelloC(b, .{ .target = default_target }));
     39     macho_step.dependOn(testHelloZig(b, .{ .target = default_target }));
     40     macho_step.dependOn(testLargeBss(b, .{ .target = default_target }));
     41     macho_step.dependOn(testLayout(b, .{ .target = default_target }));
     42     macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target }));
     43     macho_step.dependOn(testLinksection(b, .{ .target = default_target }));
     44     macho_step.dependOn(testMergeLiteralsX64(b, .{ .target = x86_64_target }));
     45     macho_step.dependOn(testMergeLiteralsArm64(b, .{ .target = aarch64_target }));
     46     macho_step.dependOn(testMergeLiteralsArm642(b, .{ .target = aarch64_target }));
     47     macho_step.dependOn(testMergeLiteralsAlignment(b, .{ .target = aarch64_target }));
     48     macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target }));
     49     macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target }));
     50     macho_step.dependOn(testNoExportsDylib(b, .{ .target = default_target }));
     51     macho_step.dependOn(testPagezeroSize(b, .{ .target = default_target }));
     52     macho_step.dependOn(testReexportsZig(b, .{ .target = default_target }));
     53     macho_step.dependOn(testRelocatable(b, .{ .target = default_target }));
     54     macho_step.dependOn(testRelocatableZig(b, .{ .target = default_target }));
     55     macho_step.dependOn(testSectionBoundarySymbols(b, .{ .target = default_target }));
     56     macho_step.dependOn(testSectionBoundarySymbols2(b, .{ .target = default_target }));
     57     macho_step.dependOn(testSegmentBoundarySymbols(b, .{ .target = default_target }));
     58     macho_step.dependOn(testSymbolStabs(b, .{ .target = default_target }));
     59     macho_step.dependOn(testStackSize(b, .{ .target = default_target }));
     60     macho_step.dependOn(testTentative(b, .{ .target = default_target }));
     61     macho_step.dependOn(testThunks(b, .{ .target = aarch64_target }));
     62     macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target }));
     63     macho_step.dependOn(testTlsZig(b, .{ .target = default_target }));
     64     macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target }));
     65     macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target }));
     66     macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));
     67     macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));
     68     macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));
     69     macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));
     70     macho_step.dependOn(testWeakRef(b, .{ .target = b.resolveTargetQuery(.{
     71         .cpu_arch = .x86_64,
     72         .os_tag = .macos,
     73         .os_version_min = .{ .semver = .{ .major = 10, .minor = 13, .patch = 0 } },
     74     }) }));
     75 
     76     // Tests requiring symlinks
     77     if (build_opts.has_symlinks) {
     78         macho_step.dependOn(testEntryPointArchive(b, .{ .target = default_target }));
     79         macho_step.dependOn(testEntryPointDylib(b, .{ .target = default_target }));
     80         macho_step.dependOn(testDylib(b, .{ .target = default_target }));
     81         macho_step.dependOn(testDylibVersionTbd(b, .{ .target = default_target }));
     82         macho_step.dependOn(testNeededLibrary(b, .{ .target = default_target }));
     83         macho_step.dependOn(testSearchStrategy(b, .{ .target = default_target }));
     84         macho_step.dependOn(testTbdv3(b, .{ .target = default_target }));
     85         macho_step.dependOn(testTls(b, .{ .target = default_target }));
     86         macho_step.dependOn(testTlsPointers(b, .{ .target = default_target }));
     87         macho_step.dependOn(testTwoLevelNamespace(b, .{ .target = default_target }));
     88         macho_step.dependOn(testWeakLibrary(b, .{ .target = default_target }));
     89 
     90         // Tests requiring presence of macOS SDK in system path
     91         if (build_opts.has_macos_sdk) {
     92             macho_step.dependOn(testDeadStripDylibs(b, .{ .target = b.graph.host }));
     93             macho_step.dependOn(testHeaderpad(b, .{ .target = b.graph.host }));
     94             macho_step.dependOn(testLinkDirectlyCppTbd(b, .{ .target = b.graph.host }));
     95             macho_step.dependOn(testMergeLiteralsObjc(b, .{ .target = b.graph.host }));
     96             macho_step.dependOn(testNeededFramework(b, .{ .target = b.graph.host }));
     97             macho_step.dependOn(testObjc(b, .{ .target = b.graph.host }));
     98             macho_step.dependOn(testObjcpp(b, .{ .target = b.graph.host }));
     99             macho_step.dependOn(testWeakFramework(b, .{ .target = b.graph.host }));
    100         }
    101     }
    102 
    103     return macho_step;
    104 }
    105 
    106 fn testDeadStrip(b: *Build, opts: Options) *Step {
    107     const test_step = addTestStep(b, "dead-strip", opts);
    108 
    109     const obj = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 
    110     \\#include <stdio.h>
    111     \\int two() { return 2; }
    112     \\int live_var1 = 1;
    113     \\int live_var2 = two();
    114     \\int dead_var1 = 3;
    115     \\int dead_var2 = 4;
    116     \\void live_fn1() {}
    117     \\void live_fn2() { live_fn1(); }
    118     \\void dead_fn1() {}
    119     \\void dead_fn2() { dead_fn1(); }
    120     \\int main() {
    121     \\  printf("%d %d\n", live_var1, live_var2);
    122     \\  live_fn2();
    123     \\}
    124     });
    125 
    126     {
    127         const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
    128         exe.addObject(obj);
    129         exe.link_gc_sections = false;
    130 
    131         const check = exe.checkObject();
    132         check.checkInSymtab();
    133         check.checkContains("live_var1");
    134         check.checkInSymtab();
    135         check.checkContains("live_var2");
    136         check.checkInSymtab();
    137         check.checkContains("dead_var1");
    138         check.checkInSymtab();
    139         check.checkContains("dead_var2");
    140         check.checkInSymtab();
    141         check.checkContains("live_fn1");
    142         check.checkInSymtab();
    143         check.checkContains("live_fn2");
    144         check.checkInSymtab();
    145         check.checkContains("dead_fn1");
    146         check.checkInSymtab();
    147         check.checkContains("dead_fn2");
    148         test_step.dependOn(&check.step);
    149 
    150         const run = addRunArtifact(exe);
    151         run.expectStdOutEqual("1 2\n");
    152         test_step.dependOn(&run.step);
    153     }
    154 
    155     {
    156         const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
    157         exe.addObject(obj);
    158         exe.link_gc_sections = true;
    159 
    160         const check = exe.checkObject();
    161         check.checkInSymtab();
    162         check.checkContains("live_var1");
    163         check.checkInSymtab();
    164         check.checkContains("live_var2");
    165         check.checkInSymtab();
    166         check.checkNotPresent("dead_var1");
    167         check.checkInSymtab();
    168         check.checkNotPresent("dead_var2");
    169         check.checkInSymtab();
    170         check.checkContains("live_fn1");
    171         check.checkInSymtab();
    172         check.checkContains("live_fn2");
    173         check.checkInSymtab();
    174         check.checkNotPresent("dead_fn1");
    175         check.checkInSymtab();
    176         check.checkNotPresent("dead_fn2");
    177         test_step.dependOn(&check.step);
    178 
    179         const run = addRunArtifact(exe);
    180         run.expectStdOutEqual("1 2\n");
    181         test_step.dependOn(&run.step);
    182     }
    183 
    184     return test_step;
    185 }
    186 
    187 fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
    188     const test_step = addTestStep(b, "duplicate-definitions", opts);
    189 
    190     const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 
    191     \\var x: usize = 1;
    192     \\export fn strong() void { x += 1; }
    193     \\export fn weak() void { x += 1; }
    194     });
    195 
    196     const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 
    197     \\var x: usize = 1;
    198     \\export fn strong() void { x += 1; }
    199     \\comptime { @export(weakImpl, .{ .name = "weak", .linkage = .weak }); }
    200     \\fn weakImpl() callconv(.C) void { x += 1; }
    201     \\extern fn weak() void;
    202     \\pub fn main() void {
    203     \\    weak();
    204     \\    strong();
    205     \\}
    206     });
    207     exe.addObject(obj);
    208 
    209     expectLinkErrors(exe, test_step, .{ .exact = &.{
    210         "error: duplicate symbol definition: _strong",
    211         "note: defined by /?/a.o",
    212         "note: defined by /?/main.o",
    213     } });
    214 
    215     return test_step;
    216 }
    217 
    218 fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
    219     const test_step = addTestStep(b, "dead-strip-dylibs", opts);
    220 
    221     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
    222     \\#include <objc/runtime.h>
    223     \\int main() {
    224     \\  if (objc_getClass("NSObject") == 0) {
    225     \\    return -1;
    226     \\  }
    227     \\  if (objc_getClass("NSApplication") == 0) {
    228     \\    return -2;
    229     \\  }
    230     \\  return 0;
    231     \\}
    232     });
    233 
    234     {
    235         const exe = addExecutable(b, opts, .{ .name = "main1" });
    236         exe.addObject(main_o);
    237         exe.root_module.linkFramework("Cocoa", .{});
    238 
    239         const check = exe.checkObject();
    240         check.checkInHeaders();
    241         check.checkExact("cmd LOAD_DYLIB");
    242         check.checkContains("Cocoa");
    243         check.checkInHeaders();
    244         check.checkExact("cmd LOAD_DYLIB");
    245         check.checkContains("libobjc");
    246         test_step.dependOn(&check.step);
    247 
    248         const run = addRunArtifact(exe);
    249         run.expectExitCode(0);
    250         test_step.dependOn(&run.step);
    251     }
    252 
    253     {
    254         const exe = addExecutable(b, opts, .{ .name = "main2" });
    255         exe.addObject(main_o);
    256         exe.root_module.linkFramework("Cocoa", .{});
    257         exe.dead_strip_dylibs = true;
    258 
    259         const run = addRunArtifact(exe);
    260         run.expectExitCode(@as(u8, @bitCast(@as(i8, -2))));
    261         test_step.dependOn(&run.step);
    262     }
    263 
    264     return test_step;
    265 }
    266 
    267 fn testDylib(b: *Build, opts: Options) *Step {
    268     const test_step = addTestStep(b, "dylib", opts);
    269 
    270     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 
    271     \\#include<stdio.h>
    272     \\char world[] = "world";
    273     \\char* hello() {
    274     \\  return "Hello";
    275     \\}
    276     });
    277 
    278     const check = dylib.checkObject();
    279     check.checkInHeaders();
    280     check.checkExact("header");
    281     check.checkNotPresent("PIE");
    282     test_step.dependOn(&check.step);
    283 
    284     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    285     \\#include<stdio.h>
    286     \\char* hello();
    287     \\extern char world[];
    288     \\int main() {
    289     \\  printf("%s %s", hello(), world);
    290     \\  return 0;
    291     \\}
    292     });
    293     exe.root_module.linkSystemLibrary("a", .{});
    294     exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
    295     exe.root_module.addRPath(dylib.getEmittedBinDirectory());
    296 
    297     const run = addRunArtifact(exe);
    298     run.expectStdOutEqual("Hello world");
    299     test_step.dependOn(&run.step);
    300 
    301     return test_step;
    302 }
    303 
    304 fn testDylibVersionTbd(b: *Build, opts: Options) *Step {
    305     const test_step = addTestStep(b, "dylib-version-tbd", opts);
    306 
    307     const tbd = tbd: {
    308         const wf = WriteFile.create(b);
    309         break :tbd wf.add("liba.tbd",
    310             \\--- !tapi-tbd
    311             \\tbd-version:     4
    312             \\targets:         [ x86_64-macos, arm64-macos ]
    313             \\uuids:
    314             \\  - target:          x86_64-macos
    315             \\    value:           DEADBEEF
    316             \\  - target:          arm64-macos
    317             \\    value:           BEEFDEAD
    318             \\install-name:    '@rpath/liba.dylib'
    319             \\current-version: 1.2
    320             \\exports:
    321             \\  - targets:     [ x86_64-macos, arm64-macos ]
    322             \\    symbols:     [ _foo ]
    323         );
    324     };
    325 
    326     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() {}" });
    327     exe.root_module.linkSystemLibrary("a", .{});
    328     exe.root_module.addLibraryPath(tbd.dirname());
    329 
    330     const check = exe.checkObject();
    331     check.checkInHeaders();
    332     check.checkExact("cmd LOAD_DYLIB");
    333     check.checkExact("name @rpath/liba.dylib");
    334     check.checkExact("current version 10200");
    335     test_step.dependOn(&check.step);
    336 
    337     return test_step;
    338 }
    339 
    340 fn testEmptyObject(b: *Build, opts: Options) *Step {
    341     const test_step = addTestStep(b, "empty-object", opts);
    342 
    343     const empty = addObject(b, opts, .{ .name = "empty", .c_source_bytes = "" });
    344 
    345     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    346     \\#include <stdio.h>
    347     \\int main() {
    348     \\  printf("Hello world!");
    349     \\}
    350     });
    351     exe.addObject(empty);
    352 
    353     const run = addRunArtifact(exe);
    354     run.expectStdOutEqual("Hello world!");
    355     test_step.dependOn(&run.step);
    356 
    357     return test_step;
    358 }
    359 
    360 fn testEmptyZig(b: *Build, opts: Options) *Step {
    361     const test_step = addTestStep(b, "empty-zig", opts);
    362 
    363     const exe = addExecutable(b, opts, .{ .name = "empty", .zig_source_bytes = "pub fn main() void {}" });
    364 
    365     const run = addRunArtifact(exe);
    366     run.expectExitCode(0);
    367     test_step.dependOn(&run.step);
    368 
    369     return test_step;
    370 }
    371 
    372 fn testEntryPoint(b: *Build, opts: Options) *Step {
    373     const test_step = addTestStep(b, "entry-point", opts);
    374 
    375     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    376     \\#include<stdio.h>
    377     \\int non_main() {
    378     \\  printf("%d", 42);
    379     \\  return 0;
    380     \\}
    381     });
    382     exe.entry = .{ .symbol_name = "_non_main" };
    383 
    384     const run = addRunArtifact(exe);
    385     run.expectStdOutEqual("42");
    386     test_step.dependOn(&run.step);
    387 
    388     const check = exe.checkObject();
    389     check.checkInHeaders();
    390     check.checkExact("segname __TEXT");
    391     check.checkExtract("vmaddr {vmaddr}");
    392     check.checkInHeaders();
    393     check.checkExact("cmd MAIN");
    394     check.checkExtract("entryoff {entryoff}");
    395     check.checkInSymtab();
    396     check.checkExtract("{n_value} (__TEXT,__text) external _non_main");
    397     check.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } });
    398     test_step.dependOn(&check.step);
    399 
    400     return test_step;
    401 }
    402 
    403 fn testEntryPointArchive(b: *Build, opts: Options) *Step {
    404     const test_step = addTestStep(b, "entry-point-archive", opts);
    405 
    406     const lib = addStaticLibrary(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
    407 
    408     {
    409         const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "" });
    410         exe.root_module.linkSystemLibrary("main", .{});
    411         exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
    412 
    413         const run = addRunArtifact(exe);
    414         run.expectExitCode(0);
    415         test_step.dependOn(&run.step);
    416     }
    417 
    418     {
    419         const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "" });
    420         exe.root_module.linkSystemLibrary("main", .{});
    421         exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
    422         exe.link_gc_sections = true;
    423 
    424         const run = addRunArtifact(exe);
    425         run.expectExitCode(0);
    426         test_step.dependOn(&run.step);
    427     }
    428 
    429     return test_step;
    430 }
    431 
    432 fn testEntryPointDylib(b: *Build, opts: Options) *Step {
    433     const test_step = addTestStep(b, "entry-point-dylib", opts);
    434 
    435     const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
    436     addCSourceBytes(dylib,
    437         \\extern int my_main();
    438         \\int bootstrap() {
    439         \\  return my_main();
    440         \\}
    441     , &.{});
    442     dylib.linker_allow_shlib_undefined = true;
    443 
    444     const exe = addExecutable(b, opts, .{ .name = "main" });
    445     addCSourceBytes(dylib,
    446         \\#include<stdio.h>
    447         \\int my_main() {
    448         \\  fprintf(stdout, "Hello!\n");
    449         \\  return 0;
    450         \\}
    451     , &.{});
    452     exe.linkLibrary(dylib);
    453     exe.entry = .{ .symbol_name = "_bootstrap" };
    454     exe.forceUndefinedSymbol("_my_main");
    455 
    456     const check = exe.checkObject();
    457     check.checkInHeaders();
    458     check.checkExact("segname __TEXT");
    459     check.checkExtract("vmaddr {text_vmaddr}");
    460     check.checkInHeaders();
    461     check.checkExact("sectname __stubs");
    462     check.checkExtract("addr {stubs_vmaddr}");
    463     check.checkInHeaders();
    464     check.checkExact("sectname __stubs");
    465     check.checkExtract("size {stubs_vmsize}");
    466     check.checkInHeaders();
    467     check.checkExact("cmd MAIN");
    468     check.checkExtract("entryoff {entryoff}");
    469     check.checkComputeCompare("text_vmaddr entryoff +", .{
    470         .op = .gte,
    471         .value = .{ .variable = "stubs_vmaddr" }, // The entrypoint should be a synthetic stub
    472     });
    473     check.checkComputeCompare("text_vmaddr entryoff + stubs_vmaddr -", .{
    474         .op = .lt,
    475         .value = .{ .variable = "stubs_vmsize" }, // The entrypoint should be a synthetic stub
    476     });
    477     test_step.dependOn(&check.step);
    478 
    479     const run = addRunArtifact(exe);
    480     run.expectStdOutEqual("Hello!\n");
    481     test_step.dependOn(&run.step);
    482 
    483     return test_step;
    484 }
    485 
    486 fn testHeaderpad(b: *Build, opts: Options) *Step {
    487     const test_step = addTestStep(b, "headerpad", opts);
    488 
    489     const addExe = struct {
    490         fn addExe(bb: *Build, o: Options, name: []const u8) *Compile {
    491             const exe = addExecutable(bb, o, .{
    492                 .name = name,
    493                 .c_source_bytes = "int main() { return 0; }",
    494             });
    495             exe.root_module.linkFramework("CoreFoundation", .{});
    496             exe.root_module.linkFramework("Foundation", .{});
    497             exe.root_module.linkFramework("Cocoa", .{});
    498             exe.root_module.linkFramework("CoreGraphics", .{});
    499             exe.root_module.linkFramework("CoreHaptics", .{});
    500             exe.root_module.linkFramework("CoreAudio", .{});
    501             exe.root_module.linkFramework("AVFoundation", .{});
    502             exe.root_module.linkFramework("CoreImage", .{});
    503             exe.root_module.linkFramework("CoreLocation", .{});
    504             exe.root_module.linkFramework("CoreML", .{});
    505             exe.root_module.linkFramework("CoreVideo", .{});
    506             exe.root_module.linkFramework("CoreText", .{});
    507             exe.root_module.linkFramework("CryptoKit", .{});
    508             exe.root_module.linkFramework("GameKit", .{});
    509             exe.root_module.linkFramework("SwiftUI", .{});
    510             exe.root_module.linkFramework("StoreKit", .{});
    511             exe.root_module.linkFramework("SpriteKit", .{});
    512             return exe;
    513         }
    514     }.addExe;
    515 
    516     {
    517         const exe = addExe(b, opts, "main1");
    518         exe.headerpad_max_install_names = true;
    519 
    520         const check = exe.checkObject();
    521         check.checkInHeaders();
    522         check.checkExact("sectname __text");
    523         check.checkExtract("offset {offset}");
    524         switch (opts.target.result.cpu.arch) {
    525             .aarch64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x4000 } }),
    526             .x86_64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x1000 } }),
    527             else => unreachable,
    528         }
    529         test_step.dependOn(&check.step);
    530 
    531         const run = addRunArtifact(exe);
    532         run.expectExitCode(0);
    533         test_step.dependOn(&run.step);
    534     }
    535 
    536     {
    537         const exe = addExe(b, opts, "main2");
    538         exe.headerpad_size = 0x10000;
    539 
    540         const check = exe.checkObject();
    541         check.checkInHeaders();
    542         check.checkExact("sectname __text");
    543         check.checkExtract("offset {offset}");
    544         check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
    545         test_step.dependOn(&check.step);
    546 
    547         const run = addRunArtifact(exe);
    548         run.expectExitCode(0);
    549         test_step.dependOn(&run.step);
    550     }
    551 
    552     {
    553         const exe = addExe(b, opts, "main3");
    554         exe.headerpad_max_install_names = true;
    555         exe.headerpad_size = 0x10000;
    556 
    557         const check = exe.checkObject();
    558         check.checkInHeaders();
    559         check.checkExact("sectname __text");
    560         check.checkExtract("offset {offset}");
    561         check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
    562         test_step.dependOn(&check.step);
    563 
    564         const run = addRunArtifact(exe);
    565         run.expectExitCode(0);
    566         test_step.dependOn(&run.step);
    567     }
    568 
    569     {
    570         const exe = addExe(b, opts, "main4");
    571         exe.headerpad_max_install_names = true;
    572         exe.headerpad_size = 0x1000;
    573 
    574         const check = exe.checkObject();
    575         check.checkInHeaders();
    576         check.checkExact("sectname __text");
    577         check.checkExtract("offset {offset}");
    578         switch (opts.target.result.cpu.arch) {
    579             .aarch64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x4000 } }),
    580             .x86_64 => check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x1000 } }),
    581             else => unreachable,
    582         }
    583         test_step.dependOn(&check.step);
    584 
    585         const run = addRunArtifact(exe);
    586         run.expectExitCode(0);
    587         test_step.dependOn(&run.step);
    588     }
    589 
    590     return test_step;
    591 }
    592 
    593 // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-header-flags.s
    594 fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
    595     const test_step = addTestStep(b, "header-weak-flags", opts);
    596 
    597     const obj1 = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
    598     \\.globl _x
    599     \\.weak_definition _x
    600     \\_x:
    601     \\ ret
    602     });
    603 
    604     const lib = addSharedLibrary(b, opts, .{ .name = "a" });
    605     lib.addObject(obj1);
    606 
    607     {
    608         const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });
    609         exe.addObject(obj1);
    610 
    611         const check = exe.checkObject();
    612         check.checkInHeaders();
    613         check.checkExact("header");
    614         check.checkContains("WEAK_DEFINES");
    615         check.checkInHeaders();
    616         check.checkExact("header");
    617         check.checkContains("BINDS_TO_WEAK");
    618         check.checkInExports();
    619         check.checkExtract("[WEAK] {vmaddr} _x");
    620         test_step.dependOn(&check.step);
    621     }
    622 
    623     {
    624         const obj = addObject(b, opts, .{ .name = "b" });
    625 
    626         switch (opts.target.result.cpu.arch) {
    627             .aarch64 => addAsmSourceBytes(obj,
    628                 \\.globl _main
    629                 \\_main:
    630                 \\  bl _x
    631                 \\  ret
    632             ),
    633             .x86_64 => addAsmSourceBytes(obj,
    634                 \\.globl _main
    635                 \\_main:
    636                 \\  callq _x
    637                 \\  ret
    638             ),
    639             else => unreachable,
    640         }
    641 
    642         const exe = addExecutable(b, opts, .{ .name = "main2" });
    643         exe.linkLibrary(lib);
    644         exe.addObject(obj);
    645 
    646         const check = exe.checkObject();
    647         check.checkInHeaders();
    648         check.checkExact("header");
    649         check.checkNotPresent("WEAK_DEFINES");
    650         check.checkInHeaders();
    651         check.checkExact("header");
    652         check.checkContains("BINDS_TO_WEAK");
    653         check.checkInExports();
    654         check.checkNotPresent("[WEAK] {vmaddr} _x");
    655         test_step.dependOn(&check.step);
    656     }
    657 
    658     {
    659         const exe = addExecutable(b, opts, .{ .name = "main3", .asm_source_bytes = 
    660         \\.globl _main, _x
    661         \\_x:
    662         \\
    663         \\_main:
    664         \\  ret
    665         });
    666         exe.linkLibrary(lib);
    667 
    668         const check = exe.checkObject();
    669         check.checkInHeaders();
    670         check.checkExact("header");
    671         check.checkNotPresent("WEAK_DEFINES");
    672         check.checkInHeaders();
    673         check.checkExact("header");
    674         check.checkNotPresent("BINDS_TO_WEAK");
    675         test_step.dependOn(&check.step);
    676     }
    677 
    678     return test_step;
    679 }
    680 
    681 fn testHelloC(b: *Build, opts: Options) *Step {
    682     const test_step = addTestStep(b, "hello-c", opts);
    683 
    684     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    685     \\#include <stdio.h>
    686     \\int main() { 
    687     \\  printf("Hello world!\n");
    688     \\  return 0;
    689     \\}
    690     });
    691 
    692     const run = addRunArtifact(exe);
    693     run.expectStdOutEqual("Hello world!\n");
    694     test_step.dependOn(&run.step);
    695 
    696     const check = exe.checkObject();
    697     check.checkInHeaders();
    698     check.checkExact("header");
    699     check.checkContains("PIE");
    700     test_step.dependOn(&check.step);
    701 
    702     return test_step;
    703 }
    704 
    705 fn testHelloZig(b: *Build, opts: Options) *Step {
    706     const test_step = addTestStep(b, "hello-zig", opts);
    707 
    708     const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 
    709     \\const std = @import("std");
    710     \\pub fn main() void {
    711     \\    std.io.getStdOut().writer().print("Hello world!\n", .{}) catch unreachable;
    712     \\}
    713     });
    714 
    715     const run = addRunArtifact(exe);
    716     run.expectStdOutEqual("Hello world!\n");
    717     test_step.dependOn(&run.step);
    718 
    719     return test_step;
    720 }
    721 
    722 fn testLargeBss(b: *Build, opts: Options) *Step {
    723     const test_step = addTestStep(b, "large-bss", opts);
    724 
    725     // TODO this test used use a 4GB zerofill section but this actually fails and causes every
    726     // linker I tried misbehave in different ways. This only happened on arm64. I thought that
    727     // maybe S_GB_ZEROFILL section is an answer to this but it doesn't seem supported by dyld
    728     // anymore. When I get some free time I will re-investigate this.
    729     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    730     \\char arr[0x1000000];
    731     \\int main() {
    732     \\  return arr[2000];
    733     \\}
    734     });
    735 
    736     const run = addRunArtifact(exe);
    737     run.expectExitCode(0);
    738     test_step.dependOn(&run.step);
    739 
    740     return test_step;
    741 }
    742 
    743 fn testLayout(b: *Build, opts: Options) *Step {
    744     const test_step = addTestStep(b, "layout", opts);
    745 
    746     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
    747     \\#include <stdio.h>
    748     \\int main() {
    749     \\  printf("Hello world!");
    750     \\  return 0;
    751     \\}
    752     });
    753 
    754     const check = exe.checkObject();
    755     check.checkInHeaders();
    756     check.checkExact("cmd SEGMENT_64");
    757     check.checkExact("segname __LINKEDIT");
    758     check.checkExtract("fileoff {fileoff}");
    759     check.checkExtract("filesz {filesz}");
    760     check.checkInHeaders();
    761     check.checkExact("cmd DYLD_INFO_ONLY");
    762     check.checkExtract("rebaseoff {rebaseoff}");
    763     check.checkExtract("rebasesize {rebasesize}");
    764     check.checkExtract("bindoff {bindoff}");
    765     check.checkExtract("bindsize {bindsize}");
    766     check.checkExtract("lazybindoff {lazybindoff}");
    767     check.checkExtract("lazybindsize {lazybindsize}");
    768     check.checkExtract("exportoff {exportoff}");
    769     check.checkExtract("exportsize {exportsize}");
    770     check.checkInHeaders();
    771     check.checkExact("cmd FUNCTION_STARTS");
    772     check.checkExtract("dataoff {fstartoff}");
    773     check.checkExtract("datasize {fstartsize}");
    774     check.checkInHeaders();
    775     check.checkExact("cmd DATA_IN_CODE");
    776     check.checkExtract("dataoff {diceoff}");
    777     check.checkExtract("datasize {dicesize}");
    778     check.checkInHeaders();
    779     check.checkExact("cmd SYMTAB");
    780     check.checkExtract("symoff {symoff}");
    781     check.checkExtract("nsyms {symnsyms}");
    782     check.checkExtract("stroff {stroff}");
    783     check.checkExtract("strsize {strsize}");
    784     check.checkInHeaders();
    785     check.checkExact("cmd DYSYMTAB");
    786     check.checkExtract("indirectsymoff {dysymoff}");
    787     check.checkExtract("nindirectsyms {dysymnsyms}");
    788 
    789     switch (opts.target.result.cpu.arch) {
    790         .aarch64 => {
    791             check.checkInHeaders();
    792             check.checkExact("cmd CODE_SIGNATURE");
    793             check.checkExtract("dataoff {codesigoff}");
    794             check.checkExtract("datasize {codesigsize}");
    795         },
    796         .x86_64 => {},
    797         else => unreachable,
    798     }
    799 
    800     // DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export,
    801     // and there are no gaps between them
    802     check.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .eq, .value = .{ .variable = "bindoff" } });
    803     check.checkComputeCompare("bindoff bindsize +", .{ .op = .eq, .value = .{ .variable = "lazybindoff" } });
    804     check.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .eq, .value = .{ .variable = "exportoff" } });
    805 
    806     // FUNCTION_STARTS directly follows DYLD_INFO_ONLY (no gap)
    807     check.checkComputeCompare("exportoff exportsize +", .{ .op = .eq, .value = .{ .variable = "fstartoff" } });
    808 
    809     // DATA_IN_CODE directly follows FUNCTION_STARTS (no gap)
    810     check.checkComputeCompare("fstartoff fstartsize +", .{ .op = .eq, .value = .{ .variable = "diceoff" } });
    811 
    812     // SYMTAB directly follows DATA_IN_CODE (no gap)
    813     check.checkComputeCompare("diceoff dicesize +", .{ .op = .eq, .value = .{ .variable = "symoff" } });
    814 
    815     // DYSYMTAB directly follows SYMTAB (no gap)
    816     check.checkComputeCompare("symnsyms 16 symoff * +", .{ .op = .eq, .value = .{ .variable = "dysymoff" } });
    817 
    818     // STRTAB follows DYSYMTAB with possible gap
    819     check.checkComputeCompare("dysymnsyms 4 dysymoff * +", .{ .op = .lte, .value = .{ .variable = "stroff" } });
    820 
    821     // all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned
    822     check.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    823     check.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    824     check.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    825     check.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    826     check.checkComputeCompare("fstartoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    827     check.checkComputeCompare("diceoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    828     check.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    829     check.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    830     check.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    831 
    832     switch (opts.target.result.cpu.arch) {
    833         .aarch64 => {
    834             // LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data
    835             check.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{
    836                 .op = .eq,
    837                 .value = .{ .literal = 0 },
    838             });
    839 
    840             // CODE_SIGNATURE data offset is 16-bytes aligned
    841             check.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
    842         },
    843         .x86_64 => {
    844             // LINKEDIT segment does not extend beyond, or does not include, strtab data
    845             check.checkComputeCompare("fileoff filesz stroff strsize + - -", .{
    846                 .op = .eq,
    847                 .value = .{ .literal = 0 },
    848             });
    849         },
    850         else => unreachable,
    851     }
    852 
    853     test_step.dependOn(&check.step);
    854 
    855     const run = addRunArtifact(exe);
    856     run.expectStdOutEqual("Hello world!");
    857     test_step.dependOn(&run.step);
    858 
    859     return test_step;
    860 }
    861 
    862 fn testLinkDirectlyCppTbd(b: *Build, opts: Options) *Step {
    863     const test_step = addTestStep(b, "link-directly-cpp-tbd", opts);
    864 
    865     const sdk = std.zig.system.darwin.getSdk(b.allocator, opts.target.result) orelse
    866         @panic("macOS SDK is required to run the test");
    867 
    868     const exe = addExecutable(b, opts, .{
    869         .name = "main",
    870         .cpp_source_bytes =
    871         \\#include <new>
    872         \\#include <cstdio>
    873         \\int main() {
    874         \\    int *x = new int;
    875         \\    *x = 5;
    876         \\    fprintf(stderr, "x: %d\n", *x);
    877         \\    delete x;
    878         \\}
    879         ,
    880         .cpp_source_flags = &.{ "-nostdlib++", "-nostdinc++" },
    881     });
    882     exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) });
    883     exe.root_module.addIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include/c++/v1" }) });
    884     exe.root_module.addObjectFile(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/lib/libc++.tbd" }) });
    885 
    886     const check = exe.checkObject();
    887     check.checkInSymtab();
    888     check.checkContains("[referenced dynamically] external __mh_execute_header");
    889     test_step.dependOn(&check.step);
    890 
    891     return test_step;
    892 }
    893 
    894 fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
    895     const test_step = addTestStep(b, "linking-static-lib", opts);
    896 
    897     const obj = addObject(b, opts, .{
    898         .name = "bobj",
    899         .zig_source_bytes = "export var bar: i32 = -42;",
    900         .strip = true, // TODO for self-hosted, we don't really emit any valid DWARF yet since we only export a global
    901     });
    902 
    903     const lib = addStaticLibrary(b, opts, .{
    904         .name = "alib",
    905         .zig_source_bytes =
    906         \\export fn foo() i32 {
    907         \\    return 42;
    908         \\}
    909         ,
    910     });
    911     lib.addObject(obj);
    912 
    913     const exe = addExecutable(b, opts, .{
    914         .name = "testlib",
    915         .zig_source_bytes =
    916         \\const std = @import("std");
    917         \\extern fn foo() i32;
    918         \\extern var bar: i32;
    919         \\pub fn main() void {
    920         \\    std.debug.print("{d}\n", .{foo() + bar});
    921         \\}
    922         ,
    923     });
    924     exe.linkLibrary(lib);
    925 
    926     const run = addRunArtifact(exe);
    927     run.expectStdErrEqual("0\n");
    928     test_step.dependOn(&run.step);
    929 
    930     return test_step;
    931 }
    932 
    933 fn testLinksection(b: *Build, opts: Options) *Step {
    934     const test_step = addTestStep(b, "linksection", opts);
    935 
    936     const obj = addObject(b, opts, .{ .name = "main", .zig_source_bytes = 
    937     \\export var test_global: u32 linksection("__DATA,__TestGlobal") = undefined;
    938     \\export fn testFn() linksection("__TEXT,__TestFn") callconv(.C) void {
    939     \\    testGenericFn("A");
    940     \\}
    941     \\fn testGenericFn(comptime suffix: []const u8) linksection("__TEXT,__TestGenFn" ++ suffix) void {}
    942     });
    943 
    944     const check = obj.checkObject();
    945     check.checkInSymtab();
    946     check.checkContains("(__DATA,__TestGlobal) external _test_global");
    947     check.checkInSymtab();
    948     check.checkContains("(__TEXT,__TestFn) external _testFn");
    949 
    950     if (opts.optimize == .Debug) {
    951         check.checkInSymtab();
    952         check.checkContains("(__TEXT,__TestGenFnA) _main.testGenericFn__anon_");
    953     }
    954 
    955     test_step.dependOn(&check.step);
    956 
    957     return test_step;
    958 }
    959 
    960 fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
    961     const test_step = addTestStep(b, "merge-literals-x64", opts);
    962 
    963     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
    964     \\.globl _q1
    965     \\.globl _s1
    966     \\
    967     \\.align 4
    968     \\_q1:
    969     \\  lea L._q1(%rip), %rax
    970     \\  mov (%rax), %xmm0
    971     \\  ret
    972     \\ 
    973     \\.section __TEXT,__cstring,cstring_literals
    974     \\l._s1:
    975     \\  .asciz "hello"
    976     \\
    977     \\.section __TEXT,__literal8,8byte_literals
    978     \\.align 8
    979     \\L._q1:
    980     \\  .double 1.2345
    981     \\
    982     \\.section __DATA,__data
    983     \\.align 8
    984     \\_s1:
    985     \\  .quad l._s1
    986     });
    987 
    988     const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 
    989     \\.globl _q2
    990     \\.globl _s2
    991     \\.globl _s3
    992     \\
    993     \\.align 4
    994     \\_q2:
    995     \\  lea L._q2(%rip), %rax
    996     \\  mov (%rax), %xmm0
    997     \\  ret
    998     \\ 
    999     \\.section __TEXT,__cstring,cstring_literals
   1000     \\l._s2:
   1001     \\  .asciz "hello"
   1002     \\l._s3:
   1003     \\  .asciz "world"
   1004     \\
   1005     \\.section __TEXT,__literal8,8byte_literals
   1006     \\.align 8
   1007     \\L._q2:
   1008     \\  .double 1.2345
   1009     \\
   1010     \\.section __DATA,__data
   1011     \\.align 8
   1012     \\_s2:
   1013     \\   .quad l._s2
   1014     \\_s3:
   1015     \\   .quad l._s3
   1016     });
   1017 
   1018     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   1019     \\#include <stdio.h>
   1020     \\extern double q1();
   1021     \\extern double q2();
   1022     \\extern const char* s1;
   1023     \\extern const char* s2;
   1024     \\extern const char* s3;
   1025     \\int main() {
   1026     \\  printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2());
   1027     \\  return 0;
   1028     \\}
   1029     });
   1030 
   1031     const runWithChecks = struct {
   1032         fn runWithChecks(step: *Step, exe: *Compile) void {
   1033             const run = addRunArtifact(exe);
   1034             run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500");
   1035             step.dependOn(&run.step);
   1036 
   1037             const check = exe.checkObject();
   1038             check.dumpSection("__TEXT,__const");
   1039             check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?");
   1040             check.dumpSection("__TEXT,__cstring");
   1041             check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00");
   1042             step.dependOn(&check.step);
   1043         }
   1044     }.runWithChecks;
   1045 
   1046     {
   1047         const exe = addExecutable(b, opts, .{ .name = "main1" });
   1048         exe.addObject(a_o);
   1049         exe.addObject(b_o);
   1050         exe.addObject(main_o);
   1051         runWithChecks(test_step, exe);
   1052     }
   1053 
   1054     {
   1055         const exe = addExecutable(b, opts, .{ .name = "main2" });
   1056         exe.addObject(b_o);
   1057         exe.addObject(a_o);
   1058         exe.addObject(main_o);
   1059         runWithChecks(test_step, exe);
   1060     }
   1061 
   1062     {
   1063         const c_o = addObject(b, opts, .{ .name = "c" });
   1064         c_o.addObject(a_o);
   1065         c_o.addObject(b_o);
   1066         c_o.addObject(main_o);
   1067 
   1068         const exe = addExecutable(b, opts, .{ .name = "main3" });
   1069         exe.addObject(c_o);
   1070         runWithChecks(test_step, exe);
   1071     }
   1072 
   1073     return test_step;
   1074 }
   1075 
   1076 fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
   1077     const test_step = addTestStep(b, "merge-literals-arm64", opts);
   1078 
   1079     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
   1080     \\.globl _q1
   1081     \\.globl _s1
   1082     \\
   1083     \\.align 4
   1084     \\_q1:
   1085     \\  adrp x8, L._q1@PAGE
   1086     \\  ldr d0, [x8, L._q1@PAGEOFF]
   1087     \\  ret
   1088     \\ 
   1089     \\.section __TEXT,__cstring,cstring_literals
   1090     \\l._s1:
   1091     \\  .asciz "hello"
   1092     \\
   1093     \\.section __TEXT,__literal8,8byte_literals
   1094     \\.align 8
   1095     \\L._q1:
   1096     \\  .double 1.2345
   1097     \\
   1098     \\.section __DATA,__data
   1099     \\.align 8
   1100     \\_s1:
   1101     \\  .quad l._s1
   1102     });
   1103 
   1104     const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 
   1105     \\.globl _q2
   1106     \\.globl _s2
   1107     \\.globl _s3
   1108     \\
   1109     \\.align 4
   1110     \\_q2:
   1111     \\  adrp x8, L._q2@PAGE
   1112     \\  ldr d0, [x8, L._q2@PAGEOFF]
   1113     \\  ret
   1114     \\ 
   1115     \\.section __TEXT,__cstring,cstring_literals
   1116     \\l._s2:
   1117     \\  .asciz "hello"
   1118     \\l._s3:
   1119     \\  .asciz "world"
   1120     \\
   1121     \\.section __TEXT,__literal8,8byte_literals
   1122     \\.align 8
   1123     \\L._q2:
   1124     \\  .double 1.2345
   1125     \\
   1126     \\.section __DATA,__data
   1127     \\.align 8
   1128     \\_s2:
   1129     \\   .quad l._s2
   1130     \\_s3:
   1131     \\   .quad l._s3
   1132     });
   1133 
   1134     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   1135     \\#include <stdio.h>
   1136     \\extern double q1();
   1137     \\extern double q2();
   1138     \\extern const char* s1;
   1139     \\extern const char* s2;
   1140     \\extern const char* s3;
   1141     \\int main() {
   1142     \\  printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2());
   1143     \\  return 0;
   1144     \\}
   1145     });
   1146 
   1147     const runWithChecks = struct {
   1148         fn runWithChecks(step: *Step, exe: *Compile) void {
   1149             const run = addRunArtifact(exe);
   1150             run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500");
   1151             step.dependOn(&run.step);
   1152 
   1153             const check = exe.checkObject();
   1154             check.dumpSection("__TEXT,__const");
   1155             check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?");
   1156             check.dumpSection("__TEXT,__cstring");
   1157             check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00");
   1158             step.dependOn(&check.step);
   1159         }
   1160     }.runWithChecks;
   1161 
   1162     {
   1163         const exe = addExecutable(b, opts, .{ .name = "main1" });
   1164         exe.addObject(a_o);
   1165         exe.addObject(b_o);
   1166         exe.addObject(main_o);
   1167         runWithChecks(test_step, exe);
   1168     }
   1169 
   1170     {
   1171         const exe = addExecutable(b, opts, .{ .name = "main2" });
   1172         exe.addObject(b_o);
   1173         exe.addObject(a_o);
   1174         exe.addObject(main_o);
   1175         runWithChecks(test_step, exe);
   1176     }
   1177 
   1178     {
   1179         const c_o = addObject(b, opts, .{ .name = "c" });
   1180         c_o.addObject(a_o);
   1181         c_o.addObject(b_o);
   1182         c_o.addObject(main_o);
   1183 
   1184         const exe = addExecutable(b, opts, .{ .name = "main3" });
   1185         exe.addObject(c_o);
   1186         runWithChecks(test_step, exe);
   1187     }
   1188 
   1189     return test_step;
   1190 }
   1191 
   1192 /// This particular test case will generate invalid machine code that will segfault at runtime.
   1193 /// However, this is by design as we want to test that the linker does not panic when linking it
   1194 /// which is also the case for the system linker and lld - linking succeeds, runtime segfaults.
   1195 /// It should also be mentioned that runtime segfault is not due to the linker but faulty input asm.
   1196 fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
   1197     const test_step = addTestStep(b, "merge-literals-arm64-2", opts);
   1198 
   1199     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
   1200     \\.globl _q1
   1201     \\.globl _s1
   1202     \\
   1203     \\.align 4
   1204     \\_q1:
   1205     \\  adrp x0, L._q1@PAGE
   1206     \\  ldr x0, [x0, L._q1@PAGEOFF]
   1207     \\  ret
   1208     \\ 
   1209     \\.section __TEXT,__cstring,cstring_literals
   1210     \\_s1:
   1211     \\  .asciz "hello"
   1212     \\
   1213     \\.section __TEXT,__literal8,8byte_literals
   1214     \\.align 8
   1215     \\L._q1:
   1216     \\  .double 1.2345
   1217     });
   1218 
   1219     const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 
   1220     \\.globl _q2
   1221     \\.globl _s2
   1222     \\.globl _s3
   1223     \\
   1224     \\.align 4
   1225     \\_q2:
   1226     \\  adrp x0, L._q2@PAGE
   1227     \\  ldr x0, [x0, L._q2@PAGEOFF]
   1228     \\  ret
   1229     \\ 
   1230     \\.section __TEXT,__cstring,cstring_literals
   1231     \\_s2:
   1232     \\  .asciz "hello"
   1233     \\_s3:
   1234     \\  .asciz "world"
   1235     \\
   1236     \\.section __TEXT,__literal8,8byte_literals
   1237     \\.align 8
   1238     \\L._q2:
   1239     \\  .double 1.2345
   1240     });
   1241 
   1242     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   1243     \\#include <stdio.h>
   1244     \\extern double q1();
   1245     \\extern double q2();
   1246     \\extern const char* s1;
   1247     \\extern const char* s2;
   1248     \\extern const char* s3;
   1249     \\int main() {
   1250     \\  printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2());
   1251     \\  return 0;
   1252     \\}
   1253     });
   1254 
   1255     const exe = addExecutable(b, opts, .{ .name = "main1" });
   1256     exe.addObject(a_o);
   1257     exe.addObject(b_o);
   1258     exe.addObject(main_o);
   1259 
   1260     const check = exe.checkObject();
   1261     check.dumpSection("__TEXT,__const");
   1262     check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?");
   1263     check.dumpSection("__TEXT,__cstring");
   1264     check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00");
   1265     test_step.dependOn(&check.step);
   1266 
   1267     return test_step;
   1268 }
   1269 
   1270 fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
   1271     const test_step = addTestStep(b, "merge-literals-alignment", opts);
   1272 
   1273     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
   1274     \\.globl _s1
   1275     \\.globl _s2
   1276     \\
   1277     \\.section __TEXT,__cstring,cstring_literals
   1278     \\.align 3
   1279     \\_s1:
   1280     \\  .asciz "str1"
   1281     \\_s2:
   1282     \\  .asciz "str2"
   1283     });
   1284 
   1285     const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = 
   1286     \\.globl _s3
   1287     \\.globl _s4
   1288     \\
   1289     \\.section __TEXT,__cstring,cstring_literals
   1290     \\.align 2
   1291     \\_s3:
   1292     \\  .asciz "str1"
   1293     \\_s4:
   1294     \\  .asciz "str2"
   1295     });
   1296 
   1297     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   1298     \\#include <assert.h>
   1299     \\#include <stdint.h>
   1300     \\#include <stdio.h>
   1301     \\extern const char* s1;
   1302     \\extern const char* s2;
   1303     \\extern const char* s3;
   1304     \\extern const char* s4;
   1305     \\int main() {
   1306     \\  assert((uintptr_t)(&s1) % 8 == 0 && s1 == s3);
   1307     \\  assert((uintptr_t)(&s2) % 8 == 0 && s2 == s4);
   1308     \\  printf("%s%s%s%s", &s1, &s2, &s3, &s4);
   1309     \\  return 0;
   1310     \\}
   1311     , .c_source_flags = &.{"-Wno-format"} });
   1312 
   1313     const runWithChecks = struct {
   1314         fn runWithChecks(step: *Step, exe: *Compile) void {
   1315             const run = addRunArtifact(exe);
   1316             run.expectStdOutEqual("str1str2str1str2");
   1317             step.dependOn(&run.step);
   1318 
   1319             const check = exe.checkObject();
   1320             check.dumpSection("__TEXT,__cstring");
   1321             check.checkContains("str1\x00\x00\x00\x00str2\x00");
   1322             check.checkInHeaders();
   1323             check.checkExact("segname __TEXT");
   1324             check.checkExact("sectname __cstring");
   1325             check.checkExact("align 3");
   1326             step.dependOn(&check.step);
   1327         }
   1328     }.runWithChecks;
   1329 
   1330     {
   1331         const exe = addExecutable(b, opts, .{ .name = "main1" });
   1332         exe.addObject(a_o);
   1333         exe.addObject(b_o);
   1334         exe.addObject(main_o);
   1335         runWithChecks(test_step, exe);
   1336     }
   1337 
   1338     {
   1339         const exe = addExecutable(b, opts, .{ .name = "main2" });
   1340         exe.addObject(b_o);
   1341         exe.addObject(a_o);
   1342         exe.addObject(main_o);
   1343         runWithChecks(test_step, exe);
   1344     }
   1345 
   1346     return test_step;
   1347 }
   1348 
   1349 fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
   1350     const test_step = addTestStep(b, "merge-literals-objc", opts);
   1351 
   1352     const main_o = addObject(b, opts, .{ .name = "main", .objc_source_bytes = 
   1353     \\#import <Foundation/Foundation.h>;
   1354     \\
   1355     \\extern void foo();
   1356     \\
   1357     \\int main() {
   1358     \\  NSString *thing = @"aaa";
   1359     \\
   1360     \\  SEL sel = @selector(lowercaseString);
   1361     \\  NSString *lower = (([thing respondsToSelector:sel]) ? @"YES" : @"NO");
   1362     \\  NSLog (@"Responds to lowercaseString: %@", lower);
   1363     \\  if ([thing respondsToSelector:sel]) //(lower == @"YES")
   1364     \\      NSLog(@"lowercaseString is: %@", [thing lowercaseString]);
   1365     \\
   1366     \\  foo();
   1367     \\}
   1368     });
   1369 
   1370     const a_o = addObject(b, opts, .{ .name = "a", .objc_source_bytes = 
   1371     \\#import <Foundation/Foundation.h>;
   1372     \\
   1373     \\void foo() {
   1374     \\  NSString *thing = @"aaa";
   1375     \\  SEL sel = @selector(lowercaseString);
   1376     \\  NSString *lower = (([thing respondsToSelector:sel]) ? @"YES" : @"NO");
   1377     \\  NSLog (@"Responds to lowercaseString in foo(): %@", lower);
   1378     \\  if ([thing respondsToSelector:sel]) //(lower == @"YES")
   1379     \\      NSLog(@"lowercaseString in foo() is: %@", [thing lowercaseString]);
   1380     \\  SEL sel2 = @selector(uppercaseString);
   1381     \\  NSString *upper = (([thing respondsToSelector:sel2]) ? @"YES" : @"NO");
   1382     \\  NSLog (@"Responds to uppercaseString in foo(): %@", upper);
   1383     \\  if ([thing respondsToSelector:sel2]) //(upper == @"YES")
   1384     \\      NSLog(@"uppercaseString in foo() is: %@", [thing uppercaseString]);
   1385     \\}
   1386     });
   1387 
   1388     const runWithChecks = struct {
   1389         fn runWithChecks(step: *Step, exe: *Compile) void {
   1390             const builder = step.owner;
   1391             const run = addRunArtifact(exe);
   1392             run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to lowercaseString: YES") });
   1393             run.addCheck(.{ .expect_stderr_match = builder.dupe("lowercaseString is: aaa") });
   1394             run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to lowercaseString in foo(): YES") });
   1395             run.addCheck(.{ .expect_stderr_match = builder.dupe("lowercaseString in foo() is: aaa") });
   1396             run.addCheck(.{ .expect_stderr_match = builder.dupe("Responds to uppercaseString in foo(): YES") });
   1397             run.addCheck(.{ .expect_stderr_match = builder.dupe("uppercaseString in foo() is: AAA") });
   1398             step.dependOn(&run.step);
   1399 
   1400             const check = exe.checkObject();
   1401             check.dumpSection("__TEXT,__objc_methname");
   1402             check.checkContains("lowercaseString\x00");
   1403             check.dumpSection("__TEXT,__objc_methname");
   1404             check.checkContains("uppercaseString\x00");
   1405             step.dependOn(&check.step);
   1406         }
   1407     }.runWithChecks;
   1408 
   1409     {
   1410         const exe = addExecutable(b, opts, .{ .name = "main1" });
   1411         exe.addObject(main_o);
   1412         exe.addObject(a_o);
   1413         exe.root_module.linkFramework("Foundation", .{});
   1414         runWithChecks(test_step, exe);
   1415     }
   1416 
   1417     {
   1418         const exe = addExecutable(b, opts, .{ .name = "main2" });
   1419         exe.addObject(a_o);
   1420         exe.addObject(main_o);
   1421         exe.root_module.linkFramework("Foundation", .{});
   1422         runWithChecks(test_step, exe);
   1423     }
   1424 
   1425     {
   1426         const b_o = addObject(b, opts, .{ .name = "b" });
   1427         b_o.addObject(a_o);
   1428         b_o.addObject(main_o);
   1429 
   1430         const exe = addExecutable(b, opts, .{ .name = "main3" });
   1431         exe.addObject(b_o);
   1432         exe.root_module.linkFramework("Foundation", .{});
   1433         runWithChecks(test_step, exe);
   1434     }
   1435 
   1436     return test_step;
   1437 }
   1438 
   1439 fn testMhExecuteHeader(b: *Build, opts: Options) *Step {
   1440     const test_step = addTestStep(b, "mh-execute-header", opts);
   1441 
   1442     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   1443 
   1444     const check = exe.checkObject();
   1445     check.checkInSymtab();
   1446     check.checkContains("[referenced dynamically] external __mh_execute_header");
   1447     test_step.dependOn(&check.step);
   1448 
   1449     return test_step;
   1450 }
   1451 
   1452 fn testNoDeadStrip(b: *Build, opts: Options) *Step {
   1453     const test_step = addTestStep(b, "no-dead-strip", opts);
   1454 
   1455     const exe = addExecutable(b, opts, .{ .name = "name", .c_source_bytes = 
   1456     \\__attribute__((used)) int bogus1 = 0;
   1457     \\int bogus2 = 0;
   1458     \\int foo = 42;
   1459     \\int main() {
   1460     \\  return foo - 42;
   1461     \\}
   1462     });
   1463     exe.link_gc_sections = true;
   1464 
   1465     const check = exe.checkObject();
   1466     check.checkInSymtab();
   1467     check.checkContains("external _bogus1");
   1468     check.checkInSymtab();
   1469     check.checkNotPresent("external _bogus2");
   1470     test_step.dependOn(&check.step);
   1471 
   1472     const run = addRunArtifact(exe);
   1473     run.expectExitCode(0);
   1474     test_step.dependOn(&run.step);
   1475 
   1476     return test_step;
   1477 }
   1478 
   1479 fn testNoExportsDylib(b: *Build, opts: Options) *Step {
   1480     const test_step = addTestStep(b, "no-exports-dylib", opts);
   1481 
   1482     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "static void abc() {}" });
   1483 
   1484     const check = dylib.checkObject();
   1485     check.checkInSymtab();
   1486     check.checkNotPresent("external _abc");
   1487     test_step.dependOn(&check.step);
   1488 
   1489     return test_step;
   1490 }
   1491 
   1492 fn testNeededFramework(b: *Build, opts: Options) *Step {
   1493     const test_step = addTestStep(b, "needed-framework", opts);
   1494 
   1495     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   1496     exe.root_module.linkFramework("Cocoa", .{ .needed = true });
   1497     exe.dead_strip_dylibs = true;
   1498 
   1499     const check = exe.checkObject();
   1500     check.checkInHeaders();
   1501     check.checkExact("cmd LOAD_DYLIB");
   1502     check.checkContains("Cocoa");
   1503     test_step.dependOn(&check.step);
   1504 
   1505     const run = addRunArtifact(exe);
   1506     run.expectExitCode(0);
   1507     test_step.dependOn(&run.step);
   1508 
   1509     return test_step;
   1510 }
   1511 
   1512 fn testNeededLibrary(b: *Build, opts: Options) *Step {
   1513     const test_step = addTestStep(b, "needed-library", opts);
   1514 
   1515     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "int a = 42;" });
   1516 
   1517     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   1518     exe.root_module.linkSystemLibrary("a", .{ .needed = true });
   1519     exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
   1520     exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   1521     exe.dead_strip_dylibs = true;
   1522 
   1523     const check = exe.checkObject();
   1524     check.checkInHeaders();
   1525     check.checkExact("cmd LOAD_DYLIB");
   1526     check.checkContains("liba.dylib");
   1527     test_step.dependOn(&check.step);
   1528 
   1529     const run = addRunArtifact(exe);
   1530     run.expectExitCode(0);
   1531     test_step.dependOn(&run.step);
   1532 
   1533     return test_step;
   1534 }
   1535 
   1536 fn testObjc(b: *Build, opts: Options) *Step {
   1537     const test_step = addTestStep(b, "objc", opts);
   1538 
   1539     const lib = addStaticLibrary(b, opts, .{ .name = "a", .objc_source_bytes = 
   1540     \\#import <Foundation/Foundation.h>
   1541     \\@interface Foo : NSObject
   1542     \\@end
   1543     \\@implementation Foo
   1544     \\@end
   1545     });
   1546 
   1547     {
   1548         const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   1549         exe.root_module.linkSystemLibrary("a", .{});
   1550         exe.root_module.linkFramework("Foundation", .{});
   1551         exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
   1552 
   1553         const check = exe.checkObject();
   1554         check.checkInSymtab();
   1555         check.checkNotPresent("_OBJC_");
   1556         test_step.dependOn(&check.step);
   1557 
   1558         const run = addRunArtifact(exe);
   1559         run.expectExitCode(0);
   1560         test_step.dependOn(&run.step);
   1561     }
   1562 
   1563     {
   1564         const exe = addExecutable(b, opts, .{ .name = "main2", .c_source_bytes = "int main() { return 0; }" });
   1565         exe.root_module.linkSystemLibrary("a", .{});
   1566         exe.root_module.linkFramework("Foundation", .{});
   1567         exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
   1568         exe.force_load_objc = true;
   1569 
   1570         const check = exe.checkObject();
   1571         check.checkInSymtab();
   1572         check.checkContains("_OBJC_");
   1573         test_step.dependOn(&check.step);
   1574 
   1575         const run = addRunArtifact(exe);
   1576         run.expectExitCode(0);
   1577         test_step.dependOn(&run.step);
   1578     }
   1579 
   1580     return test_step;
   1581 }
   1582 
   1583 fn testObjcpp(b: *Build, opts: Options) *Step {
   1584     const test_step = addTestStep(b, "objcpp", opts);
   1585 
   1586     const foo_h = foo_h: {
   1587         const wf = WriteFile.create(b);
   1588         break :foo_h wf.add("Foo.h",
   1589             \\#import <Foundation/Foundation.h>
   1590             \\@interface Foo : NSObject
   1591             \\- (NSString *)name;
   1592             \\@end
   1593         );
   1594     };
   1595 
   1596     const foo_o = addObject(b, opts, .{ .name = "foo", .objcpp_source_bytes = 
   1597     \\#import "Foo.h"
   1598     \\@implementation Foo
   1599     \\- (NSString *)name
   1600     \\{
   1601     \\      NSString *str = [[NSString alloc] initWithFormat:@"Zig"];
   1602     \\      return str;
   1603     \\}
   1604     \\@end
   1605     });
   1606     foo_o.root_module.addIncludePath(foo_h.dirname());
   1607     foo_o.linkLibCpp();
   1608 
   1609     const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes = 
   1610     \\#import "Foo.h"
   1611     \\#import <assert.h>
   1612     \\#include <iostream>
   1613     \\int main(int argc, char *argv[])
   1614     \\{
   1615     \\  @autoreleasepool {
   1616     \\      Foo *foo = [[Foo alloc] init];
   1617     \\      NSString *result = [foo name];
   1618     \\      std::cout << "Hello from C++ and " << [result UTF8String];
   1619     \\      assert([result isEqualToString:@"Zig"]);
   1620     \\      return 0;
   1621     \\  }
   1622     \\}
   1623     });
   1624     exe.root_module.addIncludePath(foo_h.dirname());
   1625     exe.addObject(foo_o);
   1626     exe.linkLibCpp();
   1627     exe.root_module.linkFramework("Foundation", .{});
   1628 
   1629     const run = addRunArtifact(exe);
   1630     run.expectStdOutEqual("Hello from C++ and Zig");
   1631     test_step.dependOn(&run.step);
   1632 
   1633     return test_step;
   1634 }
   1635 
   1636 fn testPagezeroSize(b: *Build, opts: Options) *Step {
   1637     const test_step = addTestStep(b, "pagezero-size", opts);
   1638 
   1639     {
   1640         const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main () { return 0; }" });
   1641         exe.pagezero_size = 0x4000;
   1642 
   1643         const check = exe.checkObject();
   1644         check.checkInHeaders();
   1645         check.checkExact("LC 0");
   1646         check.checkExact("segname __PAGEZERO");
   1647         check.checkExact("vmaddr 0");
   1648         check.checkExact("vmsize 4000");
   1649         check.checkInHeaders();
   1650         check.checkExact("segname __TEXT");
   1651         check.checkExact("vmaddr 4000");
   1652         test_step.dependOn(&check.step);
   1653     }
   1654 
   1655     {
   1656         const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main () { return 0; }" });
   1657         exe.pagezero_size = 0;
   1658 
   1659         const check = exe.checkObject();
   1660         check.checkInHeaders();
   1661         check.checkExact("LC 0");
   1662         check.checkExact("segname __TEXT");
   1663         check.checkExact("vmaddr 0");
   1664         test_step.dependOn(&check.step);
   1665     }
   1666 
   1667     return test_step;
   1668 }
   1669 
   1670 fn testReexportsZig(b: *Build, opts: Options) *Step {
   1671     const test_step = addTestStep(b, "reexports-zig", opts);
   1672 
   1673     const lib = addStaticLibrary(b, opts, .{ .name = "a", .zig_source_bytes = 
   1674     \\const x: i32 = 42;
   1675     \\export fn foo() i32 {
   1676     \\    return x;
   1677     \\}
   1678     \\comptime {
   1679     \\    @export(foo, .{ .name = "bar", .linkage = .strong });
   1680     \\}
   1681     });
   1682 
   1683     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   1684     \\extern int foo();
   1685     \\extern int bar();
   1686     \\int main() {
   1687     \\  return bar() - foo();
   1688     \\}
   1689     });
   1690     exe.linkLibrary(lib);
   1691 
   1692     const run = addRunArtifact(exe);
   1693     run.expectExitCode(0);
   1694     test_step.dependOn(&run.step);
   1695 
   1696     return test_step;
   1697 }
   1698 
   1699 fn testRelocatable(b: *Build, opts: Options) *Step {
   1700     const test_step = addTestStep(b, "relocatable", opts);
   1701 
   1702     const a_o = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 
   1703     \\#include <stdexcept>
   1704     \\int try_me() {
   1705     \\  throw std::runtime_error("Oh no!");
   1706     \\}
   1707     });
   1708     a_o.linkLibCpp();
   1709 
   1710     const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 
   1711     \\extern int try_me();
   1712     \\int try_again() {
   1713     \\  return try_me();
   1714     \\}
   1715     });
   1716 
   1717     const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 
   1718     \\#include <iostream>
   1719     \\#include <stdexcept>
   1720     \\extern int try_again();
   1721     \\int main() {
   1722     \\  try {
   1723     \\    try_again();
   1724     \\  } catch (const std::exception &e) {
   1725     \\    std::cout << "exception=" << e.what();
   1726     \\  }
   1727     \\  return 0;
   1728     \\}
   1729     });
   1730     main_o.linkLibCpp();
   1731 
   1732     const exp_stdout = "exception=Oh no!";
   1733 
   1734     {
   1735         const c_o = addObject(b, opts, .{ .name = "c" });
   1736         c_o.addObject(a_o);
   1737         c_o.addObject(b_o);
   1738 
   1739         const exe = addExecutable(b, opts, .{ .name = "main1" });
   1740         exe.addObject(main_o);
   1741         exe.addObject(c_o);
   1742         exe.linkLibCpp();
   1743 
   1744         const run = addRunArtifact(exe);
   1745         run.expectStdOutEqual(exp_stdout);
   1746         test_step.dependOn(&run.step);
   1747     }
   1748 
   1749     {
   1750         const d_o = addObject(b, opts, .{ .name = "d" });
   1751         d_o.addObject(a_o);
   1752         d_o.addObject(b_o);
   1753         d_o.addObject(main_o);
   1754 
   1755         const exe = addExecutable(b, opts, .{ .name = "main2" });
   1756         exe.addObject(d_o);
   1757         exe.linkLibCpp();
   1758 
   1759         const run = addRunArtifact(exe);
   1760         run.expectStdOutEqual(exp_stdout);
   1761         test_step.dependOn(&run.step);
   1762     }
   1763 
   1764     return test_step;
   1765 }
   1766 
   1767 fn testRelocatableZig(b: *Build, opts: Options) *Step {
   1768     const test_step = addTestStep(b, "relocatable-zig", opts);
   1769 
   1770     const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 
   1771     \\const std = @import("std");
   1772     \\export var foo: i32 = 0;
   1773     \\export fn incrFoo() void {
   1774     \\    foo += 1;
   1775     \\    std.debug.print("incrFoo={d}\n", .{foo});
   1776     \\}
   1777     });
   1778 
   1779     const b_o = addObject(b, opts, .{ .name = "b", .zig_source_bytes = 
   1780     \\const std = @import("std");
   1781     \\extern var foo: i32;
   1782     \\export fn decrFoo() void {
   1783     \\    foo -= 1;
   1784     \\    std.debug.print("decrFoo={d}\n", .{foo});
   1785     \\}
   1786     });
   1787 
   1788     const main_o = addObject(b, opts, .{ .name = "main", .zig_source_bytes = 
   1789     \\const std = @import("std");
   1790     \\extern var foo: i32;
   1791     \\extern fn incrFoo() void;
   1792     \\extern fn decrFoo() void;
   1793     \\pub fn main() void {
   1794     \\    const init = foo;
   1795     \\    incrFoo();
   1796     \\    decrFoo();
   1797     \\    if (init == foo) @panic("Oh no!");
   1798     \\}
   1799     });
   1800 
   1801     const c_o = addObject(b, opts, .{ .name = "c" });
   1802     c_o.addObject(a_o);
   1803     c_o.addObject(b_o);
   1804     c_o.addObject(main_o);
   1805 
   1806     const exe = addExecutable(b, opts, .{ .name = "main" });
   1807     exe.addObject(c_o);
   1808 
   1809     const run = addRunArtifact(exe);
   1810     run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
   1811     run.addCheck(.{ .expect_stderr_match = b.dupe("decrFoo=0") });
   1812     run.addCheck(.{ .expect_stderr_match = b.dupe("panic: Oh no!") });
   1813     test_step.dependOn(&run.step);
   1814 
   1815     return test_step;
   1816 }
   1817 
   1818 fn testSearchStrategy(b: *Build, opts: Options) *Step {
   1819     const test_step = addTestStep(b, "search-strategy", opts);
   1820 
   1821     const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = 
   1822     \\#include<stdio.h>
   1823     \\char world[] = "world";
   1824     \\char* hello() {
   1825     \\  return "Hello";
   1826     \\}
   1827     });
   1828 
   1829     const liba = addStaticLibrary(b, opts, .{ .name = "a" });
   1830     liba.addObject(obj);
   1831 
   1832     const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
   1833     dylib.addObject(obj);
   1834 
   1835     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   1836     \\#include<stdio.h>
   1837     \\char* hello();
   1838     \\extern char world[];
   1839     \\int main() {
   1840     \\  printf("%s %s", hello(), world);
   1841     \\  return 0;
   1842     \\}
   1843     });
   1844 
   1845     {
   1846         const exe = addExecutable(b, opts, .{ .name = "main" });
   1847         exe.addObject(main_o);
   1848         exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
   1849         exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
   1850         exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
   1851         exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   1852 
   1853         const run = addRunArtifact(exe);
   1854         run.expectStdOutEqual("Hello world");
   1855         test_step.dependOn(&run.step);
   1856 
   1857         const check = exe.checkObject();
   1858         check.checkInHeaders();
   1859         check.checkExact("cmd LOAD_DYLIB");
   1860         check.checkContains("liba.dylib");
   1861         test_step.dependOn(&check.step);
   1862     }
   1863 
   1864     {
   1865         const exe = addExecutable(b, opts, .{ .name = "main" });
   1866         exe.addObject(main_o);
   1867         exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
   1868         exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
   1869         exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
   1870         exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   1871 
   1872         const run = addRunArtifact(exe);
   1873         run.expectStdOutEqual("Hello world");
   1874         test_step.dependOn(&run.step);
   1875 
   1876         const check = exe.checkObject();
   1877         check.checkInHeaders();
   1878         check.checkExact("cmd LOAD_DYLIB");
   1879         check.checkNotPresent("liba.dylib");
   1880         test_step.dependOn(&check.step);
   1881     }
   1882 
   1883     return test_step;
   1884 }
   1885 
   1886 fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
   1887     const test_step = addTestStep(b, "section-boundary-symbols", opts);
   1888 
   1889     const obj1 = addObject(b, opts, .{
   1890         .name = "obj1",
   1891         .cpp_source_bytes =
   1892         \\constexpr const char* MESSAGE __attribute__((used, section("__DATA_CONST,__message_ptr"))) = "codebase";
   1893         ,
   1894     });
   1895 
   1896     const main_o = addObject(b, opts, .{
   1897         .name = "main",
   1898         .zig_source_bytes =
   1899         \\const std = @import("std");
   1900         \\extern fn interop() ?[*:0]const u8;
   1901         \\pub fn main() !void {
   1902         \\    std.debug.print("All your {s} are belong to us.\n", .{
   1903         \\        if (interop()) |ptr| std.mem.span(ptr) else "(null)",
   1904         \\    });
   1905         \\}
   1906         ,
   1907     });
   1908 
   1909     {
   1910         const obj2 = addObject(b, opts, .{
   1911             .name = "obj2",
   1912             .cpp_source_bytes =
   1913             \\extern const char* message_pointer __asm("section$start$__DATA_CONST$__message_ptr");
   1914             \\extern "C" const char* interop() {
   1915             \\  return message_pointer;
   1916             \\}
   1917             ,
   1918         });
   1919 
   1920         const exe = addExecutable(b, opts, .{ .name = "test" });
   1921         exe.addObject(obj1);
   1922         exe.addObject(obj2);
   1923         exe.addObject(main_o);
   1924 
   1925         const run = b.addRunArtifact(exe);
   1926         run.skip_foreign_checks = true;
   1927         run.expectStdErrEqual("All your codebase are belong to us.\n");
   1928         test_step.dependOn(&run.step);
   1929 
   1930         const check = exe.checkObject();
   1931         check.checkInSymtab();
   1932         check.checkNotPresent("external section$start$__DATA_CONST$__message_ptr");
   1933         test_step.dependOn(&check.step);
   1934     }
   1935 
   1936     {
   1937         const obj3 = addObject(b, opts, .{
   1938             .name = "obj3",
   1939             .cpp_source_bytes =
   1940             \\extern const char* message_pointer __asm("section$start$__DATA_CONST$__not_present");
   1941             \\extern "C" const char* interop() {
   1942             \\  return message_pointer;
   1943             \\}
   1944             ,
   1945         });
   1946 
   1947         const exe = addExecutable(b, opts, .{ .name = "test" });
   1948         exe.addObject(obj1);
   1949         exe.addObject(obj3);
   1950         exe.addObject(main_o);
   1951 
   1952         const run = b.addRunArtifact(exe);
   1953         run.skip_foreign_checks = true;
   1954         run.expectStdErrEqual("All your (null) are belong to us.\n");
   1955         test_step.dependOn(&run.step);
   1956 
   1957         const check = exe.checkObject();
   1958         check.checkInSymtab();
   1959         check.checkNotPresent("external section$start$__DATA_CONST$__not_present");
   1960         test_step.dependOn(&check.step);
   1961     }
   1962 
   1963     return test_step;
   1964 }
   1965 
   1966 fn testSectionBoundarySymbols2(b: *Build, opts: Options) *Step {
   1967     const test_step = addTestStep(b, "section-boundary-symbols-2", opts);
   1968 
   1969     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   1970     \\#include <stdio.h>
   1971     \\struct pair { int a; int b;  };
   1972     \\struct pair first __attribute__((section("__DATA,__pairs"))) = { 1, 2  };
   1973     \\struct pair second __attribute__((section("__DATA,__pairs"))) = { 3, 4  };
   1974     \\extern struct pair pairs_start __asm("section$start$__DATA$__pairs");
   1975     \\extern struct pair pairs_end __asm("section$end$__DATA$__pairs");
   1976     \\int main() {
   1977     \\  printf("%d,%d\n", first.a, first.b);
   1978     \\  printf("%d,%d\n", second.a, second.b);
   1979     \\  struct pair* p;
   1980     \\  for (p = &pairs_start; p < &pairs_end; p++) {
   1981     \\    p->a = 0;
   1982     \\  }
   1983     \\  printf("%d,%d\n", first.a, first.b);
   1984     \\  printf("%d,%d\n", second.a, second.b);
   1985     \\  return 0;
   1986     \\}
   1987     });
   1988 
   1989     const run = b.addRunArtifact(exe);
   1990     run.skip_foreign_checks = true;
   1991     run.expectStdOutEqual(
   1992         \\1,2
   1993         \\3,4
   1994         \\0,2
   1995         \\0,4
   1996         \\
   1997     );
   1998     test_step.dependOn(&run.step);
   1999 
   2000     return test_step;
   2001 }
   2002 
   2003 fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
   2004     const test_step = addTestStep(b, "segment-boundary-symbols", opts);
   2005 
   2006     const obj1 = addObject(b, opts, .{ .name = "a", .cpp_source_bytes = 
   2007     \\constexpr const char* MESSAGE __attribute__((used, section("__DATA_CONST_1,__message_ptr"))) = "codebase";
   2008     });
   2009 
   2010     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   2011     \\#include <stdio.h>
   2012     \\const char* interop();
   2013     \\int main() {
   2014     \\  printf("All your %s are belong to us.\n", interop());
   2015     \\  return 0;
   2016     \\}
   2017     });
   2018 
   2019     {
   2020         const obj2 = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 
   2021         \\extern const char* message_pointer __asm("segment$start$__DATA_CONST_1");
   2022         \\extern "C" const char* interop() {
   2023         \\  return message_pointer;
   2024         \\}
   2025         });
   2026 
   2027         const exe = addExecutable(b, opts, .{ .name = "main" });
   2028         exe.addObject(obj1);
   2029         exe.addObject(obj2);
   2030         exe.addObject(main_o);
   2031 
   2032         const run = addRunArtifact(exe);
   2033         run.expectStdOutEqual("All your codebase are belong to us.\n");
   2034         test_step.dependOn(&run.step);
   2035 
   2036         const check = exe.checkObject();
   2037         check.checkInSymtab();
   2038         check.checkNotPresent("external segment$start$__DATA_CONST_1");
   2039         test_step.dependOn(&check.step);
   2040     }
   2041 
   2042     {
   2043         const obj2 = addObject(b, opts, .{ .name = "c", .cpp_source_bytes = 
   2044         \\extern const char* message_pointer __asm("segment$start$__DATA_1");
   2045         \\extern "C" const char* interop() {
   2046         \\  return message_pointer;
   2047         \\}
   2048         });
   2049 
   2050         const exe = addExecutable(b, opts, .{ .name = "main2" });
   2051         exe.addObject(obj1);
   2052         exe.addObject(obj2);
   2053         exe.addObject(main_o);
   2054 
   2055         const check = exe.checkObject();
   2056         check.checkInHeaders();
   2057         check.checkExact("cmd SEGMENT_64");
   2058         check.checkExact("segname __DATA_1");
   2059         check.checkExtract("vmsize {vmsize}");
   2060         check.checkExtract("filesz {filesz}");
   2061         check.checkComputeCompare("vmsize", .{ .op = .eq, .value = .{ .literal = 0 } });
   2062         check.checkComputeCompare("filesz", .{ .op = .eq, .value = .{ .literal = 0 } });
   2063         check.checkInSymtab();
   2064         check.checkNotPresent("external segment$start$__DATA_1");
   2065         test_step.dependOn(&check.step);
   2066     }
   2067 
   2068     return test_step;
   2069 }
   2070 
   2071 fn testSymbolStabs(b: *Build, opts: Options) *Step {
   2072     const test_step = addTestStep(b, "symbol-stabs", opts);
   2073 
   2074     const a_o = addObject(b, opts, .{ .name = "a", .c_source_bytes = 
   2075     \\int foo = 42;
   2076     \\int getFoo() {
   2077     \\  return foo;
   2078     \\}
   2079     });
   2080 
   2081     const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = 
   2082     \\int bar = 24;
   2083     \\int getBar() {
   2084     \\  return bar;
   2085     \\}
   2086     });
   2087 
   2088     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   2089     \\#include <stdio.h>
   2090     \\extern int getFoo();
   2091     \\extern int getBar();
   2092     \\int main() {
   2093     \\  printf("foo=%d,bar=%d", getFoo(), getBar());
   2094     \\  return 0;
   2095     \\}
   2096     });
   2097 
   2098     const exe = addExecutable(b, opts, .{ .name = "main" });
   2099     exe.addObject(a_o);
   2100     exe.addObject(b_o);
   2101     exe.addObject(main_o);
   2102 
   2103     const run = addRunArtifact(exe);
   2104     run.expectStdOutEqual("foo=42,bar=24");
   2105     test_step.dependOn(&run.step);
   2106 
   2107     const check = exe.checkObject();
   2108     check.checkInSymtab();
   2109     check.checkContains("a.o"); // TODO we really should do a fuzzy search like OSO <ignore>/a.o
   2110     check.checkInSymtab();
   2111     check.checkContains("b.o");
   2112     check.checkInSymtab();
   2113     check.checkContains("main.o");
   2114     test_step.dependOn(&check.step);
   2115 
   2116     return test_step;
   2117 }
   2118 
   2119 fn testStackSize(b: *Build, opts: Options) *Step {
   2120     const test_step = addTestStep(b, "stack-size", opts);
   2121 
   2122     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   2123     exe.stack_size = 0x100000000;
   2124 
   2125     const run = addRunArtifact(exe);
   2126     run.expectExitCode(0);
   2127     test_step.dependOn(&run.step);
   2128 
   2129     const check = exe.checkObject();
   2130     check.checkInHeaders();
   2131     check.checkExact("cmd MAIN");
   2132     check.checkExact("stacksize 100000000");
   2133     test_step.dependOn(&check.step);
   2134 
   2135     return test_step;
   2136 }
   2137 
   2138 fn testTbdv3(b: *Build, opts: Options) *Step {
   2139     const test_step = addTestStep(b, "tbdv3", opts);
   2140 
   2141     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = "int getFoo() { return 42; }" });
   2142 
   2143     const tbd = tbd: {
   2144         const wf = WriteFile.create(b);
   2145         break :tbd wf.add("liba.tbd",
   2146             \\--- !tapi-tbd-v3
   2147             \\archs:           [ arm64, x86_64 ]
   2148             \\uuids:           [ 'arm64: DEADBEEF', 'x86_64: BEEFDEAD' ]
   2149             \\platform:        macos
   2150             \\install-name:    @rpath/liba.dylib
   2151             \\current-version: 0
   2152             \\exports:
   2153             \\  - archs:           [ arm64, x86_64 ]
   2154             \\    symbols:         [ _getFoo ]
   2155         );
   2156     };
   2157 
   2158     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2159     \\#include <stdio.h>
   2160     \\int getFoo();
   2161     \\int main() {
   2162     \\  return getFoo() - 42;
   2163     \\}
   2164     });
   2165     exe.root_module.linkSystemLibrary("a", .{});
   2166     exe.root_module.addLibraryPath(tbd.dirname());
   2167     exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   2168 
   2169     const run = addRunArtifact(exe);
   2170     run.expectExitCode(0);
   2171     test_step.dependOn(&run.step);
   2172 
   2173     return test_step;
   2174 }
   2175 
   2176 fn testTentative(b: *Build, opts: Options) *Step {
   2177     const test_step = addTestStep(b, "tentative", opts);
   2178 
   2179     const exe = addExecutable(b, opts, .{ .name = "main" });
   2180     addCSourceBytes(exe,
   2181         \\int foo;
   2182         \\int bar;
   2183         \\int baz = 42;
   2184     , &.{"-fcommon"});
   2185     addCSourceBytes(exe,
   2186         \\#include<stdio.h>
   2187         \\int foo;
   2188         \\int bar = 5;
   2189         \\int baz;
   2190         \\int main() {
   2191         \\  printf("%d %d %d\n", foo, bar, baz);
   2192         \\}
   2193     , &.{"-fcommon"});
   2194 
   2195     const run = addRunArtifact(exe);
   2196     run.expectStdOutEqual("0 5 42\n");
   2197     test_step.dependOn(&run.step);
   2198 
   2199     return test_step;
   2200 }
   2201 
   2202 fn testThunks(b: *Build, opts: Options) *Step {
   2203     const test_step = addTestStep(b, "thunks", opts);
   2204 
   2205     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2206     \\#include <stdio.h>
   2207     \\__attribute__((aligned(0x8000000))) int bar() {
   2208     \\  return 42;
   2209     \\}
   2210     \\int foobar();
   2211     \\int foo() {
   2212     \\  return bar() - foobar();
   2213     \\}
   2214     \\__attribute__((aligned(0x8000000))) int foobar() {
   2215     \\  return 42;
   2216     \\}
   2217     \\int main() {
   2218     \\  printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar());
   2219     \\  return foo();
   2220     \\}
   2221     });
   2222 
   2223     const run = addRunArtifact(exe);
   2224     run.expectStdOutEqual("bar=42, foo=0, foobar=42");
   2225     run.expectExitCode(0);
   2226     test_step.dependOn(&run.step);
   2227 
   2228     return test_step;
   2229 }
   2230 
   2231 fn testTls(b: *Build, opts: Options) *Step {
   2232     const test_step = addTestStep(b, "tls", opts);
   2233 
   2234     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 
   2235     \\_Thread_local int a;
   2236     \\int getA() {
   2237     \\  return a;
   2238     \\}
   2239     });
   2240 
   2241     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2242     \\#include<stdio.h>
   2243     \\extern _Thread_local int a;
   2244     \\extern int getA();
   2245     \\int getA2() {
   2246     \\  return a;
   2247     \\}
   2248     \\int main() {
   2249     \\  a = 2;
   2250     \\  printf("%d %d %d", a, getA(), getA2());
   2251     \\  return 0;
   2252     \\}
   2253     });
   2254     exe.root_module.linkSystemLibrary("a", .{});
   2255     exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
   2256     exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   2257 
   2258     const run = addRunArtifact(exe);
   2259     run.expectStdOutEqual("2 2 2");
   2260     test_step.dependOn(&run.step);
   2261 
   2262     return test_step;
   2263 }
   2264 
   2265 // https://github.com/ziglang/zig/issues/19221
   2266 fn testTlsPointers(b: *Build, opts: Options) *Step {
   2267     const test_step = addTestStep(b, "tls-pointers", opts);
   2268 
   2269     const foo_h = foo_h: {
   2270         const wf = WriteFile.create(b);
   2271         break :foo_h wf.add("foo.h",
   2272             \\template<typename just4fun>
   2273             \\struct Foo {
   2274             \\
   2275             \\public:
   2276             \\  static int getVar() {
   2277             \\  static int thread_local var = 0;
   2278             \\  ++var;
   2279             \\  return var;
   2280             \\}
   2281             \\};
   2282         );
   2283     };
   2284 
   2285     const bar_o = addObject(b, opts, .{ .name = "bar", .cpp_source_bytes = 
   2286     \\#include "foo.h"
   2287     \\int bar() {
   2288     \\  int v1 = Foo<int>::getVar();
   2289     \\  return v1;
   2290     \\}
   2291     });
   2292     bar_o.root_module.addIncludePath(foo_h.dirname());
   2293     bar_o.linkLibCpp();
   2294 
   2295     const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes = 
   2296     \\#include "foo.h"
   2297     \\int baz() {
   2298     \\  int v1 = Foo<unsigned>::getVar();
   2299     \\  return v1;
   2300     \\}
   2301     });
   2302     baz_o.root_module.addIncludePath(foo_h.dirname());
   2303     baz_o.linkLibCpp();
   2304 
   2305     const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 
   2306     \\extern int bar();
   2307     \\extern int baz();
   2308     \\int main() {
   2309     \\  int v1 = bar();
   2310     \\  int v2 = baz();
   2311     \\  return v1 != v2;
   2312     \\}
   2313     });
   2314     main_o.root_module.addIncludePath(foo_h.dirname());
   2315     main_o.linkLibCpp();
   2316 
   2317     const exe = addExecutable(b, opts, .{ .name = "main" });
   2318     exe.addObject(bar_o);
   2319     exe.addObject(baz_o);
   2320     exe.addObject(main_o);
   2321     exe.linkLibCpp();
   2322 
   2323     const run = addRunArtifact(exe);
   2324     run.expectExitCode(0);
   2325     test_step.dependOn(&run.step);
   2326 
   2327     return test_step;
   2328 }
   2329 
   2330 fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
   2331     const test_step = addTestStep(b, "tls-large-tbss", opts);
   2332 
   2333     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2334     \\#include <stdio.h>
   2335     \\_Thread_local int x[0x8000];
   2336     \\_Thread_local int y[0x8000];
   2337     \\int main() {
   2338     \\  x[0] = 3;
   2339     \\  x[0x7fff] = 5;
   2340     \\  printf("%d %d %d %d %d %d\n", x[0], x[1], x[0x7fff], y[0], y[1], y[0x7fff]);
   2341     \\}
   2342     });
   2343 
   2344     const run = addRunArtifact(exe);
   2345     run.expectStdOutEqual("3 0 5 0 0 0\n");
   2346     test_step.dependOn(&run.step);
   2347 
   2348     return test_step;
   2349 }
   2350 
   2351 fn testTlsZig(b: *Build, opts: Options) *Step {
   2352     const test_step = addTestStep(b, "tls-zig", opts);
   2353 
   2354     const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 
   2355     \\const std = @import("std");
   2356     \\threadlocal var x: i32 = 0;
   2357     \\threadlocal var y: i32 = -1;
   2358     \\pub fn main() void {
   2359     \\    std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable;
   2360     \\    x -= 1;
   2361     \\    y += 1;
   2362     \\    std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable;
   2363     \\}
   2364     });
   2365 
   2366     const run = addRunArtifact(exe);
   2367     run.expectStdOutEqual(
   2368         \\0 -1
   2369         \\-1 0
   2370         \\
   2371     );
   2372     test_step.dependOn(&run.step);
   2373 
   2374     return test_step;
   2375 }
   2376 
   2377 fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
   2378     const test_step = addTestStep(b, "two-level-namespace", opts);
   2379 
   2380     const liba = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 
   2381     \\#include <stdio.h>
   2382     \\int foo = 1;
   2383     \\int* ptr_to_foo = &foo;
   2384     \\int getFoo() {
   2385     \\  return foo;
   2386     \\}
   2387     \\void printInA() {
   2388     \\  printf("liba: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo);
   2389     \\}
   2390     });
   2391 
   2392     {
   2393         const check = liba.checkObject();
   2394         check.checkInDyldLazyBind();
   2395         check.checkNotPresent("(flat lookup) _getFoo");
   2396         check.checkInIndirectSymtab();
   2397         check.checkNotPresent("_getFoo");
   2398         test_step.dependOn(&check.step);
   2399     }
   2400 
   2401     const libb = addSharedLibrary(b, opts, .{ .name = "b", .c_source_bytes = 
   2402     \\#include <stdio.h>
   2403     \\int foo = 2;
   2404     \\int* ptr_to_foo = &foo;
   2405     \\int getFoo() {
   2406     \\  return foo;
   2407     \\}
   2408     \\void printInB() {
   2409     \\  printf("libb: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo);
   2410     \\}
   2411     });
   2412 
   2413     {
   2414         const check = libb.checkObject();
   2415         check.checkInDyldLazyBind();
   2416         check.checkNotPresent("(flat lookup) _getFoo");
   2417         check.checkInIndirectSymtab();
   2418         check.checkNotPresent("_getFoo");
   2419         test_step.dependOn(&check.step);
   2420     }
   2421 
   2422     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 
   2423     \\#include <stdio.h>
   2424     \\int getFoo();
   2425     \\extern int* ptr_to_foo;
   2426     \\void printInA();
   2427     \\void printInB();
   2428     \\int main() {
   2429     \\  printf("main: getFoo()=%d, ptr_to_foo=%d\n", getFoo(), *ptr_to_foo);
   2430     \\  printInA();
   2431     \\  printInB();
   2432     \\  return 0;
   2433     \\}
   2434     });
   2435 
   2436     {
   2437         const exe = addExecutable(b, opts, .{ .name = "main1" });
   2438         exe.addObject(main_o);
   2439         exe.root_module.linkSystemLibrary("a", .{});
   2440         exe.root_module.linkSystemLibrary("b", .{});
   2441         exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
   2442         exe.root_module.addLibraryPath(libb.getEmittedBinDirectory());
   2443         exe.root_module.addRPath(liba.getEmittedBinDirectory());
   2444         exe.root_module.addRPath(libb.getEmittedBinDirectory());
   2445 
   2446         const check = exe.checkObject();
   2447         check.checkInSymtab();
   2448         check.checkExact("(undefined) external _getFoo (from liba)");
   2449         check.checkInSymtab();
   2450         check.checkExact("(undefined) external _printInA (from liba)");
   2451         check.checkInSymtab();
   2452         check.checkExact("(undefined) external _printInB (from libb)");
   2453         test_step.dependOn(&check.step);
   2454 
   2455         const run = addRunArtifact(exe);
   2456         run.expectStdOutEqual(
   2457             \\main: getFoo()=1, ptr_to_foo=1
   2458             \\liba: getFoo()=1, ptr_to_foo=1
   2459             \\libb: getFoo()=2, ptr_to_foo=2
   2460             \\
   2461         );
   2462         test_step.dependOn(&run.step);
   2463     }
   2464 
   2465     {
   2466         const exe = addExecutable(b, opts, .{ .name = "main2" });
   2467         exe.addObject(main_o);
   2468         exe.root_module.linkSystemLibrary("b", .{});
   2469         exe.root_module.linkSystemLibrary("a", .{});
   2470         exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
   2471         exe.root_module.addLibraryPath(libb.getEmittedBinDirectory());
   2472         exe.root_module.addRPath(liba.getEmittedBinDirectory());
   2473         exe.root_module.addRPath(libb.getEmittedBinDirectory());
   2474 
   2475         const check = exe.checkObject();
   2476         check.checkInSymtab();
   2477         check.checkExact("(undefined) external _getFoo (from libb)");
   2478         check.checkInSymtab();
   2479         check.checkExact("(undefined) external _printInA (from liba)");
   2480         check.checkInSymtab();
   2481         check.checkExact("(undefined) external _printInB (from libb)");
   2482         test_step.dependOn(&check.step);
   2483 
   2484         const run = addRunArtifact(exe);
   2485         run.expectStdOutEqual(
   2486             \\main: getFoo()=2, ptr_to_foo=2
   2487             \\liba: getFoo()=1, ptr_to_foo=1
   2488             \\libb: getFoo()=2, ptr_to_foo=2
   2489             \\
   2490         );
   2491         test_step.dependOn(&run.step);
   2492     }
   2493 
   2494     return test_step;
   2495 }
   2496 
   2497 fn testUndefinedFlag(b: *Build, opts: Options) *Step {
   2498     const test_step = addTestStep(b, "undefined-flag", opts);
   2499 
   2500     const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
   2501 
   2502     const lib = addStaticLibrary(b, opts, .{ .name = "a" });
   2503     lib.addObject(obj);
   2504 
   2505     const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   2506 
   2507     {
   2508         const exe = addExecutable(b, opts, .{ .name = "main1" });
   2509         exe.addObject(main_o);
   2510         exe.linkLibrary(lib);
   2511         exe.forceUndefinedSymbol("_foo");
   2512 
   2513         const run = addRunArtifact(exe);
   2514         run.expectExitCode(0);
   2515         test_step.dependOn(&run.step);
   2516 
   2517         const check = exe.checkObject();
   2518         check.checkInSymtab();
   2519         check.checkContains("_foo");
   2520         test_step.dependOn(&check.step);
   2521     }
   2522 
   2523     {
   2524         const exe = addExecutable(b, opts, .{ .name = "main2" });
   2525         exe.addObject(main_o);
   2526         exe.linkLibrary(lib);
   2527         exe.forceUndefinedSymbol("_foo");
   2528         exe.link_gc_sections = true;
   2529 
   2530         const run = addRunArtifact(exe);
   2531         run.expectExitCode(0);
   2532         test_step.dependOn(&run.step);
   2533 
   2534         const check = exe.checkObject();
   2535         check.checkInSymtab();
   2536         check.checkContains("_foo");
   2537         test_step.dependOn(&check.step);
   2538     }
   2539 
   2540     {
   2541         const exe = addExecutable(b, opts, .{ .name = "main3" });
   2542         exe.addObject(main_o);
   2543         exe.addObject(obj);
   2544 
   2545         const run = addRunArtifact(exe);
   2546         run.expectExitCode(0);
   2547         test_step.dependOn(&run.step);
   2548 
   2549         const check = exe.checkObject();
   2550         check.checkInSymtab();
   2551         check.checkContains("_foo");
   2552         test_step.dependOn(&check.step);
   2553     }
   2554 
   2555     {
   2556         const exe = addExecutable(b, opts, .{ .name = "main4" });
   2557         exe.addObject(main_o);
   2558         exe.addObject(obj);
   2559         exe.link_gc_sections = true;
   2560 
   2561         const run = addRunArtifact(exe);
   2562         run.expectExitCode(0);
   2563         test_step.dependOn(&run.step);
   2564 
   2565         const check = exe.checkObject();
   2566         check.checkInSymtab();
   2567         check.checkNotPresent("_foo");
   2568         test_step.dependOn(&check.step);
   2569     }
   2570 
   2571     return test_step;
   2572 }
   2573 
   2574 fn testUnresolvedError(b: *Build, opts: Options) *Step {
   2575     const test_step = addTestStep(b, "unresolved-error", opts);
   2576 
   2577     const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes = 
   2578     \\extern fn foo() i32;
   2579     \\export fn bar() i32 { return foo() + 1; }
   2580     });
   2581 
   2582     const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes = 
   2583     \\const std = @import("std");
   2584     \\extern fn foo() i32;
   2585     \\extern fn bar() i32;
   2586     \\pub fn main() void {
   2587     \\    std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
   2588     \\}
   2589     });
   2590     exe.addObject(obj);
   2591 
   2592     // TODO order should match across backends if possible
   2593     if (opts.use_llvm) {
   2594         expectLinkErrors(exe, test_step, .{ .exact = &.{
   2595             "error: undefined symbol: _foo",
   2596             "note: referenced by /?/a.o:_bar",
   2597             "note: referenced by /?/main.o:_main.main",
   2598         } });
   2599     } else {
   2600         expectLinkErrors(exe, test_step, .{ .exact = &.{
   2601             "error: undefined symbol: _foo",
   2602             "note: referenced by /?/main.o:_main.main",
   2603             "note: referenced by /?/a.o:__TEXT$__text_zig",
   2604         } });
   2605     }
   2606 
   2607     return test_step;
   2608 }
   2609 
   2610 fn testUnwindInfo(b: *Build, opts: Options) *Step {
   2611     const test_step = addTestStep(b, "unwind-info", opts);
   2612 
   2613     const all_h = all_h: {
   2614         const wf = WriteFile.create(b);
   2615         break :all_h wf.add("all.h",
   2616             \\#ifndef ALL
   2617             \\#define ALL
   2618             \\
   2619             \\#include <cstddef>
   2620             \\#include <string>
   2621             \\#include <stdexcept>
   2622             \\
   2623             \\struct SimpleString {
   2624             \\  SimpleString(size_t max_size);
   2625             \\  ~SimpleString();
   2626             \\
   2627             \\  void print(const char* tag) const;
   2628             \\  bool append_line(const char* x);
   2629             \\
   2630             \\private:
   2631             \\  size_t max_size;
   2632             \\  char* buffer;
   2633             \\  size_t length;
   2634             \\};
   2635             \\
   2636             \\struct SimpleStringOwner {
   2637             \\  SimpleStringOwner(const char* x);
   2638             \\  ~SimpleStringOwner();
   2639             \\
   2640             \\private:
   2641             \\  SimpleString string;
   2642             \\};
   2643             \\
   2644             \\class Error: public std::exception {
   2645             \\public:
   2646             \\  explicit Error(const char* msg) : msg{ msg } {}
   2647             \\  virtual ~Error() noexcept {}
   2648             \\  virtual const char* what() const noexcept {
   2649             \\    return msg.c_str();
   2650             \\  }
   2651             \\
   2652             \\protected:
   2653             \\  std::string msg;
   2654             \\};
   2655             \\
   2656             \\#endif
   2657         );
   2658     };
   2659 
   2660     const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 
   2661     \\#include "all.h"
   2662     \\#include <cstdio>
   2663     \\
   2664     \\void fn_c() {
   2665     \\  SimpleStringOwner c{ "cccccccccc" };
   2666     \\}
   2667     \\
   2668     \\void fn_b() {
   2669     \\  SimpleStringOwner b{ "b" };
   2670     \\  fn_c();
   2671     \\}
   2672     \\
   2673     \\int main() {
   2674     \\  try {
   2675     \\    SimpleStringOwner a{ "a" };
   2676     \\    fn_b();
   2677     \\    SimpleStringOwner d{ "d" };
   2678     \\  } catch (const Error& e) {
   2679     \\    printf("Error: %s\n", e.what());
   2680     \\  } catch(const std::exception& e) {
   2681     \\    printf("Exception: %s\n", e.what());
   2682     \\  }
   2683     \\  return 0;
   2684     \\}
   2685     });
   2686     main_o.root_module.addIncludePath(all_h.dirname());
   2687     main_o.linkLibCpp();
   2688 
   2689     const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = 
   2690     \\#include "all.h"
   2691     \\#include <cstdio>
   2692     \\#include <cstring>
   2693     \\
   2694     \\SimpleString::SimpleString(size_t max_size)
   2695     \\: max_size{ max_size }, length{} {
   2696     \\  if (max_size == 0) {
   2697     \\    throw Error{ "Max size must be at least 1." };
   2698     \\  }
   2699     \\  buffer = new char[max_size];
   2700     \\  buffer[0] = 0;
   2701     \\}
   2702     \\
   2703     \\SimpleString::~SimpleString() {
   2704     \\  delete[] buffer;
   2705     \\}
   2706     \\
   2707     \\void SimpleString::print(const char* tag) const {
   2708     \\  printf("%s: %s", tag, buffer);
   2709     \\}
   2710     \\
   2711     \\bool SimpleString::append_line(const char* x) {
   2712     \\  const auto x_len = strlen(x);
   2713     \\  if (x_len + length + 2 > max_size) return false;
   2714     \\  std::strncpy(buffer + length, x, max_size - length);
   2715     \\  length += x_len;
   2716     \\  buffer[length++] = '\n';
   2717     \\  buffer[length] = 0;
   2718     \\  return true;
   2719     \\}
   2720     });
   2721     simple_string_o.root_module.addIncludePath(all_h.dirname());
   2722     simple_string_o.linkLibCpp();
   2723 
   2724     const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = 
   2725     \\#include "all.h"
   2726     \\
   2727     \\SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } {
   2728     \\  if (!string.append_line(x)) {
   2729     \\    throw Error{ "Not enough memory!" };
   2730     \\  }
   2731     \\  string.print("Constructed");
   2732     \\}
   2733     \\
   2734     \\SimpleStringOwner::~SimpleStringOwner() {
   2735     \\  string.print("About to destroy");
   2736     \\}
   2737     });
   2738     simple_string_owner_o.root_module.addIncludePath(all_h.dirname());
   2739     simple_string_owner_o.linkLibCpp();
   2740 
   2741     const exp_stdout =
   2742         \\Constructed: a
   2743         \\Constructed: b
   2744         \\About to destroy: b
   2745         \\About to destroy: a
   2746         \\Error: Not enough memory!
   2747         \\
   2748     ;
   2749 
   2750     const exe = addExecutable(b, opts, .{ .name = "main" });
   2751     exe.addObject(main_o);
   2752     exe.addObject(simple_string_o);
   2753     exe.addObject(simple_string_owner_o);
   2754     exe.linkLibCpp();
   2755 
   2756     const run = addRunArtifact(exe);
   2757     run.expectStdOutEqual(exp_stdout);
   2758     test_step.dependOn(&run.step);
   2759 
   2760     const check = exe.checkObject();
   2761     check.checkInSymtab();
   2762     check.checkContains("(was private external) ___gxx_personality_v0");
   2763     test_step.dependOn(&check.step);
   2764 
   2765     return test_step;
   2766 }
   2767 
   2768 fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
   2769     const test_step = addTestStep(b, "unwind-info-no-subsections-arm64", opts);
   2770 
   2771     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
   2772     \\.globl _foo
   2773     \\.align 4
   2774     \\_foo:
   2775     \\  .cfi_startproc
   2776     \\  stp     x29, x30, [sp, #-32]!
   2777     \\  .cfi_def_cfa_offset 32
   2778     \\  .cfi_offset w30, -24
   2779     \\  .cfi_offset w29, -32
   2780     \\  mov x29, sp
   2781     \\  .cfi_def_cfa w29, 32
   2782     \\  bl      _bar
   2783     \\  ldp     x29, x30, [sp], #32
   2784     \\  .cfi_restore w29
   2785     \\  .cfi_restore w30
   2786     \\  .cfi_def_cfa_offset 0
   2787     \\  ret
   2788     \\  .cfi_endproc
   2789     \\
   2790     \\.globl _bar
   2791     \\.align 4
   2792     \\_bar:
   2793     \\  .cfi_startproc
   2794     \\  sub     sp, sp, #32
   2795     \\  .cfi_def_cfa_offset -32
   2796     \\  stp     x29, x30, [sp, #16]
   2797     \\  .cfi_offset w30, -24
   2798     \\  .cfi_offset w29, -32
   2799     \\  mov x29, sp
   2800     \\  .cfi_def_cfa w29, 32
   2801     \\  mov     w0, #4
   2802     \\  ldp     x29, x30, [sp, #16]
   2803     \\  .cfi_restore w29
   2804     \\  .cfi_restore w30
   2805     \\  add     sp, sp, #32
   2806     \\  .cfi_def_cfa_offset 0
   2807     \\  ret
   2808     \\  .cfi_endproc
   2809     });
   2810 
   2811     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2812     \\#include <stdio.h>
   2813     \\int foo();
   2814     \\int main() {
   2815     \\  printf("%d\n", foo());
   2816     \\  return 0;
   2817     \\}
   2818     });
   2819     exe.addObject(a_o);
   2820 
   2821     const run = addRunArtifact(exe);
   2822     run.expectStdOutEqual("4\n");
   2823     test_step.dependOn(&run.step);
   2824 
   2825     return test_step;
   2826 }
   2827 
   2828 fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
   2829     const test_step = addTestStep(b, "unwind-info-no-subsections-x64", opts);
   2830 
   2831     const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = 
   2832     \\.globl _foo
   2833     \\_foo:
   2834     \\  .cfi_startproc
   2835     \\  push    %rbp
   2836     \\  .cfi_def_cfa_offset 8
   2837     \\  .cfi_offset %rbp, -8
   2838     \\  mov     %rsp, %rbp
   2839     \\  .cfi_def_cfa_register %rbp
   2840     \\  call    _bar
   2841     \\  pop     %rbp
   2842     \\  .cfi_restore %rbp
   2843     \\  .cfi_def_cfa_offset 0
   2844     \\  ret
   2845     \\  .cfi_endproc
   2846     \\
   2847     \\.globl _bar
   2848     \\_bar:
   2849     \\  .cfi_startproc
   2850     \\  push     %rbp
   2851     \\  .cfi_def_cfa_offset 8
   2852     \\  .cfi_offset %rbp, -8
   2853     \\  mov     %rsp, %rbp
   2854     \\  .cfi_def_cfa_register %rbp
   2855     \\  mov     $4, %rax
   2856     \\  pop     %rbp
   2857     \\  .cfi_restore %rbp
   2858     \\  .cfi_def_cfa_offset 0
   2859     \\  ret
   2860     \\  .cfi_endproc
   2861     });
   2862 
   2863     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   2864     \\#include <stdio.h>
   2865     \\int foo();
   2866     \\int main() {
   2867     \\  printf("%d\n", foo());
   2868     \\  return 0;
   2869     \\}
   2870     });
   2871     exe.addObject(a_o);
   2872 
   2873     const run = addRunArtifact(exe);
   2874     run.expectStdOutEqual("4\n");
   2875     test_step.dependOn(&run.step);
   2876 
   2877     return test_step;
   2878 }
   2879 
   2880 // Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-binding.s
   2881 fn testWeakBind(b: *Build, opts: Options) *Step {
   2882     const test_step = addTestStep(b, "weak-bind", opts);
   2883 
   2884     const lib = addSharedLibrary(b, opts, .{ .name = "foo", .asm_source_bytes = 
   2885     \\.globl _weak_dysym
   2886     \\.weak_definition _weak_dysym
   2887     \\_weak_dysym:
   2888     \\  .quad 0x1234
   2889     \\
   2890     \\.globl _weak_dysym_for_gotpcrel
   2891     \\.weak_definition _weak_dysym_for_gotpcrel
   2892     \\_weak_dysym_for_gotpcrel:
   2893     \\  .quad 0x1234
   2894     \\
   2895     \\.globl _weak_dysym_fn
   2896     \\.weak_definition _weak_dysym_fn
   2897     \\_weak_dysym_fn:
   2898     \\  ret
   2899     \\
   2900     \\.section __DATA,__thread_vars,thread_local_variables
   2901     \\
   2902     \\.globl _weak_dysym_tlv
   2903     \\.weak_definition _weak_dysym_tlv
   2904     \\_weak_dysym_tlv:
   2905     \\  .quad 0x1234
   2906     });
   2907 
   2908     {
   2909         const check = lib.checkObject();
   2910         check.checkInExports();
   2911         check.checkExtract("[WEAK] {vmaddr1} _weak_dysym");
   2912         check.checkExtract("[WEAK] {vmaddr2} _weak_dysym_for_gotpcrel");
   2913         check.checkExtract("[WEAK] {vmaddr3} _weak_dysym_fn");
   2914         check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_dysym_tlv");
   2915         test_step.dependOn(&check.step);
   2916     }
   2917 
   2918     const exe = addExecutable(b, opts, .{ .name = "main", .asm_source_bytes = 
   2919     \\.globl _main, _weak_external, _weak_external_for_gotpcrel, _weak_external_fn
   2920     \\.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_external_fn, _weak_internal, _weak_internal_for_gotpcrel, _weak_internal_fn
   2921     \\
   2922     \\_main:
   2923     \\  mov _weak_dysym_for_gotpcrel@GOTPCREL(%rip), %rax
   2924     \\  mov _weak_external_for_gotpcrel@GOTPCREL(%rip), %rax
   2925     \\  mov _weak_internal_for_gotpcrel@GOTPCREL(%rip), %rax
   2926     \\  mov _weak_tlv@TLVP(%rip), %rax
   2927     \\  mov _weak_dysym_tlv@TLVP(%rip), %rax
   2928     \\  mov _weak_internal_tlv@TLVP(%rip), %rax
   2929     \\  callq _weak_dysym_fn
   2930     \\  callq _weak_external_fn
   2931     \\  callq _weak_internal_fn
   2932     \\  mov $0, %rax
   2933     \\  ret
   2934     \\
   2935     \\_weak_external:
   2936     \\  .quad 0x1234
   2937     \\
   2938     \\_weak_external_for_gotpcrel:
   2939     \\  .quad 0x1234
   2940     \\
   2941     \\_weak_external_fn:
   2942     \\  ret
   2943     \\
   2944     \\_weak_internal:
   2945     \\  .quad 0x1234
   2946     \\
   2947     \\_weak_internal_for_gotpcrel:
   2948     \\  .quad 0x1234
   2949     \\
   2950     \\_weak_internal_fn:
   2951     \\  ret
   2952     \\
   2953     \\.data
   2954     \\  .quad _weak_dysym
   2955     \\  .quad _weak_external + 2
   2956     \\  .quad _weak_internal
   2957     \\
   2958     \\.tbss _weak_tlv$tlv$init, 4, 2
   2959     \\.tbss _weak_internal_tlv$tlv$init, 4, 2
   2960     \\
   2961     \\.section __DATA,__thread_vars,thread_local_variables
   2962     \\.globl _weak_tlv
   2963     \\.weak_definition  _weak_tlv, _weak_internal_tlv
   2964     \\
   2965     \\_weak_tlv:
   2966     \\  .quad __tlv_bootstrap
   2967     \\  .quad 0
   2968     \\  .quad _weak_tlv$tlv$init
   2969     \\
   2970     \\_weak_internal_tlv:
   2971     \\  .quad __tlv_bootstrap
   2972     \\  .quad 0
   2973     \\  .quad _weak_internal_tlv$tlv$init
   2974     });
   2975     exe.linkLibrary(lib);
   2976 
   2977     {
   2978         const check = exe.checkObject();
   2979 
   2980         check.checkInExports();
   2981         check.checkExtract("[WEAK] {vmaddr1} _weak_external");
   2982         check.checkExtract("[WEAK] {vmaddr2} _weak_external_for_gotpcrel");
   2983         check.checkExtract("[WEAK] {vmaddr3} _weak_external_fn");
   2984         check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_tlv");
   2985 
   2986         check.checkInDyldBind();
   2987         check.checkContains("(libfoo.dylib) _weak_dysym_for_gotpcrel");
   2988         check.checkContains("(libfoo.dylib) _weak_dysym_fn");
   2989         check.checkContains("(libfoo.dylib) _weak_dysym");
   2990         check.checkContains("(libfoo.dylib) _weak_dysym_tlv");
   2991 
   2992         check.checkInDyldWeakBind();
   2993         check.checkContains("_weak_external_for_gotpcrel");
   2994         check.checkContains("_weak_dysym_for_gotpcrel");
   2995         check.checkContains("_weak_external_fn");
   2996         check.checkContains("_weak_dysym_fn");
   2997         check.checkContains("_weak_dysym");
   2998         check.checkContains("_weak_external");
   2999         check.checkContains("_weak_tlv");
   3000         check.checkContains("_weak_dysym_tlv");
   3001 
   3002         test_step.dependOn(&check.step);
   3003     }
   3004 
   3005     const run = addRunArtifact(exe);
   3006     run.expectExitCode(0);
   3007     test_step.dependOn(&run.step);
   3008 
   3009     return test_step;
   3010 }
   3011 
   3012 fn testWeakFramework(b: *Build, opts: Options) *Step {
   3013     const test_step = addTestStep(b, "weak-framework", opts);
   3014 
   3015     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
   3016     exe.root_module.linkFramework("Cocoa", .{ .weak = true });
   3017 
   3018     const run = addRunArtifact(exe);
   3019     run.expectExitCode(0);
   3020     test_step.dependOn(&run.step);
   3021 
   3022     const check = exe.checkObject();
   3023     check.checkInHeaders();
   3024     check.checkExact("cmd LOAD_WEAK_DYLIB");
   3025     check.checkContains("Cocoa");
   3026     test_step.dependOn(&check.step);
   3027 
   3028     return test_step;
   3029 }
   3030 
   3031 fn testWeakLibrary(b: *Build, opts: Options) *Step {
   3032     const test_step = addTestStep(b, "weak-library", opts);
   3033 
   3034     const dylib = addSharedLibrary(b, opts, .{ .name = "a", .c_source_bytes = 
   3035     \\#include<stdio.h>
   3036     \\int a = 42;
   3037     \\const char* asStr() {
   3038     \\  static char str[3];
   3039     \\  sprintf(str, "%d", 42);
   3040     \\  return str;
   3041     \\}
   3042     });
   3043 
   3044     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   3045     \\#include<stdio.h>
   3046     \\extern int a;
   3047     \\extern const char* asStr();
   3048     \\int main() {
   3049     \\  printf("%d %s", a, asStr());
   3050     \\  return 0;
   3051     \\}
   3052     });
   3053     exe.root_module.linkSystemLibrary("a", .{ .weak = true });
   3054     exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
   3055     exe.root_module.addRPath(dylib.getEmittedBinDirectory());
   3056 
   3057     const check = exe.checkObject();
   3058     check.checkInHeaders();
   3059     check.checkExact("cmd LOAD_WEAK_DYLIB");
   3060     check.checkContains("liba.dylib");
   3061     check.checkInSymtab();
   3062     check.checkExact("(undefined) weakref external _a (from liba)");
   3063     check.checkInSymtab();
   3064     check.checkExact("(undefined) weakref external _asStr (from liba)");
   3065     test_step.dependOn(&check.step);
   3066 
   3067     const run = addRunArtifact(exe);
   3068     run.expectStdOutEqual("42 42");
   3069     test_step.dependOn(&run.step);
   3070 
   3071     return test_step;
   3072 }
   3073 
   3074 fn testWeakRef(b: *Build, opts: Options) *Step {
   3075     const test_step = addTestStep(b, "weak-ref", opts);
   3076 
   3077     const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = 
   3078     \\#include <stdio.h>
   3079     \\#include <sys/_types/_fd_def.h>
   3080     \\int main(int argc, char** argv) {
   3081     \\    printf("__darwin_check_fd_set_overflow: %p\n", __darwin_check_fd_set_overflow);
   3082     \\}
   3083     });
   3084 
   3085     const check = exe.checkObject();
   3086     check.checkInSymtab();
   3087     check.checkExact("(undefined) weakref external ___darwin_check_fd_set_overflow (from libSystem.B)");
   3088     test_step.dependOn(&check.step);
   3089 
   3090     return test_step;
   3091 }
   3092 
   3093 fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step {
   3094     return link.addTestStep(b, "" ++ prefix, opts);
   3095 }
   3096 
   3097 const builtin = @import("builtin");
   3098 const addAsmSourceBytes = link.addAsmSourceBytes;
   3099 const addCSourceBytes = link.addCSourceBytes;
   3100 const addRunArtifact = link.addRunArtifact;
   3101 const addObject = link.addObject;
   3102 const addExecutable = link.addExecutable;
   3103 const addStaticLibrary = link.addStaticLibrary;
   3104 const addSharedLibrary = link.addSharedLibrary;
   3105 const expectLinkErrors = link.expectLinkErrors;
   3106 const link = @import("link.zig");
   3107 const std = @import("std");
   3108 
   3109 const Build = std.Build;
   3110 const BuildOptions = link.BuildOptions;
   3111 const Compile = Step.Compile;
   3112 const Options = link.Options;
   3113 const Step = Build.Step;
   3114 const WriteFile = Step.WriteFile;