From 5e617e4b0c35c75e8079f3c0918392327a55d413 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 25 Sep 2023 17:35:48 +0200 Subject: [PATCH] elf: put libc on the linker line if requested --- src/link/Elf.zig | 75 ++++++++++++++++++++++++++++++++++++----------- test/link/elf.zig | 19 ++++++------ 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c42ee20b49..68101ae964 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -965,6 +965,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); + const target = self.base.options.target; const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); @@ -993,22 +994,63 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try positionals.append(.{ .path = key.status.success.object_path }); } + for (positionals.items) |obj| { + const in_file = try std.fs.cwd().openFile(obj.path, .{}); + defer in_file.close(); + var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; + self.parsePositional(in_file, obj.path, obj.must_link, &parse_ctx) catch |err| + try self.handleAndReportParseError(obj.path, err, &parse_ctx); + } + + var system_libs = std.ArrayList(SystemLib).init(arena); + + // libc dep + self.error_flags.missing_libc = false; + if (self.base.options.link_libc) { + if (self.base.options.libc_installation != null) { + @panic("TODO explicit libc_installation"); + } else if (target.isGnuLibC()) { + try system_libs.ensureUnusedCapacity(glibc.libs.len + 1); + for (glibc.libs) |lib| { + const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{ + comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, + }); + system_libs.appendAssumeCapacity(.{ .path = lib_path }); + } + system_libs.appendAssumeCapacity(.{ + .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"), + }); + } else if (target.isMusl()) { + const path = try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { + .Static => "libc.a", + .Dynamic => "libc.so", + }); + try system_libs.append(.{ .path = path }); + } else { + self.error_flags.missing_libc = true; + } + } + + for (system_libs.items) |lib| { + const in_file = try std.fs.cwd().openFile(lib.path, .{}); + defer in_file.close(); + var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; + self.parseLibrary(in_file, lib, false, &parse_ctx) catch |err| + try self.handleAndReportParseError(lib.path, err, &parse_ctx); + } + + // Finally, as the last input object add compiler_rt if any. const compiler_rt_path: ?[]const u8 = blk: { if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; break :blk null; }; if (compiler_rt_path) |path| { - try positionals.append(.{ .path = path }); - } - - for (positionals.items) |obj| { - const in_file = try std.fs.cwd().openFile(obj.path, .{}); + const in_file = try std.fs.cwd().openFile(path, .{}); defer in_file.close(); - var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; - self.parsePositional(in_file, obj.path, obj.must_link, &parse_ctx) catch |err| - try self.handleAndReportParseError(obj.path, err, &parse_ctx); + self.parsePositional(in_file, path, false, &parse_ctx) catch |err| + try self.handleAndReportParseError(path, err, &parse_ctx); } // Handle any lazy symbols that were emitted by incremental compilation. @@ -1347,28 +1389,22 @@ fn parsePositional( if (Object.isObject(in_file)) { try self.parseObject(in_file, path, ctx); } else { - try self.parseLibrary(in_file, path, .{ - .path = null, - .needed = false, - .weak = false, - }, must_link, ctx); + try self.parseLibrary(in_file, .{ .path = path }, must_link, ctx); } } fn parseLibrary( self: *Elf, in_file: std.fs.File, - path: []const u8, - lib: link.SystemLib, + lib: SystemLib, must_link: bool, ctx: *ParseErrorCtx, ) ParseError!void { const tracy = trace(@src()); defer tracy.end(); - _ = lib; if (Archive.isArchive(in_file)) { - try self.parseArchive(in_file, path, must_link, ctx); + try self.parseArchive(in_file, lib.path, must_link, ctx); } else return error.UnknownFileType; } @@ -4149,6 +4185,11 @@ pub const null_sym = elf.Elf64_Sym{ .st_size = 0, }; +const SystemLib = struct { + needed: bool = false, + path: []const u8, +}; + const std = @import("std"); const build_options = @import("build_options"); const builtin = @import("builtin"); diff --git a/test/link/elf.zig b/test/link/elf.zig index e29a5af158..b20498e7df 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -6,18 +6,19 @@ pub fn build(b: *Build) void { const elf_step = b.step("test-elf", "Run ELF tests"); b.default_step = elf_step; - const target: CrossTarget = .{ + const musl_target = CrossTarget{ .cpu_arch = .x86_64, // TODO relax this once ELF linker is able to handle other archs .os_tag = .linux, + .abi = .musl, }; - elf_step.dependOn(testLinkingZigStatic(b, .{ .target = target, .use_llvm = true })); - elf_step.dependOn(testLinkingZigStatic(b, .{ .target = target, .use_llvm = false })); - elf_step.dependOn(testLinkingCStatic(b, .{ .target = target, .use_llvm = true })); - // elf_step.dependOn(testLinkingCStatic(b, .{ .target = target, .use_llvm = false })); // TODO arocc + elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = true })); + elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false })); + elf_step.dependOn(testLinkingC(b, .{ .target = musl_target, .use_llvm = true })); + // elf_step.dependOn(testLinkingC(b, .{ .target = musl_target, .use_llvm = false })); // TODO arocc } -fn testLinkingZigStatic(b: *Build, opts: Options) *Step { +fn testLinkingZig(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "linking-zig-static", opts); const exe = addExecutable(b, opts); @@ -26,7 +27,6 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step { \\ @import("std").debug.print("Hello World!\n", .{}); \\} ); - exe.linkage = .static; const run = b.addRunArtifact(exe); run.expectStdErrEqual("Hello World!\n"); @@ -44,7 +44,7 @@ fn testLinkingZigStatic(b: *Build, opts: Options) *Step { return test_step; } -fn testLinkingCStatic(b: *Build, opts: Options) *Step { +fn testLinkingC(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "linking-c-static", opts); const exe = addExecutable(b, opts); @@ -56,7 +56,6 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step { \\} ); exe.is_linking_libc = true; - exe.linkage = .static; const run = b.addRunArtifact(exe); run.expectStdOutEqual("Hello World!\n"); @@ -75,7 +74,7 @@ fn testLinkingCStatic(b: *Build, opts: Options) *Step { } const Options = struct { - target: CrossTarget = .{ .os_tag = .linux }, + target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux }, optimize: std.builtin.OptimizeMode = .Debug, use_llvm: bool = true, };