diff --git a/src/Compilation.zig b/src/Compilation.zig index 2859090edc..cedbf5024f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -76,6 +76,7 @@ framework_dirs: []const []const u8, system_libs: std.StringArrayHashMapUnmanaged(SystemLib), version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, +skip_linker_dependencies: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -940,7 +941,7 @@ pub const InitOptions = struct { /// * getpid /// * mman /// * signal - wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{}, + wasi_emulated_libs: []const wasi_libc.CRTFile = &.{}, /// This means that if the output mode is an executable it will be a /// Position Independent Executable. If the output mode is not an /// executable this field is ignored. @@ -1238,7 +1239,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const sysroot = options.sysroot orelse libc_dirs.sysroot; const include_compiler_rt = options.want_compiler_rt orelse - (!options.skip_linker_dependencies and is_exe_or_dyn_lib); + (!comp.skip_linker_dependencies and is_exe_or_dyn_lib); if (include_compiler_rt and output_mode == .Obj) { // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");` @@ -1639,6 +1640,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .objects = options.link_objects, .framework_dirs = options.framework_dirs, .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, + .skip_linker_dependencies = options.skip_linker_dependencies, }; if (bin_file_emit) |emit| { @@ -1695,7 +1697,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .soname = options.soname, .compatibility_version = options.compatibility_version, .dll_export_fns = dll_export_fns, - .skip_linker_dependencies = options.skip_linker_dependencies, .parent_compilation_link_libc = options.parent_compilation_link_libc, .each_lib_rpath = each_lib_rpath, .build_id = build_id, @@ -1765,9 +1766,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; + const have_bin_emit = comp.bin_file != null or comp.whole_bin_sub_path != null; - if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) { + if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) { if (target.isDarwin()) { switch (target.abi) { .none, @@ -1808,27 +1809,34 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .{ .musl_crt_file = .crt1_o }, .{ .musl_crt_file = .scrt1_o }, .{ .musl_crt_file = .rcrt1_o }, - switch (comp.bin_file.options.link_mode) { + switch (comp.config.link_mode) { .Static => .{ .musl_crt_file = .libc_a }, .Dynamic => .{ .musl_crt_file = .libc_so }, }, }); } - if (comp.wantBuildWasiLibcFromSource()) { - if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; - const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; - try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components - for (wasi_emulated_libs) |crt_file| { - comp.work_queue.writeItemAssumeCapacity(.{ - .wasi_libc_crt_file = crt_file, - }); + if (comp.bin_file) |lf| { + if (lf.cast(link.File.Wasm)) |wasm| { + if (comp.wantBuildWasiLibcFromSource()) { + if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; + + // worst-case we need all components + try comp.work_queue.ensureUnusedCapacity(wasm.wasi_emulated_libs.len + 2); + + for (wasm.wasi_emulated_libs) |crt_file| { + comp.work_queue.writeItemAssumeCapacity(.{ + .wasi_libc_crt_file = crt_file, + }); + } + comp.work_queue.writeAssumeCapacity(&[_]Job{ + .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) }, + .{ .wasi_libc_crt_file = .libc_a }, + }); + } } - comp.work_queue.writeAssumeCapacity(&[_]Job{ - .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) }, - .{ .wasi_libc_crt_file = .libc_a }, - }); } + if (comp.wantBuildMinGWFromSource()) { if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; @@ -1863,27 +1871,29 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (comp.wantBuildLibUnwindFromSource()) { try comp.work_queue.writeItem(.{ .libunwind = {} }); } - if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) { + if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { try comp.work_queue.writeItem(.libcxx); try comp.work_queue.writeItem(.libcxxabi); } - if (build_options.have_llvm and comp.bin_file.options.tsan) { + if (build_options.have_llvm and comp.config.any_sanitize_thread) { try comp.work_queue.writeItem(.libtsan); } - if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) { - // LLD might drop some symbols as unused during LTO and GCing, therefore, - // we force mark them for resolution here. + if (comp.bin_file) |lf| { + if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) { + // LLD might drop some symbols as unused during LTO and GCing, therefore, + // we force mark them for resolution here. - const tls_index_sym = switch (comp.getTarget().cpu.arch) { - .x86 => "__tls_index", - else => "_tls_index", - }; + const tls_index_sym = switch (comp.getTarget().cpu.arch) { + .x86 => "__tls_index", + else => "_tls_index", + }; - try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); + try lf.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); + } } - if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { + if (comp.include_compiler_rt and capable_of_building_compiler_rt) { if (is_exe_or_dyn_lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); comp.job_queued_compiler_rt_lib = true; @@ -1895,8 +1905,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - if (!comp.bin_file.options.skip_linker_dependencies and is_exe_or_dyn_lib and - !comp.bin_file.options.link_libc and capable_of_building_zig_libc) + if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and + !comp.config.link_libc and capable_of_building_zig_libc) { try comp.work_queue.writeItem(.{ .zig_libc = {} }); } @@ -2425,7 +2435,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.test_evented_io); man.hash.addOptionalBytes(comp.test_filter); man.hash.addOptionalBytes(comp.test_name_prefix); - man.hash.add(comp.bin_file.options.skip_linker_dependencies); + man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.formatted_panics); man.hash.add(mod.emit_h != null); man.hash.add(mod.error_limit); @@ -2477,7 +2487,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); man.hash.add(comp.bin_file.options.each_lib_rpath); man.hash.add(comp.bin_file.build_id); - man.hash.add(comp.bin_file.options.skip_linker_dependencies); + man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.bin_file.options.z_nodelete); man.hash.add(comp.bin_file.options.z_notext); man.hash.add(comp.bin_file.options.z_defs); @@ -2489,7 +2499,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.bin_file.options.z_max_page_size orelse 0); man.hash.add(comp.bin_file.options.hash_style); man.hash.add(comp.bin_file.options.compress_debug_sections); - man.hash.add(comp.bin_file.options.include_compiler_rt); + man.hash.add(comp.include_compiler_rt); man.hash.add(comp.bin_file.options.sort_section); if (comp.config.link_libc) { man.hash.add(comp.bin_file.options.libc_installation != null); @@ -3836,7 +3846,7 @@ pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { // Also nothing that applies only to compiling .zig code. man.hash.add(comp.sanitize_c); man.hash.addListOfBytes(comp.clang_argv); - man.hash.add(comp.bin_file.options.link_libcpp); + man.hash.add(comp.config.link_libcpp); // When libc_installation is null it means that Zig generated this dir list // based on the zig library directory alone. The zig lib directory file @@ -4909,7 +4919,7 @@ pub fn addCCArgs( try argv.append("-fno-builtin"); } - if (comp.bin_file.options.link_libcpp) { + if (comp.config.link_libcpp) { const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "libcxx", "include", }); @@ -4954,7 +4964,7 @@ pub fn addCCArgs( try argv.append(libunwind_include_path); } - if (comp.bin_file.options.link_libc and target.isGnuLibC()) { + if (comp.config.link_libc and target.isGnuLibC()) { const target_version = target.os.version_range.linux.glibc; const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ target_version.minor, @@ -5944,7 +5954,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { .Lib => comp.bin_file.options.link_mode == .Dynamic, .Exe => true, }; - return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and + return comp.config.link_libc and is_exe_or_dyn_lib and comp.bin_file.options.libc_installation == null and comp.bin_file.options.target.ofmt != .c; } @@ -6164,6 +6174,7 @@ fn buildOutputFromZig( .have_zcu = true, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .link_libc = comp.config.link_libc, }); const root_mod = Package.Module.create(.{ @@ -6224,7 +6235,6 @@ fn buildOutputFromZig( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .link_libc = comp.bin_file.options.link_libc, .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6305,7 +6315,6 @@ pub fn build_crt_file( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .link_libc = comp.bin_file.options.link_libc, .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6327,7 +6336,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { // This can happen when the user uses `build-exe foo.obj -lkernel32` and // then when we create a sub-Compilation for zig libc, it also tries to // build kernel32.lib. - if (comp.bin_file.options.skip_linker_dependencies) return; + if (comp.skip_linker_dependencies) return; // This happens when an `extern "foo"` function is referenced. // If we haven't seen this library yet and we're targeting Windows, we need diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0e379212cc..aba21e4bfe 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -335,7 +335,7 @@ pub fn resolve(options: Options) !Config { break :b .Static; }; - const import_memory = options.import_memory orelse false; + const import_memory = options.import_memory orelse (options.output_mode == .Obj); const export_memory = b: { if (link_mode == .Dynamic) { if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible; diff --git a/src/Sema.zig b/src/Sema.zig index 9d1f65584e..910b1cca47 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5742,7 +5742,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); errdefer msg.destroy(gpa); - if (!comp.bin_file.options.link_libc) + if (!comp.config.link_libc) try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); const gop = try mod.cimport_errors.getOrPut(gpa, sema.owner_decl_index); @@ -9058,7 +9058,7 @@ fn resolveGenericBody( /// Given a library name, examines if the library name should end up in /// `link.File.Options.system_libs` table (for example, libc is always -/// specified via dedicated flag `link.File.Options.link_libc` instead), +/// specified via dedicated flag `link_libc` instead), /// and puts it there if it doesn't exist. /// It also dupes the library name which can then be saved as part of the /// respective `Decl` (either `ExternFn` or `Var`). @@ -9076,7 +9076,7 @@ fn handleExternLibName( const target = mod.getTarget(); log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); if (target.is_libc_lib_name(lib_name)) { - if (!comp.bin_file.options.link_libc) { + if (!comp.config.link_libc) { return sema.fail( block, src_loc, @@ -9087,18 +9087,21 @@ fn handleExternLibName( break :blk; } if (target.is_libcpp_lib_name(lib_name)) { - if (!comp.bin_file.options.link_libcpp) { - return sema.fail( - block, - src_loc, - "dependency on libc++ must be explicitly specified in the build command", - .{}, - ); - } + if (!comp.config.link_libcpp) return sema.fail( + block, + src_loc, + "dependency on libc++ must be explicitly specified in the build command", + .{}, + ); break :blk; } if (mem.eql(u8, lib_name, "unwind")) { - comp.bin_file.options.link_libunwind = true; + if (!comp.config.link_libunwind) return sema.fail( + block, + src_loc, + "dependency on libunwind must be explicitly specified in the build command", + .{}, + ); break :blk; } if (!target.isWasm() and !comp.bin_file.options.pic) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a072c6a069..522da0f8c9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3083,9 +3083,7 @@ pub const Object = struct { if (comp.unwind_tables) { try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); } - if (comp.bin_file.options.skip_linker_dependencies or - comp.bin_file.options.no_builtin) - { + if (comp.skip_linker_dependencies or comp.bin_file.options.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate // infinite recursion. For example, if we are compiling the memcpy function, // and llvm detects that the body is equivalent to memcpy, it may replace the diff --git a/src/libtsan.zig b/src/libtsan.zig index 2489eb21af..d0af65e4c6 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -119,7 +119,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { }); } - const to_c_or_not_to_c_sources = if (comp.bin_file.options.link_libc) + const to_c_or_not_to_c_sources = if (comp.config.link_libc) &sanitizer_libcdep_sources else &sanitizer_nolibc_sources; diff --git a/src/link.zig b/src/link.zig index 95a3282186..612c05f82b 100644 --- a/src/link.zig +++ b/src/link.zig @@ -133,7 +133,6 @@ pub const File = struct { export_symbol_names: []const []const u8, global_base: ?u64, dll_export_fns: bool, - skip_linker_dependencies: bool, parent_compilation_link_libc: bool, each_lib_rpath: bool, build_id: std.zig.BuildId, @@ -1099,7 +1098,7 @@ pub const File = struct { } pub fn isStatic(self: File) bool { - return self.base.comp.config.link_mode == .Static; + return self.comp.config.link_mode == .Static; } pub fn isObject(self: File) bool { diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index a321d28fb3..1719d5fa67 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -48,7 +48,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const is_lib = self.base.comp.config.output_mode == .Lib; const is_dyn_lib = self.base.comp.config.link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or self.base.comp.config.output_mode == .Exe; - const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib; + const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib; const target = self.base.comp.root_mod.resolved_target.result; const optimize_mode = self.base.comp.root_mod.optimize_mode; @@ -56,17 +56,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; - defer if (!self.base.options.disable_lld_caching) man.deinit(); + defer if (!self.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { man = comp.cache_parent.obtain(); self.base.releaseLock(); comptime assert(Compilation.link_hash_implementation_version == 10); - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -79,12 +79,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } try man.addOptionalFile(module_obj_path); - man.hash.addOptionalBytes(self.base.options.entry); + man.hash.addOptionalBytes(comp.config.entry); man.hash.add(self.base.stack_size); man.hash.addOptional(self.image_base); - man.hash.addListOfBytes(self.base.options.lib_dirs); - man.hash.add(self.base.options.skip_linker_dependencies); - if (self.base.options.link_libc) { + man.hash.addListOfBytes(self.lib_dirs); + man.hash.add(comp.skip_linker_dependencies); + if (comp.config.link_libc) { man.hash.add(self.base.comp.libc_installation != null); if (self.base.comp.libc_installation) |libc_installation| { man.hash.addBytes(libc_installation.crt_dir.?); @@ -95,18 +95,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } try link.hashAddSystemLibs(&man, self.base.comp.system_libs); - man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); - man.hash.addOptional(self.base.options.subsystem); - man.hash.add(self.base.options.is_test); - man.hash.add(self.base.options.tsaware); - man.hash.add(self.base.options.nxcompat); - man.hash.add(self.base.options.dynamicbase); + man.hash.addListOfBytes(self.base.force_undefined_symbols.keys()); + man.hash.addOptional(self.subsystem); + man.hash.add(comp.config.is_test); + man.hash.add(self.tsaware); + man.hash.add(self.nxcompat); + man.hash.add(self.dynamicbase); man.hash.addOptional(self.base.allow_shlib_undefined); // strip does not need to go into the linker hash because it is part of the hash namespace - man.hash.addOptional(self.base.options.major_subsystem_version); - man.hash.addOptional(self.base.options.minor_subsystem_version); - man.hash.addOptional(self.base.options.version); - try man.addOptionalFile(self.base.options.module_definition_file); + man.hash.addOptional(self.major_subsystem_version); + man.hash.addOptional(self.minor_subsystem_version); + man.hash.addOptional(comp.version); + try man.addOptionalFile(self.module_definition_file); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -141,8 +141,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -171,21 +171,21 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-ERRORLIMIT:0"); try argv.append("-NOLOGO"); - if (!self.base.options.strip) { + if (self.base.debug_format != .strip) { try argv.append("-DEBUG"); const out_ext = std.fs.path.extension(full_out_path); - const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ + const out_pdb = self.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ full_out_path[0 .. full_out_path.len - out_ext.len], }); try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb})); } - if (self.base.options.version) |version| { + if (comp.version) |version| { try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); } - if (self.base.options.lto) { + if (comp.config.lto) { switch (optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-OPT:lldlto=2"), @@ -209,7 +209,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - for (self.base.options.force_undefined_symbols.keys()) |symbol| { + for (self.base.force_undefined_symbols.keys()) |symbol| { try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); } @@ -217,17 +217,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-DLL"); } - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry})); } - if (self.base.options.tsaware) { + if (self.tsaware) { try argv.append("-tsaware"); } - if (self.base.options.nxcompat) { + if (self.nxcompat) { try argv.append("-nxcompat"); } - if (!self.base.options.dynamicbase) { + if (!self.dynamicbase) { try argv.append("-dynamicbase:NO"); } if (self.base.allow_shlib_undefined) { @@ -236,12 +236,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); - if (self.base.options.implib_emit) |emit| { + if (self.implib_emit) |emit| { const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path}); try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); @@ -252,12 +252,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir})); } - try argv.ensureUnusedCapacity(self.base.options.objects.len); - for (self.base.options.objects) |obj| { + try argv.ensureUnusedCapacity(comp.objects.len); + for (comp.objects) |obj| { if (obj.must_link) { argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path})); } else { @@ -279,18 +279,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(p); } - if (self.base.options.module_definition_file) |def| { + if (self.module_definition_file) |def| { try argv.append(try allocPrint(arena, "-DEF:{s}", .{def})); } const resolved_subsystem: ?std.Target.SubSystem = blk: { - if (self.base.options.subsystem) |explicit| break :blk explicit; + if (self.subsystem) |explicit| break :blk explicit; switch (target.os.tag) { .windows => { if (self.base.comp.module) |module| { if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib) break :blk null; - if (module.stage1_flags.have_c_main or self.base.options.is_test or + if (module.stage1_flags.have_c_main or comp.config.is_test or module.stage1_flags.have_winmain_crt_startup or module.stage1_flags.have_wwinmain_crt_startup) { @@ -310,8 +310,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const mode: Mode = mode: { if (resolved_subsystem) |subsystem| { const subsystem_suffix = ss: { - if (self.base.options.major_subsystem_version) |major| { - if (self.base.options.minor_subsystem_version) |minor| { + if (self.major_subsystem_version) |major| { + if (self.minor_subsystem_version) |minor| { break :ss try allocPrint(arena, ",{d}.{d}", .{ major, minor }); } else { break :ss try allocPrint(arena, ",{d}", .{major}); @@ -447,7 +447,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } else { try argv.append("-NODEFAULTLIB"); - if (!is_lib and self.base.options.entry == null) { + if (!is_lib and comp.config.entry == null) { if (self.base.comp.module) |module| { if (module.stage1_flags.have_winmain_crt_startup) { try argv.append("-ENTRY:WinMainCRTStartup"); @@ -463,18 +463,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } - if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) { - if (!self.base.options.link_libc) { + if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { + if (!comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); } @@ -492,13 +492,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod argv.appendAssumeCapacity(crt_file.full_object_path); continue; } - if (try findLib(arena, lib_basename, self.base.options.lib_dirs)) |full_path| { + if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| { argv.appendAssumeCapacity(full_path); continue; } if (target.abi.isGnu()) { const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key}); - if (try findLib(arena, fallback_name, self.base.options.lib_dirs)) |full_path| { + if (try findLib(arena, fallback_name, self.lib_dirs)) |full_path| { argv.appendAssumeCapacity(full_path); continue; } @@ -582,7 +582,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index ef803a45f1..5bd65b2227 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1022,16 +1022,18 @@ const min_nop_size = 2; /// actual_capacity + (actual_capacity / ideal_factor) const ideal_factor = 3; -pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf { - const target = &bin_file.options.target; +pub fn init(lf: *File, format: Format) Dwarf { + const comp = lf.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, else => unreachable, }; return .{ - .allocator = allocator, - .bin_file = bin_file, + .allocator = gpa, + .bin_file = lf, .format = format, .ptr_width = ptr_width, .dbg_line_header = switch (target.cpu.arch) { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index df83878494..a116c46d2f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,5 +1,6 @@ base: link.File, image_base: u64, +rdynamic: bool, ptr_width: PtrWidth, @@ -358,19 +359,21 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, .function_sections = options.function_sections, .data_sections = options.data_sections, - - .image_base = b: { - if (is_dyn_lib) break :b 0; - if (output_mode == .Exe and comp.config.pie) return 0; - return options.image_base orelse switch (ptr_width) { - .p32 => 0x1000, - .p64 => 0x1000000, - }; - }, }, .ptr_width = ptr_width, .page_size = page_size, .default_sym_version = default_sym_version, + + .image_base = b: { + if (is_dyn_lib) break :b 0; + if (output_mode == .Exe and comp.config.pie) break :b 0; + break :b options.image_base orelse switch (ptr_width) { + .p32 => 0x1000, + .p64 => 0x1000000, + }; + }, + + .rdynamic = options.rdynamic, }; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); @@ -1006,7 +1009,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node break :blk path; } } else null; - const gc_sections = self.base.gc_sections; // --verbose-link if (self.base.comp.verbose_link) try self.dumpArgv(comp); @@ -1047,14 +1049,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node var rpath_table = std.StringArrayHashMap(void).init(gpa); defer rpath_table.deinit(); - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { _ = try rpath_table.put(rpath, {}); } - if (self.base.options.each_lib_rpath) { + if (self.each_lib_rpath) { var test_path = std.ArrayList(u8).init(gpa); defer test_path.deinit(); - for (self.base.options.lib_dirs) |lib_dir_path| { + for (self.lib_dirs) |lib_dir_path| { for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; @@ -1076,9 +1078,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } // libc - if (!self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) - { + if (!comp.skip_linker_dependencies and !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try positionals.append(.{ .path = lib.full_object_path }); } @@ -1263,10 +1263,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.entry_index = if (entry) |name| self.globalByName(name) else null; } - if (gc_sections) { + if (self.base.gc_sections) { try gc.gcAtoms(self); - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try gc.dumpPrunedAtoms(self); } } @@ -1347,13 +1347,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { - const gpa = self.base.comp.gpa; + const gpa = comp.gpa; var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); - try positionals.ensureUnusedCapacity(self.base.options.objects.len); - positionals.appendSliceAssumeCapacity(self.base.options.objects); + try positionals.ensureUnusedCapacity(comp.objects.len); + positionals.appendSliceAssumeCapacity(comp.objects); // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up @@ -1495,8 +1495,8 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); - try positionals.ensureUnusedCapacity(self.base.options.objects.len); - positionals.appendSliceAssumeCapacity(self.base.options.objects); + try positionals.ensureUnusedCapacity(comp.objects.len); + positionals.appendSliceAssumeCapacity(comp.objects); // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up @@ -1606,7 +1606,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append(full_out_path); if (self.base.isRelocatable()) { - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { try argv.append(obj.path); } @@ -1626,28 +1626,28 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } if (self.base.isDynLib()) { - if (self.base.options.soname) |name| { + if (self.soname) |name| { try argv.append("-soname"); try argv.append(name); } } - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } - if (self.base.options.each_lib_rpath) { - for (self.base.options.lib_dirs) |lib_dir_path| { + if (self.each_lib_rpath) { + for (self.lib_dirs) |lib_dir_path| { try argv.append("-rpath"); try argv.append(lib_dir_path); } - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (Compilation.classifyFileExt(obj.path) == .shared_library) { const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; if (obj.loption) continue; @@ -1669,29 +1669,29 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("--gc-sections"); } - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try argv.append("--print-gc-sections"); } - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } - if (self.base.options.rdynamic) { + if (self.rdynamic) { try argv.append("--export-dynamic"); } - if (self.base.options.z_notext) { + if (self.z_notext) { try argv.append("-z"); try argv.append("notext"); } - if (self.base.options.z_nocopyreloc) { + if (self.z_nocopyreloc) { try argv.append("-z"); try argv.append("nocopyreloc"); } - if (self.base.options.z_now) { + if (self.z_now) { try argv.append("-z"); try argv.append("now"); } @@ -1702,11 +1702,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("-shared"); } - if (self.base.options.pie and self.base.isExe()) { + if (comp.config.pie and self.base.isExe()) { try argv.append("-pie"); } - if (self.base.options.strip) { + if (self.base.debug_format == .strip) { try argv.append("-s"); } @@ -1715,12 +1715,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { if (csu.crti) |v| try argv.append(v); if (csu.crtbegin) |v| try argv.append(v); - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append("-L"); try argv.append(lib_dir); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append("-L"); try argv.append(libc_installation.crt_dir.?); @@ -1728,7 +1728,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } var whole_archive = false; - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -1756,15 +1756,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append(p); } - // TSAN - if (self.base.options.tsan) { + if (comp.config.any_sanitize_thread) { try argv.append(comp.tsan_static_lib.?.full_object_path); } // libc - if (!self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) - { + if (!comp.skip_linker_dependencies and !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); } @@ -1799,18 +1796,18 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } // libc dep - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation != null) { const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); @@ -1963,8 +1960,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { defer script.deinit(gpa); try script.parse(data, self); - const lib_dirs = self.base.options.lib_dirs; - var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); @@ -1981,7 +1976,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { // TODO I think technically we should re-use the mechanism used by the frontend here. // Maybe we should hoist search-strategy all the way here? - for (lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { if (!self.isStatic()) { if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic)) break :success; @@ -1998,7 +1993,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { } else |_| {} try checked_paths.append(try gpa.dupe(u8, scr_obj.path)); - for (lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, scr_obj.path, null)) break :success; } @@ -2338,7 +2333,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const link_mode = self.base.comp.config.link_mode; const is_dyn_lib = link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; - const have_dynamic_linker = self.base.options.link_libc and + const have_dynamic_linker = comp.config.link_libc and link_mode == .Dynamic and is_exe_or_dyn_lib; const target = self.base.comp.root_mod.resolved_target.result; const compiler_rt_path: ?[]const u8 = blk: { @@ -2358,11 +2353,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; - defer if (!self.base.options.disable_lld_caching) man.deinit(); + defer if (!self.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. @@ -2370,9 +2365,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v comptime assert(Compilation.link_hash_implementation_version == 10); - try man.addOptionalFile(self.base.options.linker_script); - try man.addOptionalFile(self.base.options.version_script); - for (self.base.options.objects) |obj| { + try man.addOptionalFile(self.linker_script); + try man.addOptionalFile(self.version_script); + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); man.hash.add(obj.loption); @@ -2385,34 +2380,34 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. - man.hash.addOptionalBytes(self.base.options.entry); + man.hash.addOptionalBytes(comp.config.entry); man.hash.addOptional(self.image_base); man.hash.add(self.base.gc_sections); - man.hash.addOptional(self.base.options.sort_section); - man.hash.add(self.base.options.eh_frame_hdr); - man.hash.add(self.base.options.emit_relocs); - man.hash.add(self.base.options.rdynamic); - man.hash.addListOfBytes(self.base.options.lib_dirs); - man.hash.addListOfBytes(self.base.options.rpath_list); - man.hash.add(self.base.options.each_lib_rpath); + man.hash.addOptional(self.sort_section); + man.hash.add(self.eh_frame_hdr); + man.hash.add(self.emit_relocs); + man.hash.add(self.rdynamic); + man.hash.addListOfBytes(self.lib_dirs); + man.hash.addListOfBytes(self.base.rpath_list); + man.hash.add(self.each_lib_rpath); if (output_mode == .Exe) { man.hash.add(self.base.stack_size); man.hash.add(self.base.build_id); } - man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); - man.hash.add(self.base.options.skip_linker_dependencies); - man.hash.add(self.base.options.z_nodelete); - man.hash.add(self.base.options.z_notext); - man.hash.add(self.base.options.z_defs); - man.hash.add(self.base.options.z_origin); - man.hash.add(self.base.options.z_nocopyreloc); - man.hash.add(self.base.options.z_now); - man.hash.add(self.base.options.z_relro); - man.hash.add(self.base.options.z_common_page_size orelse 0); - man.hash.add(self.base.options.z_max_page_size orelse 0); - man.hash.add(self.base.options.hash_style); + man.hash.addListOfBytes(self.symbol_wrap_set.keys()); + man.hash.add(comp.skip_linker_dependencies); + man.hash.add(self.z_nodelete); + man.hash.add(self.z_notext); + man.hash.add(self.z_defs); + man.hash.add(self.z_origin); + man.hash.add(self.z_nocopyreloc); + man.hash.add(self.z_now); + man.hash.add(self.z_relro); + man.hash.add(self.z_common_page_size orelse 0); + man.hash.add(self.z_max_page_size orelse 0); + man.hash.add(self.hash_style); // strip does not need to go into the linker hash because it is part of the hash namespace - if (self.base.options.link_libc) { + if (comp.config.link_libc) { man.hash.add(self.base.comp.libc_installation != null); if (self.base.comp.libc_installation) |libc_installation| { man.hash.addBytes(libc_installation.crt_dir.?); @@ -2421,16 +2416,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.addOptionalBytes(target.dynamic_linker.get()); } } - man.hash.addOptionalBytes(self.base.options.soname); - man.hash.addOptional(self.base.options.version); + man.hash.addOptionalBytes(self.soname); + man.hash.addOptional(comp.version); try link.hashAddSystemLibs(&man, self.base.comp.system_libs); - man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); + man.hash.addListOfBytes(self.base.force_undefined_symbols.keys()); man.hash.add(self.base.allow_shlib_undefined); - man.hash.add(self.base.options.bind_global_refs_locally); - man.hash.add(self.base.options.compress_debug_sections); - man.hash.add(self.base.options.tsan); - man.hash.addOptionalBytes(self.base.options.sysroot); - man.hash.add(self.base.options.linker_optimization); + man.hash.add(self.bind_global_refs_locally); + man.hash.add(self.compress_debug_sections); + man.hash.add(comp.config.any_sanitize_thread); + man.hash.addOptionalBytes(self.sysroot); + man.hash.add(self.optimization); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -2466,14 +2461,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails // before even generating the relocatable. if (output_mode == .Obj and - (self.base.options.lto or target.isBpfFreestanding())) + (comp.config.lto or target.isBpfFreestanding())) { // In this case we must do a simple file copy // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -2505,32 +2500,32 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--error-limit=0"); - if (self.base.options.sysroot) |sysroot| { + if (self.sysroot) |sysroot| { try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } - if (self.base.options.lto) { - switch (self.base.options.optimize_mode) { + if (comp.config.lto) { + switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("--lto-O2"), .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), } } try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{ - self.base.options.linker_optimization, + self.optimization, })); - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } - for (self.base.options.force_undefined_symbols.keys()) |sym| { + for (self.base.force_undefined_symbols.keys()) |sym| { try argv.append("-u"); try argv.append(sym); } - switch (self.base.options.hash_style) { + switch (self.hash_style) { .gnu => try argv.append("--hash-style=gnu"), .sysv => try argv.append("--hash-style=sysv"), .both => {}, // this is the default @@ -2559,12 +2554,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base})); - if (self.base.options.linker_script) |linker_script| { + if (self.linker_script) |linker_script| { try argv.append("-T"); try argv.append(linker_script); } - if (self.base.options.sort_section) |how| { + if (self.sort_section) |how| { const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)}); try argv.append(arg); } @@ -2573,67 +2568,67 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--gc-sections"); } - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try argv.append("--print-gc-sections"); } - if (self.base.options.print_icf_sections) { + if (self.print_icf_sections) { try argv.append("--print-icf-sections"); } - if (self.base.options.print_map) { + if (self.print_map) { try argv.append("--print-map"); } - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } - if (self.base.options.emit_relocs) { + if (self.emit_relocs) { try argv.append("--emit-relocs"); } - if (self.base.options.rdynamic) { + if (self.rdynamic) { try argv.append("--export-dynamic"); } - if (self.base.options.strip) { + if (self.base.debug_format == .strip) { try argv.append("-s"); } - if (self.base.options.z_nodelete) { + if (self.z_nodelete) { try argv.append("-z"); try argv.append("nodelete"); } - if (self.base.options.z_notext) { + if (self.z_notext) { try argv.append("-z"); try argv.append("notext"); } - if (self.base.options.z_defs) { + if (self.z_defs) { try argv.append("-z"); try argv.append("defs"); } - if (self.base.options.z_origin) { + if (self.z_origin) { try argv.append("-z"); try argv.append("origin"); } - if (self.base.options.z_nocopyreloc) { + if (self.z_nocopyreloc) { try argv.append("-z"); try argv.append("nocopyreloc"); } - if (self.base.options.z_now) { + if (self.z_now) { // LLD defaults to -zlazy try argv.append("-znow"); } - if (!self.base.options.z_relro) { + if (!self.z_relro) { // LLD defaults to -zrelro try argv.append("-znorelro"); } - if (self.base.options.z_common_page_size) |size| { + if (self.z_common_page_size) |size| { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size})); } - if (self.base.options.z_max_page_size) |size| { + if (self.z_max_page_size) |size| { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size})); } @@ -2658,7 +2653,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-shared"); } - if (self.base.options.pie and output_mode == .Exe) { + if (comp.config.pie and output_mode == .Exe) { try argv.append("-pie"); } @@ -2683,20 +2678,20 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // rpaths var rpath_table = std.StringHashMap(void).init(gpa); defer rpath_table.deinit(); - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { if ((try rpath_table.fetchPut(rpath, {})) == null) { try argv.append("-rpath"); try argv.append(rpath); } } - for (self.base.options.symbol_wrap_set.keys()) |symbol_name| { + for (self.symbol_wrap_set.keys()) |symbol_name| { try argv.appendSlice(&.{ "-wrap", symbol_name }); } - if (self.base.options.each_lib_rpath) { + if (self.each_lib_rpath) { var test_path = std.ArrayList(u8).init(arena); - for (self.base.options.lib_dirs) |lib_dir_path| { + for (self.lib_dirs) |lib_dir_path| { for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; @@ -2706,7 +2701,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } } - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (Compilation.classifyFileExt(obj.path) == .shared_library) { const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; if (obj.loption) continue; @@ -2719,12 +2714,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append("-L"); try argv.append(lib_dir); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append("-L"); try argv.append(libc_installation.crt_dir.?); @@ -2739,11 +2734,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } if (is_dyn_lib) { - if (self.base.options.soname) |soname| { + if (self.soname) |soname| { try argv.append("-soname"); try argv.append(soname); } - if (self.base.options.version_script) |version_script| { + if (self.version_script) |version_script| { try argv.append("-version-script"); try argv.append(version_script); } @@ -2751,7 +2746,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // Positional arguments to the linker such as object files. var whole_archive = false; - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -2779,15 +2774,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(p); } - // TSAN - if (self.base.options.tsan) { + if (comp.config.any_sanitize_thread) { try argv.append(comp.tsan_static_lib.?.full_object_path); } // libc if (is_exe_or_dyn_lib and - !self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) + !comp.skip_linker_dependencies and + !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); @@ -2832,19 +2826,19 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } // libc dep self.error_flags.missing_libc = false; - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation != null) { const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); @@ -2884,13 +2878,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--allow-shlib-undefined"); } - switch (self.base.options.compress_debug_sections) { + switch (self.compress_debug_sections) { .none => {}, .zlib => try argv.append("--compress-debug-sections=zlib"), .zstd => try argv.append("--compress-debug-sections=zstd"), } - if (self.base.options.bind_global_refs_locally) { + if (self.bind_global_refs_locally) { try argv.append("-Bsymbolic"); } @@ -2964,7 +2958,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { @@ -3101,7 +3095,8 @@ fn writeElfHeader(self: *Elf) !void { }; index += 1; - const target = self.base.comp.root_mod.resolved_target.result; + const comp = self.base.comp; + const target = comp.root_mod.resolved_target.result; const endian = target.cpu.arch.endian(); hdr_buf[index] = switch (endian) { .little => elf.ELFDATA2LSB, @@ -3120,10 +3115,10 @@ fn writeElfHeader(self: *Elf) !void { assert(index == 16); - const output_mode = self.base.comp.config.output_mode; - const link_mode = self.base.comp.config.link_mode; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; const elf_type: elf.ET = switch (output_mode) { - .Exe => if (self.base.options.pie) .DYN else .EXEC, + .Exe => if (comp.config.pie) .DYN else .EXEC, .Obj => .REL, .Lib => switch (link_mode) { .Static => @as(elf.ET, .REL), @@ -3283,7 +3278,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { self.plt_index = try linker_defined.addGlobal("_PROCEDURE_LINKAGE_TABLE_", self); self.end_index = try linker_defined.addGlobal("_end", self); - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { self.gnu_eh_frame_hdr_index = try linker_defined.addGlobal("__GNU_EH_FRAME_HDR", self); } @@ -3314,7 +3309,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { } fn allocateLinkerDefinedSymbols(self: *Elf) void { - const link_mode = self.base.comp.config.link_mode; + const comp = self.base.comp; + const link_mode = comp.config.link_mode; // _DYNAMIC if (self.dynamic_section_index) |shndx| { @@ -3398,7 +3394,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { // __rela_iplt_start, __rela_iplt_end if (self.rela_dyn_section_index) |shndx| blk: { - if (link_mode != .Static or self.base.options.pie) break :blk; + if (link_mode != .Static or comp.config.pie) break :blk; const shdr = &self.shdrs.items[shndx]; const end_addr = shdr.sh_addr + shdr.sh_size; const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); @@ -3445,7 +3441,8 @@ fn initOutputSections(self: *Elf) !void { } fn initSyntheticSections(self: *Elf) !void { - const target = self.base.comp.root_mod.resolved_target.result; + const comp = self.base.comp; + const target = comp.root_mod.resolved_target.result; const ptr_size = self.ptrWidthBytes(); const needs_eh_frame = for (self.objects.items) |index| { @@ -3460,7 +3457,7 @@ fn initSyntheticSections(self: *Elf) !void { .offset = std.math.maxInt(u64), }); - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { self.eh_frame_hdr_section_index = try self.addSection(.{ .name = ".eh_frame_hdr", .type = elf.SHT_PROGBITS, @@ -3554,7 +3551,7 @@ fn initSyntheticSections(self: *Elf) !void { // In this case, if we do generate .interp section and segment, we will get // a segfault in the dynamic linker trying to load a binary that is static // and doesn't contain .dynamic section. - if (self.isStatic() and !self.base.options.pie) break :blk false; + if (self.isStatic() and !comp.config.pie) break :blk false; break :blk target.dynamic_linker.get() != null; }; if (needs_interp) { @@ -3567,7 +3564,7 @@ fn initSyntheticSections(self: *Elf) !void { }); } - if (self.base.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) { + if (self.base.isDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) { self.dynstrtab_section_index = try self.addSection(.{ .name = ".dynstr", .flags = elf.SHF_ALLOC, @@ -3859,7 +3856,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { } if (self.base.isDynLib()) { - if (self.base.options.soname) |soname| { + if (self.soname) |soname| { try self.dynamic.setSoname(soname, self); } } diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index b3d7b51d3e..dc330fa54b 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -543,7 +543,7 @@ fn scanReloc( try self.reportPicError(symbol, rel, elf_file), .copyrel => { - if (elf_file.base.options.z_nocopyreloc) { + if (elf_file.z_nocopyreloc) { if (symbol.isAbs(elf_file)) try self.reportNoPicError(symbol, rel, elf_file) else @@ -553,9 +553,9 @@ fn scanReloc( }, .dyn_copyrel => { - if (is_writeable or elf_file.base.options.z_nocopyreloc) { + if (is_writeable or elf_file.z_nocopyreloc) { if (!is_writeable) { - if (elf_file.base.options.z_notext) { + if (elf_file.z_notext) { elf_file.has_text_reloc = true; } else { try self.reportTextRelocError(symbol, rel, elf_file); @@ -587,7 +587,7 @@ fn scanReloc( .dynrel, .baserel, .ifunc => { if (!is_writeable) { - if (elf_file.base.options.z_notext) { + if (elf_file.z_notext) { elf_file.has_text_reloc = true; } else { try self.reportTextRelocError(symbol, rel, elf_file); @@ -657,11 +657,12 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { } fn outputType(elf_file: *Elf) u2 { + const comp = elf_file.base.comp; assert(!elf_file.isRelocatable()); return switch (elf_file.base.comp.config.output_mode) { .Obj => unreachable, .Lib => 0, - .Exe => if (elf_file.base.options.pie) 1 else 2, + .Exe => if (comp.config.pie) 1 else 2, }; } @@ -979,7 +980,7 @@ fn resolveDynAbsReloc( => try writer.writeInt(i32, @as(i32, @truncate(S + A)), .little), .dyn_copyrel => { - if (is_writeable or elf_file.base.options.z_nocopyreloc) { + if (is_writeable or elf_file.z_nocopyreloc) { elf_file.addRelaDynAssumeCapacity(.{ .offset = P, .sym = target.extra(elf_file).?.dynamic, diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 347f96d451..5fa31711e6 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -299,7 +299,7 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { if (mem.startsWith(u8, name, ".note")) break :blk true; if (mem.startsWith(u8, name, ".comment")) break :blk true; if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; - if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and + if (elf_file.base.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true; break :blk false; }; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 15ae3bb943..05ff55dd18 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -97,7 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { symbol_ptr.esym_index = esym_index; if (elf_file.base.debug_format != .strip) { - self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32); + self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 1e7f2f4f9f..92d5318c02 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -32,7 +32,7 @@ pub const DynamicSection = struct { fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 { _ = dt; var flags: u64 = 0; - if (elf_file.base.options.z_now) { + if (elf_file.z_now) { flags |= elf.DF_BIND_NOW; } for (elf_file.got.entries.items) |entry| switch (entry.tag) { @@ -49,15 +49,16 @@ pub const DynamicSection = struct { } fn getFlags1(dt: DynamicSection, elf_file: *Elf) ?u64 { + const comp = elf_file.base.comp; _ = dt; var flags_1: u64 = 0; - if (elf_file.base.options.z_now) { + if (elf_file.z_now) { flags_1 |= elf.DF_1_NOW; } - if (elf_file.isExe() and elf_file.base.options.pie) { + if (elf_file.isExe() and comp.config.pie) { flags_1 |= elf.DF_1_PIE; } - // if (elf_file.base.options.z_nodlopen) { + // if (elf_file.z_nodlopen) { // flags_1 |= elf.DF_1_NOOPEN; // } return if (flags_1 > 0) flags_1 else null; @@ -246,12 +247,13 @@ pub const ZigGotSection = struct { } pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + const comp = elf_file.base.comp; const index = try zig_got.allocateEntry(elf_file.base.allocator); const entry = &zig_got.entries.items[index]; entry.* = sym_index; const symbol = elf_file.symbol(sym_index); symbol.flags.has_zig_got = true; - if (elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) { + if (elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) { zig_got.flags.needs_rela = true; } if (symbol.extra(elf_file)) |extra| { @@ -478,6 +480,7 @@ pub const GotSection = struct { } pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + const comp = elf_file.base.comp; const index = try got.allocateEntry(elf_file.base.allocator); const entry = &got.entries.items[index]; entry.tag = .got; @@ -485,7 +488,7 @@ pub const GotSection = struct { const symbol = elf_file.symbol(sym_index); symbol.flags.has_got = true; if (symbol.flags.import or symbol.isIFunc(elf_file) or - ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and !symbol.isAbs(elf_file))) + ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file))) { got.flags.needs_rela = true; } @@ -561,6 +564,7 @@ pub const GotSection = struct { } pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); const apply_relocs = true; // TODO add user option for this @@ -576,7 +580,7 @@ pub const GotSection = struct { if (symbol.?.flags.import) break :blk 0; if (symbol.?.isIFunc(elf_file)) break :blk if (apply_relocs) value else 0; - if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file)) { break :blk if (apply_relocs) value else 0; @@ -623,6 +627,7 @@ pub const GotSection = struct { } pub fn addRela(got: GotSection, elf_file: *Elf) !void { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file)); @@ -652,7 +657,7 @@ pub const GotSection = struct { }); continue; } - if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file)) { elf_file.addRelaDynAssumeCapacity(.{ @@ -725,6 +730,7 @@ pub const GotSection = struct { } pub fn numRela(got: GotSection, elf_file: *Elf) usize { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); var num: usize = 0; for (got.entries.items) |entry| { @@ -734,7 +740,7 @@ pub const GotSection = struct { }; switch (entry.tag) { .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or - ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file))) { num += 1; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3da076ba56..87faec6537 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -252,7 +252,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { self.d_sym = .{ .allocator = gpa, - .dwarf = link.File.Dwarf.init(gpa, &self.base, .dwarf32), + .dwarf = link.File.Dwarf.init(&self.base, .dwarf32), .file = d_sym_file, }; } @@ -573,7 +573,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.writeLinkeditSegmentData(); - var codesig: ?CodeSignature = if (requiresCodeSignature(&self.base.options)) blk: { + var codesig: ?CodeSignature = if (self.requiresCodeSignature()) blk: { // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values // written out to the file. @@ -619,12 +619,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No }); }, .Lib => if (self.base.comp.config.link_mode == .Dynamic) { - try load_commands.writeDylibIdLC(gpa, &self.base.options, lc_writer); + try load_commands.writeDylibIdLC(self, lc_writer); }, else => {}, } - try load_commands.writeRpathLCs(gpa, &self.base.options, lc_writer); + try load_commands.writeRpathLCs(self, lc_writer); try lc_writer.writeStruct(macho.source_version_command{ .version = 0, }); @@ -713,7 +713,7 @@ pub fn resolveLibSystem( success: { if (self.sdk_layout) |sdk_layout| switch (sdk_layout) { .sdk => { - const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" }); + const dir = try fs.path.join(arena, &[_][]const u8{ comp.sysroot.?, "usr", "lib" }); if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success; }, .vendored => { @@ -1156,7 +1156,8 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void { // 2) afterwards, we parse dependents of the included dylibs // TODO this should not be performed if the user specifies `-flat_namespace` flag. // See ld64 manpages. - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; while (dependent_libs.readItem()) |dep_id| { defer dep_id.id.deinit(gpa); @@ -1176,7 +1177,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void { var checked_paths = std.ArrayList([]const u8).init(arena); success: { - if (self.base.options.sysroot) |root| { + if (comp.sysroot) |root| { const dir = try fs.path.join(arena, &[_][]const u8{ root, dirname }); if (try accessLibPath(gpa, &test_path, &checked_paths, dir, stem)) break :success; } @@ -1713,12 +1714,12 @@ pub fn resolveSymbols(self: *MachO) !void { // we search for it in libraries should there be no object files specified // on the linker line. if (output_mode == .Exe) { - const entry_name = self.base.options.entry orelse load_commands.default_entry_point; + const entry_name = comp.config.entry.?; _ = try self.addUndefined(entry_name, .{}); } // Force resolution of any symbols requested by the user. - for (self.base.options.force_undefined_symbols.keys()) |sym_name| { + for (self.base.force_undefined_symbols.keys()) |sym_name| { _ = try self.addUndefined(sym_name, .{}); } @@ -4367,7 +4368,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { // We generate stabs last in order to ensure that the strtab always has debug info // strings trailing - if (!self.base.options.strip) { + if (self.base.debug_format != .strip) { for (self.objects.items) |object| { assert(self.d_sym == null); // TODO try self.generateSymbolStabs(object, &locals); @@ -5171,7 +5172,8 @@ pub fn getStubsEntryAddress(self: *MachO, sym_with_loc: SymbolWithLoc) ?u64 { /// Returns symbol location corresponding to the set entrypoint if any. /// Asserts output mode is executable. pub fn getEntryPoint(self: MachO) ?SymbolWithLoc { - const entry_name = self.base.options.entry orelse load_commands.default_entry_point; + const comp = self.base.comp; + const entry_name = comp.config.entry orelse return null; const global = self.getGlobal(entry_name) orelse return null; return global; } @@ -5189,11 +5191,13 @@ pub inline fn getPageSize(cpu_arch: std.Target.Cpu.Arch) u16 { }; } -pub fn requiresCodeSignature(options: *const link.Options) bool { - if (options.entitlements) |_| return true; - const cpu_arch = options.target.cpu.arch; - const os_tag = options.target.os.tag; - const abi = options.target.abi; +pub fn requiresCodeSignature(m: *MachO) bool { + if (m.entitlements) |_| return true; + const comp = m.base.comp; + const target = comp.root_mod.resolved_target.result; + const cpu_arch = target.cpu.arch; + const os_tag = target.os.tag; + const abi = target.abi; if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) return true; return false; } diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 2e7f8e49af..74a4afeb54 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -198,10 +198,10 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 } pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { + const comp = macho_file.base.comp; // TODO This linker code currently assumes there is only 1 compilation unit // and it corresponds to the Zig source code. - const options = macho_file.base.options; - const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; for (self.relocs.items) |*reloc| { const sym = switch (reloc.type) { @@ -245,7 +245,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?]; const low_pc = text_section.addr; const high_pc = text_section.addr + text_section.size; - try self.dwarf.writeDbgInfoHeader(module, low_pc, high_pc); + try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc); self.debug_info_header_dirty = false; } @@ -572,6 +572,5 @@ const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; const Dwarf = @import("../Dwarf.zig"); const MachO = @import("../MachO.zig"); -const Module = @import("../../Module.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type; diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index 51a43351ba..a92126c07e 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -60,7 +60,7 @@ fn collectRoots(macho_file: *MachO, roots: *AtomTable) !void { } // Add all symbols force-defined by the user. - for (macho_file.base.options.force_undefined_symbols.keys()) |sym_name| { + for (macho_file.base.force_undefined_symbols.keys()) |sym_name| { const global_index = macho_file.resolver.get(sym_name).?; const global = macho_file.globals.items[global_index]; const sym = macho_file.getSymbol(global); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index be8ac63642..3bffc7f73e 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -1,6 +1,3 @@ -/// Default implicit entrypoint symbol name. -pub const default_entry_point: []const u8 = "_main"; - /// Default path to dyld. pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; @@ -17,7 +14,9 @@ const CalcLCsSizeCtx = struct { wants_function_starts: bool = true, }; -fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 { +fn calcLCsSize(m: *MachO, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 { + const comp = m.base.comp; + const gpa = comp.gpa; var has_text_segment: bool = false; var sizeofcmds: u64 = 0; for (ctx.segments) |seg| { @@ -46,15 +45,15 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx false, ); // LC_MAIN - if (options.output_mode == .Exe) { + if (comp.config.output_mode == .Exe) { sizeofcmds += @sizeOf(macho.entry_point_command); } // LC_ID_DYLIB - if (options.output_mode == .Lib and options.link_mode == .Dynamic) { + if (comp.config.output_mode == .Lib and comp.config.link_mode == .Dynamic) { sizeofcmds += blk: { - const emit = options.emit.?; - const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); - defer if (options.install_name == null) gpa.free(install_name); + const emit = m.base.emit; + const install_name = m.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); + defer if (m.install_name == null) gpa.free(install_name); break :blk calcInstallNameLen( @sizeOf(macho.dylib_command), install_name, @@ -64,7 +63,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx } // LC_RPATH { - var it = RpathIterator.init(gpa, options.rpath_list); + var it = RpathIterator.init(gpa, m.rpath_list); defer it.deinit(); while (try it.next()) |rpath| { sizeofcmds += calcInstallNameLen( @@ -78,7 +77,8 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx sizeofcmds += @sizeOf(macho.source_version_command); // LC_BUILD_VERSION or LC_VERSION_MIN_ or nothing { - const platform = Platform.fromTarget(options.target); + const target = comp.root_mod.resolved_target.result; + const platform = Platform.fromTarget(target); if (platform.isBuildVersionCompatible()) { // LC_BUILD_VERSION sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); @@ -100,19 +100,19 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx ); } // LC_CODE_SIGNATURE - if (MachO.requiresCodeSignature(options)) { + if (m.requiresCodeSignature()) { sizeofcmds += @sizeOf(macho.linkedit_data_command); } - return @as(u32, @intCast(sizeofcmds)); + return @intCast(sizeofcmds); } -pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx) !u64 { - var padding: u32 = (try calcLCsSize(gpa, options, ctx, false)) + (options.headerpad_size orelse 0); +pub fn calcMinHeaderPad(m: *MachO, ctx: CalcLCsSizeCtx) !u64 { + var padding: u32 = (try calcLCsSize(m, ctx, false)) + m.headerpad_size; log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)}); - if (options.headerpad_max_install_names) { - const min_headerpad_size: u32 = try calcLCsSize(gpa, options, ctx, true); + if (m.headerpad_max_install_names) { + const min_headerpad_size: u32 = try calcLCsSize(m, ctx, true); log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{ min_headerpad_size + @sizeOf(macho.mach_header_64), }); diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 8b0aa90f96..f40aaea4db 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -499,7 +499,7 @@ pub fn linkWithZld( } // Write code signature padding if required - var codesig: ?CodeSignature = if (MachO.requiresCodeSignature(&macho_file.base.options)) blk: { + var codesig: ?CodeSignature = if (macho_file.requiresCodeSignature()) blk: { // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values // written out to the file. @@ -547,12 +547,12 @@ pub fn linkWithZld( }); }, .Lib => if (link_mode == .Dynamic) { - try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer); + try load_commands.writeDylibIdLC(macho_file, lc_writer); }, else => {}, } - try load_commands.writeRpathLCs(gpa, &macho_file.base.options, lc_writer); + try load_commands.writeRpathLCs(macho_file, lc_writer); try lc_writer.writeStruct(macho.source_version_command{ .version = 0, }); @@ -1072,11 +1072,10 @@ fn calcSectionSizes(macho_file: *MachO) !void { } fn allocateSegments(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; for (macho_file.segments.items, 0..) |*segment, segment_index| { const is_text_segment = mem.eql(u8, segment.segName(), "__TEXT"); const base_size = if (is_text_segment) - try load_commands.calcMinHeaderPad(gpa, &macho_file.base.options, .{ + try load_commands.calcMinHeaderPad(macho_file, .{ .segments = macho_file.segments.items, .dylibs = macho_file.dylibs.items, .referenced_dylibs = macho_file.referenced_dylibs.keys(), diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 1cfc14cef0..846e496ec1 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -57,6 +57,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, .function_sections = options.function_sections, .data_sections = options.data_sections, }, @@ -66,7 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { return nvptx; } -pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx { +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { const target = options.comp.root_mod.resolved_target.result; assert(target.ofmt == .nvptx); return createEmpty(arena, options); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 247986d767..b3c08fb66b 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -295,26 +295,36 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { } pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { - _ = arena; - const target = options.comp.root_mod.resolved_target.result; - const gpa = options.comp.gpa; + const comp = options.comp; + const target = comp.root_mod.resolved_target.result; + const gpa = comp.gpa; + const optimize_mode = comp.root_mod.optimize_mode; + const output_mode = comp.config.output_mode; - const sixtyfour_bit: bool = switch (options.target.ptrBitWidth()) { + const sixtyfour_bit: bool = switch (target.ptrBitWidth()) { 0...32 => false, 33...64 => true, else => return error.UnsupportedP9Architecture, }; - const arena_allocator = std.heap.ArenaAllocator.init(gpa); - - const self = try gpa.create(Plan9); + const self = try arena.create(Plan9); self.* = .{ - .path_arena = arena_allocator, + .path_arena = std.heap.ArenaAllocator.init(gpa), .base = .{ .tag = .plan9, - .options = options, - .allocator = gpa, + .comp = comp, + .emit = options.emit, + .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .stack_size = options.stack_size orelse 16777216, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .sixtyfour_bit = sixtyfour_bit, .bases = undefined, @@ -602,7 +612,7 @@ pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) li const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; assert(!use_lld); - switch (self.base.options.effectiveOutputMode()) { + switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) { .Exe => {}, // plan9 object files are totally different .Obj => return error.TODOImplementPlan9Objs, diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 414ebcf987..d8f78c32f1 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -67,6 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { .force_undefined_symbols = options.force_undefined_symbols, .function_sections = options.function_sections, .data_sections = options.data_sections, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, }, .object = codegen.Object.init(gpa), }; @@ -102,7 +103,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV { errdefer spirv.base.destroy(); // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.?.directory.handle.createFile(options.emit.sub_path, .{ + const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ .truncate = true, .read = true, }); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 0a728c7b6b..74d83e6c3c 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -37,6 +37,13 @@ pub const Relocation = types.Relocation; pub const base_tag: link.File.Tag = .wasm; base: link.File, +import_symbols: bool, +export_symbol_names: []const []const u8, +rdynamic: bool, +global_base: ?u64, +initial_memory: ?u64, +max_memory: ?u64, +wasi_emulated_libs: []const wasi_libc.CRTFile, /// Output name of the file name: []const u8, /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. @@ -368,13 +375,15 @@ pub const StringTable = struct { pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { if (build_options.only_c) unreachable; - const gpa = options.comp.gpa; - const target = options.comp.root_mod.resolved_target.result; + const comp = options.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; + const shared_memory = comp.config.shared_memory; const wasm = try createEmpty(arena, options); errdefer wasm.base.destroy(); @@ -395,7 +404,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { }; // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.?.directory.handle.createFile(sub_path, .{ + const file = try options.emit.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) @@ -480,7 +489,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { } // shared-memory symbols for TLS support - if (wasm.base.options.shared_memory) { + if (shared_memory) { { const loc = try wasm.createSyntheticSymbol("__tls_base", .global); const symbol = loc.getSymbol(wasm); @@ -522,14 +531,15 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { } pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; + const comp = options.comp; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; const wasm = try arena.create(Wasm); wasm.* = .{ .base = .{ .tag = .wasm, - .comp = options.comp, + .comp = comp, .emit = options.emit, .gc_sections = options.gc_sections orelse (output_mode != .Obj), .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB @@ -546,6 +556,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .name = undefined, .import_table = options.import_table, .export_table = options.export_table, + .import_symbols = options.import_symbols, + .export_symbol_names = options.export_symbol_names, + .rdynamic = options.rdynamic, + .global_base = options.global_base, + .initial_memory = options.initial_memory, + .max_memory = options.max_memory, + .wasi_emulated_libs = options.wasi_emulated_libs, }; if (use_llvm) { @@ -909,7 +926,10 @@ fn writeI32Const(writer: anytype, val: u32) !void { } fn setupInitMemoryFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; // Passive segments are used to avoid memory being reinitialized on each // thread's instantiation. These passive segments are initialized and @@ -920,7 +940,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { return; } - const flag_address: u32 = if (wasm.base.options.shared_memory) address: { + const flag_address: u32 = if (shared_memory) address: { // when we have passive initialization segments and shared memory // `setupMemory` will create this symbol and set its virtual address. const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?; @@ -934,7 +954,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { // we have 0 locals try leb.writeULEB128(writer, @as(u32, 0)); - if (wasm.base.options.shared_memory) { + if (shared_memory) { // destination blocks // based on values we jump to corresponding label try writer.writeByte(std.wasm.opcode(.block)); // $drop @@ -968,14 +988,14 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { var segment_index: u32 = 0; while (it.next()) |entry| : (segment_index += 1) { const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) { + if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { // For passive BSS segments we can simple issue a memory.fill(0). // For non-BSS segments we do a memory.init. Both these // instructions take as their first argument the destination // address. try writeI32Const(writer, segment.offset); - if (wasm.base.options.shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { + if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { // When we initialize the TLS segment we also set the `__tls_base` // global. This allows the runtime to use this static copy of the // TLS data for the first/main thread. @@ -1000,7 +1020,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { } } - if (wasm.base.options.shared_memory) { + if (shared_memory) { // we set the init memory flag to value '2' try writeI32Const(writer, flag_address); try writeI32Const(writer, 2); @@ -1043,12 +1063,12 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { while (it.next()) |entry| : (segment_index += 1) { const name = entry.key_ptr.*; const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, name) and + if (segment.needsPassiveInitialization(import_memory, name) and !std.mem.eql(u8, name, ".bss")) { // The TLS region should not be dropped since its is needed // during the initialization of each thread (__wasm_init_tls). - if (wasm.base.options.shared_memory and std.mem.eql(u8, name, ".tdata")) { + if (shared_memory and std.mem.eql(u8, name, ".tdata")) { continue; } @@ -1071,11 +1091,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { /// Constructs a synthetic function that performs runtime relocations for /// TLS symbols. This function is called by `__wasm_init_tls`. fn setupTLSRelocationsFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; // When we have TLS GOT entries and shared memory is enabled, // we must perform runtime relocations or else we don't create the function. - if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) { + if (!shared_memory or !wasm.requiresTLSReloc()) { return; } @@ -1119,7 +1141,9 @@ fn validateFeatures( to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool, emit_features_count: *u32, ) !void { - const target = wasm.base.comp.root_mod.resolved_target.result; + const comp = wasm.base.comp; + const target = comp.root_mod.resolved_target.result; + const shared_memory = comp.config.shared_memory; const cpu_features = target.cpu.features; const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. const known_features_count = @typeInfo(types.Feature.Tag).Enum.fields.len; @@ -1190,7 +1214,7 @@ fn validateFeatures( return error.InvalidFeatureSet; } - if (wasm.base.options.shared_memory) { + if (shared_memory) { const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)]; if (@as(u1, @truncate(disallowed_feature)) != 0) { log.err( @@ -1255,7 +1279,9 @@ fn validateFeatures( /// if one or multiple undefined references exist. When none exist, the symbol will /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. fn resolveLazySymbols(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; if (wasm.string_table.getOffset("__heap_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { @@ -1273,7 +1299,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { } } - if (!wasm.base.options.shared_memory) { + if (!shared_memory) { if (wasm.string_table.getOffset("__tls_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); @@ -1306,8 +1332,9 @@ pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc { } fn checkUndefinedSymbols(wasm: *const Wasm) !void { - if (wasm.base.comp.config.output_mode == .Obj) return; - if (wasm.base.options.import_symbols) return; + const comp = wasm.base.comp; + if (comp.config.output_mode == .Obj) return; + if (wasm.import_symbols) return; var found_undefined_symbols = false; for (wasm.undefs.values()) |undef| { @@ -2182,7 +2209,10 @@ const Kind = union(enum) { /// Parses an Atom and inserts its metadata into the corresponding sections. fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; const atom = wasm.getAtomPtr(atom_index); const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); const do_garbage_collect = wasm.base.gc_sections; @@ -2233,7 +2263,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { // we set the entire region of it to zeroes. // We do not have to do this when exporting the memory (the default) because the runtime // will do it for us, and we do not emit the bss segment at all. - if ((wasm.base.comp.config.output_mode == .Obj or wasm.base.options.import_memory) and kind.data == .uninitialized) { + if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { @memset(atom.code.items, 0); } @@ -2250,7 +2280,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { } else { const index: u32 = @intCast(wasm.segments.items.len); var flags: u32 = 0; - if (wasm.base.options.shared_memory) { + if (shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } try wasm.segments.append(gpa, .{ @@ -2679,9 +2709,11 @@ fn setupStartSection(wasm: *Wasm) !void { } fn initializeTLSFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; - if (!wasm.base.options.shared_memory) return; + if (!shared_memory) return; var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); @@ -2940,7 +2972,7 @@ fn setupExports(wasm: *Wasm) !void { if (wasm.base.comp.config.output_mode == .Obj) return; log.debug("Building exports from symbols", .{}); - const force_exp_names = wasm.base.options.export_symbol_names; + const force_exp_names = wasm.export_symbol_names; if (force_exp_names.len > 0) { var failed_exports = false; @@ -2962,7 +2994,7 @@ fn setupExports(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const symbol = sym_loc.getSymbol(wasm); - if (!symbol.isExported(wasm.base.options.rdynamic)) continue; + if (!symbol.isExported(wasm.rdynamic)) continue; const sym_name = sym_loc.getName(wasm); const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { @@ -2997,8 +3029,9 @@ fn setupExports(wasm: *Wasm) !void { } fn setupStart(wasm: *Wasm) !void { + const comp = wasm.base.comp; // do not export entry point if user set none or no default was set. - const entry_name = wasm.base.options.entry orelse return; + const entry_name = comp.config.entry orelse return; const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse { log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name}); @@ -3012,13 +3045,15 @@ fn setupStart(wasm: *Wasm) !void { } // Ensure the symbol is exported so host environment can access it - if (wasm.base.comp.config.output_mode != .Obj) { + if (comp.config.output_mode != .Obj) { symbol.setFlag(.WASM_SYM_EXPORTED); } } /// Sets up the memory section of the wasm module, as well as the stack. fn setupMemory(wasm: *Wasm) !void { + const comp = wasm.base.comp; + const shared_memory = comp.config.shared_memory; log.debug("Setting up memory layout", .{}); const page_size = std.wasm.page_size; // 64kb const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention @@ -3027,12 +3062,12 @@ fn setupMemory(wasm: *Wasm) !void { // Always place the stack at the start by default // unless the user specified the global-base flag var place_stack_first = true; - var memory_ptr: u64 = if (wasm.base.options.global_base) |base| blk: { + var memory_ptr: u64 = if (wasm.global_base) |base| blk: { place_stack_first = false; break :blk base; } else 0; - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = comp.config.output_mode == .Obj; if (place_stack_first and !is_obj) { memory_ptr = stack_alignment.forward(memory_ptr); @@ -3059,7 +3094,7 @@ fn setupMemory(wasm: *Wasm) !void { } if (wasm.findGlobalSymbol("__tls_base")) |loc| { const sym = loc.getSymbol(wasm); - wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (wasm.base.options.shared_memory) + wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) @as(i32, 0) else @as(i32, @intCast(memory_ptr)); @@ -3072,7 +3107,7 @@ fn setupMemory(wasm: *Wasm) !void { } // create the memory init flag which is used by the init memory function - if (wasm.base.options.shared_memory and wasm.hasPassiveInitializationSegments()) { + if (shared_memory and wasm.hasPassiveInitializationSegments()) { // align to pointer size memory_ptr = mem.alignForward(u64, memory_ptr, 4); const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data); @@ -3098,7 +3133,7 @@ fn setupMemory(wasm: *Wasm) !void { // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1 const max_memory_allowed: u64 = (1 << 32) - 1; - if (wasm.base.options.initial_memory) |initial_memory| { + if (wasm.initial_memory) |initial_memory| { if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) { log.err("Initial memory must be {d}-byte aligned", .{page_size}); return error.MissAlignment; @@ -3124,7 +3159,7 @@ fn setupMemory(wasm: *Wasm) !void { symbol.virtual_address = @as(u32, @intCast(memory_ptr)); } - if (wasm.base.options.max_memory) |max_memory| { + if (wasm.max_memory) |max_memory| { if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) { log.err("Maximum memory must be {d}-byte aligned", .{page_size}); return error.MissAlignment; @@ -3139,7 +3174,7 @@ fn setupMemory(wasm: *Wasm) !void { } wasm.memories.limits.max = @as(u32, @intCast(max_memory / page_size)); wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX); - if (wasm.base.options.shared_memory) { + if (shared_memory) { wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED); } log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max}); @@ -3150,20 +3185,22 @@ fn setupMemory(wasm: *Wasm) !void { /// index of the segment within the final data section. When the segment does not yet /// exist, a new one will be initialized and appended. The new index will be returned in that case. pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; const object: Object = wasm.objects.items[object_index]; const symbol = object.symtable[symbol_index]; const index: u32 = @intCast(wasm.segments.items.len); + const shared_memory = comp.config.shared_memory; switch (symbol.tag) { .data => { const segment_info = object.segment_info[symbol.index]; - const merge_segment = wasm.base.comp.config.output_mode != .Obj; + const merge_segment = comp.config.output_mode != .Obj; const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment)); if (!result.found_existing) { result.value_ptr.* = index; var flags: u32 = 0; - if (wasm.base.options.shared_memory) { + if (shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } try wasm.segments.append(gpa, .{ @@ -3445,6 +3482,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l defer tracy.end(); const gpa = wasm.base.comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; // Used for all temporary memory allocated during flushin var arena_instance = std.heap.ArenaAllocator.init(gpa); @@ -3509,8 +3548,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l man.hash.addOptionalBytes(wasm.base.comp.config.entry); man.hash.add(wasm.base.stack_size); man.hash.add(wasm.base.build_id); - man.hash.add(wasm.base.comp.config.import_memory); - man.hash.add(wasm.base.comp.config.shared_memory); + man.hash.add(import_memory); + man.hash.add(shared_memory); man.hash.add(wasm.import_table); man.hash.add(wasm.export_table); man.hash.addOptional(wasm.initial_memory); @@ -3726,8 +3765,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { // for safe build modes, we store the atom in the data segment, // whereas for unsafe build modes we store it in bss. - const is_initialized = wasm.base.options.optimize_mode == .Debug or - wasm.base.options.optimize_mode == .ReleaseSafe; + const decl_namespace = mod.namespacePtr(decl.src_namespace); + const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; + const is_initialized = switch (optimize_mode) { + .Debug, .ReleaseSafe => true, + .ReleaseFast, .ReleaseSmall => false, + }; try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); } else { // when the decl is all zeroes, we store the atom in the bss segment, @@ -3788,9 +3831,13 @@ fn writeToFile( feature_count: u32, arena: Allocator, ) !void { - const gpa = wasm.base.comp.gpa; - const use_llvm = wasm.base.comp.config.use_llvm; - const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const use_llvm = comp.config.use_llvm; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; + const export_memory = comp.config.export_memory; // Size of each section header const header_size = 5 + 1; @@ -3800,7 +3847,7 @@ fn writeToFile( var code_section_index: ?u32 = null; // Index of the data section. Used to tell relocation table where the section lives. var data_section_index: ?u32 = null; - const is_obj = wasm.base.comp.config.output_mode == .Obj or (!use_llvm and use_lld); + const is_obj = comp.config.output_mode == .Obj or (!use_llvm and use_lld); var binary_bytes = std.ArrayList(u8).init(gpa); defer binary_bytes.deinit(); @@ -3840,8 +3887,6 @@ fn writeToFile( } // Import section - const import_memory = wasm.base.options.import_memory or is_obj; - const export_memory = wasm.base.options.export_memory; if (wasm.imports.count() != 0 or import_memory) { const header_offset = try reserveVecSectionHeader(&binary_bytes); @@ -4018,7 +4063,7 @@ fn writeToFile( // When the shared-memory option is enabled, we *must* emit the 'data count' section. const data_segments_count = wasm.data_segments.count() - @intFromBool(wasm.data_segments.contains(".bss") and !import_memory); - if (data_segments_count != 0 and wasm.base.options.shared_memory) { + if (data_segments_count != 0 and shared_memory) { const header_offset = try reserveVecSectionHeader(&binary_bytes); try writeVecSectionHeader( binary_bytes.items, @@ -4160,11 +4205,11 @@ fn writeToFile( if (data_section_index) |data_index| { try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table); } - } else if (!wasm.base.options.strip) { + } else if (wasm.base.debug_format != .strip) { try wasm.emitNameSection(&binary_bytes, arena); } - if (!wasm.base.options.strip) { + if (wasm.base.debug_format != .strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. switch (wasm.base.build_id) { @@ -4193,7 +4238,7 @@ fn writeToFile( } // if (wasm.dwarf) |*dwarf| { - // const mod = wasm.base.comp.module.?; + // const mod = comp.module.?; // try dwarf.writeDbgAbbrev(); // // for debug info and ranges, the address is always 0, // // as locations are always offsets relative to 'code' section. @@ -4380,6 +4425,8 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con } fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void { + const comp = wasm.base.comp; + const import_memory = comp.config.import_memory; const Name = struct { index: u32, name: []const u8, @@ -4418,7 +4465,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem for (wasm.data_segments.keys()) |key| { // bss section is not emitted when this condition holds true, so we also // do not output a name for it. - if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue; + if (!import_memory and std.mem.eql(u8, key, ".bss")) continue; segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key }); data_segment_index += 1; } @@ -4528,6 +4575,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const tracy = trace(@src()); defer tracy.end(); + const shared_memory = comp.config.shared_memory; + const export_memory = comp.config.export_memory; + const import_memory = comp.config.import_memory; + const target = comp.root_mod.resolved_target.result; + const gpa = wasm.base.comp.gpa; var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); @@ -4560,8 +4612,6 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! break :blk null; }; - const target = wasm.base.comp.root_mod.resolved_target.result; - const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; @@ -4577,7 +4627,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! comptime assert(Compilation.link_hash_implementation_version == 10); - for (wasm.base.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -4589,17 +4639,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! man.hash.addOptionalBytes(wasm.base.comp.config.entry); man.hash.add(wasm.base.stack_size); man.hash.add(wasm.base.build_id); - man.hash.add(wasm.base.options.import_memory); - man.hash.add(wasm.base.options.export_memory); + man.hash.add(import_memory); + man.hash.add(export_memory); man.hash.add(wasm.import_table); man.hash.add(wasm.export_table); - man.hash.addOptional(wasm.base.options.initial_memory); - man.hash.addOptional(wasm.base.options.max_memory); - man.hash.add(wasm.base.options.shared_memory); - man.hash.addOptional(wasm.base.options.global_base); - man.hash.add(wasm.base.options.export_symbol_names.len); + man.hash.addOptional(wasm.initial_memory); + man.hash.addOptional(wasm.max_memory); + man.hash.add(shared_memory); + man.hash.addOptional(wasm.global_base); + man.hash.add(wasm.export_symbol_names.len); // strip does not need to go into the linker hash because it is part of the hash namespace - for (wasm.base.options.export_symbol_names) |symbol_name| { + for (wasm.export_symbol_names) |symbol_name| { man.hash.addBytes(symbol_name); } @@ -4637,8 +4687,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (wasm.base.options.objects.len != 0) - break :blk wasm.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -4666,19 +4716,19 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); try argv.append("--error-limit=0"); - if (wasm.base.options.lto) { - switch (wasm.base.options.optimize_mode) { + if (comp.config.lto) { + switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-O2"), .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), } } - if (wasm.base.options.import_memory) { + if (import_memory) { try argv.append("--import-memory"); } - if (wasm.base.options.export_memory) { + if (export_memory) { try argv.append("--export-memory"); } @@ -4698,25 +4748,25 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--no-gc-sections"); } - if (wasm.base.options.strip) { + if (wasm.base.debug_format == .strip) { try argv.append("-s"); } - if (wasm.base.options.initial_memory) |initial_memory| { + if (wasm.initial_memory) |initial_memory| { const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory}); try argv.append(arg); } - if (wasm.base.options.max_memory) |max_memory| { + if (wasm.max_memory) |max_memory| { const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory}); try argv.append(arg); } - if (wasm.base.options.shared_memory) { + if (shared_memory) { try argv.append("--shared-memory"); } - if (wasm.base.options.global_base) |global_base| { + if (wasm.global_base) |global_base| { const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base}); try argv.append(arg); } else { @@ -4728,16 +4778,16 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } // Users are allowed to specify which symbols they want to export to the wasm host. - for (wasm.base.options.export_symbol_names) |symbol_name| { + for (wasm.export_symbol_names) |symbol_name| { const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); try argv.append(arg); } - if (wasm.base.options.rdynamic) { + if (wasm.rdynamic) { try argv.append("--export-dynamic"); } - if (wasm.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } else { @@ -4749,14 +4799,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}), }); - if (wasm.base.options.import_symbols) { + if (wasm.import_symbols) { try argv.append("--allow-undefined"); } if (wasm.base.comp.config.output_mode == .Lib and wasm.base.comp.config.link_mode == .Dynamic) { try argv.append("--shared"); } - if (wasm.base.options.pie) { + if (comp.config.pie) { try argv.append("--pie"); } @@ -4782,15 +4832,15 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! )); } - if (wasm.base.options.link_libc) { + if (comp.config.link_libc) { try argv.append(try comp.get_libc_crt_file( arena, - wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model), + wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model), )); try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); } - if (wasm.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxx_static_lib.?.full_object_path); try argv.append(comp.libcxxabi_static_lib.?.full_object_path); } @@ -4799,7 +4849,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // Positional arguments to the linker such as object files. var whole_archive = false; - for (wasm.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -4822,8 +4872,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } if (wasm.base.comp.config.output_mode != .Obj and - !wasm.base.options.skip_linker_dependencies and - !wasm.base.options.link_libc) + !comp.skip_linker_dependencies and + !comp.config.link_libc) { try argv.append(comp.libc_static_lib.?.full_object_path); } @@ -5168,10 +5218,13 @@ fn emitDataRelocations( } fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { + const comp = wasm.base.comp; + const import_memory = comp.config.import_memory; + var it = wasm.data_segments.iterator(); while (it.next()) |entry| { const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) { + if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { return true; } } @@ -5227,14 +5280,14 @@ fn markReferences(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); - if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { + if (sym.isExported(wasm.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { try wasm.mark(sym_loc); continue; } // Debug sections may require to be parsed and marked when it contains // relocations to alive symbols. - if (sym.tag == .section and !wasm.base.options.strip) { + if (sym.tag == .section and wasm.base.debug_format != .strip) { const file = sym_loc.file orelse continue; // Incremental debug info is done independently const object = &wasm.objects.items[file]; const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm);