test/link/macho: test weak binding

This commit is contained in:
Jakub Konka 2024-01-14 00:23:11 +01:00
parent 2c0c86944e
commit 1e0eb3c809

View File

@ -7,6 +7,10 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
const default_target = b.resolveTargetQuery(.{
.os_tag = .macos,
});
const x86_64_target = b.resolveTargetQuery(.{
.cpu_arch = .x86_64,
.os_tag = .macos,
});
macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
macho_step.dependOn(testEntryPointDylib(b, .{ .target = default_target }));
@ -17,6 +21,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target }));
macho_step.dependOn(testSectionBoundarySymbols(b, .{ .target = default_target }));
macho_step.dependOn(testSegmentBoundarySymbols(b, .{ .target = default_target }));
macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));
// Tests requiring symlinks when tested on Windows
if (build_opts.has_symlinks_windows) {
@ -629,6 +634,138 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *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);
const lib = addSharedLibrary(b, opts, .{ .name = "foo", .asm_source_bytes =
\\.globl _weak_dysym
\\.weak_definition _weak_dysym
\\_weak_dysym:
\\ .quad 0x1234
\\
\\.globl _weak_dysym_for_gotpcrel
\\.weak_definition _weak_dysym_for_gotpcrel
\\_weak_dysym_for_gotpcrel:
\\ .quad 0x1234
\\
\\.globl _weak_dysym_fn
\\.weak_definition _weak_dysym_fn
\\_weak_dysym_fn:
\\ ret
\\
\\.section __DATA,__thread_vars,thread_local_variables
\\
\\.globl _weak_dysym_tlv
\\.weak_definition _weak_dysym_tlv
\\_weak_dysym_tlv:
\\ .quad 0x1234
});
{
const check = lib.checkObject();
check.checkInExports();
check.checkExtract("[WEAK] {vmaddr1} _weak_dysym");
check.checkExtract("[WEAK] {vmaddr2} _weak_dysym_for_gotpcrel");
check.checkExtract("[WEAK] {vmaddr3} _weak_dysym_fn");
check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_dysym_tlv");
test_step.dependOn(&check.step);
}
const exe = addExecutable(b, opts, .{ .name = "main", .asm_source_bytes =
\\.globl _main, _weak_external, _weak_external_for_gotpcrel, _weak_external_fn
\\.weak_definition _weak_external, _weak_external_for_gotpcrel, _weak_external_fn, _weak_internal, _weak_internal_for_gotpcrel, _weak_internal_fn
\\
\\_main:
\\ mov _weak_dysym_for_gotpcrel@GOTPCREL(%rip), %rax
\\ mov _weak_external_for_gotpcrel@GOTPCREL(%rip), %rax
\\ mov _weak_internal_for_gotpcrel@GOTPCREL(%rip), %rax
\\ mov _weak_tlv@TLVP(%rip), %rax
\\ mov _weak_dysym_tlv@TLVP(%rip), %rax
\\ mov _weak_internal_tlv@TLVP(%rip), %rax
\\ callq _weak_dysym_fn
\\ callq _weak_external_fn
\\ callq _weak_internal_fn
\\ mov $0, %rax
\\ ret
\\
\\_weak_external:
\\ .quad 0x1234
\\
\\_weak_external_for_gotpcrel:
\\ .quad 0x1234
\\
\\_weak_external_fn:
\\ ret
\\
\\_weak_internal:
\\ .quad 0x1234
\\
\\_weak_internal_for_gotpcrel:
\\ .quad 0x1234
\\
\\_weak_internal_fn:
\\ ret
\\
\\.data
\\ .quad _weak_dysym
\\ .quad _weak_external + 2
\\ .quad _weak_internal
\\
\\.tbss _weak_tlv$tlv$init, 4, 2
\\.tbss _weak_internal_tlv$tlv$init, 4, 2
\\
\\.section __DATA,__thread_vars,thread_local_variables
\\.globl _weak_tlv
\\.weak_definition _weak_tlv, _weak_internal_tlv
\\
\\_weak_tlv:
\\ .quad __tlv_bootstrap
\\ .quad 0
\\ .quad _weak_tlv$tlv$init
\\
\\_weak_internal_tlv:
\\ .quad __tlv_bootstrap
\\ .quad 0
\\ .quad _weak_internal_tlv$tlv$init
});
exe.linkLibrary(lib);
{
const check = exe.checkObject();
check.checkInExports();
check.checkExtract("[WEAK] {vmaddr1} _weak_external");
check.checkExtract("[WEAK] {vmaddr2} _weak_external_for_gotpcrel");
check.checkExtract("[WEAK] {vmaddr3} _weak_external_fn");
check.checkExtract("[THREAD_LOCAL, WEAK] {vmaddr4} _weak_tlv");
check.checkInDyldBind();
check.checkContains("(libfoo.dylib) _weak_dysym_for_gotpcrel");
check.checkContains("(libfoo.dylib) _weak_dysym_fn");
check.checkContains("(libfoo.dylib) _weak_dysym");
check.checkContains("(libfoo.dylib) _weak_dysym_tlv");
check.checkInDyldWeakBind();
check.checkContains("_weak_external_for_gotpcrel");
check.checkContains("_weak_dysym_for_gotpcrel");
check.checkContains("_weak_external_fn");
check.checkContains("_weak_dysym_fn");
check.checkContains("_weak_dysym");
check.checkContains("_weak_external");
check.checkContains("_weak_tlv");
check.checkContains("_weak_dysym_tlv");
test_step.dependOn(&check.step);
}
const run = addRunArtifact(exe);
run.expectExitCode(0);
test_step.dependOn(&run.step);
return test_step;
}
fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step {
return link.addTestStep(b, "macho-" ++ prefix, opts);
}