authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-25 17:35:48+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-26 21:07:47+02:00
log5e617e4b0c35c75e8079f3c0918392327a55d413
treefd1925e67793570b54aa0f42c2eae6416d73d4ff
parente7c6dfde3d2e52ac8180fc3c147064528124301d

elf: put libc on the linker line if requested


2 files changed, 67 insertions(+), 27 deletions(-)

src/link/Elf.zig+58-17
...@@ -965,6 +965,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -965,6 +965,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
965 defer arena_allocator.deinit();965 defer arena_allocator.deinit();
966 const arena = arena_allocator.allocator();966 const arena = arena_allocator.allocator();
967967
968 const target = self.base.options.target;
968 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.969 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
969 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});970 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
970971
...@@ -993,22 +994,63 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -993,22 +994,63 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
993 try positionals.append(.{ .path = key.status.success.object_path });994 try positionals.append(.{ .path = key.status.success.object_path });
994 }995 }
995996
997 for (positionals.items) |obj| {
998 const in_file = try std.fs.cwd().openFile(obj.path, .{});
999 defer in_file.close();
1000 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1001 self.parsePositional(in_file, obj.path, obj.must_link, &parse_ctx) catch |err|
1002 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1003 }
1004
1005 var system_libs = std.ArrayList(SystemLib).init(arena);
1006
1007 // libc dep
1008 self.error_flags.missing_libc = false;
1009 if (self.base.options.link_libc) {
1010 if (self.base.options.libc_installation != null) {
1011 @panic("TODO explicit libc_installation");
1012 } else if (target.isGnuLibC()) {
1013 try system_libs.ensureUnusedCapacity(glibc.libs.len + 1);
1014 for (glibc.libs) |lib| {
1015 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1016 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1017 });
1018 system_libs.appendAssumeCapacity(.{ .path = lib_path });
1019 }
1020 system_libs.appendAssumeCapacity(.{
1021 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
1022 });
1023 } else if (target.isMusl()) {
1024 const path = try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1025 .Static => "libc.a",
1026 .Dynamic => "libc.so",
1027 });
1028 try system_libs.append(.{ .path = path });
1029 } else {
1030 self.error_flags.missing_libc = true;
1031 }
1032 }
1033
1034 for (system_libs.items) |lib| {
1035 const in_file = try std.fs.cwd().openFile(lib.path, .{});
1036 defer in_file.close();
1037 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1038 self.parseLibrary(in_file, lib, false, &parse_ctx) catch |err|
1039 try self.handleAndReportParseError(lib.path, err, &parse_ctx);
1040 }
1041
1042 // Finally, as the last input object add compiler_rt if any.
996 const compiler_rt_path: ?[]const u8 = blk: {1043 const compiler_rt_path: ?[]const u8 = blk: {
997 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1044 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
998 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;1045 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
999 break :blk null;1046 break :blk null;
1000 };1047 };
1001 if (compiler_rt_path) |path| {1048 if (compiler_rt_path) |path| {
1002 try positionals.append(.{ .path = path });1049 const in_file = try std.fs.cwd().openFile(path, .{});
1003 }
1004
1005 for (positionals.items) |obj| {
1006 const in_file = try std.fs.cwd().openFile(obj.path, .{});
1007 defer in_file.close();1050 defer in_file.close();
1008
1009 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1051 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1010 self.parsePositional(in_file, obj.path, obj.must_link, &parse_ctx) catch |err|1052 self.parsePositional(in_file, path, false, &parse_ctx) catch |err|
1011 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1053 try self.handleAndReportParseError(path, err, &parse_ctx);
1012 }1054 }
10131055
1014 // Handle any lazy symbols that were emitted by incremental compilation.1056 // Handle any lazy symbols that were emitted by incremental compilation.
...@@ -1347,28 +1389,22 @@ fn parsePositional(...@@ -1347,28 +1389,22 @@ fn parsePositional(
1347 if (Object.isObject(in_file)) {1389 if (Object.isObject(in_file)) {
1348 try self.parseObject(in_file, path, ctx);1390 try self.parseObject(in_file, path, ctx);
1349 } else {1391 } else {
1350 try self.parseLibrary(in_file, path, .{1392 try self.parseLibrary(in_file, .{ .path = path }, must_link, ctx);
1351 .path = null,
1352 .needed = false,
1353 .weak = false,
1354 }, must_link, ctx);
1355 }1393 }
1356}1394}
13571395
1358fn parseLibrary(1396fn parseLibrary(
1359 self: *Elf,1397 self: *Elf,
1360 in_file: std.fs.File,1398 in_file: std.fs.File,
1361 path: []const u8,1399 lib: SystemLib,
1362 lib: link.SystemLib,
1363 must_link: bool,1400 must_link: bool,
1364 ctx: *ParseErrorCtx,1401 ctx: *ParseErrorCtx,
1365) ParseError!void {1402) ParseError!void {
1366 const tracy = trace(@src());1403 const tracy = trace(@src());
1367 defer tracy.end();1404 defer tracy.end();
1368 _ = lib;
13691405
1370 if (Archive.isArchive(in_file)) {1406 if (Archive.isArchive(in_file)) {
1371 try self.parseArchive(in_file, path, must_link, ctx);1407 try self.parseArchive(in_file, lib.path, must_link, ctx);
1372 } else return error.UnknownFileType;1408 } else return error.UnknownFileType;
1373}1409}
13741410
...@@ -4149,6 +4185,11 @@ pub const null_sym = elf.Elf64_Sym{...@@ -4149,6 +4185,11 @@ pub const null_sym = elf.Elf64_Sym{
4149 .st_size = 0,4185 .st_size = 0,
4150};4186};
41514187
4188const SystemLib = struct {
4189 needed: bool = false,
4190 path: []const u8,
4191};
4192
4152const std = @import("std");4193const std = @import("std");
4153const build_options = @import("build_options");4194const build_options = @import("build_options");
4154const builtin = @import("builtin");4195const builtin = @import("builtin");
test/link/elf.zig+9-10
...@@ -6,18 +6,19 @@ pub fn build(b: *Build) void {...@@ -6,18 +6,19 @@ pub fn build(b: *Build) void {
6 const elf_step = b.step("test-elf", "Run ELF tests");6 const elf_step = b.step("test-elf", "Run ELF tests");
7 b.default_step = elf_step;7 b.default_step = elf_step;
88
9 const target: CrossTarget = .{9 const musl_target = CrossTarget{
10 .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs10 .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs
11 .os_tag = .linux,11 .os_tag = .linux,
12 .abi = .musl,
12 };13 };
1314
14 elf_step.dependOn(testLinkingZigStatic(b, .{ .target = target, .use_llvm = true }));15 elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = true }));
15 elf_step.dependOn(testLinkingZigStatic(b, .{ .target = target, .use_llvm = false }));16 elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false }));
16 elf_step.dependOn(testLinkingCStatic(b, .{ .target = target, .use_llvm = true }));17 elf_step.dependOn(testLinkingC(b, .{ .target = musl_target, .use_llvm = true }));
17 // elf_step.dependOn(testLinkingCStatic(b, .{ .target = target, .use_llvm = false })); // TODO arocc18 // elf_step.dependOn(testLinkingC(b, .{ .target = musl_target, .use_llvm = false })); // TODO arocc
18}19}
1920
20fn testLinkingZigStatic(b: *Build, opts: Options) *Step {21fn testLinkingZig(b: *Build, opts: Options) *Step {
21 const test_step = addTestStep(b, "linking-zig-static", opts);22 const test_step = addTestStep(b, "linking-zig-static", opts);
2223
23 const exe = addExecutable(b, opts);24 const exe = addExecutable(b, opts);
...@@ -26,7 +27,6 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step {...@@ -26,7 +27,6 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step {
26 \\ @import("std").debug.print("Hello World!\n", .{});27 \\ @import("std").debug.print("Hello World!\n", .{});
27 \\}28 \\}
28 );29 );
29 exe.linkage = .static;
3030
31 const run = b.addRunArtifact(exe);31 const run = b.addRunArtifact(exe);
32 run.expectStdErrEqual("Hello World!\n");32 run.expectStdErrEqual("Hello World!\n");
...@@ -44,7 +44,7 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step {...@@ -44,7 +44,7 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step {
44 return test_step;44 return test_step;
45}45}
4646
47fn testLinkingCStatic(b: *Build, opts: Options) *Step {47fn testLinkingC(b: *Build, opts: Options) *Step {
48 const test_step = addTestStep(b, "linking-c-static", opts);48 const test_step = addTestStep(b, "linking-c-static", opts);
4949
50 const exe = addExecutable(b, opts);50 const exe = addExecutable(b, opts);
...@@ -56,7 +56,6 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step {...@@ -56,7 +56,6 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step {
56 \\}56 \\}
57 );57 );
58 exe.is_linking_libc = true;58 exe.is_linking_libc = true;
59 exe.linkage = .static;
6059
61 const run = b.addRunArtifact(exe);60 const run = b.addRunArtifact(exe);
62 run.expectStdOutEqual("Hello World!\n");61 run.expectStdOutEqual("Hello World!\n");
...@@ -75,7 +74,7 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step {...@@ -75,7 +74,7 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step {
75}74}
7675
77const Options = struct {76const Options = struct {
78 target: CrossTarget = .{ .os_tag = .linux },77 target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux },
79 optimize: std.builtin.OptimizeMode = .Debug,78 optimize: std.builtin.OptimizeMode = .Debug,
80 use_llvm: bool = true,79 use_llvm: bool = true,
81};80};