master
1pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
2 _ = build_opts;
3 const elf_step = b.step("test-elf", "Run ELF tests");
4
5 // https://github.com/ziglang/zig/issues/25323
6 if (builtin.os.tag == .freebsd) return elf_step;
7
8 // https://github.com/ziglang/zig/issues/25961
9 if (comptime builtin.cpu.arch.endian() == .big) return elf_step;
10
11 const default_target = b.resolveTargetQuery(.{
12 .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs
13 .os_tag = .linux,
14 });
15 const x86_64_musl = b.resolveTargetQuery(.{
16 .cpu_arch = .x86_64,
17 .os_tag = .linux,
18 .abi = .musl,
19 });
20 const x86_64_gnu = b.resolveTargetQuery(.{
21 .cpu_arch = .x86_64,
22 .os_tag = .linux,
23 .abi = .gnu,
24 });
25 const aarch64_musl = b.resolveTargetQuery(.{
26 .cpu_arch = .aarch64,
27 .os_tag = .linux,
28 .abi = .musl,
29 });
30 const riscv64_musl = b.resolveTargetQuery(.{
31 .cpu_arch = .riscv64,
32 .os_tag = .linux,
33 .abi = .musl,
34 });
35
36 // Common tests
37 for (&[_]std.Target.Cpu.Arch{
38 .x86_64,
39 .aarch64,
40 }) |cpu_arch| {
41 const musl_target = b.resolveTargetQuery(.{
42 .cpu_arch = cpu_arch,
43 .os_tag = .linux,
44 .abi = .musl,
45 });
46 const gnu_target = b.resolveTargetQuery(.{
47 .cpu_arch = cpu_arch,
48 .os_tag = .linux,
49 .abi = .gnu,
50 });
51
52 // Exercise linker in -r mode
53 elf_step.dependOn(testEmitRelocatable(b, .{ .target = musl_target }));
54 elf_step.dependOn(testRelocatableArchive(b, .{ .target = musl_target }));
55 elf_step.dependOn(testRelocatableEhFrame(b, .{ .target = musl_target }));
56 elf_step.dependOn(testRelocatableEhFrameComdatHeavy(b, .{ .target = musl_target }));
57 elf_step.dependOn(testRelocatableNoEhFrame(b, .{ .target = musl_target }));
58
59 // Exercise linker in ar mode
60 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
61 elf_step.dependOn(testEmitStaticLibZig(b, .{ .target = musl_target }));
62
63 // Exercise linker with LLVM backend
64 // musl tests
65 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));
66 elf_step.dependOn(testComdatElimination(b, .{ .target = musl_target }));
67 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));
68 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));
69 elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));
70 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));
71 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));
72 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));
73 elf_step.dependOn(testGcSectionsZig(b, .{ .target = musl_target }));
74 elf_step.dependOn(testImageBase(b, .{ .target = musl_target }));
75 elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target }));
76 elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target }));
77 // https://github.com/ziglang/zig/issues/17449
78 // elf_step.dependOn(testLargeBss(b, .{ .target = musl_target }));
79 elf_step.dependOn(testLinkingC(b, .{ .target = musl_target }));
80 elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target }));
81 elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target }));
82 elf_step.dependOn(testLinksection(b, .{ .target = musl_target }));
83 elf_step.dependOn(testMergeStrings(b, .{ .target = musl_target }));
84 elf_step.dependOn(testMergeStrings2(b, .{ .target = musl_target }));
85 // https://github.com/ziglang/zig/issues/17451
86 // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target }));
87 elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target }));
88 elf_step.dependOn(testStrip(b, .{ .target = musl_target }));
89
90 // glibc tests
91 elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target }));
92 // https://github.com/ziglang/zig/issues/17430
93 // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target }));
94 elf_step.dependOn(testCommentString(b, .{ .target = gnu_target }));
95 elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target }));
96 // https://github.com/ziglang/zig/issues/17430
97 // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target }));
98 // https://github.com/ziglang/zig/issues/17430
99 // elf_step.dependOn(testCopyrelAlignment(b, .{ .target = gnu_target }));
100 elf_step.dependOn(testDsoPlt(b, .{ .target = gnu_target }));
101 elf_step.dependOn(testDsoUndef(b, .{ .target = gnu_target }));
102 elf_step.dependOn(testExportDynamic(b, .{ .target = gnu_target }));
103 elf_step.dependOn(testExportSymbolsFromExe(b, .{ .target = gnu_target }));
104 // https://github.com/ziglang/zig/issues/17430
105 // elf_step.dependOn(testFuncAddress(b, .{ .target = gnu_target }));
106 elf_step.dependOn(testHiddenWeakUndef(b, .{ .target = gnu_target }));
107 elf_step.dependOn(testIFuncAlias(b, .{ .target = gnu_target }));
108 // https://github.com/ziglang/zig/issues/17430
109 // elf_step.dependOn(testIFuncDlopen(b, .{ .target = gnu_target }));
110 elf_step.dependOn(testIFuncDso(b, .{ .target = gnu_target }));
111 elf_step.dependOn(testIFuncDynamic(b, .{ .target = gnu_target }));
112 elf_step.dependOn(testIFuncExport(b, .{ .target = gnu_target }));
113 elf_step.dependOn(testIFuncFuncPtr(b, .{ .target = gnu_target }));
114 elf_step.dependOn(testIFuncNoPlt(b, .{ .target = gnu_target }));
115 // https://github.com/ziglang/zig/issues/17430 ??
116 // elf_step.dependOn(testIFuncStatic(b, .{ .target = gnu_target }));
117 // elf_step.dependOn(testIFuncStaticPie(b, .{ .target = gnu_target }));
118 elf_step.dependOn(testInitArrayOrder(b, .{ .target = gnu_target }));
119 elf_step.dependOn(testLargeAlignmentDso(b, .{ .target = gnu_target }));
120 elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = gnu_target }));
121 elf_step.dependOn(testLargeBss(b, .{ .target = gnu_target }));
122 elf_step.dependOn(testLinkOrder(b, .{ .target = gnu_target }));
123 elf_step.dependOn(testLdScript(b, .{ .target = gnu_target }));
124 // https://github.com/ziglang/zig/issues/23125
125 // elf_step.dependOn(testLdScriptPathError(b, .{ .target = gnu_target }));
126 elf_step.dependOn(testLdScriptAllowUndefinedVersion(b, .{ .target = gnu_target, .use_lld = true }));
127 elf_step.dependOn(testLdScriptDisallowUndefinedVersion(b, .{ .target = gnu_target, .use_lld = true }));
128 // https://github.com/ziglang/zig/issues/17451
129 // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = gnu_target }));
130 elf_step.dependOn(testPie(b, .{ .target = gnu_target }));
131 elf_step.dependOn(testPltGot(b, .{ .target = gnu_target }));
132 elf_step.dependOn(testPreinitArray(b, .{ .target = gnu_target }));
133 elf_step.dependOn(testSharedAbsSymbol(b, .{ .target = gnu_target }));
134 elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = gnu_target }));
135 elf_step.dependOn(testTlsDso(b, .{ .target = gnu_target }));
136 elf_step.dependOn(testTlsGd(b, .{ .target = gnu_target }));
137 elf_step.dependOn(testTlsGdNoPlt(b, .{ .target = gnu_target }));
138 elf_step.dependOn(testTlsGdToIe(b, .{ .target = gnu_target }));
139 elf_step.dependOn(testTlsIe(b, .{ .target = gnu_target }));
140 elf_step.dependOn(testTlsLargeAlignment(b, .{ .target = gnu_target }));
141 elf_step.dependOn(testTlsLargeTbss(b, .{ .target = gnu_target }));
142 elf_step.dependOn(testTlsLargeStaticImage(b, .{ .target = gnu_target }));
143 elf_step.dependOn(testTlsLd(b, .{ .target = gnu_target }));
144 elf_step.dependOn(testTlsLdDso(b, .{ .target = gnu_target }));
145 elf_step.dependOn(testTlsLdNoPlt(b, .{ .target = gnu_target }));
146 // https://github.com/ziglang/zig/issues/17430
147 // elf_step.dependOn(testTlsNoPic(b, .{ .target = gnu_target }));
148 elf_step.dependOn(testTlsOffsetAlignment(b, .{ .target = gnu_target }));
149 elf_step.dependOn(testTlsPic(b, .{ .target = gnu_target }));
150 elf_step.dependOn(testTlsSmallAlignment(b, .{ .target = gnu_target }));
151 elf_step.dependOn(testUnknownFileTypeError(b, .{ .target = gnu_target }));
152 elf_step.dependOn(testUnresolvedError(b, .{ .target = gnu_target }));
153 elf_step.dependOn(testWeakExports(b, .{ .target = gnu_target }));
154 elf_step.dependOn(testWeakUndefsDso(b, .{ .target = gnu_target }));
155 elf_step.dependOn(testZNow(b, .{ .target = gnu_target }));
156 elf_step.dependOn(testZStackSize(b, .{ .target = gnu_target }));
157 }
158
159 // x86_64 specific tests
160 elf_step.dependOn(testMismatchedCpuArchitectureError(b, .{ .target = x86_64_musl }));
161 elf_step.dependOn(testZText(b, .{ .target = x86_64_gnu }));
162
163 // aarch64 specific tests
164 elf_step.dependOn(testThunks(b, .{ .target = aarch64_musl }));
165
166 // x86_64 self-hosted backend
167 elf_step.dependOn(testCommentString(b, .{ .use_llvm = false, .target = default_target }));
168 elf_step.dependOn(testCommentStringStaticLib(b, .{ .use_llvm = false, .target = default_target }));
169 elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl }));
170 elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl }));
171 elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target }));
172 elf_step.dependOn(testLinkingObj(b, .{ .use_llvm = false, .target = default_target }));
173 elf_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = default_target }));
174 elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false, .target = default_target }));
175 elf_step.dependOn(testLinksection(b, .{ .use_llvm = false, .target = default_target }));
176 elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = x86_64_gnu }));
177 elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = x86_64_musl }));
178
179 // riscv64 linker backend is currently not complete enough to support more
180 elf_step.dependOn(testLinkingC(b, .{ .target = riscv64_musl }));
181
182 return elf_step;
183}
184
185fn testAbsSymbols(b: *Build, opts: Options) *Step {
186 const test_step = addTestStep(b, "abs-symbols", opts);
187
188 const obj = addObject(b, opts, .{
189 .name = "obj",
190 .asm_source_bytes =
191 \\.globl foo
192 \\foo = 0x800008
193 \\
194 ,
195 });
196
197 const exe = addExecutable(b, opts, .{
198 .name = "test",
199 .c_source_bytes =
200 \\#include <signal.h>
201 \\#include <stdio.h>
202 \\#include <stdlib.h>
203 \\#include <ucontext.h>
204 \\#include <assert.h>
205 \\void handler(int signum, siginfo_t *info, void *ptr) {
206 \\ assert((size_t)info->si_addr == 0x800008);
207 \\ exit(0);
208 \\}
209 \\extern int foo;
210 \\int main() {
211 \\ struct sigaction act;
212 \\ act.sa_flags = SA_SIGINFO | SA_RESETHAND;
213 \\ act.sa_sigaction = handler;
214 \\ sigemptyset(&act.sa_mask);
215 \\ sigaction(SIGSEGV, &act, 0);
216 \\ foo = 5;
217 \\ return 0;
218 \\}
219 ,
220 });
221 exe.root_module.addObject(obj);
222 exe.root_module.link_libc = true;
223
224 const run = addRunArtifact(exe);
225 run.expectExitCode(0);
226 test_step.dependOn(&run.step);
227
228 return test_step;
229}
230
231fn testAsNeeded(b: *Build, opts: Options) *Step {
232 const test_step = addTestStep(b, "as-needed", opts);
233
234 const main_o = addObject(b, opts, .{
235 .name = "main",
236 .c_source_bytes =
237 \\#include <stdio.h>
238 \\int baz();
239 \\int main() {
240 \\ printf("%d\n", baz());
241 \\ return 0;
242 \\}
243 \\
244 ,
245 });
246 main_o.root_module.link_libc = true;
247
248 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
249 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
250
251 const libbar = addSharedLibrary(b, opts, .{ .name = "bar" });
252 addCSourceBytes(libbar, "int bar() { return 42; }", &.{});
253
254 const libbaz = addSharedLibrary(b, opts, .{ .name = "baz" });
255 addCSourceBytes(libbaz,
256 \\int foo();
257 \\int baz() { return foo(); }
258 , &.{});
259
260 {
261 const exe = addExecutable(b, opts, .{
262 .name = "test",
263 });
264 exe.root_module.addObject(main_o);
265 exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
266 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
267 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
268 exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
269 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
270 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
271 exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
272 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
273 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
274 exe.root_module.link_libc = true;
275
276 const run = addRunArtifact(exe);
277 run.expectStdOutEqual("42\n");
278 test_step.dependOn(&run.step);
279
280 const check = exe.checkObject();
281 check.checkInDynamicSection();
282 check.checkExact("NEEDED libfoo.so");
283 check.checkExact("NEEDED libbar.so");
284 check.checkExact("NEEDED libbaz.so");
285 test_step.dependOn(&check.step);
286 }
287
288 {
289 const exe = addExecutable(b, opts, .{
290 .name = "test",
291 });
292 exe.root_module.addObject(main_o);
293 exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
294 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
295 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
296 exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
297 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
298 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
299 exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
300 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
301 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
302 exe.root_module.link_libc = true;
303
304 const run = addRunArtifact(exe);
305 run.expectStdOutEqual("42\n");
306 test_step.dependOn(&run.step);
307
308 const check = exe.checkObject();
309 check.checkInDynamicSection();
310 check.checkNotPresent("NEEDED libbar.so");
311 check.checkInDynamicSection();
312 check.checkExact("NEEDED libfoo.so");
313 check.checkExact("NEEDED libbaz.so");
314 test_step.dependOn(&check.step);
315 }
316
317 return test_step;
318}
319
320fn testCanonicalPlt(b: *Build, opts: Options) *Step {
321 const test_step = addTestStep(b, "canonical-plt", opts);
322
323 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
324 addCSourceBytes(dso,
325 \\void *foo() {
326 \\ return foo;
327 \\}
328 \\void *bar() {
329 \\ return bar;
330 \\}
331 , &.{});
332
333 const b_o = addObject(b, opts, .{
334 .name = "obj",
335 .c_source_bytes =
336 \\void *bar();
337 \\void *baz() {
338 \\ return bar;
339 \\}
340 \\
341 ,
342 .pic = true,
343 });
344
345 const main_o = addObject(b, opts, .{
346 .name = "main",
347 .c_source_bytes =
348 \\#include <assert.h>
349 \\void *foo();
350 \\void *bar();
351 \\void *baz();
352 \\int main() {
353 \\ assert(foo == foo());
354 \\ assert(bar == bar());
355 \\ assert(bar == baz());
356 \\ return 0;
357 \\}
358 \\
359 ,
360 .pic = false,
361 });
362 main_o.root_module.link_libc = true;
363
364 const exe = addExecutable(b, opts, .{
365 .name = "main",
366 });
367 exe.root_module.addObject(main_o);
368 exe.root_module.addObject(b_o);
369 exe.root_module.linkLibrary(dso);
370 exe.root_module.link_libc = true;
371 exe.pie = false;
372
373 const run = addRunArtifact(exe);
374 run.expectExitCode(0);
375 test_step.dependOn(&run.step);
376
377 return test_step;
378}
379
380fn testComdatElimination(b: *Build, opts: Options) *Step {
381 const test_step = addTestStep(b, "comdat-elimination", opts);
382
383 const a_o = addObject(b, opts, .{
384 .name = "a",
385 .cpp_source_bytes =
386 \\#include <stdio.h>
387 \\inline void foo() {
388 \\ printf("calling foo in a\n");
389 \\}
390 \\void hello() {
391 \\ foo();
392 \\}
393 ,
394 });
395 a_o.root_module.link_libcpp = true;
396
397 const main_o = addObject(b, opts, .{
398 .name = "main",
399 .cpp_source_bytes =
400 \\#include <stdio.h>
401 \\inline void foo() {
402 \\ printf("calling foo in main\n");
403 \\}
404 \\void hello();
405 \\int main() {
406 \\ foo();
407 \\ hello();
408 \\ return 0;
409 \\}
410 ,
411 });
412 main_o.root_module.link_libcpp = true;
413
414 {
415 const exe = addExecutable(b, opts, .{ .name = "main1" });
416 exe.root_module.addObject(a_o);
417 exe.root_module.addObject(main_o);
418 exe.root_module.link_libcpp = true;
419
420 const run = addRunArtifact(exe);
421 run.expectStdOutEqual(
422 \\calling foo in a
423 \\calling foo in a
424 \\
425 );
426 test_step.dependOn(&run.step);
427 }
428
429 {
430 const exe = addExecutable(b, opts, .{ .name = "main2" });
431 exe.root_module.addObject(main_o);
432 exe.root_module.addObject(a_o);
433 exe.root_module.link_libcpp = true;
434
435 const run = addRunArtifact(exe);
436 run.expectStdOutEqual(
437 \\calling foo in main
438 \\calling foo in main
439 \\
440 );
441 test_step.dependOn(&run.step);
442 }
443
444 {
445 const c_o = addObject(b, opts, .{ .name = "c" });
446 c_o.root_module.addObject(main_o);
447 c_o.root_module.addObject(a_o);
448
449 const exe = addExecutable(b, opts, .{ .name = "main3" });
450 exe.root_module.addObject(c_o);
451 exe.root_module.link_libcpp = true;
452
453 const run = addRunArtifact(exe);
454 run.expectStdOutEqual(
455 \\calling foo in main
456 \\calling foo in main
457 \\
458 );
459 test_step.dependOn(&run.step);
460 }
461
462 {
463 const d_o = addObject(b, opts, .{ .name = "d" });
464 d_o.root_module.addObject(a_o);
465 d_o.root_module.addObject(main_o);
466
467 const exe = addExecutable(b, opts, .{ .name = "main4" });
468 exe.root_module.addObject(d_o);
469 exe.root_module.link_libcpp = true;
470
471 const run = addRunArtifact(exe);
472 run.expectStdOutEqual(
473 \\calling foo in a
474 \\calling foo in a
475 \\
476 );
477 test_step.dependOn(&run.step);
478 }
479
480 return test_step;
481}
482
483fn testCommentString(b: *Build, opts: Options) *Step {
484 const test_step = addTestStep(b, "comment-string", opts);
485
486 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes =
487 \\pub fn main() void {}
488 });
489
490 const check = exe.checkObject();
491 check.dumpSection(".comment");
492 check.checkContains("zig");
493 test_step.dependOn(&check.step);
494
495 return test_step;
496}
497
498fn testCommentStringStaticLib(b: *Build, opts: Options) *Step {
499 const test_step = addTestStep(b, "comment-string-static-lib", opts);
500
501 const lib = addStaticLibrary(b, opts, .{ .name = "lib", .zig_source_bytes =
502 \\export fn foo() void {}
503 });
504
505 const check = lib.checkObject();
506 check.dumpSection(".comment");
507 check.checkContains("zig");
508 test_step.dependOn(&check.step);
509
510 return test_step;
511}
512
513fn testCommonSymbols(b: *Build, opts: Options) *Step {
514 const test_step = addTestStep(b, "common-symbols", opts);
515
516 const exe = addExecutable(b, opts, .{
517 .name = "test",
518 });
519 addCSourceBytes(exe,
520 \\int foo;
521 \\int bar;
522 \\int baz = 42;
523 , &.{"-fcommon"});
524 addCSourceBytes(exe,
525 \\#include<stdio.h>
526 \\int foo;
527 \\int bar = 5;
528 \\int baz;
529 \\int main() {
530 \\ printf("%d %d %d\n", foo, bar, baz);
531 \\}
532 , &.{"-fcommon"});
533 exe.root_module.link_libc = true;
534
535 const run = addRunArtifact(exe);
536 run.expectStdOutEqual("0 5 42\n");
537 test_step.dependOn(&run.step);
538
539 return test_step;
540}
541
542fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
543 const test_step = addTestStep(b, "common-symbols-in-archive", opts);
544
545 const a_o = addObject(b, opts, .{
546 .name = "a",
547 .c_source_bytes =
548 \\#include <stdio.h>
549 \\int foo;
550 \\int bar;
551 \\extern int baz;
552 \\__attribute__((weak)) int two();
553 \\int main() {
554 \\ printf("%d %d %d %d\n", foo, bar, baz, two ? two() : -1);
555 \\}
556 \\
557 ,
558 .c_source_flags = &.{"-fcommon"},
559 });
560 a_o.root_module.link_libc = true;
561
562 const b_o = addObject(b, opts, .{
563 .name = "b",
564 .c_source_bytes = "int foo = 5;",
565 .c_source_flags = &.{"-fcommon"},
566 });
567
568 {
569 const c_o = addObject(b, opts, .{
570 .name = "c",
571 .c_source_bytes =
572 \\int bar;
573 \\int two() { return 2; }
574 \\
575 ,
576 .c_source_flags = &.{"-fcommon"},
577 });
578
579 const d_o = addObject(b, opts, .{
580 .name = "d",
581 .c_source_bytes = "int baz;",
582 .c_source_flags = &.{"-fcommon"},
583 });
584
585 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
586 lib.root_module.addObject(b_o);
587 lib.root_module.addObject(c_o);
588 lib.root_module.addObject(d_o);
589
590 const exe = addExecutable(b, opts, .{
591 .name = "test",
592 });
593 exe.root_module.addObject(a_o);
594 exe.root_module.linkLibrary(lib);
595 exe.root_module.link_libc = true;
596
597 const run = addRunArtifact(exe);
598 run.expectStdOutEqual("5 0 0 -1\n");
599 test_step.dependOn(&run.step);
600 }
601
602 {
603 const e_o = addObject(b, opts, .{
604 .name = "e",
605 .c_source_bytes =
606 \\int bar = 0;
607 \\int baz = 7;
608 \\int two() { return 2; }
609 ,
610 .c_source_flags = &.{"-fcommon"},
611 });
612
613 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
614 lib.root_module.addObject(b_o);
615 lib.root_module.addObject(e_o);
616
617 const exe = addExecutable(b, opts, .{
618 .name = "test",
619 });
620 exe.root_module.addObject(a_o);
621 exe.root_module.linkLibrary(lib);
622 exe.root_module.link_libc = true;
623
624 const run = addRunArtifact(exe);
625 run.expectStdOutEqual("5 0 7 2\n");
626 test_step.dependOn(&run.step);
627 }
628
629 return test_step;
630}
631
632fn testCopyrel(b: *Build, opts: Options) *Step {
633 const test_step = addTestStep(b, "copyrel", opts);
634
635 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
636 addCSourceBytes(dso,
637 \\int foo = 3;
638 \\int bar = 5;
639 , &.{});
640
641 const exe = addExecutable(b, opts, .{
642 .name = "main",
643 .c_source_bytes =
644 \\#include<stdio.h>
645 \\extern int foo, bar;
646 \\int main() {
647 \\ printf("%d %d\n", foo, bar);
648 \\ return 0;
649 \\}
650 ,
651 });
652 exe.root_module.linkLibrary(dso);
653 exe.root_module.link_libc = true;
654
655 const run = addRunArtifact(exe);
656 run.expectStdOutEqual("3 5\n");
657 test_step.dependOn(&run.step);
658
659 return test_step;
660}
661
662fn testCopyrelAlias(b: *Build, opts: Options) *Step {
663 const test_step = addTestStep(b, "copyrel-alias", opts);
664
665 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
666 addCSourceBytes(dso,
667 \\int bruh = 31;
668 \\int foo = 42;
669 \\extern int bar __attribute__((alias("foo")));
670 \\extern int baz __attribute__((alias("foo")));
671 , &.{});
672
673 const exe = addExecutable(b, opts, .{
674 .name = "main",
675 .pic = false,
676 });
677 addCSourceBytes(exe,
678 \\#include<stdio.h>
679 \\extern int foo;
680 \\extern int *get_bar();
681 \\int main() {
682 \\ printf("%d %d %d\n", foo, *get_bar(), &foo == get_bar());
683 \\ return 0;
684 \\}
685 , &.{});
686 addCSourceBytes(exe,
687 \\extern int bar;
688 \\int *get_bar() { return &bar; }
689 , &.{});
690 exe.root_module.linkLibrary(dso);
691 exe.root_module.link_libc = true;
692 exe.pie = false;
693
694 const run = addRunArtifact(exe);
695 run.expectStdOutEqual("42 42 1\n");
696 test_step.dependOn(&run.step);
697
698 return test_step;
699}
700
701fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
702 const test_step = addTestStep(b, "copyrel-alignment", opts);
703
704 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
705 addCSourceBytes(a_so, "__attribute__((aligned(32))) int foo = 5;", &.{});
706
707 const b_so = addSharedLibrary(b, opts, .{ .name = "b" });
708 addCSourceBytes(b_so, "__attribute__((aligned(8))) int foo = 5;", &.{});
709
710 const c_so = addSharedLibrary(b, opts, .{ .name = "c" });
711 addCSourceBytes(c_so, "__attribute__((aligned(256))) int foo = 5;", &.{});
712
713 const obj = addObject(b, opts, .{
714 .name = "main",
715 .c_source_bytes =
716 \\#include <stdio.h>
717 \\extern int foo;
718 \\int main() { printf("%d\n", foo); }
719 \\
720 ,
721 .pic = false,
722 });
723 obj.root_module.link_libc = true;
724
725 const exp_stdout = "5\n";
726
727 {
728 const exe = addExecutable(b, opts, .{ .name = "main" });
729 exe.root_module.addObject(obj);
730 exe.root_module.linkLibrary(a_so);
731 exe.root_module.link_libc = true;
732 exe.pie = false;
733
734 const run = addRunArtifact(exe);
735 run.expectStdOutEqual(exp_stdout);
736 test_step.dependOn(&run.step);
737
738 const check = exe.checkObject();
739 check.checkInHeaders();
740 check.checkExact("section headers");
741 check.checkExact("name .copyrel");
742 check.checkExact("addralign 20");
743 test_step.dependOn(&check.step);
744 }
745
746 {
747 const exe = addExecutable(b, opts, .{ .name = "main" });
748 exe.root_module.addObject(obj);
749 exe.root_module.linkLibrary(b_so);
750 exe.root_module.link_libc = true;
751 exe.pie = false;
752
753 const run = addRunArtifact(exe);
754 run.expectStdOutEqual(exp_stdout);
755 test_step.dependOn(&run.step);
756
757 const check = exe.checkObject();
758 check.checkInHeaders();
759 check.checkExact("section headers");
760 check.checkExact("name .copyrel");
761 check.checkExact("addralign 8");
762 test_step.dependOn(&check.step);
763 }
764
765 {
766 const exe = addExecutable(b, opts, .{ .name = "main" });
767 exe.root_module.addObject(obj);
768 exe.root_module.linkLibrary(c_so);
769 exe.root_module.link_libc = true;
770 exe.pie = false;
771
772 const run = addRunArtifact(exe);
773 run.expectStdOutEqual(exp_stdout);
774 test_step.dependOn(&run.step);
775
776 const check = exe.checkObject();
777 check.checkInHeaders();
778 check.checkExact("section headers");
779 check.checkExact("name .copyrel");
780 check.checkExact("addralign 100");
781 test_step.dependOn(&check.step);
782 }
783
784 return test_step;
785}
786
787fn testDsoPlt(b: *Build, opts: Options) *Step {
788 const test_step = addTestStep(b, "dso-plt", opts);
789
790 const dso = addSharedLibrary(b, opts, .{ .name = "dso" });
791 addCSourceBytes(dso,
792 \\#include<stdio.h>
793 \\void world() {
794 \\ printf("world\n");
795 \\}
796 \\void real_hello() {
797 \\ printf("Hello ");
798 \\ world();
799 \\}
800 \\void hello() {
801 \\ real_hello();
802 \\}
803 , &.{});
804 dso.root_module.link_libc = true;
805
806 const exe = addExecutable(b, opts, .{ .name = "test" });
807 addCSourceBytes(exe,
808 \\#include<stdio.h>
809 \\void world() {
810 \\ printf("WORLD\n");
811 \\}
812 \\void hello();
813 \\int main() {
814 \\ hello();
815 \\}
816 , &.{});
817 exe.root_module.linkLibrary(dso);
818 exe.root_module.link_libc = true;
819
820 const run = addRunArtifact(exe);
821 run.expectStdOutEqual("Hello WORLD\n");
822 test_step.dependOn(&run.step);
823
824 return test_step;
825}
826
827fn testDsoUndef(b: *Build, opts: Options) *Step {
828 const test_step = addTestStep(b, "dso-undef", opts);
829
830 const dso = addSharedLibrary(b, opts, .{ .name = "dso" });
831 addCSourceBytes(dso,
832 \\extern int foo;
833 \\int bar = 5;
834 \\int baz() { return foo; }
835 , &.{});
836 dso.root_module.link_libc = true;
837
838 const obj = addObject(b, opts, .{
839 .name = "obj",
840 .c_source_bytes = "int foo = 3;",
841 });
842
843 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
844 lib.root_module.addObject(obj);
845
846 const exe = addExecutable(b, opts, .{ .name = "test" });
847 exe.root_module.linkLibrary(dso);
848 exe.root_module.linkLibrary(lib);
849 addCSourceBytes(exe,
850 \\extern int bar;
851 \\int main() {
852 \\ return bar - 5;
853 \\}
854 , &.{});
855 exe.root_module.link_libc = true;
856
857 const run = addRunArtifact(exe);
858 run.expectExitCode(0);
859 test_step.dependOn(&run.step);
860
861 const check = exe.checkObject();
862 check.checkInDynamicSymtab();
863 check.checkContains("foo");
864 test_step.dependOn(&check.step);
865
866 return test_step;
867}
868
869fn testEmitRelocatable(b: *Build, opts: Options) *Step {
870 const test_step = addTestStep(b, "emit-relocatable", opts);
871
872 const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes =
873 \\const std = @import("std");
874 \\extern var bar: i32;
875 \\export fn foo() i32 {
876 \\ return bar;
877 \\}
878 \\export fn printFoo() void {
879 \\ std.debug.print("foo={d}\n", .{foo()});
880 \\}
881 });
882 a_o.root_module.link_libc = true;
883
884 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
885 \\#include <stdio.h>
886 \\int bar = 42;
887 \\void printBar() {
888 \\ fprintf(stderr, "bar=%d\n", bar);
889 \\}
890 });
891 b_o.root_module.link_libc = true;
892
893 const c_o = addObject(b, opts, .{ .name = "c" });
894 c_o.root_module.addObject(a_o);
895 c_o.root_module.addObject(b_o);
896
897 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
898 \\const std = @import("std");
899 \\extern fn printFoo() void;
900 \\extern fn printBar() void;
901 \\pub fn main() void {
902 \\ printFoo();
903 \\ printBar();
904 \\}
905 });
906 exe.root_module.addObject(c_o);
907 exe.root_module.link_libc = true;
908
909 const run = addRunArtifact(exe);
910 run.expectStdErrEqual(
911 \\foo=42
912 \\bar=42
913 \\
914 );
915 test_step.dependOn(&run.step);
916
917 return test_step;
918}
919
920fn testEmitStaticLib(b: *Build, opts: Options) *Step {
921 const test_step = addTestStep(b, "emit-static-lib", opts);
922
923 const obj1 = addObject(b, opts, .{
924 .name = "obj1",
925 .c_source_bytes =
926 \\int foo = 0;
927 \\int bar = 2;
928 \\int fooBar() {
929 \\ return foo + bar;
930 \\}
931 ,
932 });
933
934 const obj2 = addObject(b, opts, .{
935 .name = "obj2",
936 .c_source_bytes = "int tentative;",
937 .c_source_flags = &.{"-fcommon"},
938 });
939
940 const obj3 = addObject(b, opts, .{
941 .name = "a_very_long_file_name_so_that_it_ends_up_in_strtab",
942 .zig_source_bytes =
943 \\fn weakFoo() callconv(.c) usize {
944 \\ return 42;
945 \\}
946 \\export var strongBar: usize = 100;
947 \\comptime {
948 \\ @export(&weakFoo, .{ .name = "weakFoo", .linkage = .weak });
949 \\ @export(&strongBar, .{ .name = "strongBarAlias", .linkage = .strong });
950 \\}
951 ,
952 });
953
954 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
955 lib.root_module.addObject(obj1);
956 lib.root_module.addObject(obj2);
957 lib.root_module.addObject(obj3);
958
959 const check = lib.checkObject();
960 check.checkInArchiveSymtab();
961 check.checkExact("in object obj1.o");
962 check.checkExact("foo");
963 check.checkInArchiveSymtab();
964 check.checkExact("in object obj1.o");
965 check.checkExact("bar");
966 check.checkInArchiveSymtab();
967 check.checkExact("in object obj1.o");
968 check.checkExact("fooBar");
969 check.checkInArchiveSymtab();
970 check.checkExact("in object obj2.o");
971 check.checkExact("tentative");
972 check.checkInArchiveSymtab();
973 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
974 check.checkExact("weakFoo");
975 check.checkInArchiveSymtab();
976 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
977 check.checkExact("strongBar");
978 check.checkInArchiveSymtab();
979 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
980 check.checkExact("strongBarAlias");
981 test_step.dependOn(&check.step);
982
983 return test_step;
984}
985
986fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
987 const test_step = addTestStep(b, "emit-static-lib-zig", opts);
988
989 const obj1 = addObject(b, opts, .{
990 .name = "obj1",
991 .zig_source_bytes =
992 \\export var foo: i32 = 42;
993 \\export var bar: i32 = 2;
994 ,
995 });
996
997 const lib = addStaticLibrary(b, opts, .{
998 .name = "lib",
999 .zig_source_bytes =
1000 \\extern var foo: i32;
1001 \\extern var bar: i32;
1002 \\export fn fooBar() i32 {
1003 \\ return foo + bar;
1004 \\}
1005 ,
1006 });
1007 lib.root_module.addObject(obj1);
1008
1009 const exe = addExecutable(b, opts, .{
1010 .name = "test",
1011 .zig_source_bytes =
1012 \\const std = @import("std");
1013 \\extern fn fooBar() i32;
1014 \\pub fn main() void {
1015 \\ std.debug.print("{d}", .{fooBar()});
1016 \\}
1017 ,
1018 });
1019 exe.root_module.linkLibrary(lib);
1020
1021 const run = addRunArtifact(exe);
1022 run.expectStdErrEqual("44");
1023 test_step.dependOn(&run.step);
1024
1025 return test_step;
1026}
1027
1028fn testEmptyObject(b: *Build, opts: Options) *Step {
1029 const test_step = addTestStep(b, "empty-object", opts);
1030
1031 const exe = addExecutable(b, opts, .{ .name = "test" });
1032 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1033 addCSourceBytes(exe, "", &.{});
1034 exe.root_module.link_libc = true;
1035
1036 const run = addRunArtifact(exe);
1037 run.expectExitCode(0);
1038 test_step.dependOn(&run.step);
1039
1040 return test_step;
1041}
1042
1043fn testEntryPoint(b: *Build, opts: Options) *Step {
1044 const test_step = addTestStep(b, "entry-point", opts);
1045
1046 const a_o = addObject(b, opts, .{
1047 .name = "a",
1048 .asm_source_bytes =
1049 \\.globl foo, bar
1050 \\foo = 0x1000
1051 \\bar = 0x2000
1052 \\
1053 ,
1054 });
1055
1056 const b_o = addObject(b, opts, .{
1057 .name = "b",
1058 .c_source_bytes = "int main() { return 0; }",
1059 });
1060
1061 {
1062 const exe = addExecutable(b, opts, .{ .name = "main" });
1063 exe.root_module.addObject(a_o);
1064 exe.root_module.addObject(b_o);
1065 exe.entry = .{ .symbol_name = "foo" };
1066
1067 const check = exe.checkObject();
1068 check.checkInHeaders();
1069 check.checkExact("header");
1070 check.checkExact("entry 1000");
1071 test_step.dependOn(&check.step);
1072 }
1073
1074 {
1075 // TODO looks like not assigning a unique name to this executable will
1076 // cause an artifact collision taking the cached executable from the above
1077 // step instead of generating a new one.
1078 const exe = addExecutable(b, opts, .{ .name = "other" });
1079 exe.root_module.addObject(a_o);
1080 exe.root_module.addObject(b_o);
1081 exe.entry = .{ .symbol_name = "bar" };
1082
1083 const check = exe.checkObject();
1084 check.checkInHeaders();
1085 check.checkExact("header");
1086 check.checkExact("entry 2000");
1087 test_step.dependOn(&check.step);
1088 }
1089
1090 return test_step;
1091}
1092
1093fn testExportDynamic(b: *Build, opts: Options) *Step {
1094 const test_step = addTestStep(b, "export-dynamic", opts);
1095
1096 const obj = addObject(b, opts, .{
1097 .name = "obj",
1098 .asm_source_bytes =
1099 \\.text
1100 \\ .globl foo
1101 \\ .hidden foo
1102 \\foo:
1103 \\ nop
1104 \\ .globl bar
1105 \\bar:
1106 \\ nop
1107 \\ .globl _start
1108 \\_start:
1109 \\ nop
1110 \\
1111 ,
1112 });
1113
1114 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1115 addCSourceBytes(dso, "int baz = 10;", &.{});
1116
1117 const exe = addExecutable(b, opts, .{ .name = "main" });
1118 addCSourceBytes(exe,
1119 \\extern int baz;
1120 \\int callBaz() {
1121 \\ return baz;
1122 \\}
1123 , &.{});
1124 exe.root_module.addObject(obj);
1125 exe.root_module.linkLibrary(dso);
1126 exe.rdynamic = true;
1127
1128 const check = exe.checkObject();
1129 check.checkInDynamicSymtab();
1130 check.checkContains("bar");
1131 check.checkInDynamicSymtab();
1132 check.checkContains("_start");
1133 test_step.dependOn(&check.step);
1134
1135 return test_step;
1136}
1137
1138fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
1139 const test_step = addTestStep(b, "export-symbols-from-exe", opts);
1140
1141 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1142 addCSourceBytes(dso,
1143 \\void expfn1();
1144 \\void expfn2() {}
1145 \\
1146 \\void foo() {
1147 \\ expfn1();
1148 \\}
1149 , &.{});
1150
1151 const exe = addExecutable(b, opts, .{ .name = "main" });
1152 addCSourceBytes(exe,
1153 \\void expfn1() {}
1154 \\void expfn2() {}
1155 \\void foo();
1156 \\
1157 \\int main() {
1158 \\ expfn1();
1159 \\ expfn2();
1160 \\ foo();
1161 \\}
1162 , &.{});
1163 exe.root_module.linkLibrary(dso);
1164 exe.root_module.link_libc = true;
1165
1166 const check = exe.checkObject();
1167 check.checkInDynamicSymtab();
1168 check.checkContains("expfn2");
1169 check.checkInDynamicSymtab();
1170 check.checkContains("expfn1");
1171 test_step.dependOn(&check.step);
1172
1173 return test_step;
1174}
1175
1176fn testFuncAddress(b: *Build, opts: Options) *Step {
1177 const test_step = addTestStep(b, "func-address", opts);
1178
1179 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1180 addCSourceBytes(dso, "void fn() {}", &.{});
1181
1182 const exe = addExecutable(b, opts, .{ .name = "main" });
1183 addCSourceBytes(exe,
1184 \\#include <assert.h>
1185 \\typedef void Func();
1186 \\void fn();
1187 \\Func *const ptr = fn;
1188 \\int main() {
1189 \\ assert(fn == ptr);
1190 \\}
1191 , &.{});
1192 exe.root_module.linkLibrary(dso);
1193 exe.root_module.pic = false;
1194 exe.pie = false;
1195
1196 const run = addRunArtifact(exe);
1197 run.expectExitCode(0);
1198 test_step.dependOn(&run.step);
1199
1200 return test_step;
1201}
1202
1203fn testGcSections(b: *Build, opts: Options) *Step {
1204 const test_step = addTestStep(b, "gc-sections", opts);
1205
1206 const obj = addObject(b, opts, .{
1207 .name = "obj",
1208 .cpp_source_bytes =
1209 \\#include <stdio.h>
1210 \\int two() { return 2; }
1211 \\int live_var1 = 1;
1212 \\int live_var2 = two();
1213 \\int dead_var1 = 3;
1214 \\int dead_var2 = 4;
1215 \\void live_fn1() {}
1216 \\void live_fn2() { live_fn1(); }
1217 \\void dead_fn1() {}
1218 \\void dead_fn2() { dead_fn1(); }
1219 \\int main() {
1220 \\ printf("%d %d\n", live_var1, live_var2);
1221 \\ live_fn2();
1222 \\}
1223 ,
1224 });
1225 obj.link_function_sections = true;
1226 obj.link_data_sections = true;
1227 obj.root_module.link_libc = true;
1228 obj.root_module.link_libcpp = true;
1229
1230 {
1231 const exe = addExecutable(b, opts, .{ .name = "test" });
1232 exe.root_module.addObject(obj);
1233 exe.link_gc_sections = false;
1234 exe.root_module.link_libc = true;
1235 exe.root_module.link_libcpp = true;
1236
1237 const run = addRunArtifact(exe);
1238 run.expectStdOutEqual("1 2\n");
1239 test_step.dependOn(&run.step);
1240
1241 const check = exe.checkObject();
1242 check.checkInSymtab();
1243 check.checkContains("live_var1");
1244 check.checkInSymtab();
1245 check.checkContains("live_var2");
1246 check.checkInSymtab();
1247 check.checkContains("dead_var1");
1248 check.checkInSymtab();
1249 check.checkContains("dead_var2");
1250 check.checkInSymtab();
1251 check.checkContains("live_fn1");
1252 check.checkInSymtab();
1253 check.checkContains("live_fn2");
1254 check.checkInSymtab();
1255 check.checkContains("dead_fn1");
1256 check.checkInSymtab();
1257 check.checkContains("dead_fn2");
1258 test_step.dependOn(&check.step);
1259 }
1260
1261 {
1262 const exe = addExecutable(b, opts, .{ .name = "test" });
1263 exe.root_module.addObject(obj);
1264 exe.link_gc_sections = true;
1265 exe.root_module.link_libc = true;
1266 exe.root_module.link_libcpp = true;
1267
1268 const run = addRunArtifact(exe);
1269 run.expectStdOutEqual("1 2\n");
1270 test_step.dependOn(&run.step);
1271
1272 const check = exe.checkObject();
1273 check.checkInSymtab();
1274 check.checkContains("live_var1");
1275 check.checkInSymtab();
1276 check.checkContains("live_var2");
1277 check.checkInSymtab();
1278 check.checkNotPresent("dead_var1");
1279 check.checkInSymtab();
1280 check.checkNotPresent("dead_var2");
1281 check.checkInSymtab();
1282 check.checkContains("live_fn1");
1283 check.checkInSymtab();
1284 check.checkContains("live_fn2");
1285 check.checkInSymtab();
1286 check.checkNotPresent("dead_fn1");
1287 check.checkInSymtab();
1288 check.checkNotPresent("dead_fn2");
1289 test_step.dependOn(&check.step);
1290 }
1291
1292 return test_step;
1293}
1294
1295fn testGcSectionsZig(b: *Build, opts: Options) *Step {
1296 const test_step = addTestStep(b, "gc-sections-zig", opts);
1297
1298 const obj = addObject(b, .{
1299 .target = opts.target,
1300 .use_llvm = true,
1301 }, .{
1302 .name = "obj",
1303 .c_source_bytes =
1304 \\int live_var1 = 1;
1305 \\int live_var2 = 2;
1306 \\int dead_var1 = 3;
1307 \\int dead_var2 = 4;
1308 \\void live_fn1() {}
1309 \\void live_fn2() { live_fn1(); }
1310 \\void dead_fn1() {}
1311 \\void dead_fn2() { dead_fn1(); }
1312 ,
1313 });
1314 obj.link_function_sections = true;
1315 obj.link_data_sections = true;
1316
1317 {
1318 const exe = addExecutable(b, opts, .{
1319 .name = "test1",
1320 .zig_source_bytes =
1321 \\const std = @import("std");
1322 \\extern var live_var1: i32;
1323 \\extern var live_var2: i32;
1324 \\extern fn live_fn2() void;
1325 \\pub fn main() void {
1326 \\ var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
1327 \\ stdout_writer.interface.print("{d} {d}\n", .{ live_var1, live_var2 }) catch @panic("fail");
1328 \\ live_fn2();
1329 \\}
1330 ,
1331 });
1332 exe.root_module.addObject(obj);
1333 exe.link_gc_sections = false;
1334
1335 const run = addRunArtifact(exe);
1336 run.expectStdOutEqual("1 2\n");
1337 test_step.dependOn(&run.step);
1338
1339 const check = exe.checkObject();
1340 check.checkInSymtab();
1341 check.checkContains("live_var1");
1342 check.checkInSymtab();
1343 check.checkContains("live_var2");
1344 check.checkInSymtab();
1345 check.checkContains("dead_var1");
1346 check.checkInSymtab();
1347 check.checkContains("dead_var2");
1348 check.checkInSymtab();
1349 check.checkContains("live_fn1");
1350 check.checkInSymtab();
1351 check.checkContains("live_fn2");
1352 check.checkInSymtab();
1353 check.checkContains("dead_fn1");
1354 check.checkInSymtab();
1355 check.checkContains("dead_fn2");
1356 test_step.dependOn(&check.step);
1357 }
1358
1359 {
1360 const exe = addExecutable(b, opts, .{
1361 .name = "test2",
1362 .zig_source_bytes =
1363 \\const std = @import("std");
1364 \\extern var live_var1: i32;
1365 \\extern var live_var2: i32;
1366 \\extern fn live_fn2() void;
1367 \\pub fn main() void {
1368 \\ var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
1369 \\ stdout_writer.interface.print("{d} {d}\n", .{ live_var1, live_var2 }) catch @panic("fail");
1370 \\ live_fn2();
1371 \\}
1372 ,
1373 });
1374 exe.root_module.addObject(obj);
1375 exe.link_gc_sections = true;
1376
1377 const run = addRunArtifact(exe);
1378 run.expectStdOutEqual("1 2\n");
1379 test_step.dependOn(&run.step);
1380
1381 const check = exe.checkObject();
1382 check.checkInSymtab();
1383 check.checkContains("live_var1");
1384 check.checkInSymtab();
1385 check.checkContains("live_var2");
1386 check.checkInSymtab();
1387 check.checkNotPresent("dead_var1");
1388 check.checkInSymtab();
1389 check.checkNotPresent("dead_var2");
1390 check.checkInSymtab();
1391 check.checkContains("live_fn1");
1392 check.checkInSymtab();
1393 check.checkContains("live_fn2");
1394 check.checkInSymtab();
1395 check.checkNotPresent("dead_fn1");
1396 check.checkInSymtab();
1397 check.checkNotPresent("dead_fn2");
1398 test_step.dependOn(&check.step);
1399 }
1400
1401 return test_step;
1402}
1403
1404fn testHiddenWeakUndef(b: *Build, opts: Options) *Step {
1405 const test_step = addTestStep(b, "hidden-weak-undef", opts);
1406
1407 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1408 addCSourceBytes(dso,
1409 \\__attribute__((weak, visibility("hidden"))) void foo();
1410 \\void bar() { foo(); }
1411 , &.{});
1412
1413 const check = dso.checkObject();
1414 check.checkInDynamicSymtab();
1415 check.checkNotPresent("foo");
1416 check.checkInDynamicSymtab();
1417 check.checkContains("bar");
1418 test_step.dependOn(&check.step);
1419
1420 return test_step;
1421}
1422
1423fn testIFuncAlias(b: *Build, opts: Options) *Step {
1424 const test_step = addTestStep(b, "ifunc-alias", opts);
1425
1426 const exe = addExecutable(b, opts, .{ .name = "main" });
1427 addCSourceBytes(exe,
1428 \\#include <assert.h>
1429 \\void foo() {}
1430 \\int bar() __attribute__((ifunc("resolve_bar")));
1431 \\void *resolve_bar() { return foo; }
1432 \\void *bar2 = bar;
1433 \\int main() {
1434 \\ assert(bar == bar2);
1435 \\}
1436 , &.{});
1437 exe.root_module.pic = true;
1438 exe.root_module.link_libc = true;
1439
1440 const run = addRunArtifact(exe);
1441 run.expectExitCode(0);
1442 test_step.dependOn(&run.step);
1443
1444 return test_step;
1445}
1446
1447fn testIFuncDlopen(b: *Build, opts: Options) *Step {
1448 const test_step = addTestStep(b, "ifunc-dlopen", opts);
1449
1450 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1451 addCSourceBytes(dso,
1452 \\__attribute__((ifunc("resolve_foo")))
1453 \\void foo(void);
1454 \\static void real_foo(void) {
1455 \\}
1456 \\typedef void Func();
1457 \\static Func *resolve_foo(void) {
1458 \\ return real_foo;
1459 \\}
1460 , &.{});
1461
1462 const exe = addExecutable(b, opts, .{ .name = "main" });
1463 addCSourceBytes(exe,
1464 \\#include <dlfcn.h>
1465 \\#include <assert.h>
1466 \\#include <stdlib.h>
1467 \\typedef void Func();
1468 \\void foo(void);
1469 \\int main() {
1470 \\ void *handle = dlopen(NULL, RTLD_NOW);
1471 \\ Func *p = dlsym(handle, "foo");
1472 \\
1473 \\ foo();
1474 \\ p();
1475 \\ assert(foo == p);
1476 \\}
1477 , &.{});
1478 exe.root_module.linkLibrary(dso);
1479 exe.root_module.link_libc = true;
1480 exe.root_module.linkSystemLibrary("dl", .{});
1481 exe.root_module.pic = false;
1482 exe.pie = false;
1483
1484 const run = addRunArtifact(exe);
1485 run.expectExitCode(0);
1486 test_step.dependOn(&run.step);
1487
1488 return test_step;
1489}
1490
1491fn testIFuncDso(b: *Build, opts: Options) *Step {
1492 const test_step = addTestStep(b, "ifunc-dso", opts);
1493
1494 const dso = addSharedLibrary(b, opts, .{
1495 .name = "a",
1496 .c_source_bytes =
1497 \\#include<stdio.h>
1498 \\__attribute__((ifunc("resolve_foobar")))
1499 \\void foobar(void);
1500 \\static void real_foobar(void) {
1501 \\ printf("Hello world\n");
1502 \\}
1503 \\typedef void Func();
1504 \\static Func *resolve_foobar(void) {
1505 \\ return real_foobar;
1506 \\}
1507 ,
1508 });
1509 dso.root_module.link_libc = true;
1510
1511 const exe = addExecutable(b, opts, .{
1512 .name = "main",
1513 .c_source_bytes =
1514 \\void foobar(void);
1515 \\int main() {
1516 \\ foobar();
1517 \\}
1518 ,
1519 });
1520 exe.root_module.linkLibrary(dso);
1521
1522 const run = addRunArtifact(exe);
1523 run.expectStdOutEqual("Hello world\n");
1524 test_step.dependOn(&run.step);
1525
1526 return test_step;
1527}
1528
1529fn testIFuncDynamic(b: *Build, opts: Options) *Step {
1530 const test_step = addTestStep(b, "ifunc-dynamic", opts);
1531
1532 const main_c =
1533 \\#include <stdio.h>
1534 \\__attribute__((ifunc("resolve_foobar")))
1535 \\static void foobar(void);
1536 \\static void real_foobar(void) {
1537 \\ printf("Hello world\n");
1538 \\}
1539 \\typedef void Func();
1540 \\static Func *resolve_foobar(void) {
1541 \\ return real_foobar;
1542 \\}
1543 \\int main() {
1544 \\ foobar();
1545 \\}
1546 ;
1547
1548 {
1549 const exe = addExecutable(b, opts, .{ .name = "main" });
1550 addCSourceBytes(exe, main_c, &.{});
1551 exe.root_module.link_libc = true;
1552 exe.link_z_lazy = true;
1553
1554 const run = addRunArtifact(exe);
1555 run.expectStdOutEqual("Hello world\n");
1556 test_step.dependOn(&run.step);
1557 }
1558 {
1559 const exe = addExecutable(b, opts, .{ .name = "other" });
1560 addCSourceBytes(exe, main_c, &.{});
1561 exe.root_module.link_libc = true;
1562
1563 const run = addRunArtifact(exe);
1564 run.expectStdOutEqual("Hello world\n");
1565 test_step.dependOn(&run.step);
1566 }
1567
1568 return test_step;
1569}
1570
1571fn testIFuncExport(b: *Build, opts: Options) *Step {
1572 const test_step = addTestStep(b, "ifunc-export", opts);
1573
1574 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1575 addCSourceBytes(dso,
1576 \\#include <stdio.h>
1577 \\__attribute__((ifunc("resolve_foobar")))
1578 \\void foobar(void);
1579 \\void real_foobar(void) {
1580 \\ printf("Hello world\n");
1581 \\}
1582 \\typedef void Func();
1583 \\Func *resolve_foobar(void) {
1584 \\ return real_foobar;
1585 \\}
1586 , &.{});
1587 dso.root_module.link_libc = true;
1588
1589 const check = dso.checkObject();
1590 check.checkInDynamicSymtab();
1591 check.checkContains("IFUNC GLOBAL DEFAULT foobar");
1592 test_step.dependOn(&check.step);
1593
1594 return test_step;
1595}
1596
1597fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
1598 const test_step = addTestStep(b, "ifunc-func-ptr", opts);
1599
1600 const exe = addExecutable(b, opts, .{ .name = "main" });
1601 addCSourceBytes(exe,
1602 \\typedef int Fn();
1603 \\int foo() __attribute__((ifunc("resolve_foo")));
1604 \\int real_foo() { return 3; }
1605 \\Fn *resolve_foo(void) {
1606 \\ return real_foo;
1607 \\}
1608 , &.{});
1609 addCSourceBytes(exe,
1610 \\typedef int Fn();
1611 \\int foo();
1612 \\Fn *get_foo() { return foo; }
1613 , &.{});
1614 addCSourceBytes(exe,
1615 \\#include <stdio.h>
1616 \\typedef int Fn();
1617 \\Fn *get_foo();
1618 \\int main() {
1619 \\ Fn *f = get_foo();
1620 \\ printf("%d\n", f());
1621 \\}
1622 , &.{});
1623 exe.root_module.pic = true;
1624 exe.root_module.link_libc = true;
1625
1626 const run = addRunArtifact(exe);
1627 run.expectStdOutEqual("3\n");
1628 test_step.dependOn(&run.step);
1629
1630 return test_step;
1631}
1632
1633fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
1634 const test_step = addTestStep(b, "ifunc-noplt", opts);
1635
1636 const exe = addExecutable(b, opts, .{ .name = "main" });
1637 addCSourceBytes(exe,
1638 \\#include <stdio.h>
1639 \\__attribute__((ifunc("resolve_foo")))
1640 \\void foo(void);
1641 \\void hello(void) {
1642 \\ printf("Hello world\n");
1643 \\}
1644 \\typedef void Fn();
1645 \\Fn *resolve_foo(void) {
1646 \\ return hello;
1647 \\}
1648 \\int main() {
1649 \\ foo();
1650 \\}
1651 , &.{"-fno-plt"});
1652 exe.root_module.pic = true;
1653 exe.root_module.link_libc = true;
1654
1655 const run = addRunArtifact(exe);
1656 run.expectStdOutEqual("Hello world\n");
1657 test_step.dependOn(&run.step);
1658
1659 return test_step;
1660}
1661
1662fn testIFuncStatic(b: *Build, opts: Options) *Step {
1663 const test_step = addTestStep(b, "ifunc-static", opts);
1664
1665 const exe = addExecutable(b, opts, .{ .name = "main" });
1666 addCSourceBytes(exe,
1667 \\#include <stdio.h>
1668 \\void foo() __attribute__((ifunc("resolve_foo")));
1669 \\void hello() {
1670 \\ printf("Hello world\n");
1671 \\}
1672 \\void *resolve_foo() {
1673 \\ return hello;
1674 \\}
1675 \\int main() {
1676 \\ foo();
1677 \\ return 0;
1678 \\}
1679 , &.{});
1680 exe.root_module.link_libc = true;
1681 exe.linkage = .static;
1682
1683 const run = addRunArtifact(exe);
1684 run.expectStdOutEqual("Hello world\n");
1685 test_step.dependOn(&run.step);
1686
1687 return test_step;
1688}
1689
1690fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
1691 const test_step = addTestStep(b, "ifunc-static-pie", opts);
1692
1693 const exe = addExecutable(b, opts, .{ .name = "main" });
1694 addCSourceBytes(exe,
1695 \\#include <stdio.h>
1696 \\void foo() __attribute__((ifunc("resolve_foo")));
1697 \\void hello() {
1698 \\ printf("Hello world\n");
1699 \\}
1700 \\void *resolve_foo() {
1701 \\ return hello;
1702 \\}
1703 \\int main() {
1704 \\ foo();
1705 \\ return 0;
1706 \\}
1707 , &.{});
1708 exe.linkage = .static;
1709 exe.root_module.pic = true;
1710 exe.pie = true;
1711 exe.root_module.link_libc = true;
1712
1713 const run = addRunArtifact(exe);
1714 run.expectStdOutEqual("Hello world\n");
1715 test_step.dependOn(&run.step);
1716
1717 const check = exe.checkObject();
1718 check.checkInHeaders();
1719 check.checkExact("header");
1720 check.checkExact("type DYN");
1721 check.checkInHeaders();
1722 check.checkExact("section headers");
1723 check.checkExact("name .dynamic");
1724 check.checkInHeaders();
1725 check.checkExact("section headers");
1726 check.checkNotPresent("name .interp");
1727 test_step.dependOn(&check.step);
1728
1729 return test_step;
1730}
1731
1732fn testImageBase(b: *Build, opts: Options) *Step {
1733 const test_step = addTestStep(b, "image-base", opts);
1734
1735 {
1736 const exe = addExecutable(b, opts, .{ .name = "main1" });
1737 addCSourceBytes(exe,
1738 \\#include <stdio.h>
1739 \\int main() {
1740 \\ printf("Hello World!\n");
1741 \\ return 0;
1742 \\}
1743 , &.{});
1744 exe.root_module.link_libc = true;
1745 exe.image_base = 0x8000000;
1746
1747 const run = addRunArtifact(exe);
1748 run.expectStdOutEqual("Hello World!\n");
1749 test_step.dependOn(&run.step);
1750
1751 const check = exe.checkObject();
1752 check.checkInHeaders();
1753 check.checkExact("header");
1754 check.checkExtract("entry {addr}");
1755 check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0x8000000 } });
1756 test_step.dependOn(&check.step);
1757 }
1758
1759 {
1760 const exe = addExecutable(b, opts, .{ .name = "main2" });
1761 addCSourceBytes(exe, "void _start() {}", &.{});
1762 exe.image_base = 0xffffffff8000000;
1763
1764 const check = exe.checkObject();
1765 check.checkInHeaders();
1766 check.checkExact("header");
1767 check.checkExtract("entry {addr}");
1768 check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0xffffffff8000000 } });
1769 test_step.dependOn(&check.step);
1770 }
1771
1772 return test_step;
1773}
1774
1775fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1776 const test_step = addTestStep(b, "importing-data-dynamic", opts);
1777
1778 const dso = addSharedLibrary(b, .{
1779 .target = opts.target,
1780 .optimize = opts.optimize,
1781 .use_llvm = true,
1782 }, .{
1783 .name = "a",
1784 .c_source_bytes =
1785 \\#include <stdio.h>
1786 \\int foo = 42;
1787 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
1788 ,
1789 });
1790 dso.root_module.link_libc = true;
1791
1792 const main = addExecutable(b, opts, .{
1793 .name = "main",
1794 .zig_source_bytes =
1795 \\const std = @import("std");
1796 \\extern var foo: i32;
1797 \\extern fn printFoo() void;
1798 \\pub fn main() void {
1799 \\ std.debug.print("exe foo={d}\n", .{foo});
1800 \\ printFoo();
1801 \\ foo += 1;
1802 \\ std.debug.print("exe foo={d}\n", .{foo});
1803 \\ printFoo();
1804 \\}
1805 ,
1806 .strip = true, // TODO temp hack
1807 });
1808 main.pie = true;
1809 main.root_module.linkLibrary(dso);
1810
1811 const run = addRunArtifact(main);
1812 run.expectStdErrEqual(
1813 \\exe foo=42
1814 \\lib foo=42
1815 \\exe foo=43
1816 \\lib foo=43
1817 \\
1818 );
1819 test_step.dependOn(&run.step);
1820
1821 return test_step;
1822}
1823
1824fn testImportingDataStatic(b: *Build, opts: Options) *Step {
1825 const test_step = addTestStep(b, "importing-data-static", opts);
1826
1827 const obj = addObject(b, .{
1828 .target = opts.target,
1829 .optimize = opts.optimize,
1830 .use_llvm = true,
1831 }, .{
1832 .name = "a",
1833 .c_source_bytes = "int foo = 42;",
1834 });
1835
1836 const lib = addStaticLibrary(b, .{
1837 .target = opts.target,
1838 .optimize = opts.optimize,
1839 .use_llvm = true,
1840 }, .{
1841 .name = "a",
1842 });
1843 lib.root_module.addObject(obj);
1844
1845 const main = addExecutable(b, opts, .{
1846 .name = "main",
1847 .zig_source_bytes =
1848 \\extern var foo: i32;
1849 \\pub fn main() void {
1850 \\ @import("std").debug.print("{d}\n", .{foo});
1851 \\}
1852 ,
1853 .strip = true, // TODO temp hack
1854 });
1855 main.root_module.linkLibrary(lib);
1856 main.root_module.link_libc = true;
1857
1858 const run = addRunArtifact(main);
1859 run.expectStdErrEqual("42\n");
1860 test_step.dependOn(&run.step);
1861
1862 return test_step;
1863}
1864
1865fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1866 const test_step = addTestStep(b, "init-array-order", opts);
1867
1868 const a_o = addObject(b, opts, .{
1869 .name = "a",
1870 .c_source_bytes =
1871 \\#include <stdio.h>
1872 \\__attribute__((constructor(10000))) void init4() { printf("1"); }
1873 ,
1874 });
1875 a_o.root_module.link_libc = true;
1876
1877 const b_o = addObject(b, opts, .{
1878 .name = "b",
1879 .c_source_bytes =
1880 \\#include <stdio.h>
1881 \\__attribute__((constructor(1000))) void init3() { printf("2"); }
1882 ,
1883 });
1884 b_o.root_module.link_libc = true;
1885
1886 const c_o = addObject(b, opts, .{
1887 .name = "c",
1888 .c_source_bytes =
1889 \\#include <stdio.h>
1890 \\__attribute__((constructor)) void init1() { printf("3"); }
1891 ,
1892 });
1893 c_o.root_module.link_libc = true;
1894
1895 const d_o = addObject(b, opts, .{
1896 .name = "d",
1897 .c_source_bytes =
1898 \\#include <stdio.h>
1899 \\__attribute__((constructor)) void init2() { printf("4"); }
1900 ,
1901 });
1902 d_o.root_module.link_libc = true;
1903
1904 const e_o = addObject(b, opts, .{
1905 .name = "e",
1906 .c_source_bytes =
1907 \\#include <stdio.h>
1908 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }
1909 ,
1910 });
1911 e_o.root_module.link_libc = true;
1912
1913 const f_o = addObject(b, opts, .{
1914 .name = "f",
1915 .c_source_bytes =
1916 \\#include <stdio.h>
1917 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }
1918 ,
1919 });
1920 f_o.root_module.link_libc = true;
1921
1922 const g_o = addObject(b, opts, .{
1923 .name = "g",
1924 .c_source_bytes =
1925 \\#include <stdio.h>
1926 \\__attribute__((destructor)) void fini1() { printf("7"); }
1927 ,
1928 });
1929 g_o.root_module.link_libc = true;
1930
1931 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
1932 \\#include <stdio.h>
1933 \\__attribute__((destructor)) void fini2() { printf("8"); }
1934 });
1935 h_o.root_module.link_libc = true;
1936
1937 const exe = addExecutable(b, opts, .{ .name = "main" });
1938 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1939 exe.root_module.addObject(a_o);
1940 exe.root_module.addObject(b_o);
1941 exe.root_module.addObject(c_o);
1942 exe.root_module.addObject(d_o);
1943 exe.root_module.addObject(e_o);
1944 exe.root_module.addObject(f_o);
1945 exe.root_module.addObject(g_o);
1946 exe.root_module.addObject(h_o);
1947
1948 if (opts.target.result.isGnuLibC()) {
1949 // TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets
1950 exe.pie = true;
1951 }
1952
1953 const run = addRunArtifact(exe);
1954 run.expectStdOutEqual("21348756");
1955 test_step.dependOn(&run.step);
1956
1957 return test_step;
1958}
1959
1960fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
1961 const test_step = addTestStep(b, "large-alignment-dso", opts);
1962
1963 const dso = addSharedLibrary(b, opts, .{ .name = "dso" });
1964 addCSourceBytes(dso,
1965 \\#include <stdio.h>
1966 \\#include <stdint.h>
1967 \\void hello() __attribute__((aligned(32768), section(".hello")));
1968 \\void world() __attribute__((aligned(32768), section(".world")));
1969 \\void hello() {
1970 \\ printf("Hello");
1971 \\}
1972 \\void world() {
1973 \\ printf(" world");
1974 \\}
1975 \\void greet() {
1976 \\ hello();
1977 \\ world();
1978 \\}
1979 , &.{});
1980 dso.link_function_sections = true;
1981 dso.root_module.link_libc = true;
1982
1983 const check = dso.checkObject();
1984 check.checkInSymtab();
1985 check.checkExtract("{addr1} {size1} {shndx1} FUNC GLOBAL DEFAULT hello");
1986 check.checkInSymtab();
1987 check.checkExtract("{addr2} {size2} {shndx2} FUNC GLOBAL DEFAULT world");
1988 check.checkComputeCompare("addr1 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
1989 check.checkComputeCompare("addr2 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
1990 test_step.dependOn(&check.step);
1991
1992 const exe = addExecutable(b, opts, .{ .name = "test" });
1993 addCSourceBytes(exe,
1994 \\void greet();
1995 \\int main() { greet(); }
1996 , &.{});
1997 exe.root_module.linkLibrary(dso);
1998 exe.root_module.link_libc = true;
1999
2000 const run = addRunArtifact(exe);
2001 run.expectStdOutEqual("Hello world");
2002 test_step.dependOn(&run.step);
2003
2004 return test_step;
2005}
2006
2007fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
2008 const test_step = addTestStep(b, "large-alignment-exe", opts);
2009
2010 const exe = addExecutable(b, opts, .{ .name = "test" });
2011 addCSourceBytes(exe,
2012 \\#include <stdio.h>
2013 \\#include <stdint.h>
2014 \\
2015 \\void hello() __attribute__((aligned(32768), section(".hello")));
2016 \\void world() __attribute__((aligned(32768), section(".world")));
2017 \\
2018 \\void hello() {
2019 \\ printf("Hello");
2020 \\}
2021 \\
2022 \\void world() {
2023 \\ printf(" world");
2024 \\}
2025 \\
2026 \\int main() {
2027 \\ hello();
2028 \\ world();
2029 \\}
2030 , &.{});
2031 exe.link_function_sections = true;
2032 exe.root_module.link_libc = true;
2033
2034 const check = exe.checkObject();
2035 check.checkInSymtab();
2036 check.checkExtract("{addr1} {size1} {shndx1} FUNC LOCAL DEFAULT hello");
2037 check.checkInSymtab();
2038 check.checkExtract("{addr2} {size2} {shndx2} FUNC LOCAL DEFAULT world");
2039 check.checkComputeCompare("addr1 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
2040 check.checkComputeCompare("addr2 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
2041 test_step.dependOn(&check.step);
2042
2043 const run = addRunArtifact(exe);
2044 run.expectStdOutEqual("Hello world");
2045 test_step.dependOn(&run.step);
2046
2047 return test_step;
2048}
2049
2050fn testLargeBss(b: *Build, opts: Options) *Step {
2051 const test_step = addTestStep(b, "large-bss", opts);
2052
2053 const exe = addExecutable(b, opts, .{ .name = "main" });
2054 addCSourceBytes(exe,
2055 \\char arr[0x100000000];
2056 \\int main() {
2057 \\ return arr[2000];
2058 \\}
2059 , &.{});
2060 exe.root_module.link_libc = true;
2061 // Disabled to work around the ELF linker crashing.
2062 // Can be reproduced on a x86_64-linux host by commenting out the line below.
2063 exe.root_module.sanitize_c = .off;
2064
2065 const run = addRunArtifact(exe);
2066 run.expectExitCode(0);
2067 test_step.dependOn(&run.step);
2068
2069 return test_step;
2070}
2071
2072fn testLinkOrder(b: *Build, opts: Options) *Step {
2073 const test_step = addTestStep(b, "link-order", opts);
2074
2075 const obj = addObject(b, opts, .{
2076 .name = "obj",
2077 .c_source_bytes = "void foo() {}",
2078 .pic = true,
2079 });
2080
2081 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2082 dso.root_module.addObject(obj);
2083
2084 const lib = addStaticLibrary(b, opts, .{ .name = "b" });
2085 lib.root_module.addObject(obj);
2086
2087 const main_o = addObject(b, opts, .{
2088 .name = "main",
2089 .c_source_bytes =
2090 \\void foo();
2091 \\int main() {
2092 \\ foo();
2093 \\}
2094 ,
2095 });
2096
2097 // https://github.com/ziglang/zig/issues/17450
2098 // {
2099 // const exe = addExecutable(b, opts, .{ .name = "main1"});
2100 // exe.root_module.addObject(main_o);
2101 // exe.root_module.linkSystemLibrary("a", .{});
2102 // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2103 // exe.root_module.addRPath(dso.getEmittedBinDirectory());
2104 // exe.root_module.linkSystemLibrary("b", .{});
2105 // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2106 // exe.root_module.addRPath(lib.getEmittedBinDirectory());
2107 // exe.root_module.link_libc = true;
2108
2109 // const check = exe.checkObject();
2110 // check.checkInDynamicSection();
2111 // check.checkContains("libb.so");
2112 // test_step.dependOn(&check.step);
2113 // }
2114
2115 {
2116 const exe = addExecutable(b, opts, .{ .name = "main2" });
2117 exe.root_module.addObject(main_o);
2118 exe.root_module.linkSystemLibrary("b", .{});
2119 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2120 exe.root_module.addRPath(lib.getEmittedBinDirectory());
2121 exe.root_module.linkSystemLibrary("a", .{});
2122 exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2123 exe.root_module.addRPath(dso.getEmittedBinDirectory());
2124 exe.root_module.link_libc = true;
2125
2126 const check = exe.checkObject();
2127 check.checkInDynamicSection();
2128 check.checkNotPresent("libb.so");
2129 test_step.dependOn(&check.step);
2130 }
2131
2132 return test_step;
2133}
2134
2135fn testLdScript(b: *Build, opts: Options) *Step {
2136 const test_step = addTestStep(b, "ld-script", opts);
2137
2138 const bar = addSharedLibrary(b, opts, .{ .name = "bar" });
2139 addCSourceBytes(bar, "int bar() { return 42; }", &.{});
2140
2141 const baz = addSharedLibrary(b, opts, .{ .name = "baz" });
2142 addCSourceBytes(baz, "int baz() { return 42; }", &.{});
2143
2144 const scripts = WriteFile.create(b);
2145 _ = scripts.add("liba.so", "INPUT(libfoo.so libfoo2.so.1)");
2146 _ = scripts.add("libfoo.so", "GROUP(AS_NEEDED(-lbar))");
2147
2148 // Check finding a versioned .so file that is elsewhere in the library search paths.
2149 const scripts2 = WriteFile.create(b);
2150 _ = scripts2.add("libfoo2.so.1", "GROUP(AS_NEEDED(-lbaz))");
2151
2152 const exe = addExecutable(b, opts, .{ .name = "main" });
2153 addCSourceBytes(exe,
2154 \\int bar();
2155 \\int baz();
2156 \\int main() {
2157 \\ return bar() - baz();
2158 \\}
2159 , &.{});
2160 exe.root_module.linkSystemLibrary("a", .{});
2161 exe.root_module.addLibraryPath(scripts.getDirectory());
2162 exe.root_module.addLibraryPath(scripts2.getDirectory());
2163 exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
2164 exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
2165 exe.root_module.addRPath(bar.getEmittedBinDirectory());
2166 exe.root_module.addRPath(baz.getEmittedBinDirectory());
2167 exe.root_module.link_libc = true;
2168 exe.allow_so_scripts = true;
2169
2170 const run = addRunArtifact(exe);
2171 run.expectExitCode(0);
2172 test_step.dependOn(&run.step);
2173
2174 return test_step;
2175}
2176
2177fn testLdScriptPathError(b: *Build, opts: Options) *Step {
2178 const test_step = addTestStep(b, "ld-script-path-error", opts);
2179
2180 const scripts = WriteFile.create(b);
2181 _ = scripts.add("liba.so", "INPUT(libfoo.so)");
2182
2183 const exe = addExecutable(b, opts, .{ .name = "main" });
2184 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2185 exe.root_module.linkSystemLibrary("a", .{});
2186 exe.root_module.addLibraryPath(scripts.getDirectory());
2187 exe.root_module.link_libc = true;
2188 exe.allow_so_scripts = true;
2189
2190 // TODO: A future enhancement could make this error message also mention
2191 // the file that references the missing library.
2192 expectLinkErrors(exe, test_step, .{
2193 .stderr_contains = "error: libfoo.so: file listed in linker script not found",
2194 });
2195
2196 return test_step;
2197}
2198
2199fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
2200 const test_step = addTestStep(b, "ld-script-allow-undefined-version", opts);
2201
2202 const so = addSharedLibrary(b, opts, .{
2203 .name = "add",
2204 .zig_source_bytes =
2205 \\export fn add(a: i32, b: i32) i32 {
2206 \\ return a + b;
2207 \\}
2208 ,
2209 });
2210 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
2211 so.setLinkerScript(ld);
2212 so.linker_allow_undefined_version = true;
2213
2214 const exe = addExecutable(b, opts, .{
2215 .name = "main",
2216 .zig_source_bytes =
2217 \\const std = @import("std");
2218 \\extern fn add(a: i32, b: i32) i32;
2219 \\pub fn main() void {
2220 \\ std.debug.print("{d}\n", .{add(1, 2)});
2221 \\}
2222 ,
2223 });
2224 exe.root_module.linkLibrary(so);
2225 exe.root_module.link_libc = true;
2226 exe.allow_so_scripts = true;
2227
2228 const run = addRunArtifact(exe);
2229 run.expectStdErrEqual("3\n");
2230 test_step.dependOn(&run.step);
2231
2232 return test_step;
2233}
2234
2235fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {
2236 const test_step = addTestStep(b, "ld-script-disallow-undefined-version", opts);
2237
2238 const so = addSharedLibrary(b, opts, .{
2239 .name = "add",
2240 .zig_source_bytes =
2241 \\export fn add(a: i32, b: i32) i32 {
2242 \\ return a + b;
2243 \\}
2244 ,
2245 });
2246 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
2247 so.setLinkerScript(ld);
2248 so.linker_allow_undefined_version = false;
2249 so.allow_so_scripts = true;
2250
2251 expectLinkErrors(
2252 so,
2253 test_step,
2254 .{
2255 .contains = "error: ld.lld: version script assignment of 'ADD_1.0' to symbol 'sub' failed: symbol not defined",
2256 },
2257 );
2258
2259 return test_step;
2260}
2261
2262fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
2263 const test_step = addTestStep(b, "mismatched-cpu-architecture-error", opts);
2264
2265 const obj = addObject(b, .{
2266 .target = b.resolveTargetQuery(.{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .gnu }),
2267 }, .{
2268 .name = "a",
2269 .c_source_bytes = "int foo;",
2270 .strip = true,
2271 });
2272
2273 const exe = addExecutable(b, opts, .{ .name = "main" });
2274 addCSourceBytes(exe,
2275 \\extern int foo;
2276 \\int main() {
2277 \\ return foo;
2278 \\}
2279 , &.{});
2280 exe.root_module.addObject(obj);
2281 exe.root_module.link_libc = true;
2282
2283 expectLinkErrors(exe, test_step, .{ .exact = &.{
2284 "invalid ELF machine type: AARCH64",
2285 "note: while parsing /?/a.o",
2286 } });
2287
2288 return test_step;
2289}
2290
2291fn testLinkingC(b: *Build, opts: Options) *Step {
2292 const test_step = addTestStep(b, "linking-c", opts);
2293
2294 const exe = addExecutable(b, opts, .{ .name = "test" });
2295 addCSourceBytes(exe,
2296 \\#include <stdio.h>
2297 \\int main() {
2298 \\ printf("Hello World!\n");
2299 \\ return 0;
2300 \\}
2301 , &.{});
2302 exe.root_module.link_libc = true;
2303
2304 const run = addRunArtifact(exe);
2305 run.expectStdOutEqual("Hello World!\n");
2306 test_step.dependOn(&run.step);
2307
2308 const check = exe.checkObject();
2309 check.checkInHeaders();
2310 check.checkExact("header");
2311 check.checkExact("type EXEC");
2312 check.checkInHeaders();
2313 check.checkExact("section headers");
2314 check.checkNotPresent("name .dynamic");
2315 test_step.dependOn(&check.step);
2316
2317 return test_step;
2318}
2319
2320fn testLinkingCpp(b: *Build, opts: Options) *Step {
2321 const test_step = addTestStep(b, "linking-cpp", opts);
2322
2323 const exe = addExecutable(b, opts, .{ .name = "test" });
2324 addCppSourceBytes(exe,
2325 \\#include <iostream>
2326 \\int main() {
2327 \\ std::cout << "Hello World!" << std::endl;
2328 \\ return 0;
2329 \\}
2330 , &.{});
2331 exe.root_module.link_libc = true;
2332 exe.root_module.link_libcpp = true;
2333
2334 const run = addRunArtifact(exe);
2335 run.expectStdOutEqual("Hello World!\n");
2336 test_step.dependOn(&run.step);
2337
2338 const check = exe.checkObject();
2339 check.checkInHeaders();
2340 check.checkExact("header");
2341 check.checkExact("type EXEC");
2342 check.checkInHeaders();
2343 check.checkExact("section headers");
2344 check.checkNotPresent("name .dynamic");
2345 test_step.dependOn(&check.step);
2346
2347 return test_step;
2348}
2349
2350fn testLinkingObj(b: *Build, opts: Options) *Step {
2351 const test_step = addTestStep(b, "linking-obj", opts);
2352
2353 const obj = addObject(b, opts, .{
2354 .name = "aobj",
2355 .zig_source_bytes =
2356 \\extern var mod: usize;
2357 \\export fn callMe() usize {
2358 \\ return me * mod;
2359 \\}
2360 \\var me: usize = 42;
2361 ,
2362 });
2363
2364 const exe = addExecutable(b, opts, .{
2365 .name = "testobj",
2366 .zig_source_bytes =
2367 \\const std = @import("std");
2368 \\extern fn callMe() usize;
2369 \\export var mod: usize = 2;
2370 \\pub fn main() void {
2371 \\ std.debug.print("{d}\n", .{callMe()});
2372 \\}
2373 ,
2374 });
2375 exe.root_module.addObject(obj);
2376
2377 const run = addRunArtifact(exe);
2378 run.expectStdErrEqual("84\n");
2379 test_step.dependOn(&run.step);
2380
2381 return test_step;
2382}
2383
2384fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
2385 const test_step = addTestStep(b, "linking-static-lib", opts);
2386
2387 const obj = addObject(b, opts, .{
2388 .name = "bobj",
2389 .zig_source_bytes = "export var bar: i32 = -42;",
2390 });
2391
2392 const lib = addStaticLibrary(b, opts, .{
2393 .name = "alib",
2394 .zig_source_bytes =
2395 \\export fn foo() i32 {
2396 \\ return 42;
2397 \\}
2398 ,
2399 });
2400 lib.root_module.addObject(obj);
2401
2402 const exe = addExecutable(b, opts, .{
2403 .name = "testlib",
2404 .zig_source_bytes =
2405 \\const std = @import("std");
2406 \\extern fn foo() i32;
2407 \\extern var bar: i32;
2408 \\pub fn main() void {
2409 \\ std.debug.print("{d}\n", .{foo() + bar});
2410 \\}
2411 ,
2412 });
2413 exe.root_module.linkLibrary(lib);
2414
2415 const run = addRunArtifact(exe);
2416 run.expectStdErrEqual("0\n");
2417 test_step.dependOn(&run.step);
2418
2419 return test_step;
2420}
2421
2422fn testLinkingZig(b: *Build, opts: Options) *Step {
2423 const test_step = addTestStep(b, "linking-zig-static", opts);
2424
2425 const exe = addExecutable(b, opts, .{
2426 .name = "test",
2427 .zig_source_bytes =
2428 \\pub fn main() void {
2429 \\ @import("std").debug.print("Hello World!\n", .{});
2430 \\}
2431 ,
2432 });
2433
2434 const run = addRunArtifact(exe);
2435 run.expectStdErrEqual("Hello World!\n");
2436 test_step.dependOn(&run.step);
2437
2438 const check = exe.checkObject();
2439 check.checkInHeaders();
2440 check.checkExact("header");
2441 check.checkExact("type EXEC");
2442 check.checkInHeaders();
2443 check.checkExact("section headers");
2444 check.checkNotPresent("name .dynamic");
2445 test_step.dependOn(&check.step);
2446
2447 return test_step;
2448}
2449
2450fn testLinksection(b: *Build, opts: Options) *Step {
2451 const test_step = addTestStep(b, "linksection", opts);
2452
2453 const obj = addObject(b, opts, .{ .name = "main", .zig_source_bytes =
2454 \\export var test_global: u32 linksection(".TestGlobal") = undefined;
2455 \\export fn testFn() linksection(".TestFn") callconv(.c) void {
2456 \\ TestGenericFn("A").f();
2457 \\}
2458 \\fn TestGenericFn(comptime suffix: []const u8) type {
2459 \\ return struct {
2460 \\ fn f() linksection(".TestGenFn" ++ suffix) void {}
2461 \\ };
2462 \\}
2463 });
2464
2465 const check = obj.checkObject();
2466 check.checkInSymtab();
2467 check.checkContains("SECTION LOCAL DEFAULT .TestGlobal");
2468 check.checkInSymtab();
2469 check.checkContains("SECTION LOCAL DEFAULT .TestFn");
2470 check.checkInSymtab();
2471 check.checkContains("SECTION LOCAL DEFAULT .TestGenFnA");
2472 check.checkInSymtab();
2473 check.checkContains("OBJECT GLOBAL DEFAULT test_global");
2474 check.checkInSymtab();
2475 check.checkContains("FUNC GLOBAL DEFAULT testFn");
2476
2477 if (opts.optimize == .Debug) {
2478 check.checkInSymtab();
2479 check.checkContains("FUNC LOCAL DEFAULT main.TestGenericFn(");
2480 }
2481
2482 test_step.dependOn(&check.step);
2483
2484 return test_step;
2485}
2486
2487// Adapted from https://github.com/rui314/mold/blob/main/test/elf/mergeable-strings.sh
2488fn testMergeStrings(b: *Build, opts: Options) *Step {
2489 const test_step = addTestStep(b, "merge-strings", opts);
2490
2491 const obj1 = addObject(b, opts, .{ .name = "a.o" });
2492 addCSourceBytes(obj1,
2493 \\#include <uchar.h>
2494 \\#include <wchar.h>
2495 \\char *cstr1 = "foo";
2496 \\wchar_t *wide1 = L"foo";
2497 \\char16_t *utf16_1 = u"foo";
2498 \\char32_t *utf32_1 = U"foo";
2499 , &.{"-O2"});
2500 obj1.root_module.link_libc = true;
2501
2502 const obj2 = addObject(b, opts, .{ .name = "b.o" });
2503 addCSourceBytes(obj2,
2504 \\#include <stdio.h>
2505 \\#include <assert.h>
2506 \\#include <uchar.h>
2507 \\#include <wchar.h>
2508 \\extern char *cstr1;
2509 \\extern wchar_t *wide1;
2510 \\extern char16_t *utf16_1;
2511 \\extern char32_t *utf32_1;
2512 \\char *cstr2 = "foo";
2513 \\wchar_t *wide2 = L"foo";
2514 \\char16_t *utf16_2 = u"foo";
2515 \\char32_t *utf32_2 = U"foo";
2516 \\int main() {
2517 \\ printf("%p %p %p %p %p %p %p %p\n",
2518 \\ cstr1, cstr2, wide1, wide2, utf16_1, utf16_2, utf32_1, utf32_2);
2519 \\ assert((void*)cstr1 == (void*)cstr2);
2520 \\ assert((void*)wide1 == (void*)wide2);
2521 \\ assert((void*)utf16_1 == (void*)utf16_2);
2522 \\ assert((void*)utf32_1 == (void*)utf32_2);
2523 \\ assert((void*)wide1 == (void*)utf32_1);
2524 \\ assert((void*)cstr1 != (void*)wide1);
2525 \\ assert((void*)cstr1 != (void*)utf32_1);
2526 \\ assert((void*)wide1 != (void*)utf16_1);
2527 \\}
2528 , &.{"-O2"});
2529 obj2.root_module.link_libc = true;
2530
2531 const exe = addExecutable(b, opts, .{ .name = "main" });
2532 exe.root_module.addObject(obj1);
2533 exe.root_module.addObject(obj2);
2534 exe.root_module.link_libc = true;
2535
2536 const run = addRunArtifact(exe);
2537 run.expectExitCode(0);
2538 test_step.dependOn(&run.step);
2539
2540 return test_step;
2541}
2542
2543fn testMergeStrings2(b: *Build, opts: Options) *Step {
2544 const test_step = addTestStep(b, "merge-strings2", opts);
2545
2546 const obj1 = addObject(b, opts, .{ .name = "a", .zig_source_bytes =
2547 \\const std = @import("std");
2548 \\export fn foo() void {
2549 \\ var arr: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
2550 \\ const slice = std.mem.sliceTo(&arr, 3);
2551 \\ std.testing.expectEqualSlices(u16, arr[0..2], slice) catch unreachable;
2552 \\}
2553 });
2554
2555 const obj2 = addObject(b, opts, .{ .name = "b", .zig_source_bytes =
2556 \\const std = @import("std");
2557 \\extern fn foo() void;
2558 \\pub fn main() void {
2559 \\ foo();
2560 \\ var arr: [5:0]u16 = [_:0]u16{ 5, 4, 3, 2, 1 };
2561 \\ const slice = std.mem.sliceTo(&arr, 3);
2562 \\ std.testing.expectEqualSlices(u16, arr[0..2], slice) catch unreachable;
2563 \\}
2564 });
2565
2566 {
2567 const exe = addExecutable(b, opts, .{ .name = "main1" });
2568 exe.root_module.addObject(obj1);
2569 exe.root_module.addObject(obj2);
2570
2571 const run = addRunArtifact(exe);
2572 run.expectExitCode(0);
2573 test_step.dependOn(&run.step);
2574
2575 const check = exe.checkObject();
2576 check.dumpSection(".rodata.str");
2577 check.checkContains("\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x00\x00");
2578 check.dumpSection(".rodata.str");
2579 check.checkContains("\x05\x00\x04\x00\x03\x00\x02\x00\x01\x00\x00\x00");
2580 test_step.dependOn(&check.step);
2581 }
2582
2583 {
2584 const obj3 = addObject(b, opts, .{ .name = "c" });
2585 obj3.root_module.addObject(obj1);
2586 obj3.root_module.addObject(obj2);
2587
2588 const exe = addExecutable(b, opts, .{ .name = "main2" });
2589 exe.root_module.addObject(obj3);
2590
2591 const run = addRunArtifact(exe);
2592 run.expectExitCode(0);
2593 test_step.dependOn(&run.step);
2594
2595 const check = exe.checkObject();
2596 check.dumpSection(".rodata.str");
2597 check.checkContains("\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x00\x00");
2598 check.dumpSection(".rodata.str");
2599 check.checkContains("\x05\x00\x04\x00\x03\x00\x02\x00\x01\x00\x00\x00");
2600 test_step.dependOn(&check.step);
2601 }
2602
2603 return test_step;
2604}
2605
2606fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
2607 const test_step = addTestStep(b, "no-eh-frame-hdr", opts);
2608
2609 const exe = addExecutable(b, opts, .{ .name = "main" });
2610 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2611 exe.link_eh_frame_hdr = false;
2612 exe.root_module.link_libc = true;
2613
2614 const check = exe.checkObject();
2615 check.checkInHeaders();
2616 check.checkExact("section headers");
2617 check.checkNotPresent("name .eh_frame_hdr");
2618 test_step.dependOn(&check.step);
2619
2620 return test_step;
2621}
2622
2623fn testPie(b: *Build, opts: Options) *Step {
2624 const test_step = addTestStep(b, "hello-pie", opts);
2625
2626 const exe = addExecutable(b, opts, .{ .name = "main" });
2627 addCSourceBytes(exe,
2628 \\#include <stdio.h>
2629 \\int main() {
2630 \\ printf("Hello!\n");
2631 \\ return 0;
2632 \\}
2633 , &.{});
2634 exe.root_module.link_libc = true;
2635 exe.root_module.pic = true;
2636 exe.pie = true;
2637
2638 const run = addRunArtifact(exe);
2639 run.expectStdOutEqual("Hello!\n");
2640 test_step.dependOn(&run.step);
2641
2642 const check = exe.checkObject();
2643 check.checkInHeaders();
2644 check.checkExact("header");
2645 check.checkExact("type DYN");
2646 check.checkInHeaders();
2647 check.checkExact("section headers");
2648 check.checkExact("name .dynamic");
2649 test_step.dependOn(&check.step);
2650
2651 return test_step;
2652}
2653
2654fn testPltGot(b: *Build, opts: Options) *Step {
2655 const test_step = addTestStep(b, "plt-got", opts);
2656
2657 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2658 addCSourceBytes(dso,
2659 \\#include <stdio.h>
2660 \\void ignore(void *foo) {}
2661 \\void hello() {
2662 \\ printf("Hello world\n");
2663 \\}
2664 , &.{});
2665 dso.root_module.link_libc = true;
2666
2667 const exe = addExecutable(b, opts, .{ .name = "main" });
2668 addCSourceBytes(exe,
2669 \\void ignore(void *);
2670 \\int hello();
2671 \\void foo() { ignore(hello); }
2672 \\int main() { hello(); }
2673 , &.{});
2674 exe.root_module.linkLibrary(dso);
2675 exe.root_module.pic = true;
2676 exe.root_module.link_libc = true;
2677
2678 const run = addRunArtifact(exe);
2679 run.expectStdOutEqual("Hello world\n");
2680 test_step.dependOn(&run.step);
2681
2682 return test_step;
2683}
2684
2685fn testPreinitArray(b: *Build, opts: Options) *Step {
2686 const test_step = addTestStep(b, "preinit-array", opts);
2687
2688 {
2689 const obj = addObject(b, opts, .{
2690 .name = "obj",
2691 .c_source_bytes = "void _start() {}",
2692 });
2693
2694 const exe = addExecutable(b, opts, .{ .name = "main1" });
2695 exe.root_module.addObject(obj);
2696
2697 const check = exe.checkObject();
2698 check.checkInDynamicSection();
2699 check.checkNotPresent("PREINIT_ARRAY");
2700 }
2701
2702 {
2703 const exe = addExecutable(b, opts, .{ .name = "main2" });
2704 addCSourceBytes(exe,
2705 \\void preinit_fn() {}
2706 \\int main() {}
2707 \\__attribute__((section(".preinit_array")))
2708 \\void *preinit[] = { preinit_fn };
2709 , &.{});
2710 exe.root_module.link_libc = true;
2711
2712 const check = exe.checkObject();
2713 check.checkInDynamicSection();
2714 check.checkContains("PREINIT_ARRAY");
2715 }
2716
2717 return test_step;
2718}
2719
2720fn testRelocatableArchive(b: *Build, opts: Options) *Step {
2721 const test_step = addTestStep(b, "relocatable-archive", opts);
2722
2723 const obj1 = addObject(b, opts, .{
2724 .name = "obj1",
2725 .c_source_bytes =
2726 \\void bar();
2727 \\void foo() {
2728 \\ bar();
2729 \\}
2730 ,
2731 });
2732
2733 const obj2 = addObject(b, opts, .{
2734 .name = "obj2",
2735 .c_source_bytes =
2736 \\void bar() {}
2737 ,
2738 });
2739
2740 const obj3 = addObject(b, opts, .{
2741 .name = "obj3",
2742 .c_source_bytes =
2743 \\void baz();
2744 ,
2745 });
2746
2747 const obj4 = addObject(b, opts, .{
2748 .name = "obj4",
2749 .c_source_bytes =
2750 \\void foo();
2751 \\int main() {
2752 \\ foo();
2753 \\}
2754 ,
2755 });
2756
2757 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
2758 lib.root_module.addObject(obj1);
2759 lib.root_module.addObject(obj2);
2760 lib.root_module.addObject(obj3);
2761
2762 const obj5 = addObject(b, opts, .{
2763 .name = "obj5",
2764 });
2765 obj5.root_module.addObject(obj4);
2766 obj5.root_module.linkLibrary(lib);
2767
2768 const check = obj5.checkObject();
2769 check.checkInSymtab();
2770 check.checkContains("foo");
2771 check.checkInSymtab();
2772 check.checkContains("bar");
2773 check.checkInSymtab();
2774 check.checkNotPresent("baz");
2775 test_step.dependOn(&check.step);
2776
2777 return test_step;
2778}
2779
2780fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2781 const test_step = addTestStep(b, "relocatable-eh-frame", opts);
2782
2783 const obj1 = addObject(b, opts, .{
2784 .name = "obj1",
2785 .cpp_source_bytes =
2786 \\#include <stdexcept>
2787 \\int try_me() {
2788 \\ throw std::runtime_error("Oh no!");
2789 \\}
2790 ,
2791 });
2792 obj1.root_module.link_libcpp = true;
2793 const obj2 = addObject(b, opts, .{
2794 .name = "obj2",
2795 .cpp_source_bytes =
2796 \\extern int try_me();
2797 \\int try_again() {
2798 \\ return try_me();
2799 \\}
2800 ,
2801 });
2802 obj2.root_module.link_libcpp = true;
2803 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
2804 \\#include <iostream>
2805 \\#include <stdexcept>
2806 \\extern int try_again();
2807 \\int main() {
2808 \\ try {
2809 \\ try_again();
2810 \\ } catch (const std::exception &e) {
2811 \\ std::cout << "exception=" << e.what();
2812 \\ }
2813 \\ return 0;
2814 \\}
2815 });
2816 obj3.root_module.link_libcpp = true;
2817
2818 {
2819 const obj = addObject(b, opts, .{ .name = "obj" });
2820 obj.root_module.addObject(obj1);
2821 obj.root_module.addObject(obj2);
2822 obj.root_module.link_libcpp = true;
2823
2824 const exe = addExecutable(b, opts, .{ .name = "test1" });
2825 exe.root_module.addObject(obj3);
2826 exe.root_module.addObject(obj);
2827 exe.root_module.link_libcpp = true;
2828
2829 const run = addRunArtifact(exe);
2830 run.expectStdOutEqual("exception=Oh no!");
2831 test_step.dependOn(&run.step);
2832 }
2833 {
2834 // Flipping the order should not influence the end result.
2835 const obj = addObject(b, opts, .{ .name = "obj" });
2836 obj.root_module.addObject(obj2);
2837 obj.root_module.addObject(obj1);
2838 obj.root_module.link_libcpp = true;
2839
2840 const exe = addExecutable(b, opts, .{ .name = "test2" });
2841 exe.root_module.addObject(obj3);
2842 exe.root_module.addObject(obj);
2843 exe.root_module.link_libcpp = true;
2844
2845 const run = addRunArtifact(exe);
2846 run.expectStdOutEqual("exception=Oh no!");
2847 test_step.dependOn(&run.step);
2848 }
2849
2850 return test_step;
2851}
2852
2853fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2854 const test_step = addTestStep(b, "relocatable-eh-frame-comdat-heavy", opts);
2855
2856 const obj1 = addObject(b, opts, .{
2857 .name = "obj1",
2858 .cpp_source_bytes =
2859 \\#include <stdexcept>
2860 \\int try_me() {
2861 \\ throw std::runtime_error("Oh no!");
2862 \\}
2863 ,
2864 });
2865 obj1.root_module.link_libcpp = true;
2866 const obj2 = addObject(b, opts, .{
2867 .name = "obj2",
2868 .cpp_source_bytes =
2869 \\extern int try_me();
2870 \\int try_again() {
2871 \\ return try_me();
2872 \\}
2873 ,
2874 });
2875 obj2.root_module.link_libcpp = true;
2876 const obj3 = addObject(b, opts, .{
2877 .name = "obj3",
2878 .cpp_source_bytes =
2879 \\#include <iostream>
2880 \\#include <stdexcept>
2881 \\extern int try_again();
2882 \\int main() {
2883 \\ try {
2884 \\ try_again();
2885 \\ } catch (const std::exception &e) {
2886 \\ std::cout << "exception=" << e.what();
2887 \\ }
2888 \\ return 0;
2889 \\}
2890 ,
2891 });
2892 obj3.root_module.link_libcpp = true;
2893
2894 const obj = addObject(b, opts, .{ .name = "obj" });
2895 obj.root_module.addObject(obj1);
2896 obj.root_module.addObject(obj2);
2897 obj.root_module.addObject(obj3);
2898 obj.root_module.link_libcpp = true;
2899
2900 const exe = addExecutable(b, opts, .{ .name = "test2" });
2901 exe.root_module.addObject(obj);
2902 exe.root_module.link_libcpp = true;
2903
2904 const run = addRunArtifact(exe);
2905 run.expectStdOutEqual("exception=Oh no!");
2906 test_step.dependOn(&run.step);
2907
2908 return test_step;
2909}
2910
2911// Adapted from https://github.com/rui314/mold/blob/main/test/elf/relocatable-mergeable-sections.sh
2912fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
2913 const test_step = addTestStep(b, "relocatable-merge-strings", opts);
2914
2915 const obj1 = addObject(b, opts, .{ .name = "a", .asm_source_bytes =
2916 \\.section .rodata.str1.1,"aMS",@progbits,1
2917 \\val1:
2918 \\.ascii "Hello \0"
2919 \\.section .rodata.str1.1,"aMS",@progbits,1
2920 \\val5:
2921 \\.ascii "World \0"
2922 \\.section .rodata.str1.1,"aMS",@progbits,1
2923 \\val7:
2924 \\.ascii "Hello \0"
2925 });
2926
2927 const obj2 = addObject(b, opts, .{ .name = "b" });
2928 obj2.root_module.addObject(obj1);
2929
2930 const check = obj2.checkObject();
2931 check.dumpSection(".rodata.str1.1");
2932 check.checkExact("Hello \x00World \x00");
2933 test_step.dependOn(&check.step);
2934
2935 return test_step;
2936}
2937
2938fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
2939 const test_step = addTestStep(b, "relocatable-no-eh-frame", opts);
2940
2941 const obj1 = addObject(b, opts, .{
2942 .name = "obj1",
2943 .c_source_bytes = "int bar() { return 42; }",
2944 .c_source_flags = &.{
2945 "-fno-unwind-tables",
2946 "-fno-asynchronous-unwind-tables",
2947 },
2948 });
2949
2950 const obj2 = addObject(b, opts, .{
2951 .name = "obj2",
2952 });
2953 obj2.root_module.addObject(obj1);
2954
2955 const check1 = obj1.checkObject();
2956 check1.checkInHeaders();
2957 check1.checkExact("section headers");
2958 check1.checkNotPresent(".eh_frame");
2959 test_step.dependOn(&check1.step);
2960
2961 const check2 = obj2.checkObject();
2962 check2.checkInHeaders();
2963 check2.checkExact("section headers");
2964 check2.checkNotPresent(".eh_frame");
2965 test_step.dependOn(&check2.step);
2966
2967 return test_step;
2968}
2969
2970fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2971 const test_step = addTestStep(b, "shared-abs-symbol", opts);
2972
2973 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2974 addAsmSourceBytes(dso,
2975 \\.globl foo
2976 \\foo = 3;
2977 );
2978
2979 const obj = addObject(b, opts, .{
2980 .name = "obj",
2981 .c_source_bytes =
2982 \\#include <stdio.h>
2983 \\extern char foo;
2984 \\int main() { printf("foo=%p\n", &foo); }
2985 ,
2986 .pic = true,
2987 });
2988 obj.root_module.link_libc = true;
2989
2990 {
2991 const exe = addExecutable(b, opts, .{ .name = "main1" });
2992 exe.root_module.addObject(obj);
2993 exe.root_module.linkLibrary(dso);
2994 exe.pie = true;
2995
2996 const run = addRunArtifact(exe);
2997 run.expectStdOutEqual("foo=0x3\n");
2998 test_step.dependOn(&run.step);
2999
3000 const check = exe.checkObject();
3001 check.checkInHeaders();
3002 check.checkExact("header");
3003 check.checkExact("type DYN");
3004 // TODO fix/improve in CheckObject
3005 // check.checkInSymtab();
3006 // check.checkNotPresent("foo");
3007 test_step.dependOn(&check.step);
3008 }
3009
3010 // https://github.com/ziglang/zig/issues/17430
3011 // {
3012 // const exe = addExecutable(b, opts, .{ .name = "main2"});
3013 // exe.root_module.addObject(obj);
3014 // exe.root_module.linkLibrary(dso);
3015 // exe.pie = false;
3016
3017 // const run = addRunArtifact(exe);
3018 // run.expectStdOutEqual("foo=0x3\n");
3019 // test_step.dependOn(&run.step);
3020
3021 // const check = exe.checkObject();
3022 // check.checkInHeaders();
3023 // check.checkExact("header");
3024 // check.checkExact("type EXEC");
3025 // // TODO fix/improve in CheckObject
3026 // // check.checkInSymtab();
3027 // // check.checkNotPresent("foo");
3028 // test_step.dependOn(&check.step);
3029 // }
3030
3031 return test_step;
3032}
3033
3034fn testStrip(b: *Build, opts: Options) *Step {
3035 const test_step = addTestStep(b, "strip", opts);
3036
3037 const obj = addObject(b, opts, .{
3038 .name = "obj",
3039 .c_source_bytes =
3040 \\#include <stdio.h>
3041 \\int main() {
3042 \\ printf("Hello!\n");
3043 \\ return 0;
3044 \\}
3045 ,
3046 });
3047 obj.root_module.link_libc = true;
3048
3049 {
3050 const exe = addExecutable(b, opts, .{ .name = "main1" });
3051 exe.root_module.addObject(obj);
3052 exe.root_module.strip = false;
3053 exe.root_module.link_libc = true;
3054
3055 const check = exe.checkObject();
3056 check.checkInHeaders();
3057 check.checkExact("section headers");
3058 check.checkExact("name .debug_info");
3059 test_step.dependOn(&check.step);
3060 }
3061
3062 {
3063 const exe = addExecutable(b, opts, .{ .name = "main2" });
3064 exe.root_module.addObject(obj);
3065 exe.root_module.strip = true;
3066 exe.root_module.link_libc = true;
3067
3068 const check = exe.checkObject();
3069 check.checkInHeaders();
3070 check.checkExact("section headers");
3071 check.checkNotPresent("name .debug_info");
3072 test_step.dependOn(&check.step);
3073 }
3074
3075 return test_step;
3076}
3077
3078fn testThunks(b: *Build, opts: Options) *Step {
3079 const test_step = addTestStep(b, "thunks", opts);
3080
3081 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
3082 \\void foo();
3083 \\__attribute__((section(".bar"))) void bar() {
3084 \\ return foo();
3085 \\}
3086 \\__attribute__((section(".foo"))) void foo() {
3087 \\ return bar();
3088 \\}
3089 \\int main() {
3090 \\ foo();
3091 \\ bar();
3092 \\ return 0;
3093 \\}
3094 });
3095
3096 const check = exe.checkObject();
3097 check.checkInSymtab();
3098 check.checkContains("foo$thunk");
3099 check.checkInSymtab();
3100 check.checkContains("bar$thunk");
3101 test_step.dependOn(&check.step);
3102
3103 return test_step;
3104}
3105
3106fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
3107 const test_step = addTestStep(b, "tls-df-static-tls", opts);
3108
3109 const obj = addObject(b, opts, .{
3110 .name = "obj",
3111 .c_source_bytes =
3112 \\static _Thread_local int foo = 5;
3113 \\void mutate() { ++foo; }
3114 \\int bar() { return foo; }
3115 ,
3116 .c_source_flags = &.{"-ftls-model=initial-exec"},
3117 .pic = true,
3118 });
3119
3120 {
3121 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3122 dso.root_module.addObject(obj);
3123 // dso.link_relax = true;
3124
3125 const check = dso.checkObject();
3126 check.checkInDynamicSection();
3127 check.checkContains("STATIC_TLS");
3128 test_step.dependOn(&check.step);
3129 }
3130
3131 // TODO add -Wl,--no-relax
3132 // {
3133 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3134 // dso.root_module.addObject(obj);
3135 // dso.link_relax = false;
3136
3137 // const check = dso.checkObject();
3138 // check.checkInDynamicSection();
3139 // check.checkContains("STATIC_TLS");
3140 // test_step.dependOn(&check.step);
3141 // }
3142
3143 return test_step;
3144}
3145
3146fn testTlsDso(b: *Build, opts: Options) *Step {
3147 const test_step = addTestStep(b, "tls-dso", opts);
3148
3149 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3150 addCSourceBytes(dso,
3151 \\extern _Thread_local int foo;
3152 \\_Thread_local int bar;
3153 \\int get_foo1() { return foo; }
3154 \\int get_bar1() { return bar; }
3155 , &.{});
3156
3157 const exe = addExecutable(b, opts, .{ .name = "main" });
3158 addCSourceBytes(exe,
3159 \\#include <stdio.h>
3160 \\_Thread_local int foo;
3161 \\extern _Thread_local int bar;
3162 \\int get_foo1();
3163 \\int get_bar1();
3164 \\int get_foo2() { return foo; }
3165 \\int get_bar2() { return bar; }
3166 \\int main() {
3167 \\ foo = 5;
3168 \\ bar = 3;
3169 \\ printf("%d %d %d %d %d %d\n",
3170 \\ foo, bar,
3171 \\ get_foo1(), get_bar1(),
3172 \\ get_foo2(), get_bar2());
3173 \\ return 0;
3174 \\}
3175 , &.{});
3176 exe.root_module.linkLibrary(dso);
3177 exe.root_module.link_libc = true;
3178
3179 const run = addRunArtifact(exe);
3180 run.expectStdOutEqual("5 3 5 3 5 3\n");
3181 test_step.dependOn(&run.step);
3182
3183 return test_step;
3184}
3185
3186fn testTlsGd(b: *Build, opts: Options) *Step {
3187 const test_step = addTestStep(b, "tls-gd", opts);
3188
3189 const main_o = addObject(b, opts, .{
3190 .name = "main",
3191 .c_source_bytes =
3192 \\#include <stdio.h>
3193 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1;
3194 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x2;
3195 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x3;
3196 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x4;
3197 \\int get_x5();
3198 \\int get_x6();
3199 \\int main() {
3200 \\ x2 = 2;
3201 \\ printf("%d %d %d %d %d %d\n", x1, x2, x3, x4, get_x5(), get_x6());
3202 \\ return 0;
3203 \\}
3204 ,
3205 .pic = true,
3206 });
3207 main_o.root_module.link_libc = true;
3208
3209 const a_o = addObject(b, opts, .{
3210 .name = "a",
3211 .c_source_bytes =
3212 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x3 = 3;
3213 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x5 = 5;
3214 \\int get_x5() { return x5; }
3215 ,
3216 .pic = true,
3217 });
3218
3219 const b_o = addObject(b, opts, .{
3220 .name = "b",
3221 .c_source_bytes =
3222 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x4 = 4;
3223 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x6 = 6;
3224 \\int get_x6() { return x6; }
3225 ,
3226 .pic = true,
3227 });
3228
3229 const exp_stdout = "1 2 3 4 5 6\n";
3230
3231 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
3232 dso1.root_module.addObject(a_o);
3233
3234 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
3235 dso2.root_module.addObject(b_o);
3236 // dso2.link_relax = false; // TODO
3237
3238 {
3239 const exe = addExecutable(b, opts, .{ .name = "main1" });
3240 exe.root_module.addObject(main_o);
3241 exe.root_module.linkLibrary(dso1);
3242 exe.root_module.linkLibrary(dso2);
3243
3244 const run = addRunArtifact(exe);
3245 run.expectStdOutEqual(exp_stdout);
3246 test_step.dependOn(&run.step);
3247 }
3248
3249 {
3250 const exe = addExecutable(b, opts, .{ .name = "main2" });
3251 exe.root_module.addObject(main_o);
3252 // exe.link_relax = false; // TODO
3253 exe.root_module.linkLibrary(dso1);
3254 exe.root_module.linkLibrary(dso2);
3255
3256 const run = addRunArtifact(exe);
3257 run.expectStdOutEqual(exp_stdout);
3258 test_step.dependOn(&run.step);
3259 }
3260
3261 // https://github.com/ziglang/zig/issues/17430 ??
3262 // {
3263 // const exe = addExecutable(b, opts, .{ .name = "main3"});
3264 // exe.root_module.addObject(main_o);
3265 // exe.root_module.linkLibrary(dso1);
3266 // exe.root_module.linkLibrary(dso2);
3267 // exe.linkage = .static;
3268
3269 // const run = addRunArtifact(exe);
3270 // run.expectStdOutEqual(exp_stdout);
3271 // test_step.dependOn(&run.step);
3272 // }
3273
3274 // {
3275 // const exe = addExecutable(b, opts, .{ .name = "main4"});
3276 // exe.root_module.addObject(main_o);
3277 // // exe.link_relax = false; // TODO
3278 // exe.root_module.linkLibrary(dso1);
3279 // exe.root_module.linkLibrary(dso2);
3280 // exe.linkage = .static;
3281
3282 // const run = addRunArtifact(exe);
3283 // run.expectStdOutEqual(exp_stdout);
3284 // test_step.dependOn(&run.step);
3285 // }
3286
3287 return test_step;
3288}
3289
3290fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
3291 const test_step = addTestStep(b, "tls-gd-no-plt", opts);
3292
3293 const obj = addObject(b, opts, .{
3294 .name = "obj",
3295 .c_source_bytes =
3296 \\#include <stdio.h>
3297 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1;
3298 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x2;
3299 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x3;
3300 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x4;
3301 \\int get_x5();
3302 \\int get_x6();
3303 \\int main() {
3304 \\ x2 = 2;
3305 \\
3306 \\ printf("%d %d %d %d %d %d\n", x1, x2, x3, x4, get_x5(), get_x6());
3307 \\ return 0;
3308 \\}
3309 ,
3310 .c_source_flags = &.{"-fno-plt"},
3311 .pic = true,
3312 });
3313 obj.root_module.link_libc = true;
3314
3315 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
3316 addCSourceBytes(a_so,
3317 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x3 = 3;
3318 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x5 = 5;
3319 \\int get_x5() { return x5; }
3320 , &.{"-fno-plt"});
3321
3322 const b_so = addSharedLibrary(b, opts, .{ .name = "b" });
3323 addCSourceBytes(b_so,
3324 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x4 = 4;
3325 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x6 = 6;
3326 \\int get_x6() { return x6; }
3327 , &.{"-fno-plt"});
3328 // b_so.link_relax = false; // TODO
3329
3330 {
3331 const exe = addExecutable(b, opts, .{ .name = "main1" });
3332 exe.root_module.addObject(obj);
3333 exe.root_module.linkLibrary(a_so);
3334 exe.root_module.linkLibrary(b_so);
3335 exe.root_module.link_libc = true;
3336
3337 const run = addRunArtifact(exe);
3338 run.expectStdOutEqual("1 2 3 4 5 6\n");
3339 test_step.dependOn(&run.step);
3340 }
3341
3342 {
3343 const exe = addExecutable(b, opts, .{ .name = "main2" });
3344 exe.root_module.addObject(obj);
3345 exe.root_module.linkLibrary(a_so);
3346 exe.root_module.linkLibrary(b_so);
3347 exe.root_module.link_libc = true;
3348 // exe.link_relax = false; // TODO
3349
3350 const run = addRunArtifact(exe);
3351 run.expectStdOutEqual("1 2 3 4 5 6\n");
3352 test_step.dependOn(&run.step);
3353 }
3354
3355 return test_step;
3356}
3357
3358fn testTlsGdToIe(b: *Build, opts: Options) *Step {
3359 const test_step = addTestStep(b, "tls-gd-to-ie", opts);
3360
3361 const a_o = addObject(b, opts, .{
3362 .name = "a",
3363 .c_source_bytes =
3364 \\#include <stdio.h>
3365 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1;
3366 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x2 = 2;
3367 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x3;
3368 \\int foo() {
3369 \\ x3 = 3;
3370 \\
3371 \\ printf("%d %d %d\n", x1, x2, x3);
3372 \\ return 0;
3373 \\}
3374 ,
3375 .pic = true,
3376 });
3377 a_o.root_module.link_libc = true;
3378
3379 const b_o = addObject(b, opts, .{
3380 .name = "b",
3381 .c_source_bytes =
3382 \\int foo();
3383 \\int main() { foo(); }
3384 ,
3385 .pic = true,
3386 });
3387
3388 {
3389 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
3390 dso.root_module.addObject(a_o);
3391
3392 const exe = addExecutable(b, opts, .{ .name = "main1" });
3393 exe.root_module.addObject(b_o);
3394 exe.root_module.linkLibrary(dso);
3395 exe.root_module.link_libc = true;
3396
3397 const run = addRunArtifact(exe);
3398 run.expectStdOutEqual("1 2 3\n");
3399 test_step.dependOn(&run.step);
3400 }
3401
3402 {
3403 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
3404 dso.root_module.addObject(a_o);
3405 // dso.link_relax = false; // TODO
3406
3407 const exe = addExecutable(b, opts, .{ .name = "main2" });
3408 exe.root_module.addObject(b_o);
3409 exe.root_module.linkLibrary(dso);
3410 exe.root_module.link_libc = true;
3411
3412 const run = addRunArtifact(exe);
3413 run.expectStdOutEqual("1 2 3\n");
3414 test_step.dependOn(&run.step);
3415 }
3416
3417 // {
3418 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3419 // dso.root_module.addObject(a_o);
3420 // dso.link_z_nodlopen = true;
3421
3422 // const exe = addExecutable(b, opts, .{ .name = "main"});
3423 // exe.root_module.addObject(b_o);
3424 // exe.root_module.linkLibrary(dso);
3425
3426 // const run = addRunArtifact(exe);
3427 // run.expectStdOutEqual("1 2 3\n");
3428 // test_step.dependOn(&run.step);
3429 // }
3430
3431 // {
3432 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3433 // dso.root_module.addObject(a_o);
3434 // dso.link_relax = false;
3435 // dso.link_z_nodlopen = true;
3436
3437 // const exe = addExecutable(b, opts, .{ .name = "main"});
3438 // exe.root_module.addObject(b_o);
3439 // exe.root_module.linkLibrary(dso);
3440
3441 // const run = addRunArtifact(exe);
3442 // run.expectStdOutEqual("1 2 3\n");
3443 // test_step.dependOn(&run.step);
3444 // }
3445
3446 return test_step;
3447}
3448
3449fn testTlsIe(b: *Build, opts: Options) *Step {
3450 const test_step = addTestStep(b, "tls-ie", opts);
3451
3452 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3453 addCSourceBytes(dso,
3454 \\#include <stdio.h>
3455 \\__attribute__((tls_model("initial-exec"))) static _Thread_local int foo;
3456 \\__attribute__((tls_model("initial-exec"))) static _Thread_local int bar;
3457 \\void set() {
3458 \\ foo = 3;
3459 \\ bar = 5;
3460 \\}
3461 \\void print() {
3462 \\ printf("%d %d ", foo, bar);
3463 \\}
3464 , &.{});
3465 dso.root_module.link_libc = true;
3466
3467 const main_o = addObject(b, opts, .{
3468 .name = "main",
3469 .c_source_bytes =
3470 \\#include <stdio.h>
3471 \\_Thread_local int baz;
3472 \\void set();
3473 \\void print();
3474 \\int main() {
3475 \\ baz = 7;
3476 \\ print();
3477 \\ set();
3478 \\ print();
3479 \\ printf("%d\n", baz);
3480 \\}
3481 ,
3482 });
3483 main_o.root_module.link_libc = true;
3484
3485 const exp_stdout = "0 0 3 5 7\n";
3486
3487 {
3488 const exe = addExecutable(b, opts, .{ .name = "main1" });
3489 exe.root_module.addObject(main_o);
3490 exe.root_module.linkLibrary(dso);
3491 exe.root_module.link_libc = true;
3492
3493 const run = addRunArtifact(exe);
3494 run.expectStdOutEqual(exp_stdout);
3495 test_step.dependOn(&run.step);
3496 }
3497
3498 {
3499 const exe = addExecutable(b, opts, .{ .name = "main2" });
3500 exe.root_module.addObject(main_o);
3501 exe.root_module.linkLibrary(dso);
3502 exe.root_module.link_libc = true;
3503 // exe.link_relax = false; // TODO
3504
3505 const run = addRunArtifact(exe);
3506 run.expectStdOutEqual(exp_stdout);
3507 test_step.dependOn(&run.step);
3508 }
3509
3510 return test_step;
3511}
3512
3513fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
3514 const test_step = addTestStep(b, "tls-large-alignment", opts);
3515
3516 const a_o = addObject(b, opts, .{
3517 .name = "a",
3518 .c_source_bytes =
3519 \\__attribute__((section(".tdata1")))
3520 \\_Thread_local int x = 42;
3521 ,
3522 .c_source_flags = &.{"-std=c11"},
3523 .pic = true,
3524 });
3525
3526 const b_o = addObject(b, opts, .{
3527 .name = "b",
3528 .c_source_bytes =
3529 \\__attribute__((section(".tdata2")))
3530 \\_Alignas(256) _Thread_local int y[] = { 1, 2, 3 };
3531 ,
3532 .c_source_flags = &.{"-std=c11"},
3533 .pic = true,
3534 });
3535
3536 const c_o = addObject(b, opts, .{
3537 .name = "c",
3538 .c_source_bytes =
3539 \\#include <stdio.h>
3540 \\extern _Thread_local int x;
3541 \\extern _Thread_local int y[];
3542 \\int main() {
3543 \\ printf("%d %d %d %d\n", x, y[0], y[1], y[2]);
3544 \\}
3545 ,
3546 .pic = true,
3547 });
3548 c_o.root_module.link_libc = true;
3549
3550 {
3551 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3552 dso.root_module.addObject(a_o);
3553 dso.root_module.addObject(b_o);
3554
3555 const exe = addExecutable(b, opts, .{ .name = "main" });
3556 exe.root_module.addObject(c_o);
3557 exe.root_module.linkLibrary(dso);
3558 exe.root_module.link_libc = true;
3559
3560 const run = addRunArtifact(exe);
3561 run.expectStdOutEqual("42 1 2 3\n");
3562 test_step.dependOn(&run.step);
3563 }
3564
3565 {
3566 const exe = addExecutable(b, opts, .{ .name = "main" });
3567 exe.root_module.addObject(a_o);
3568 exe.root_module.addObject(b_o);
3569 exe.root_module.addObject(c_o);
3570 exe.root_module.link_libc = true;
3571
3572 const run = addRunArtifact(exe);
3573 run.expectStdOutEqual("42 1 2 3\n");
3574 test_step.dependOn(&run.step);
3575 }
3576
3577 return test_step;
3578}
3579
3580fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
3581 const test_step = addTestStep(b, "tls-large-tbss", opts);
3582
3583 const exe = addExecutable(b, opts, .{ .name = "main" });
3584 addAsmSourceBytes(exe,
3585 \\.globl x, y
3586 \\.section .tbss,"awT",@nobits
3587 \\x:
3588 \\.zero 1024
3589 \\.section .tcommon,"awT",@nobits
3590 \\y:
3591 \\.zero 1024
3592 );
3593 addCSourceBytes(exe,
3594 \\#include <stdio.h>
3595 \\extern _Thread_local char x[1024000];
3596 \\extern _Thread_local char y[1024000];
3597 \\int main() {
3598 \\ x[0] = 3;
3599 \\ x[1023] = 5;
3600 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
3601 \\}
3602 , &.{});
3603 exe.root_module.link_libc = true;
3604 // Disabled to work around the ELF linker crashing.
3605 // Can be reproduced on a x86_64-linux host by commenting out the line below.
3606 exe.root_module.sanitize_c = .off;
3607
3608 const run = addRunArtifact(exe);
3609 run.expectStdOutEqual("3 0 5 0 0 0\n");
3610 test_step.dependOn(&run.step);
3611
3612 return test_step;
3613}
3614
3615fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
3616 const test_step = addTestStep(b, "tls-large-static-image", opts);
3617
3618 const exe = addExecutable(b, opts, .{ .name = "main" });
3619 addCSourceBytes(exe, "_Thread_local int x[] = { 1, 2, 3, [10000] = 5 };", &.{});
3620 addCSourceBytes(exe,
3621 \\#include <stdio.h>
3622 \\extern _Thread_local int x[];
3623 \\int main() {
3624 \\ printf("%d %d %d %d %d\n", x[0], x[1], x[2], x[3], x[10000]);
3625 \\}
3626 , &.{});
3627 exe.root_module.pic = true;
3628 exe.root_module.link_libc = true;
3629
3630 const run = addRunArtifact(exe);
3631 run.expectStdOutEqual("1 2 3 0 5\n");
3632 test_step.dependOn(&run.step);
3633
3634 return test_step;
3635}
3636
3637fn testTlsLd(b: *Build, opts: Options) *Step {
3638 const test_step = addTestStep(b, "tls-ld", opts);
3639
3640 const main_o = addObject(b, opts, .{
3641 .name = "main",
3642 .c_source_bytes =
3643 \\#include <stdio.h>
3644 \\extern _Thread_local int foo;
3645 \\static _Thread_local int bar;
3646 \\int *get_foo_addr() { return &foo; }
3647 \\int *get_bar_addr() { return &bar; }
3648 \\int main() {
3649 \\ bar = 5;
3650 \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar);
3651 \\ return 0;
3652 \\}
3653 ,
3654 .c_source_flags = &.{"-ftls-model=local-dynamic"},
3655 .pic = true,
3656 });
3657 main_o.root_module.link_libc = true;
3658
3659 const a_o = addObject(b, opts, .{
3660 .name = "a",
3661 .c_source_bytes = "_Thread_local int foo = 3;",
3662 .c_source_flags = &.{"-ftls-model=local-dynamic"},
3663 .pic = true,
3664 });
3665
3666 const exp_stdout = "3 5 3 5\n";
3667
3668 {
3669 const exe = addExecutable(b, opts, .{ .name = "main1" });
3670 exe.root_module.addObject(main_o);
3671 exe.root_module.addObject(a_o);
3672 exe.root_module.link_libc = true;
3673
3674 const run = addRunArtifact(exe);
3675 run.expectStdOutEqual(exp_stdout);
3676 test_step.dependOn(&run.step);
3677 }
3678
3679 {
3680 const exe = addExecutable(b, opts, .{ .name = "main2" });
3681 exe.root_module.addObject(main_o);
3682 exe.root_module.addObject(a_o);
3683 exe.root_module.link_libc = true;
3684 // exe.link_relax = false; // TODO
3685
3686 const run = addRunArtifact(exe);
3687 run.expectStdOutEqual(exp_stdout);
3688 test_step.dependOn(&run.step);
3689 }
3690
3691 return test_step;
3692}
3693
3694fn testTlsLdDso(b: *Build, opts: Options) *Step {
3695 const test_step = addTestStep(b, "tls-ld-dso", opts);
3696
3697 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3698 addCSourceBytes(dso,
3699 \\static _Thread_local int def, def1;
3700 \\int f0() { return ++def; }
3701 \\int f1() { return ++def1 + def; }
3702 , &.{"-ftls-model=local-dynamic"});
3703
3704 const exe = addExecutable(b, opts, .{ .name = "main" });
3705 addCSourceBytes(exe,
3706 \\#include <stdio.h>
3707 \\extern int f0();
3708 \\extern int f1();
3709 \\int main() {
3710 \\ int x = f0();
3711 \\ int y = f1();
3712 \\ printf("%d %d\n", x, y);
3713 \\ return 0;
3714 \\}
3715 , &.{});
3716 exe.root_module.linkLibrary(dso);
3717 exe.root_module.link_libc = true;
3718
3719 const run = addRunArtifact(exe);
3720 run.expectStdOutEqual("1 2\n");
3721 test_step.dependOn(&run.step);
3722
3723 return test_step;
3724}
3725
3726fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
3727 const test_step = addTestStep(b, "tls-ld-no-plt", opts);
3728
3729 const a_o = addObject(b, opts, .{
3730 .name = "a",
3731 .c_source_bytes =
3732 \\#include <stdio.h>
3733 \\extern _Thread_local int foo;
3734 \\static _Thread_local int bar;
3735 \\int *get_foo_addr() { return &foo; }
3736 \\int *get_bar_addr() { return &bar; }
3737 \\int main() {
3738 \\ bar = 5;
3739 \\
3740 \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar);
3741 \\ return 0;
3742 \\}
3743 ,
3744 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
3745 .pic = true,
3746 });
3747 a_o.root_module.link_libc = true;
3748
3749 const b_o = addObject(b, opts, .{
3750 .name = "b",
3751 .c_source_bytes = "_Thread_local int foo = 3;",
3752 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
3753 .pic = true,
3754 });
3755
3756 {
3757 const exe = addExecutable(b, opts, .{ .name = "main1" });
3758 exe.root_module.addObject(a_o);
3759 exe.root_module.addObject(b_o);
3760 exe.root_module.link_libc = true;
3761
3762 const run = addRunArtifact(exe);
3763 run.expectStdOutEqual("3 5 3 5\n");
3764 test_step.dependOn(&run.step);
3765 }
3766
3767 {
3768 const exe = addExecutable(b, opts, .{ .name = "main2" });
3769 exe.root_module.addObject(a_o);
3770 exe.root_module.addObject(b_o);
3771 exe.root_module.link_libc = true;
3772 // exe.link_relax = false; // TODO
3773
3774 const run = addRunArtifact(exe);
3775 run.expectStdOutEqual("3 5 3 5\n");
3776 test_step.dependOn(&run.step);
3777 }
3778
3779 return test_step;
3780}
3781
3782fn testTlsNoPic(b: *Build, opts: Options) *Step {
3783 const test_step = addTestStep(b, "tls-no-pic", opts);
3784
3785 const exe = addExecutable(b, opts, .{ .name = "main" });
3786 addCSourceBytes(exe,
3787 \\#include <stdio.h>
3788 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int foo;
3789 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int bar;
3790 \\int *get_foo_addr() { return &foo; }
3791 \\int *get_bar_addr() { return &bar; }
3792 \\int main() {
3793 \\ foo = 3;
3794 \\ bar = 5;
3795 \\
3796 \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar);
3797 \\ return 0;
3798 \\}
3799 , .{});
3800 addCSourceBytes(exe,
3801 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
3802 , &.{});
3803 exe.root_module.pic = false;
3804 exe.root_module.link_libc = true;
3805
3806 const run = addRunArtifact(exe);
3807 run.expectStdOutEqual("3 5 3 5\n");
3808 test_step.dependOn(&run.step);
3809
3810 return test_step;
3811}
3812
3813fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
3814 const test_step = addTestStep(b, "tls-offset-alignment", opts);
3815
3816 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3817 addCSourceBytes(dso,
3818 \\#include <assert.h>
3819 \\#include <stdlib.h>
3820 \\
3821 \\// .tdata
3822 \\_Thread_local int x = 42;
3823 \\// .tbss
3824 \\__attribute__ ((aligned(64)))
3825 \\_Thread_local int y = 0;
3826 \\
3827 \\void *verify(void *unused) {
3828 \\ assert((unsigned long)(&y) % 64 == 0);
3829 \\ return NULL;
3830 \\}
3831 , &.{});
3832 dso.root_module.link_libc = true;
3833
3834 const exe = addExecutable(b, opts, .{ .name = "main" });
3835 addCSourceBytes(exe,
3836 \\#include <pthread.h>
3837 \\#include <dlfcn.h>
3838 \\#include <assert.h>
3839 \\#include <stdio.h>
3840 \\void *(*verify)(void *);
3841 \\
3842 \\int main() {
3843 \\ void *handle = dlopen("liba.so", RTLD_NOW);
3844 \\ if (!handle) {
3845 \\ fprintf(stderr, "dlopen failed: %s\n", dlerror());
3846 \\ return 1;
3847 \\ }
3848 \\ *(void**)(&verify) = dlsym(handle, "verify");
3849 \\ assert(verify);
3850 \\
3851 \\ pthread_t thread;
3852 \\
3853 \\ verify(NULL);
3854 \\
3855 \\ pthread_create(&thread, NULL, verify, NULL);
3856 \\ pthread_join(thread, NULL);
3857 \\}
3858 , &.{});
3859 exe.root_module.addRPath(dso.getEmittedBinDirectory());
3860 exe.root_module.link_libc = true;
3861 exe.root_module.pic = true;
3862
3863 const run = addRunArtifact(exe);
3864 run.expectExitCode(0);
3865 test_step.dependOn(&run.step);
3866
3867 return test_step;
3868}
3869
3870fn testTlsPic(b: *Build, opts: Options) *Step {
3871 const test_step = addTestStep(b, "tls-pic", opts);
3872
3873 const obj = addObject(b, opts, .{
3874 .name = "obj",
3875 .c_source_bytes =
3876 \\#include <stdio.h>
3877 \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int foo;
3878 \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int bar;
3879 \\int *get_foo_addr() { return &foo; }
3880 \\int *get_bar_addr() { return &bar; }
3881 \\int main() {
3882 \\ bar = 5;
3883 \\
3884 \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar);
3885 \\ return 0;
3886 \\}
3887 ,
3888 .pic = true,
3889 });
3890 obj.root_module.link_libc = true;
3891
3892 const exe = addExecutable(b, opts, .{ .name = "main" });
3893 addCSourceBytes(exe,
3894 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
3895 , &.{});
3896 exe.root_module.addObject(obj);
3897 exe.root_module.link_libc = true;
3898
3899 const run = addRunArtifact(exe);
3900 run.expectStdOutEqual("3 5 3 5\n");
3901 test_step.dependOn(&run.step);
3902
3903 return test_step;
3904}
3905
3906fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
3907 const test_step = addTestStep(b, "tls-small-alignment", opts);
3908
3909 const a_o = addObject(b, opts, .{
3910 .name = "a",
3911 .asm_source_bytes =
3912 \\.text
3913 \\.byte 0
3914 \\
3915 ,
3916 .pic = true,
3917 });
3918
3919 const b_o = addObject(b, opts, .{
3920 .name = "b",
3921 .c_source_bytes = "_Thread_local char x = 42;",
3922 .c_source_flags = &.{"-std=c11"},
3923 .pic = true,
3924 });
3925
3926 const c_o = addObject(b, opts, .{
3927 .name = "c",
3928 .c_source_bytes =
3929 \\#include <stdio.h>
3930 \\extern _Thread_local char x;
3931 \\int main() {
3932 \\ printf("%d\n", x);
3933 \\}
3934 ,
3935 .pic = true,
3936 });
3937 c_o.root_module.link_libc = true;
3938
3939 {
3940 const exe = addExecutable(b, opts, .{ .name = "main" });
3941 exe.root_module.addObject(a_o);
3942 exe.root_module.addObject(b_o);
3943 exe.root_module.addObject(c_o);
3944 exe.root_module.link_libc = true;
3945
3946 const run = addRunArtifact(exe);
3947 run.expectStdOutEqual("42\n");
3948 test_step.dependOn(&run.step);
3949 }
3950
3951 {
3952 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3953 dso.root_module.addObject(a_o);
3954 dso.root_module.addObject(b_o);
3955
3956 const exe = addExecutable(b, opts, .{ .name = "main" });
3957 exe.root_module.addObject(c_o);
3958 exe.root_module.linkLibrary(dso);
3959 exe.root_module.link_libc = true;
3960
3961 const run = addRunArtifact(exe);
3962 run.expectStdOutEqual("42\n");
3963 test_step.dependOn(&run.step);
3964 }
3965
3966 return test_step;
3967}
3968
3969fn testTlsStatic(b: *Build, opts: Options) *Step {
3970 const test_step = addTestStep(b, "tls-static", opts);
3971
3972 const exe = addExecutable(b, opts, .{ .name = "test" });
3973 addCSourceBytes(exe,
3974 \\#include <stdio.h>
3975 \\_Thread_local int a = 10;
3976 \\_Thread_local int b;
3977 \\_Thread_local char c = 'a';
3978 \\int main(int argc, char* argv[]) {
3979 \\ printf("%d %d %c\n", a, b, c);
3980 \\ a += 1;
3981 \\ b += 1;
3982 \\ c += 1;
3983 \\ printf("%d %d %c\n", a, b, c);
3984 \\ return 0;
3985 \\}
3986 , &.{});
3987 exe.root_module.link_libc = true;
3988
3989 const run = addRunArtifact(exe);
3990 run.expectStdOutEqual(
3991 \\10 0 a
3992 \\11 1 b
3993 \\
3994 );
3995 test_step.dependOn(&run.step);
3996
3997 return test_step;
3998}
3999
4000fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
4001 const test_step = addTestStep(b, "unknown-file-type-error", opts);
4002
4003 const dylib = addSharedLibrary(b, .{
4004 .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .macos }),
4005 }, .{
4006 .name = "a",
4007 .zig_source_bytes = "export var foo: i32 = 0;",
4008 });
4009
4010 const exe = addExecutable(b, opts, .{ .name = "main" });
4011 addCSourceBytes(exe,
4012 \\extern int foo;
4013 \\int main() {
4014 \\ return foo;
4015 \\}
4016 , &.{});
4017 exe.root_module.linkLibrary(dylib);
4018 exe.root_module.link_libc = true;
4019
4020 expectLinkErrors(exe, test_step, .{
4021 .contains = "error: failed to parse shared library: BadMagic",
4022 });
4023
4024 return test_step;
4025}
4026
4027fn testUnresolvedError(b: *Build, opts: Options) *Step {
4028 const test_step = addTestStep(b, "unresolved-error", opts);
4029
4030 const obj1 = addObject(b, opts, .{
4031 .name = "a",
4032 .c_source_bytes =
4033 \\#include <stdio.h>
4034 \\int foo();
4035 \\int bar() {
4036 \\ return foo() + 1;
4037 \\}
4038 ,
4039 .c_source_flags = &.{"-ffunction-sections"},
4040 });
4041 obj1.root_module.link_libc = true;
4042
4043 const obj2 = addObject(b, opts, .{
4044 .name = "b",
4045 .c_source_bytes =
4046 \\#include <stdio.h>
4047 \\int foo();
4048 \\int bar();
4049 \\int main() {
4050 \\ return foo() + bar();
4051 \\}
4052 ,
4053 .c_source_flags = &.{"-ffunction-sections"},
4054 });
4055 obj2.root_module.link_libc = true;
4056
4057 const exe = addExecutable(b, opts, .{ .name = "main" });
4058 exe.root_module.addObject(obj1);
4059 exe.root_module.addObject(obj2);
4060 exe.root_module.link_libc = true;
4061
4062 expectLinkErrors(exe, test_step, .{ .exact = &.{
4063 "error: undefined symbol: foo",
4064 "note: referenced by /?/a.o:.text.bar",
4065 "note: referenced by /?/b.o:.text.main",
4066 } });
4067
4068 return test_step;
4069}
4070
4071fn testWeakExports(b: *Build, opts: Options) *Step {
4072 const test_step = addTestStep(b, "weak-exports", opts);
4073
4074 const obj = addObject(b, opts, .{
4075 .name = "obj",
4076 .c_source_bytes =
4077 \\#include <stdio.h>
4078 \\__attribute__((weak)) int foo();
4079 \\int main() {
4080 \\ printf("%d\n", foo ? foo() : 3);
4081 \\}
4082 ,
4083 .pic = true,
4084 });
4085 obj.root_module.link_libc = true;
4086
4087 {
4088 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4089 dso.root_module.addObject(obj);
4090 dso.root_module.link_libc = true;
4091
4092 const check = dso.checkObject();
4093 check.checkInDynamicSymtab();
4094 check.checkContains("UND NOTYPE WEAK DEFAULT foo");
4095 test_step.dependOn(&check.step);
4096 }
4097
4098 {
4099 const exe = addExecutable(b, opts, .{ .name = "main" });
4100 exe.root_module.addObject(obj);
4101 exe.root_module.link_libc = true;
4102
4103 const check = exe.checkObject();
4104 check.checkInDynamicSymtab();
4105 check.checkNotPresent("UND NOTYPE WEAK DEFAULT foo");
4106 test_step.dependOn(&check.step);
4107
4108 const run = addRunArtifact(exe);
4109 run.expectStdOutEqual("3\n");
4110 test_step.dependOn(&run.step);
4111 }
4112
4113 return test_step;
4114}
4115
4116fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
4117 const test_step = addTestStep(b, "weak-undef-dso", opts);
4118
4119 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4120 addCSourceBytes(dso,
4121 \\__attribute__((weak)) int foo();
4122 \\int bar() { return foo ? foo() : -1; }
4123 , &.{});
4124
4125 {
4126 const exe = addExecutable(b, opts, .{ .name = "main" });
4127 addCSourceBytes(exe,
4128 \\#include <stdio.h>
4129 \\int bar();
4130 \\int main() { printf("bar=%d\n", bar()); }
4131 , &.{});
4132 exe.root_module.linkLibrary(dso);
4133 exe.root_module.link_libc = true;
4134
4135 const run = addRunArtifact(exe);
4136 run.expectStdOutEqual("bar=-1\n");
4137 test_step.dependOn(&run.step);
4138 }
4139
4140 {
4141 const exe = addExecutable(b, opts, .{ .name = "main" });
4142 addCSourceBytes(exe,
4143 \\#include <stdio.h>
4144 \\int foo() { return 5; }
4145 \\int bar();
4146 \\int main() { printf("bar=%d\n", bar()); }
4147 , &.{});
4148 exe.root_module.linkLibrary(dso);
4149 exe.root_module.link_libc = true;
4150
4151 const run = addRunArtifact(exe);
4152 run.expectStdOutEqual("bar=5\n");
4153 test_step.dependOn(&run.step);
4154 }
4155
4156 return test_step;
4157}
4158
4159fn testZNow(b: *Build, opts: Options) *Step {
4160 const test_step = addTestStep(b, "z-now", opts);
4161
4162 const obj = addObject(b, opts, .{
4163 .name = "obj",
4164 .c_source_bytes = "int main() { return 0; }",
4165 .pic = true,
4166 });
4167
4168 {
4169 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4170 dso.root_module.addObject(obj);
4171
4172 const check = dso.checkObject();
4173 check.checkInDynamicSection();
4174 check.checkContains("NOW");
4175 test_step.dependOn(&check.step);
4176 }
4177
4178 {
4179 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4180 dso.root_module.addObject(obj);
4181 dso.link_z_lazy = true;
4182
4183 const check = dso.checkObject();
4184 check.checkInDynamicSection();
4185 check.checkNotPresent("NOW");
4186 test_step.dependOn(&check.step);
4187 }
4188
4189 return test_step;
4190}
4191
4192fn testZStackSize(b: *Build, opts: Options) *Step {
4193 const test_step = addTestStep(b, "z-stack-size", opts);
4194
4195 const exe = addExecutable(b, opts, .{ .name = "main" });
4196 addCSourceBytes(exe, "int main() { return 0; }", &.{});
4197 exe.stack_size = 0x800000;
4198 exe.root_module.link_libc = true;
4199
4200 const check = exe.checkObject();
4201 check.checkInHeaders();
4202 check.checkExact("program headers");
4203 check.checkExact("type GNU_STACK");
4204 check.checkExact("memsz 800000");
4205 test_step.dependOn(&check.step);
4206
4207 return test_step;
4208}
4209
4210fn testZText(b: *Build, opts: Options) *Step {
4211 const test_step = addTestStep(b, "z-text", opts);
4212
4213 // Previously, following mold, this test tested text relocs present in a PIE executable.
4214 // However, as we want to cover musl AND glibc, it is now modified to test presence of
4215 // text relocs in a DSO which is then linked with an executable.
4216 // According to Rich and this thread https://www.openwall.com/lists/musl/2020/09/25/4
4217 // musl supports only a very limited number of text relocations and only in DSOs (and
4218 // rightly so!).
4219
4220 const a_o = addObject(b, opts, .{
4221 .name = "a",
4222 .asm_source_bytes =
4223 \\.globl fn1
4224 \\fn1:
4225 \\ sub $8, %rsp
4226 \\ movabs ptr, %rax
4227 \\ call *%rax
4228 \\ add $8, %rsp
4229 \\ ret
4230 \\
4231 ,
4232 });
4233
4234 const b_o = addObject(b, opts, .{
4235 .name = "b",
4236 .c_source_bytes =
4237 \\int fn1();
4238 \\int fn2() {
4239 \\ return 3;
4240 \\}
4241 \\void *ptr = fn2;
4242 \\int fnn() {
4243 \\ return fn1();
4244 \\}
4245 ,
4246 .pic = true,
4247 });
4248
4249 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4250 dso.root_module.addObject(a_o);
4251 dso.root_module.addObject(b_o);
4252 dso.link_z_notext = true;
4253
4254 const exe = addExecutable(b, opts, .{ .name = "main" });
4255 addCSourceBytes(exe,
4256 \\#include <stdio.h>
4257 \\int fnn();
4258 \\int main() {
4259 \\ printf("%d\n", fnn());
4260 \\}
4261 , &.{});
4262 exe.root_module.linkLibrary(dso);
4263 exe.root_module.link_libc = true;
4264
4265 const run = addRunArtifact(exe);
4266 run.expectStdOutEqual("3\n");
4267 test_step.dependOn(&run.step);
4268
4269 // Check for DT_TEXTREL in a DSO
4270 const check = dso.checkObject();
4271 check.checkInDynamicSection();
4272 // check.checkExact("TEXTREL 0"); // TODO fix in CheckObject parser
4273 check.checkContains("FLAGS TEXTREL");
4274 test_step.dependOn(&check.step);
4275
4276 return test_step;
4277}
4278
4279fn addTestStep(b: *Build, comptime prefix: []const u8, opts: Options) *Step {
4280 return link.addTestStep(b, "elf-" ++ prefix, opts);
4281}
4282
4283const addAsmSourceBytes = link.addAsmSourceBytes;
4284const addCSourceBytes = link.addCSourceBytes;
4285const addCppSourceBytes = link.addCppSourceBytes;
4286const addExecutable = link.addExecutable;
4287const addObject = link.addObject;
4288const addRunArtifact = link.addRunArtifact;
4289const addSharedLibrary = link.addSharedLibrary;
4290const addStaticLibrary = link.addStaticLibrary;
4291const expectLinkErrors = link.expectLinkErrors;
4292const link = @import("link.zig");
4293const std = @import("std");
4294const builtin = @import("builtin");
4295
4296const Build = std.Build;
4297const BuildOptions = link.BuildOptions;
4298const Options = link.Options;
4299const Step = Build.Step;
4300const WriteFile = Step.WriteFile;