Commit a3f68c6fa2
Changed files (10)
test
link
macho
test/link/macho/reexports/a.zig
@@ -1,7 +0,0 @@
-const x: i32 = 42;
-export fn foo() i32 {
- return x;
-}
-comptime {
- @export(foo, .{ .name = "bar", .linkage = .Strong });
-}
test/link/macho/reexports/build.zig
@@ -1,38 +0,0 @@
-const std = @import("std");
-
-pub const requires_symlinks = true;
-
-pub fn build(b: *std.Build) void {
- const test_step = b.step("test", "Test it");
- b.default_step = test_step;
-
- add(b, test_step, .Debug);
- add(b, test_step, .ReleaseFast);
- add(b, test_step, .ReleaseSmall);
- add(b, test_step, .ReleaseSafe);
-}
-
-fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
- const target = b.resolveTargetQuery(.{ .os_tag = .macos });
-
- const lib = b.addStaticLibrary(.{
- .name = "a",
- .root_source_file = .{ .path = "a.zig" },
- .optimize = optimize,
- .target = target,
- });
-
- const exe = b.addExecutable(.{
- .name = "test",
- .optimize = optimize,
- .target = target,
- });
- exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
- exe.linkLibrary(lib);
- exe.linkLibC();
-
- const run = b.addRunArtifact(exe);
- run.skip_foreign_checks = true;
- run.expectExitCode(0);
- test_step.dependOn(&run.step);
-}
test/link/macho/reexports/main.c
@@ -1,5 +0,0 @@
-extern int foo();
-extern int bar();
-int main() {
- return bar() - foo();
-}
test/link/macho/unwind_info/all.h
@@ -1,41 +0,0 @@
-#ifndef ALL
-#define ALL
-
-#include <cstddef>
-#include <string>
-#include <stdexcept>
-
-struct SimpleString {
- SimpleString(size_t max_size);
- ~SimpleString();
-
- void print(const char* tag) const;
- bool append_line(const char* x);
-
-private:
- size_t max_size;
- char* buffer;
- size_t length;
-};
-
-struct SimpleStringOwner {
- SimpleStringOwner(const char* x);
- ~SimpleStringOwner();
-
-private:
- SimpleString string;
-};
-
-class Error: public std::exception {
-public:
- explicit Error(const char* msg) : msg{ msg } {}
- virtual ~Error() noexcept {}
- virtual const char* what() const noexcept {
- return msg.c_str();
- }
-
-protected:
- std::string msg;
-};
-
-#endif
test/link/macho/unwind_info/build.zig
@@ -1,88 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-
-pub const requires_symlinks = true;
-
-pub fn build(b: *std.Build) void {
- const test_step = b.step("test", "Test it");
- b.default_step = test_step;
-
- add(b, test_step, .Debug);
- add(b, test_step, .ReleaseFast);
- add(b, test_step, .ReleaseSmall);
- add(b, test_step, .ReleaseSafe);
-}
-
-fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
- const target = b.resolveTargetQuery(.{ .os_tag = .macos });
-
- testUnwindInfo(b, test_step, optimize, target, false, "no-dead-strip");
- testUnwindInfo(b, test_step, optimize, target, true, "yes-dead-strip");
-}
-
-fn testUnwindInfo(
- b: *std.Build,
- test_step: *std.Build.Step,
- optimize: std.builtin.OptimizeMode,
- target: std.Build.ResolvedTarget,
- dead_strip: bool,
- name: []const u8,
-) void {
- const exe = createScenario(b, optimize, target, name);
- exe.link_gc_sections = dead_strip;
-
- const check = exe.checkObject();
- check.checkInHeaders();
- check.checkExact("segname __TEXT");
- check.checkExact("sectname __gcc_except_tab");
- check.checkExact("sectname __unwind_info");
-
- switch (builtin.cpu.arch) {
- .aarch64 => {
- check.checkExact("sectname __eh_frame");
- },
- .x86_64 => {}, // We do not expect `__eh_frame` section on x86_64 in this case
- else => unreachable,
- }
-
- check.checkInSymtab();
- check.checkContains("(was private external) ___gxx_personality_v0");
- test_step.dependOn(&check.step);
-
- const run = b.addRunArtifact(exe);
- run.skip_foreign_checks = true;
- run.expectStdOutEqual(
- \\Constructed: a
- \\Constructed: b
- \\About to destroy: b
- \\About to destroy: a
- \\Error: Not enough memory!
- \\
- );
-
- test_step.dependOn(&run.step);
-}
-
-fn createScenario(
- b: *std.Build,
- optimize: std.builtin.OptimizeMode,
- target: std.Build.ResolvedTarget,
- name: []const u8,
-) *std.Build.Step.Compile {
- const exe = b.addExecutable(.{
- .name = name,
- .optimize = optimize,
- .target = target,
- });
- b.default_step.dependOn(&exe.step);
- exe.addIncludePath(.{ .path = "." });
- exe.addCSourceFiles(.{
- .files = &[_][]const u8{
- "main.cpp",
- "simple_string.cpp",
- "simple_string_owner.cpp",
- },
- });
- exe.linkLibCpp();
- return exe;
-}
test/link/macho/unwind_info/main.cpp
@@ -1,24 +0,0 @@
-#include "all.h"
-#include <cstdio>
-
-void fn_c() {
- SimpleStringOwner c{ "cccccccccc" };
-}
-
-void fn_b() {
- SimpleStringOwner b{ "b" };
- fn_c();
-}
-
-int main() {
- try {
- SimpleStringOwner a{ "a" };
- fn_b();
- SimpleStringOwner d{ "d" };
- } catch (const Error& e) {
- printf("Error: %s\n", e.what());
- } catch(const std::exception& e) {
- printf("Exception: %s\n", e.what());
- }
- return 0;
-}
test/link/macho/unwind_info/simple_string.cpp
@@ -1,30 +0,0 @@
-#include "all.h"
-#include <cstdio>
-#include <cstring>
-
-SimpleString::SimpleString(size_t max_size)
-: max_size{ max_size }, length{} {
- if (max_size == 0) {
- throw Error{ "Max size must be at least 1." };
- }
- buffer = new char[max_size];
- buffer[0] = 0;
-}
-
-SimpleString::~SimpleString() {
- delete[] buffer;
-}
-
-void SimpleString::print(const char* tag) const {
- printf("%s: %s", tag, buffer);
-}
-
-bool SimpleString::append_line(const char* x) {
- const auto x_len = strlen(x);
- if (x_len + length + 2 > max_size) return false;
- std::strncpy(buffer + length, x, max_size - length);
- length += x_len;
- buffer[length++] = '\n';
- buffer[length] = 0;
- return true;
-}
test/link/macho/unwind_info/simple_string_owner.cpp
@@ -1,12 +0,0 @@
-#include "all.h"
-
-SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } {
- if (!string.append_line(x)) {
- throw Error{ "Not enough memory!" };
- }
- string.print("Constructed");
-}
-
-SimpleStringOwner::~SimpleStringOwner() {
- string.print("About to destroy");
-}
test/link/macho.zig
@@ -38,6 +38,9 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
macho_step.dependOn(testThunks(b, .{ .target = aarch64_target }));
macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target }));
macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target }));
+ macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));
+ macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));
+ macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));
macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));
// Tests requiring symlinks when tested on Windows
@@ -1589,6 +1592,276 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
return test_step;
}
+fn testUnwindInfo(b: *Build, opts: Options) *Step {
+ const test_step = addTestStep(b, "macho-unwind-info", opts);
+
+ const all_h = all_h: {
+ const wf = WriteFile.create(b);
+ break :all_h wf.add("all.h",
+ \\#ifndef ALL
+ \\#define ALL
+ \\
+ \\#include <cstddef>
+ \\#include <string>
+ \\#include <stdexcept>
+ \\
+ \\struct SimpleString {
+ \\ SimpleString(size_t max_size);
+ \\ ~SimpleString();
+ \\
+ \\ void print(const char* tag) const;
+ \\ bool append_line(const char* x);
+ \\
+ \\private:
+ \\ size_t max_size;
+ \\ char* buffer;
+ \\ size_t length;
+ \\};
+ \\
+ \\struct SimpleStringOwner {
+ \\ SimpleStringOwner(const char* x);
+ \\ ~SimpleStringOwner();
+ \\
+ \\private:
+ \\ SimpleString string;
+ \\};
+ \\
+ \\class Error: public std::exception {
+ \\public:
+ \\ explicit Error(const char* msg) : msg{ msg } {}
+ \\ virtual ~Error() noexcept {}
+ \\ virtual const char* what() const noexcept {
+ \\ return msg.c_str();
+ \\ }
+ \\
+ \\protected:
+ \\ std::string msg;
+ \\};
+ \\
+ \\#endif
+ );
+ };
+
+ const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
+ \\#include "all.h"
+ \\#include <cstdio>
+ \\
+ \\void fn_c() {
+ \\ SimpleStringOwner c{ "cccccccccc" };
+ \\}
+ \\
+ \\void fn_b() {
+ \\ SimpleStringOwner b{ "b" };
+ \\ fn_c();
+ \\}
+ \\
+ \\int main() {
+ \\ try {
+ \\ SimpleStringOwner a{ "a" };
+ \\ fn_b();
+ \\ SimpleStringOwner d{ "d" };
+ \\ } catch (const Error& e) {
+ \\ printf("Error: %s\n", e.what());
+ \\ } catch(const std::exception& e) {
+ \\ printf("Exception: %s\n", e.what());
+ \\ }
+ \\ return 0;
+ \\}
+ });
+ main_o.root_module.addIncludePath(all_h.dirname());
+ main_o.linkLibCpp();
+
+ const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
+ \\#include "all.h"
+ \\#include <cstdio>
+ \\#include <cstring>
+ \\
+ \\SimpleString::SimpleString(size_t max_size)
+ \\: max_size{ max_size }, length{} {
+ \\ if (max_size == 0) {
+ \\ throw Error{ "Max size must be at least 1." };
+ \\ }
+ \\ buffer = new char[max_size];
+ \\ buffer[0] = 0;
+ \\}
+ \\
+ \\SimpleString::~SimpleString() {
+ \\ delete[] buffer;
+ \\}
+ \\
+ \\void SimpleString::print(const char* tag) const {
+ \\ printf("%s: %s", tag, buffer);
+ \\}
+ \\
+ \\bool SimpleString::append_line(const char* x) {
+ \\ const auto x_len = strlen(x);
+ \\ if (x_len + length + 2 > max_size) return false;
+ \\ std::strncpy(buffer + length, x, max_size - length);
+ \\ length += x_len;
+ \\ buffer[length++] = '\n';
+ \\ buffer[length] = 0;
+ \\ return true;
+ \\}
+ });
+ simple_string_o.root_module.addIncludePath(all_h.dirname());
+ simple_string_o.linkLibCpp();
+
+ const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
+ \\#include "all.h"
+ \\
+ \\SimpleStringOwner::SimpleStringOwner(const char* x) : string{ 10 } {
+ \\ if (!string.append_line(x)) {
+ \\ throw Error{ "Not enough memory!" };
+ \\ }
+ \\ string.print("Constructed");
+ \\}
+ \\
+ \\SimpleStringOwner::~SimpleStringOwner() {
+ \\ string.print("About to destroy");
+ \\}
+ });
+ simple_string_owner_o.root_module.addIncludePath(all_h.dirname());
+ simple_string_owner_o.linkLibCpp();
+
+ const exp_stdout =
+ \\Constructed: a
+ \\Constructed: b
+ \\About to destroy: b
+ \\About to destroy: a
+ \\Error: Not enough memory!
+ \\
+ ;
+
+ const exe = addExecutable(b, opts, .{ .name = "main" });
+ exe.addObject(main_o);
+ exe.addObject(simple_string_o);
+ exe.addObject(simple_string_owner_o);
+ exe.linkLibCpp();
+
+ const run = addRunArtifact(exe);
+ run.expectStdOutEqual(exp_stdout);
+ test_step.dependOn(&run.step);
+
+ const check = exe.checkObject();
+ check.checkInSymtab();
+ check.checkContains("(was private external) ___gxx_personality_v0");
+ test_step.dependOn(&check.step);
+
+ return test_step;
+}
+
+fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
+ const test_step = addTestStep(b, "macho-unwind-info-no-subsections-arm64", opts);
+
+ const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes =
+ \\.globl _foo
+ \\.align 4
+ \\_foo:
+ \\ .cfi_startproc
+ \\ stp x29, x30, [sp, #-32]!
+ \\ .cfi_def_cfa_offset 32
+ \\ .cfi_offset w30, -24
+ \\ .cfi_offset w29, -32
+ \\ mov x29, sp
+ \\ .cfi_def_cfa w29, 32
+ \\ bl _bar
+ \\ ldp x29, x30, [sp], #32
+ \\ .cfi_restore w29
+ \\ .cfi_restore w30
+ \\ .cfi_def_cfa_offset 0
+ \\ ret
+ \\ .cfi_endproc
+ \\
+ \\.globl _bar
+ \\.align 4
+ \\_bar:
+ \\ .cfi_startproc
+ \\ sub sp, sp, #32
+ \\ .cfi_def_cfa_offset -32
+ \\ stp x29, x30, [sp, #16]
+ \\ .cfi_offset w30, -24
+ \\ .cfi_offset w29, -32
+ \\ mov x29, sp
+ \\ .cfi_def_cfa w29, 32
+ \\ mov w0, #4
+ \\ ldp x29, x30, [sp, #16]
+ \\ .cfi_restore w29
+ \\ .cfi_restore w30
+ \\ add sp, sp, #32
+ \\ .cfi_def_cfa_offset 0
+ \\ ret
+ \\ .cfi_endproc
+ });
+
+ const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
+ \\#include <stdio.h>
+ \\int foo();
+ \\int main() {
+ \\ printf("%d\n", foo());
+ \\ return 0;
+ \\}
+ });
+ exe.addObject(a_o);
+
+ const run = addRunArtifact(exe);
+ run.expectStdOutEqual("4\n");
+ test_step.dependOn(&run.step);
+
+ return test_step;
+}
+
+fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
+ const test_step = addTestStep(b, "macho-unwind-info-no-subsections-x64", opts);
+
+ const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes =
+ \\.globl _foo
+ \\_foo:
+ \\ .cfi_startproc
+ \\ push %rbp
+ \\ .cfi_def_cfa_offset 8
+ \\ .cfi_offset %rbp, -8
+ \\ mov %rsp, %rbp
+ \\ .cfi_def_cfa_register %rbp
+ \\ call _bar
+ \\ pop %rbp
+ \\ .cfi_restore %rbp
+ \\ .cfi_def_cfa_offset 0
+ \\ ret
+ \\ .cfi_endproc
+ \\
+ \\.globl _bar
+ \\_bar:
+ \\ .cfi_startproc
+ \\ push %rbp
+ \\ .cfi_def_cfa_offset 8
+ \\ .cfi_offset %rbp, -8
+ \\ mov %rsp, %rbp
+ \\ .cfi_def_cfa_register %rbp
+ \\ mov $4, %rax
+ \\ pop %rbp
+ \\ .cfi_restore %rbp
+ \\ .cfi_def_cfa_offset 0
+ \\ ret
+ \\ .cfi_endproc
+ });
+
+ const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
+ \\#include <stdio.h>
+ \\int foo();
+ \\int main() {
+ \\ printf("%d\n", foo());
+ \\ return 0;
+ \\}
+ });
+ exe.addObject(a_o);
+
+ const run = addRunArtifact(exe);
+ run.expectStdOutEqual("4\n");
+ test_step.dependOn(&run.step);
+
+ return test_step;
+}
+
// Adapted from https://github.com/llvm/llvm-project/blob/main/lld/test/MachO/weak-binding.s
fn testWeakBind(b: *Build, opts: Options) *Step {
const test_step = addTestStep(b, "macho-weak-bind", opts);
test/link.zig
@@ -115,16 +115,8 @@ pub const cases = [_]Case{
.build_root = "test/link/macho/objcpp",
.import = @import("link/macho/objcpp/build.zig"),
},
- .{
- .build_root = "test/link/macho/reexports",
- .import = @import("link/macho/reexports/build.zig"),
- },
.{
.build_root = "test/link/macho/tbdv3",
.import = @import("link/macho/tbdv3/build.zig"),
},
- .{
- .build_root = "test/link/macho/unwind_info",
- .import = @import("link/macho/unwind_info/build.zig"),
- },
};