diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-10-09 14:23:57 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-10-16 19:33:05 +0200 |
| commit | 9487007ffe332affe3960a5cca6c87759ffdfd22 (patch) | |
| tree | 74c7d3796643c2b96a0b0c263d5092537751ccc2 /test | |
| parent | 1efc0519ce711ba8e7ee4d621a5bd13766c23020 (diff) | |
| download | zig-9487007ffe332affe3960a5cca6c87759ffdfd22.tar.gz zig-9487007ffe332affe3960a5cca6c87759ffdfd22.zip | |
elf: port more linker tests
Diffstat (limited to 'test')
| -rw-r--r-- | test/link/elf.zig | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/test/link/elf.zig b/test/link/elf.zig index 04454b21fd..383f3695b7 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -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); |
