mirror of
https://github.com/ziglang/zig.git
synced 2026-01-24 16:25:25 +00:00
elf: port more linker tests
This commit is contained in:
parent
1efc0519ce
commit
9487007ffe
@ -27,6 +27,8 @@ pub fn build(b: *Build) void {
|
||||
elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testImageBase(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testLinkingC(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target }));
|
||||
@ -44,8 +46,24 @@ pub fn build(b: *Build) void {
|
||||
elf_step.dependOn(testDsoUndef(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testExportDynamic(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testExportSymbolsFromExe(b, .{ .target = glibc_target }));
|
||||
// https://github.com/ziglang/zig/issues/17430
|
||||
// elf_step.dependOn(testFuncAddress(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testHiddenWeakUndef(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncAlias(b, .{ .target = glibc_target }));
|
||||
// https://github.com/ziglang/zig/issues/17430
|
||||
// elf_step.dependOn(testIFuncDlopen(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncDso(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncDynamic(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncExport(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncFuncPtr(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testIFuncNoPlt(b, .{ .target = glibc_target }));
|
||||
// https://github.com/ziglang/zig/issues/17430 ??
|
||||
// elf_step.dependOn(testIFuncStatic(b, .{ .target = glibc_target }));
|
||||
// elf_step.dependOn(testIFuncStaticPie(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testInitArrayOrder(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testLargeAlignmentDso(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = glibc_target }));
|
||||
elf_step.dependOn(testPie(b, .{ .target = glibc_target }));
|
||||
}
|
||||
|
||||
fn testAbsSymbols(b: *Build, opts: Options) *Step {
|
||||
@ -686,6 +704,32 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testFuncAddress(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "func-address", opts);
|
||||
|
||||
const dso = addSharedLibrary(b, "a", opts);
|
||||
addCSourceBytes(dso, "void fn() {}", &.{});
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <assert.h>
|
||||
\\typedef void Func();
|
||||
\\void fn();
|
||||
\\Func *const ptr = fn;
|
||||
\\int main() {
|
||||
\\ assert(fn == ptr);
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibrary(dso);
|
||||
exe.force_pic = false;
|
||||
exe.pie = false;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testGcSections(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "gc-sections", opts);
|
||||
|
||||
@ -776,6 +820,449 @@ fn testGcSections(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testHiddenWeakUndef(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "hidden-weak-undef", opts);
|
||||
|
||||
const dso = addSharedLibrary(b, "a", opts);
|
||||
addCSourceBytes(dso,
|
||||
\\__attribute__((weak, visibility("hidden"))) void foo();
|
||||
\\void bar() { foo(); }
|
||||
, &.{});
|
||||
|
||||
const check = dso.checkObject();
|
||||
check.checkInDynamicSymtab();
|
||||
check.checkNotPresent("foo");
|
||||
check.checkInDynamicSymtab();
|
||||
check.checkContains("bar");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncAlias(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-alias", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <assert.h>
|
||||
\\void foo() {}
|
||||
\\int bar() __attribute__((ifunc("resolve_bar")));
|
||||
\\void *resolve_bar() { return foo; }
|
||||
\\void *bar2 = bar;
|
||||
\\int main() {
|
||||
\\ assert(bar == bar2);
|
||||
\\}
|
||||
, &.{});
|
||||
exe.force_pic = true;
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectExitCode(0);
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncDlopen(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-dlopen", opts);
|
||||
|
||||
const dso = addSharedLibrary(b, "a", opts);
|
||||
addCSourceBytes(dso,
|
||||
\\__attribute__((ifunc("resolve_foo")))
|
||||
\\void foo(void);
|
||||
\\static void real_foo(void) {
|
||||
\\}
|
||||
\\typedef void Func();
|
||||
\\static Func *resolve_foo(void) {
|
||||
\\ return real_foo;
|
||||
\\}
|
||||
, &.{});
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <dlfcn.h>
|
||||
\\#include <assert.h>
|
||||
\\#include <stdlib.h>
|
||||
\\typedef void Func();
|
||||
\\void foo(void);
|
||||
\\int main() {
|
||||
\\ void *handle = dlopen(NULL, RTLD_NOW);
|
||||
\\ Func *p = dlsym(handle, "foo");
|
||||
\\
|
||||
\\ foo();
|
||||
\\ p();
|
||||
\\ assert(foo == p);
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibrary(dso);
|
||||
exe.linkLibC();
|
||||
exe.linkSystemLibrary2("dl", .{});
|
||||
exe.force_pic = false;
|
||||
exe.pie = false;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncDso(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-dso", opts);
|
||||
|
||||
const dso = addSharedLibrary(b, "a", opts);
|
||||
addCSourceBytes(dso,
|
||||
\\#include<stdio.h>
|
||||
\\__attribute__((ifunc("resolve_foobar")))
|
||||
\\void foobar(void);
|
||||
\\static void real_foobar(void) {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\typedef void Func();
|
||||
\\static Func *resolve_foobar(void) {
|
||||
\\ return real_foobar;
|
||||
\\}
|
||||
, &.{});
|
||||
dso.linkLibC();
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\void foobar(void);
|
||||
\\int main() {
|
||||
\\ foobar();
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibrary(dso);
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncDynamic(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-dynamic", opts);
|
||||
|
||||
const main_c =
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((ifunc("resolve_foobar")))
|
||||
\\static void foobar(void);
|
||||
\\static void real_foobar(void) {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\typedef void Func();
|
||||
\\static Func *resolve_foobar(void) {
|
||||
\\ return real_foobar;
|
||||
\\}
|
||||
\\int main() {
|
||||
\\ foobar();
|
||||
\\}
|
||||
;
|
||||
|
||||
{
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe, main_c, &.{});
|
||||
exe.linkLibC();
|
||||
exe.link_z_lazy = true;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
{
|
||||
const exe = addExecutable(b, "other", opts);
|
||||
addCSourceBytes(exe, main_c, &.{});
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncExport(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-export", opts);
|
||||
|
||||
const dso = addSharedLibrary(b, "a", opts);
|
||||
addCSourceBytes(dso,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((ifunc("resolve_foobar")))
|
||||
\\void foobar(void);
|
||||
\\void real_foobar(void) {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\typedef void Func();
|
||||
\\Func *resolve_foobar(void) {
|
||||
\\ return real_foobar;
|
||||
\\}
|
||||
, &.{});
|
||||
dso.linkLibC();
|
||||
|
||||
const check = dso.checkObject();
|
||||
check.checkInDynamicSymtab();
|
||||
check.checkContains("IFUNC GLOBAL DEFAULT foobar");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-func-ptr", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\typedef int Fn();
|
||||
\\int foo() __attribute__((ifunc("resolve_foo")));
|
||||
\\int real_foo() { return 3; }
|
||||
\\Fn *resolve_foo(void) {
|
||||
\\ return real_foo;
|
||||
\\}
|
||||
, &.{});
|
||||
addCSourceBytes(exe,
|
||||
\\typedef int Fn();
|
||||
\\int foo();
|
||||
\\Fn *get_foo() { return foo; }
|
||||
, &.{});
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\typedef int Fn();
|
||||
\\Fn *get_foo();
|
||||
\\int main() {
|
||||
\\ Fn *f = get_foo();
|
||||
\\ printf("%d\n", f());
|
||||
\\}
|
||||
, &.{});
|
||||
exe.force_pic = true;
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("3\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-noplt", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((ifunc("resolve_foo")))
|
||||
\\void foo(void);
|
||||
\\void hello(void) {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\typedef void Fn();
|
||||
\\Fn *resolve_foo(void) {
|
||||
\\ return hello;
|
||||
\\}
|
||||
\\int main() {
|
||||
\\ foo();
|
||||
\\}
|
||||
, &.{"-fno-plt"});
|
||||
exe.force_pic = true;
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncStatic(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-static", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\void foo() __attribute__((ifunc("resolve_foo")));
|
||||
\\void hello() {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\void *resolve_foo() {
|
||||
\\ return hello;
|
||||
\\}
|
||||
\\int main() {
|
||||
\\ foo();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibC();
|
||||
exe.linkage = .static;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "ifunc-static-pie", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\void foo() __attribute__((ifunc("resolve_foo")));
|
||||
\\void hello() {
|
||||
\\ printf("Hello world\n");
|
||||
\\}
|
||||
\\void *resolve_foo() {
|
||||
\\ return hello;
|
||||
\\}
|
||||
\\int main() {
|
||||
\\ foo();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkage = .static;
|
||||
exe.force_pic = true;
|
||||
exe.pie = true;
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello world\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type DYN");
|
||||
check.checkStart();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .dynamic");
|
||||
check.checkStart();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .interp");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testImageBase(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "image-base", opts);
|
||||
|
||||
{
|
||||
const exe = addExecutable(b, "main1", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\int main() {
|
||||
\\ printf("Hello World!\n");
|
||||
\\ return 0;
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibC();
|
||||
exe.image_base = 0x8000000;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello World!\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkExact("header");
|
||||
check.checkExtract("entry {addr}");
|
||||
check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0x8000000 } });
|
||||
test_step.dependOn(&check.step);
|
||||
}
|
||||
|
||||
{
|
||||
const exe = addExecutable(b, "main2", opts);
|
||||
addCSourceBytes(exe, "void _start() {}", &.{});
|
||||
exe.image_base = 0xffffffff8000000;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkExact("header");
|
||||
check.checkExtract("entry {addr}");
|
||||
check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0xffffffff8000000 } });
|
||||
test_step.dependOn(&check.step);
|
||||
}
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testInitArrayOrder(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "init-array-order", opts);
|
||||
|
||||
const a_o = addObject(b, "a", opts);
|
||||
addCSourceBytes(a_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((constructor(10000))) void init4() { printf("1"); }
|
||||
, &.{});
|
||||
a_o.linkLibC();
|
||||
|
||||
const b_o = addObject(b, "b", opts);
|
||||
addCSourceBytes(b_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((constructor(1000))) void init3() { printf("2"); }
|
||||
, &.{});
|
||||
b_o.linkLibC();
|
||||
|
||||
const c_o = addObject(b, "c", opts);
|
||||
addCSourceBytes(c_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((constructor)) void init1() { printf("3"); }
|
||||
, &.{});
|
||||
c_o.linkLibC();
|
||||
|
||||
const d_o = addObject(b, "d", opts);
|
||||
addCSourceBytes(d_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((constructor)) void init2() { printf("4"); }
|
||||
, &.{});
|
||||
d_o.linkLibC();
|
||||
|
||||
const e_o = addObject(b, "e", opts);
|
||||
addCSourceBytes(e_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((destructor(10000))) void fini4() { printf("5"); }
|
||||
, &.{});
|
||||
e_o.linkLibC();
|
||||
|
||||
const f_o = addObject(b, "f", opts);
|
||||
addCSourceBytes(f_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((destructor(1000))) void fini3() { printf("6"); }
|
||||
, &.{});
|
||||
f_o.linkLibC();
|
||||
|
||||
const g_o = addObject(b, "g", opts);
|
||||
addCSourceBytes(g_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((destructor)) void fini1() { printf("7"); }
|
||||
, &.{});
|
||||
g_o.linkLibC();
|
||||
|
||||
const h_o = addObject(b, "h", opts);
|
||||
addCSourceBytes(h_o,
|
||||
\\#include <stdio.h>
|
||||
\\__attribute__((destructor)) void fini2() { printf("8"); }
|
||||
, &.{});
|
||||
h_o.linkLibC();
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe, "int main() { return 0; }", &.{});
|
||||
exe.addObject(a_o);
|
||||
exe.addObject(b_o);
|
||||
exe.addObject(c_o);
|
||||
exe.addObject(d_o);
|
||||
exe.addObject(e_o);
|
||||
exe.addObject(f_o);
|
||||
exe.addObject(g_o);
|
||||
exe.addObject(h_o);
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("21348756");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "large-alignment-dso", opts);
|
||||
|
||||
@ -951,6 +1438,37 @@ fn testLinkingZig(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testPie(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "hello-pie", opts);
|
||||
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
addCSourceBytes(exe,
|
||||
\\#include <stdio.h>
|
||||
\\int main() {
|
||||
\\ printf("Hello!\n");
|
||||
\\ return 0;
|
||||
\\}
|
||||
, &.{});
|
||||
exe.linkLibC();
|
||||
exe.force_pic = true;
|
||||
exe.pie = true;
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("Hello!\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type DYN");
|
||||
check.checkStart();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .dynamic");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testTlsStatic(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "tls-static", opts);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user