authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-12-11 21:16:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:18-07:00
log2bef0715c740024c515dce73d267ead5af49d1a9
tree0fa39b660ea8f9478fdd04f59ad8a5ece042bce6
parent12de7e3472cb2292e75578d33a8b8cc91f1ef0b0

move a large chunk of linker logic away from "options"

These options are only supposed to be provided to the initialization functions, resolved, and then computed values stored in the appropriate place (base struct or the object-format-specific structs). Many more to go...

18 files changed, 1245 insertions(+), 962 deletions(-)

src/Compilation.zig+56-38
......@@ -69,6 +69,8 @@ root_name: [:0]const u8,
6969cache_mode: CacheMode,
7070include_compiler_rt: bool,
7171objects: []Compilation.LinkObject,
72/// Needed only for passing -F args to clang.
73framework_dirs: []const []const u8,
7274/// These are *always* dynamically linked. Static libraries will be
7375/// provided as positional arguments.
7476system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
......@@ -133,6 +135,7 @@ verbose_llvm_ir: ?[]const u8,
133135verbose_llvm_bc: ?[]const u8,
134136verbose_cimport: bool,
135137verbose_llvm_cpu_features: bool,
138verbose_link: bool,
136139disable_c_depfile: bool,
137140time_report: bool,
138141stack_report: bool,
......@@ -220,6 +223,8 @@ emit_llvm_bc: ?EmitLoc,
220223work_queue_wait_group: WaitGroup = .{},
221224astgen_wait_group: WaitGroup = .{},
222225
226llvm_opt_bisect_limit: c_int,
227
223228pub const Emit = struct {
224229 /// Where the output will go.
225230 directory: Directory,
......@@ -340,7 +345,7 @@ const Job = union(enum) {
340345 /// one of WASI libc static objects
341346 wasi_libc_crt_file: wasi_libc.CRTFile,
342347
343 /// The value is the index into `link.File.Options.system_libs`.
348 /// The value is the index into `system_libs`.
344349 windows_import_lib: usize,
345350};
346351
......@@ -819,6 +824,20 @@ pub const cache_helpers = struct {
819824 addEmitLoc(hh, optional_emit_loc orelse return);
820825 }
821826
827 pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?link.File.DebugFormat) void {
828 hh.add(x != null);
829 addDebugFormat(hh, x orelse return);
830 }
831
832 pub fn addDebugFormat(hh: *Cache.HashHelper, x: link.File.DebugFormat) void {
833 const tag: @typeInfo(link.File.DebugFormat).Union.tag_type.? = x;
834 hh.add(tag);
835 switch (x) {
836 .strip, .code_view => {},
837 .dwarf => |f| hh.add(f),
838 }
839 }
840
822841 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {
823842 _ = try self.addFile(c_source.src_path, null);
824843 // Hash the extra flags, with special care to call addFile for file parameters.
......@@ -846,7 +865,7 @@ pub const ClangPreprocessorMode = enum {
846865 stdout,
847866};
848867
849pub const Framework = link.Framework;
868pub const Framework = link.File.MachO.Framework;
850869pub const SystemLib = link.SystemLib;
851870pub const CacheMode = link.CacheMode;
852871
......@@ -952,7 +971,7 @@ pub const InitOptions = struct {
952971 linker_print_gc_sections: bool = false,
953972 linker_print_icf_sections: bool = false,
954973 linker_print_map: bool = false,
955 linker_opt_bisect_limit: i32 = -1,
974 llvm_opt_bisect_limit: i32 = -1,
956975 each_lib_rpath: ?bool = null,
957976 build_id: ?std.zig.BuildId = null,
958977 disable_c_depfile: bool = false,
......@@ -994,7 +1013,7 @@ pub const InitOptions = struct {
9941013 hash_style: link.HashStyle = .both,
9951014 entry: ?[]const u8 = null,
9961015 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{},
997 stack_size_override: ?u64 = null,
1016 stack_size: ?u64 = null,
9981017 image_base_override: ?u64 = null,
9991018 version: ?std.SemanticVersion = null,
10001019 compatibility_version: ?std.SemanticVersion = null,
......@@ -1007,7 +1026,7 @@ pub const InitOptions = struct {
10071026 test_name_prefix: ?[]const u8 = null,
10081027 test_runner_path: ?[]const u8 = null,
10091028 subsystem: ?std.Target.SubSystem = null,
1010 dwarf_format: ?std.dwarf.Format = null,
1029 debug_format: ?link.File.DebugFormat = null,
10111030 /// (Zig compiler development) Enable dumping linker's state as JSON.
10121031 enable_link_snapshots: bool = false,
10131032 /// (Darwin) Install name of the dylib
......@@ -1297,7 +1316,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12971316 cache.hash.add(options.config.link_libcpp);
12981317 cache.hash.add(options.config.link_libunwind);
12991318 cache.hash.add(output_mode);
1300 cache.hash.addOptional(options.dwarf_format);
1319 cache_helpers.addOptionalDebugFormat(&cache.hash, options.debug_format);
13011320 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
13021321 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
13031322 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs);
......@@ -1596,6 +1615,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
15961615 .verbose_llvm_bc = options.verbose_llvm_bc,
15971616 .verbose_cimport = options.verbose_cimport,
15981617 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
1618 .verbose_link = options.verbose_link,
15991619 .disable_c_depfile = options.disable_c_depfile,
16001620 .owned_link_dir = owned_link_dir,
16011621 .color = options.color,
......@@ -1617,6 +1637,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16171637 .libc_installation = libc_dirs.libc_installation,
16181638 .include_compiler_rt = include_compiler_rt,
16191639 .objects = options.link_objects,
1640 .framework_dirs = options.framework_dirs,
1641 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
16201642 };
16211643
16221644 if (bin_file_emit) |emit| {
......@@ -1636,7 +1658,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16361658 .z_max_page_size = options.linker_z_max_page_size,
16371659 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
16381660 .frameworks = options.frameworks,
1639 .framework_dirs = options.framework_dirs,
16401661 .wasi_emulated_libs = options.wasi_emulated_libs,
16411662 .lib_dirs = options.lib_dirs,
16421663 .rpath_list = options.rpath_list,
......@@ -1659,13 +1680,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16591680 .print_gc_sections = options.linker_print_gc_sections,
16601681 .print_icf_sections = options.linker_print_icf_sections,
16611682 .print_map = options.linker_print_map,
1662 .opt_bisect_limit = options.linker_opt_bisect_limit,
16631683 .tsaware = options.linker_tsaware,
16641684 .nxcompat = options.linker_nxcompat,
16651685 .dynamicbase = options.linker_dynamicbase,
16661686 .major_subsystem_version = options.major_subsystem_version,
16671687 .minor_subsystem_version = options.minor_subsystem_version,
1668 .stack_size_override = options.stack_size_override,
1688 .stack_size = options.stack_size,
16691689 .image_base_override = options.image_base_override,
16701690 .version_script = options.version_script,
16711691 .gc_sections = options.linker_gc_sections,
......@@ -1674,7 +1694,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16741694 .rdynamic = options.rdynamic,
16751695 .soname = options.soname,
16761696 .compatibility_version = options.compatibility_version,
1677 .verbose_link = options.verbose_link,
16781697 .dll_export_fns = dll_export_fns,
16791698 .skip_linker_dependencies = options.skip_linker_dependencies,
16801699 .parent_compilation_link_libc = options.parent_compilation_link_libc,
......@@ -1682,7 +1701,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16821701 .build_id = build_id,
16831702 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
16841703 .subsystem = options.subsystem,
1685 .dwarf_format = options.dwarf_format,
1704 .debug_format = options.debug_format,
16861705 .hash_style = options.hash_style,
16871706 .enable_link_snapshots = options.enable_link_snapshots,
16881707 .install_name = options.install_name,
......@@ -1826,7 +1845,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18261845
18271846 // When linking mingw-w64 there are some import libs we always need.
18281847 for (mingw.always_link_libs) |name| {
1829 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{
1848 try comp.system_libs.put(comp.gpa, name, .{
18301849 .needed = false,
18311850 .weak = false,
18321851 .path = null,
......@@ -1835,7 +1854,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18351854 }
18361855 // Generate Windows import libs.
18371856 if (target.os.tag == .windows) {
1838 const count = comp.bin_file.options.system_libs.count();
1857 const count = comp.system_libs.count();
18391858 try comp.work_queue.ensureUnusedCapacity(count);
18401859 for (0..count) |i| {
18411860 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });
......@@ -2450,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
24502469 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
24512470 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
24522471
2453 man.hash.addOptional(comp.bin_file.options.stack_size_override);
2472 man.hash.add(comp.bin_file.stack_size);
24542473 man.hash.addOptional(comp.bin_file.options.image_base_override);
24552474 man.hash.addOptional(comp.bin_file.options.gc_sections);
24562475 man.hash.add(comp.bin_file.options.eh_frame_hdr);
......@@ -2460,7 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
24602479 man.hash.addListOfBytes(comp.bin_file.options.rpath_list);
24612480 man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys());
24622481 man.hash.add(comp.bin_file.options.each_lib_rpath);
2463 man.hash.add(comp.bin_file.options.build_id);
2482 man.hash.add(comp.bin_file.build_id);
24642483 man.hash.add(comp.bin_file.options.skip_linker_dependencies);
24652484 man.hash.add(comp.bin_file.options.z_nodelete);
24662485 man.hash.add(comp.bin_file.options.z_notext);
......@@ -2488,9 +2507,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
24882507 }
24892508 man.hash.addOptionalBytes(comp.bin_file.options.soname);
24902509 man.hash.addOptional(comp.bin_file.options.version);
2491 try link.hashAddSystemLibs(man, comp.bin_file.options.system_libs);
2510 try link.hashAddSystemLibs(man, comp.system_libs);
24922511 man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys());
2493 man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined);
2512 man.hash.addOptional(comp.bin_file.allow_shlib_undefined);
24942513 man.hash.add(comp.bin_file.options.bind_global_refs_locally);
24952514 man.hash.add(comp.bin_file.options.tsan);
24962515 man.hash.addOptionalBytes(comp.bin_file.options.sysroot);
......@@ -2505,7 +2524,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
25052524 man.hash.addOptional(comp.bin_file.options.global_base);
25062525
25072526 // Mach-O specific stuff
2508 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
2527 man.hash.addListOfBytes(comp.framework_dirs);
25092528 try link.hashAddFrameworks(man, comp.bin_file.options.frameworks);
25102529 try man.addOptionalFile(comp.bin_file.options.entitlements);
25112530 man.hash.addOptional(comp.bin_file.options.pagezero_size);
......@@ -3561,7 +3580,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
35613580 const named_frame = tracy.namedFrame("windows_import_lib");
35623581 defer named_frame.end();
35633582
3564 const link_lib = comp.bin_file.options.system_libs.keys()[index];
3583 const link_lib = comp.system_libs.keys()[index];
35653584 mingw.buildImportLib(comp, link_lib) catch |err| {
35663585 // TODO Surface more error details.
35673586 comp.lockAndSetMiscFailure(
......@@ -4964,7 +4983,7 @@ pub fn addCCArgs(
49644983 try argv.appendSlice(&.{ "-iframework", framework_dir });
49654984 }
49664985
4967 for (comp.bin_file.options.framework_dirs) |framework_dir| {
4986 for (comp.framework_dirs) |framework_dir| {
49684987 try argv.appendSlice(&.{ "-F", framework_dir });
49694988 }
49704989
......@@ -5219,22 +5238,21 @@ pub fn addCCArgs(
52195238 },
52205239 }
52215240
5222 if (!comp.bin_file.options.strip) {
5223 switch (target.ofmt) {
5224 .coff => {
5225 // -g is required here because -gcodeview doesn't trigger debug info
5226 // generation, it only changes the type of information generated.
5227 try argv.appendSlice(&.{ "-g", "-gcodeview" });
5228 },
5229 .elf, .macho => {
5230 try argv.append("-gdwarf-4");
5231 if (comp.bin_file.options.dwarf_format) |f| switch (f) {
5232 .@"32" => try argv.append("-gdwarf32"),
5233 .@"64" => try argv.append("-gdwarf64"),
5234 };
5235 },
5236 else => try argv.append("-g"),
5237 }
5241 try argv.ensureUnusedCapacity(2);
5242 switch (comp.bin_file.debug_format) {
5243 .strip => {},
5244 .code_view => {
5245 // -g is required here because -gcodeview doesn't trigger debug info
5246 // generation, it only changes the type of information generated.
5247 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" });
5248 },
5249 .dwarf => |f| {
5250 argv.appendAssumeCapacity("-gdwarf-4");
5251 switch (f) {
5252 .@"32" => argv.appendAssumeCapacity("-gdwarf32"),
5253 .@"64" => argv.appendAssumeCapacity("-gdwarf64"),
5254 }
5255 },
52385256 }
52395257
52405258 if (target_util.llvmMachineAbi(target)) |mabi| {
......@@ -6306,7 +6324,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
63066324 // This happens when an `extern "foo"` function is referenced.
63076325 // If we haven't seen this library yet and we're targeting Windows, we need
63086326 // to queue up a work item to produce the DLL import library for this.
6309 const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);
6327 const gop = try comp.system_libs.getOrPut(comp.gpa, lib_name);
63106328 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
63116329 gop.value_ptr.* = .{
63126330 .needed = true,
......@@ -6314,7 +6332,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
63146332 .path = null,
63156333 };
63166334 try comp.work_queue.writeItem(.{
6317 .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,
6335 .windows_import_lib = comp.system_libs.count() - 1,
63186336 });
63196337 }
63206338}
src/Compilation/Config.zig+24-12
......@@ -137,7 +137,11 @@ pub fn resolve(options: Options) !Config {
137137 const use_llvm = b: {
138138 // If emitting to LLVM bitcode object format, must use LLVM backend.
139139 if (options.emit_llvm_ir or options.emit_llvm_bc) {
140 if (options.use_llvm == false) return error.EmittingLlvmModuleRequiresLlvmBackend;
140 if (options.use_llvm == false)
141 return error.EmittingLlvmModuleRequiresLlvmBackend;
142 if (!target_util.hasLlvmSupport(target, target.ofmt))
143 return error.LlvmLacksTargetSupport;
144
141145 break :b true;
142146 }
143147
......@@ -147,6 +151,12 @@ pub fn resolve(options: Options) !Config {
147151 break :b false;
148152 }
149153
154 // If Zig does not support the target, then we can't use it.
155 if (target_util.zigBackend(target, false) == .other) {
156 if (options.use_llvm == false) return error.ZigLacksTargetSupport;
157 break :b true;
158 }
159
150160 if (options.use_llvm) |x| break :b x;
151161
152162 // If we have no zig code to compile, no need for LLVM.
......@@ -166,16 +176,23 @@ pub fn resolve(options: Options) !Config {
166176 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
167177 };
168178
169 if (!use_lib_llvm and use_llvm and options.emit_bin) {
170 // Explicit request to use LLVM to produce an object file, but without
171 // using LLVM libraries. Impossible.
172 return error.EmittingBinaryRequiresLlvmLibrary;
179 if (options.emit_bin) {
180 if (!use_lib_llvm and use_llvm) {
181 // Explicit request to use LLVM to produce an object file, but without
182 // using LLVM libraries. Impossible.
183 return error.EmittingBinaryRequiresLlvmLibrary;
184 }
185
186 if (target_util.zigBackend(target, use_llvm) == .other) {
187 // There is no compiler backend available for this target.
188 return error.ZigLacksTargetSupport;
189 }
173190 }
174191
175192 // Make a decision on whether to use LLD or our own linker.
176193 const use_lld = b: {
177 if (target.isDarwin()) {
178 if (options.use_lld == true) return error.LldIncompatibleOs;
194 if (!target_util.hasLldSupport(target.ofmt)) {
195 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
179196 break :b false;
180197 }
181198
......@@ -184,11 +201,6 @@ pub fn resolve(options: Options) !Config {
184201 break :b false;
185202 }
186203
187 if (target.ofmt == .c) {
188 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
189 break :b false;
190 }
191
192204 if (options.lto == true) {
193205 if (options.use_lld == false) return error.LtoRequiresLld;
194206 break :b true;
src/codegen/llvm.zig+44-30
......@@ -854,15 +854,21 @@ pub const Object = struct {
854854 pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);
855855
856856 pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object {
857 const gpa = options.comp.gpa;
858 const llvm_target_triple = try targetTriple(arena, options.target);
857 if (build_options.only_c) unreachable;
858 const comp = options.comp;
859 const gpa = comp.gpa;
860 const target = comp.root_mod.resolved_target.result;
861 const llvm_target_triple = try targetTriple(arena, target);
862 const strip = comp.root_mod.strip;
863 const optimize_mode = comp.root_mod.optimize_mode;
864 const pic = comp.root_mod.pic;
859865
860866 var builder = try Builder.init(.{
861867 .allocator = gpa,
862 .use_lib_llvm = options.use_lib_llvm,
863 .strip = options.strip or !options.use_lib_llvm, // TODO
864 .name = options.root_name,
865 .target = options.target,
868 .use_lib_llvm = comp.config.use_lib_llvm,
869 .strip = strip or !comp.config.use_lib_llvm, // TODO
870 .name = comp.root_name,
871 .target = target,
866872 .triple = llvm_target_triple,
867873 });
868874 errdefer builder.deinit();
......@@ -870,10 +876,18 @@ pub const Object = struct {
870876 var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined;
871877 var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined;
872878 if (builder.useLibLlvm()) {
873 if (!options.strip) {
874 switch (options.target.ofmt) {
875 .coff => builder.llvm.module.?.addModuleCodeViewFlag(),
876 else => builder.llvm.module.?.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"),
879 debug_info: {
880 const debug_format = options.debug_format orelse b: {
881 if (strip) break :b .strip;
882 break :b switch (target.ofmt) {
883 .coff => .code_view,
884 else => .{ .dwarf = .@"32" },
885 };
886 };
887 switch (debug_format) {
888 .strip => break :debug_info,
889 .code_view => builder.llvm.module.?.addModuleCodeViewFlag(),
890 .dwarf => |f| builder.llvm.module.?.addModuleDebugInfoFlag(f == .@"64"),
877891 }
878892 builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true);
879893
......@@ -892,8 +906,8 @@ pub const Object = struct {
892906 // TODO: the only concern I have with this is WASI as either host or target, should
893907 // we leave the paths as relative then?
894908 const compile_unit_dir_z = blk: {
895 if (options.module) |mod| m: {
896 const d = try mod.root_mod.root.joinStringZ(arena, "");
909 if (comp.module) |zcu| m: {
910 const d = try zcu.root_mod.root.joinStringZ(arena, "");
897911 if (d.len == 0) break :m;
898912 if (std.fs.path.isAbsolute(d)) break :blk d;
899913 break :blk std.fs.realpathAlloc(arena, d) catch d;
......@@ -903,9 +917,9 @@ pub const Object = struct {
903917
904918 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
905919 DW.LANG.C99,
906 builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z),
920 builder.llvm.di_builder.?.createFile(comp.root_name, compile_unit_dir_z),
907921 producer.slice(&builder).?,
908 options.optimize_mode != .Debug,
922 optimize_mode != .Debug,
909923 "", // flags
910924 0, // runtime version
911925 "", // split name
......@@ -914,19 +928,19 @@ pub const Object = struct {
914928 );
915929 }
916930
917 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
931 const opt_level: llvm.CodeGenOptLevel = if (optimize_mode == .Debug)
918932 .None
919933 else
920934 .Aggressive;
921935
922 const reloc_mode: llvm.RelocMode = if (options.pic)
936 const reloc_mode: llvm.RelocMode = if (pic)
923937 .PIC
924 else if (options.link_mode == .Dynamic)
938 else if (comp.config.link_mode == .Dynamic)
925939 llvm.RelocMode.DynamicNoPIC
926940 else
927941 .Static;
928942
929 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
943 const code_model: llvm.CodeModel = switch (comp.root_mod.code_model) {
930944 .default => .Default,
931945 .tiny => .Tiny,
932946 .small => .Small,
......@@ -941,15 +955,15 @@ pub const Object = struct {
941955 target_machine = llvm.TargetMachine.create(
942956 builder.llvm.target.?,
943957 builder.target_triple.slice(&builder).?,
944 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
945 options.llvm_cpu_features,
958 if (target.cpu.model.llvm_name) |s| s.ptr else null,
959 comp.root_mod.resolved_target.llvm_cpu_features.?,
946960 opt_level,
947961 reloc_mode,
948962 code_model,
949 options.function_sections,
950 options.data_sections,
963 options.function_sections orelse false,
964 options.data_sections orelse false,
951965 float_abi,
952 if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null,
966 if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
953967 );
954968 errdefer target_machine.dispose();
955969
......@@ -958,15 +972,15 @@ pub const Object = struct {
958972
959973 builder.llvm.module.?.setModuleDataLayout(target_data);
960974
961 if (options.pic) builder.llvm.module.?.setModulePICLevel();
962 if (options.pie) builder.llvm.module.?.setModulePIELevel();
975 if (pic) builder.llvm.module.?.setModulePICLevel();
976 if (comp.config.pie) builder.llvm.module.?.setModulePIELevel();
963977 if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);
964978
965 if (options.opt_bisect_limit >= 0) {
966 builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));
979 if (comp.llvm_opt_bisect_limit >= 0) {
980 builder.llvm.context.setOptBisectLimit(comp.llvm_opt_bisect_limit);
967981 }
968982
969 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }});
983 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }});
970984 if (std.debug.runtime_safety) {
971985 const rep = target_data.stringRep();
972986 defer llvm.disposeMessage(rep);
......@@ -981,13 +995,13 @@ pub const Object = struct {
981995 obj.* = .{
982996 .gpa = gpa,
983997 .builder = builder,
984 .module = options.module.?,
998 .module = comp.module.?,
985999 .di_map = .{},
9861000 .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO
9871001 .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null,
9881002 .target_machine = target_machine,
9891003 .target_data = target_data,
990 .target = options.target,
1004 .target = target,
9911005 .decl_map = .{},
9921006 .anon_decl_map = .{},
9931007 .named_enum_map = .{},
src/link.zig+84-49
......@@ -32,13 +32,6 @@ pub const SystemLib = struct {
3232 path: ?[]const u8,
3333};
3434
35/// When adding a new field, remember to update `hashAddFrameworks`.
36pub const Framework = struct {
37 needed: bool = false,
38 weak: bool = false,
39 path: []const u8,
40};
41
4235pub const SortSection = enum { name, alignment };
4336
4437pub const CacheMode = enum { incremental, whole };
......@@ -56,14 +49,6 @@ pub fn hashAddSystemLibs(
5649 }
5750}
5851
59pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
60 for (hm) |value| {
61 man.hash.add(value.needed);
62 man.hash.add(value.weak);
63 _ = try man.addFile(value.path, null);
64 }
65}
66
6752pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
6853
6954pub const HashStyle = enum { sysv, gnu, both };
......@@ -81,6 +66,19 @@ pub const File = struct {
8166 /// When linking with LLD, this linker code will output an object file only at
8267 /// this location, and then this path can be placed on the LLD linker line.
8368 intermediary_basename: ?[]const u8 = null,
69 disable_lld_caching: bool,
70 gc_sections: bool,
71 build_id: std.zig.BuildId,
72 rpath_list: []const []const u8,
73 /// List of symbols forced as undefined in the symbol table
74 /// thus forcing their resolution by the linker.
75 /// Corresponds to `-u <symbol>` for ELF/MachO and `/include:<symbol>` for COFF/PE.
76 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
77 allow_shlib_undefined: bool,
78 stack_size: u64,
79 debug_format: DebugFormat,
80 function_sections: bool,
81 data_sections: bool,
8482
8583 /// Prevents other processes from clobbering files in the output directory
8684 /// of this linking operation.
......@@ -88,6 +86,12 @@ pub const File = struct {
8886
8987 child_pid: ?std.ChildProcess.Id = null,
9088
89 pub const DebugFormat = union(enum) {
90 strip,
91 dwarf: std.dwarf.Format,
92 code_view,
93 };
94
9195 pub const OpenOptions = struct {
9296 comp: *Compilation,
9397 emit: Compilation.Emit,
......@@ -97,7 +101,7 @@ pub const File = struct {
97101
98102 /// Virtual address of the entry point procedure relative to image base.
99103 entry_addr: ?u64,
100 stack_size_override: ?u64,
104 stack_size: ?u64,
101105 image_base_override: ?u64,
102106 function_sections: bool,
103107 data_sections: bool,
......@@ -128,7 +132,6 @@ pub const File = struct {
128132 max_memory: ?u64,
129133 export_symbol_names: []const []const u8,
130134 global_base: ?u64,
131 verbose_link: bool,
132135 dll_export_fns: bool,
133136 skip_linker_dependencies: bool,
134137 parent_compilation_link_libc: bool,
......@@ -139,7 +142,7 @@ pub const File = struct {
139142 sort_section: ?SortSection,
140143 major_subsystem_version: ?u32,
141144 minor_subsystem_version: ?u32,
142 gc_sections: ?bool = null,
145 gc_sections: ?bool,
143146 allow_shlib_undefined: ?bool,
144147 subsystem: ?std.Target.SubSystem,
145148 version_script: ?[]const u8,
......@@ -147,11 +150,7 @@ pub const File = struct {
147150 print_gc_sections: bool,
148151 print_icf_sections: bool,
149152 print_map: bool,
150 opt_bisect_limit: i32,
151153
152 /// List of symbols forced as undefined in the symbol table
153 /// thus forcing their resolution by the linker.
154 /// Corresponds to `-u <symbol>` for ELF/MachO and `/include:<symbol>` for COFF/PE.
155154 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
156155 /// Use a wrapper function for symbol. Any undefined reference to symbol
157156 /// will be resolved to __wrap_symbol. Any undefined reference to
......@@ -163,7 +162,7 @@ pub const File = struct {
163162
164163 compatibility_version: ?std.SemanticVersion,
165164
166 dwarf_format: ?std.dwarf.Format,
165 debug_format: ?DebugFormat,
167166
168167 // TODO: remove this. libraries are resolved by the frontend.
169168 lib_dirs: []const []const u8,
......@@ -184,8 +183,7 @@ pub const File = struct {
184183 headerpad_max_install_names: bool,
185184 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
186185 dead_strip_dylibs: bool,
187 framework_dirs: []const []const u8,
188 frameworks: []const Framework,
186 frameworks: []const MachO.Framework,
189187 darwin_sdk_layout: ?MachO.SdkLayout,
190188
191189 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
......@@ -228,7 +226,7 @@ pub const File = struct {
228226 .coff, .elf, .macho, .plan9, .wasm => {
229227 if (build_options.only_c) unreachable;
230228 if (base.file != null) return;
231 const emit = base.options.emit orelse return;
229 const emit = base.emit;
232230 if (base.child_pid) |pid| {
233231 if (builtin.os.tag == .windows) {
234232 base.cast(Coff).?.ptraceAttach(pid) catch |err| {
......@@ -256,10 +254,13 @@ pub const File = struct {
256254 }
257255 }
258256 }
257 const use_lld = build_options.have_llvm and base.comp.config.use_lld;
258 const output_mode = base.comp.config.output_mode;
259 const link_mode = base.comp.config.link_mode;
259260 base.file = try emit.directory.handle.createFile(emit.sub_path, .{
260261 .truncate = false,
261262 .read = true,
262 .mode = determineMode(base.options),
263 .mode = determineMode(use_lld, output_mode, link_mode),
263264 });
264265 },
265266 .c, .spirv, .nvptx => {},
......@@ -267,9 +268,13 @@ pub const File = struct {
267268 }
268269
269270 pub fn makeExecutable(base: *File) !void {
270 switch (base.options.output_mode) {
271 const output_mode = base.comp.config.output_mode;
272 const link_mode = base.comp.config.link_mode;
273 const use_lld = build_options.have_llvm and base.comp.config.use_lld;
274
275 switch (output_mode) {
271276 .Obj => return,
272 .Lib => switch (base.options.link_mode) {
277 .Lib => switch (link_mode) {
273278 .Static => return,
274279 .Dynamic => {},
275280 },
......@@ -278,7 +283,6 @@ pub const File = struct {
278283 switch (base.tag) {
279284 .elf => if (base.file) |f| {
280285 if (build_options.only_c) unreachable;
281 const use_lld = build_options.have_llvm and base.options.use_lld;
282286 if (base.intermediary_basename != null and use_lld) {
283287 // The file we have open is not the final file that we want to
284288 // make executable, so we don't have to close it.
......@@ -596,7 +600,7 @@ pub const File = struct {
596600 return @fieldParentPtr(C, "base", base).flush(comp, prog_node);
597601 }
598602 if (comp.clang_preprocessor_mode == .yes) {
599 const emit = base.options.emit orelse return; // -fno-emit-bin
603 const emit = base.emit;
600604 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
601605 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
602606 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
......@@ -610,8 +614,10 @@ pub const File = struct {
610614 return;
611615 }
612616
613 const use_lld = build_options.have_llvm and base.options.use_lld;
614 if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static) {
617 const use_lld = build_options.have_llvm and base.comp.config.use_lld;
618 const output_mode = base.comp.config.output_mode;
619 const link_mode = base.comp.config.link_mode;
620 if (use_lld and output_mode == .Lib and link_mode == .Static) {
615621 return base.linkAsArchive(comp, prog_node);
616622 }
617623 switch (base.tag) {
......@@ -845,8 +851,6 @@ pub const File = struct {
845851 }
846852
847853 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
848 const emit = base.options.emit orelse return;
849
850854 const tracy = trace(@src());
851855 defer tracy.end();
852856
......@@ -854,22 +858,23 @@ pub const File = struct {
854858 defer arena_allocator.deinit();
855859 const arena = arena_allocator.allocator();
856860
857 const directory = emit.directory; // Just an alias to make it shorter to type.
858 const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path});
861 const directory = base.emit.directory; // Just an alias to make it shorter to type.
862 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
859863 const full_out_path_z = try arena.dupeZ(u8, full_out_path);
864 const opt_zcu = base.comp.module;
860865
861866 // If there is no Zig code to compile, then we should skip flushing the output file
862867 // because it will not be part of the linker line anyway.
863 const module_obj_path: ?[]const u8 = if (base.options.module != null) blk: {
868 const zcu_obj_path: ?[]const u8 = if (opt_zcu != null) blk: {
864869 try base.flushModule(comp, prog_node);
865870
866871 const dirname = fs.path.dirname(full_out_path_z) orelse ".";
867872 break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? });
868873 } else null;
869874
870 log.debug("module_obj_path={s}", .{if (module_obj_path) |s| s else "(null)"});
875 log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"});
871876
872 const compiler_rt_path: ?[]const u8 = if (base.options.include_compiler_rt)
877 const compiler_rt_path: ?[]const u8 = if (base.comp.include_compiler_rt)
873878 comp.compiler_rt_obj.?.full_object_path
874879 else
875880 null;
......@@ -881,17 +886,19 @@ pub const File = struct {
881886 const id_symlink_basename = "llvm-ar.id";
882887
883888 var man: Cache.Manifest = undefined;
884 defer if (!base.options.disable_lld_caching) man.deinit();
889 defer if (!base.disable_lld_caching) man.deinit();
890
891 const objects = base.comp.objects;
885892
886893 var digest: [Cache.hex_digest_len]u8 = undefined;
887894
888 if (!base.options.disable_lld_caching) {
895 if (!base.disable_lld_caching) {
889896 man = comp.cache_parent.obtain();
890897
891898 // We are about to obtain this lock, so here we give other processes a chance first.
892899 base.releaseLock();
893900
894 for (base.options.objects) |obj| {
901 for (objects) |obj| {
895902 _ = try man.addFile(obj.path, null);
896903 man.hash.add(obj.must_link);
897904 man.hash.add(obj.loption);
......@@ -904,7 +911,7 @@ pub const File = struct {
904911 _ = try man.addFile(key.status.success.res_path, null);
905912 }
906913 }
907 try man.addOptionalFile(module_obj_path);
914 try man.addOptionalFile(zcu_obj_path);
908915 try man.addOptionalFile(compiler_rt_path);
909916
910917 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
......@@ -934,11 +941,11 @@ pub const File = struct {
934941 }
935942
936943 const win32_resource_table_len = if (build_options.only_core_functionality) 0 else comp.win32_resource_table.count();
937 const num_object_files = base.options.objects.len + comp.c_object_table.count() + win32_resource_table_len + 2;
944 const num_object_files = objects.len + comp.c_object_table.count() + win32_resource_table_len + 2;
938945 var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files);
939946 defer object_files.deinit();
940947
941 for (base.options.objects) |obj| {
948 for (objects) |obj| {
942949 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));
943950 }
944951 for (comp.c_object_table.keys()) |key| {
......@@ -949,14 +956,14 @@ pub const File = struct {
949956 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
950957 }
951958 }
952 if (module_obj_path) |p| {
959 if (zcu_obj_path) |p| {
953960 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
954961 }
955962 if (compiler_rt_path) |p| {
956963 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
957964 }
958965
959 if (base.options.verbose_link) {
966 if (comp.verbose_link) {
960967 std.debug.print("ar rcs {s}", .{full_out_path_z});
961968 for (object_files.items) |arg| {
962969 std.debug.print(" {s}", .{arg});
......@@ -972,7 +979,7 @@ pub const File = struct {
972979 const bad = llvm_bindings.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_tag);
973980 if (bad) return error.UnableToWriteArchive;
974981
975 if (!base.options.disable_lld_caching) {
982 if (!base.disable_lld_caching) {
976983 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
977984 log.warn("failed to save archive hash digest file: {s}", .{@errorName(err)});
978985 };
......@@ -1090,6 +1097,34 @@ pub const File = struct {
10901097 }
10911098 }
10921099
1100 pub fn isStatic(self: File) bool {
1101 return self.base.options.link_mode == .Static;
1102 }
1103
1104 pub fn isObject(self: File) bool {
1105 const output_mode = self.comp.config.output_mode;
1106 return output_mode == .Obj;
1107 }
1108
1109 pub fn isExe(self: File) bool {
1110 const output_mode = self.comp.config.output_mode;
1111 return output_mode == .Exe;
1112 }
1113
1114 pub fn isStaticLib(self: File) bool {
1115 const output_mode = self.comp.config.output_mode;
1116 return output_mode == .Lib and self.isStatic();
1117 }
1118
1119 pub fn isRelocatable(self: File) bool {
1120 return self.isObject() or self.isStaticLib();
1121 }
1122
1123 pub fn isDynLib(self: File) bool {
1124 const output_mode = self.comp.config.output_mode;
1125 return output_mode == .Lib and !self.isStatic();
1126 }
1127
10931128 pub const C = @import("link/C.zig");
10941129 pub const Coff = @import("link/Coff.zig");
10951130 pub const Plan9 = @import("link/Plan9.zig");
src/link/C.zig+34-20
......@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
55const fs = std.fs;
66
77const C = @This();
8const build_options = @import("build_options");
89const Module = @import("../Module.zig");
910const InternPool = @import("../InternPool.zig");
1011const Alignment = InternPool.Alignment;
......@@ -91,28 +92,40 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
9192 };
9293}
9394
94pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C {
95pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C {
9596 assert(options.target.ofmt == .c);
97 const optimize_mode = options.comp.root_mod.optimize_mode;
98 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
99 const use_llvm = options.comp.config.use_llvm;
96100
97 if (options.use_llvm) return error.LLVMHasNoCBackend;
98 if (options.use_lld) return error.LLDHasNoCBackend;
101 // These are caught by `Compilation.Config.resolve`.
102 assert(!use_lld);
103 assert(!use_llvm);
99104
100 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
105 const emit = options.emit;
106
107 const file = try emit.directory.handle.createFile(emit.sub_path, .{
101108 // Truncation is done on `flush`.
102109 .truncate = false,
103110 .mode = link.determineMode(options),
104111 });
105112 errdefer file.close();
106113
107 const c_file = try gpa.create(C);
108 errdefer gpa.destroy(c_file);
114 const c_file = try arena.create(C);
109115
110116 c_file.* = .{
111117 .base = .{
112118 .tag = .c,
113 .options = options,
119 .comp = options.comp,
120 .emit = emit,
121 .gc_sections = options.gc_sections orelse optimize_mode != .Debug,
122 .stack_size = options.stack_size orelse 16777216,
123 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
114124 .file = file,
115 .allocator = gpa,
125 .disable_lld_caching = options.disable_lld_caching,
126 .build_id = options.build_id,
127 .rpath_list = options.rpath_list,
128 .force_undefined_symbols = options.force_undefined_symbols,
116129 },
117130 };
118131
......@@ -120,7 +133,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
120133}
121134
122135pub fn deinit(self: *C) void {
123 const gpa = self.base.allocator;
136 const gpa = self.base.comp.gpa;
124137
125138 for (self.decl_table.values()) |*db| {
126139 db.deinit(gpa);
......@@ -141,7 +154,7 @@ pub fn deinit(self: *C) void {
141154}
142155
143156pub fn freeDecl(self: *C, decl_index: InternPool.DeclIndex) void {
144 const gpa = self.base.allocator;
157 const gpa = self.base.comp.gpa;
145158 if (self.decl_table.fetchSwapRemove(decl_index)) |kv| {
146159 var decl_block = kv.value;
147160 decl_block.deinit(gpa);
......@@ -155,7 +168,7 @@ pub fn updateFunc(
155168 air: Air,
156169 liveness: Liveness,
157170) !void {
158 const gpa = self.base.allocator;
171 const gpa = self.base.comp.gpa;
159172
160173 const func = module.funcInfo(func_index);
161174 const decl_index = func.owner_decl;
......@@ -223,7 +236,7 @@ pub fn updateFunc(
223236}
224237
225238fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
226 const gpa = self.base.allocator;
239 const gpa = self.base.comp.gpa;
227240 const anon_decl = self.anon_decls.keys()[i];
228241
229242 const fwd_decl = &self.fwd_decl_buf;
......@@ -285,7 +298,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: InternPool.DeclIndex) !
285298 const tracy = trace(@src());
286299 defer tracy.end();
287300
288 const gpa = self.base.allocator;
301 const gpa = self.base.comp.gpa;
289302
290303 const gop = try self.decl_table.getOrPut(gpa, decl_index);
291304 if (!gop.found_existing) {
......@@ -352,7 +365,8 @@ pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void
352365}
353366
354367fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
355 var defines = std.ArrayList(u8).init(self.base.allocator);
368 const gpa = self.base.comp.gpa;
369 var defines = std.ArrayList(u8).init(gpa);
356370 errdefer defines.deinit();
357371 const writer = defines.writer();
358372 switch (target.abi) {
......@@ -371,7 +385,7 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
371385 sub_prog_node.activate();
372386 defer sub_prog_node.end();
373387
374 const gpa = self.base.allocator;
388 const gpa = self.base.comp.gpa;
375389 const module = self.base.options.module.?;
376390
377391 {
......@@ -520,7 +534,7 @@ fn flushCTypes(
520534 pass: codegen.DeclGen.Pass,
521535 decl_ctypes: codegen.CType.Store,
522536) FlushDeclError!void {
523 const gpa = self.base.allocator;
537 const gpa = self.base.comp.gpa;
524538 const mod = self.base.options.module.?;
525539
526540 const decl_ctypes_len = decl_ctypes.count();
......@@ -601,7 +615,7 @@ fn flushCTypes(
601615}
602616
603617fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
604 const gpa = self.base.allocator;
618 const gpa = self.base.comp.gpa;
605619
606620 const fwd_decl = &self.lazy_fwd_decl_buf;
607621 const code = &self.lazy_code_buf;
......@@ -643,7 +657,7 @@ fn flushLazyFn(
643657 ctypes: *codegen.CType.Store,
644658 lazy_fn: codegen.LazyFnMap.Entry,
645659) FlushDeclError!void {
646 const gpa = self.base.allocator;
660 const gpa = self.base.comp.gpa;
647661
648662 const fwd_decl = &self.lazy_fwd_decl_buf;
649663 const code = &self.lazy_code_buf;
......@@ -683,7 +697,7 @@ fn flushLazyFn(
683697}
684698
685699fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
686 const gpa = self.base.allocator;
700 const gpa = self.base.comp.gpa;
687701 try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(lazy_fns.count()));
688702
689703 var it = lazy_fns.iterator();
......@@ -702,7 +716,7 @@ fn flushDeclBlock(
702716 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
703717 extern_symbol_name: InternPool.OptionalNullTerminatedString,
704718) FlushDeclError!void {
705 const gpa = self.base.allocator;
719 const gpa = self.base.comp.gpa;
706720 try self.flushLazyFns(f, decl_block.lazy_fns);
707721 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
708722 fwd_decl: {
src/link/Coff.zig+14-11
......@@ -232,7 +232,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {
232232 errdefer self.base.destroy();
233233
234234 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
235 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
235 const use_llvm = options.comp.config.use_llvm;
236236
237237 if (use_lld and use_llvm) {
238238 // LLVM emits the object file; LLD links it into the final product.
......@@ -353,6 +353,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {
353353
354354pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {
355355 const target = options.comp.root_mod.resolved_target.result;
356 const optimize_mode = options.comp.root_mod.optimize_mode;
356357 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
357358 0...32 => .p32,
358359 33...64 => .p64,
......@@ -367,14 +368,24 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {
367368 .tag = .coff,
368369 .comp = options.comp,
369370 .emit = options.emit,
371 .stack_size = options.stack_size orelse 16777216,
372 .gc_sections = options.gc_sections orelse (optimize_mode != .Debug),
373 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
370374 .file = null,
375 .disable_lld_caching = options.disable_lld_caching,
376 .build_id = options.build_id,
377 .rpath_list = options.rpath_list,
378 .force_undefined_symbols = options.force_undefined_symbols,
379 .debug_format = options.debug_format orelse .code_view,
380 .function_sections = options.function_sections,
381 .data_sections = options.data_sections,
371382 },
372383 .ptr_width = ptr_width,
373384 .page_size = page_size,
374385 .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory),
375386 };
376387
377 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
388 const use_llvm = options.comp.config.use_llvm;
378389 if (use_llvm and options.comp.config.have_zcu) {
379390 self.llvm_object = try LlvmObject.create(arena, options);
380391 }
......@@ -1494,8 +1505,6 @@ pub fn updateExports(
14941505
14951506 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
14961507
1497 if (self.base.options.emit == null) return;
1498
14991508 const gpa = self.base.comp.gpa;
15001509
15011510 const metadata = switch (exported) {
......@@ -1645,13 +1654,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
16451654}
16461655
16471656pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
1648 if (self.base.options.emit == null) {
1649 if (self.llvm_object) |llvm_object| {
1650 return try llvm_object.flushModule(comp, prog_node);
1651 }
1652 return;
1653 }
1654 const use_lld = build_options.have_llvm and self.base.options.use_lld;
1657 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
16551658 if (use_lld) {
16561659 return lld.linkWithLLD(self, comp, prog_node);
16571660 }
src/link/Coff/lld.zig+15-17
......@@ -25,8 +25,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
2525 defer arena_allocator.deinit();
2626 const arena = arena_allocator.allocator();
2727
28 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
29 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
28 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
29 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
3030
3131 // If there is no Zig code to compile, then we should skip flushing the output file because it
3232 // will not be part of the linker line anyway.
......@@ -50,6 +50,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
5050 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
5151 const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib;
5252 const target = self.base.options.target;
53 const optimize_mode = self.base.comp.root_mod.optimize_mode;
5354
5455 // See link/Elf.zig for comments on how this mechanism works.
5556 const id_symlink_basename = "lld.id";
......@@ -79,7 +80,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
7980 }
8081 try man.addOptionalFile(module_obj_path);
8182 man.hash.addOptionalBytes(self.base.options.entry);
82 man.hash.addOptional(self.base.options.stack_size_override);
83 man.hash.add(self.base.stack_size);
8384 man.hash.addOptional(self.base.options.image_base_override);
8485 man.hash.addListOfBytes(self.base.options.lib_dirs);
8586 man.hash.add(self.base.options.skip_linker_dependencies);
......@@ -93,14 +94,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
9394 }
9495 }
9596 }
96 try link.hashAddSystemLibs(&man, self.base.options.system_libs);
97 try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
9798 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
9899 man.hash.addOptional(self.base.options.subsystem);
99100 man.hash.add(self.base.options.is_test);
100101 man.hash.add(self.base.options.tsaware);
101102 man.hash.add(self.base.options.nxcompat);
102103 man.hash.add(self.base.options.dynamicbase);
103 man.hash.addOptional(self.base.options.allow_shlib_undefined);
104 man.hash.addOptional(self.base.allow_shlib_undefined);
104105 // strip does not need to go into the linker hash because it is part of the hash namespace
105106 man.hash.addOptional(self.base.options.major_subsystem_version);
106107 man.hash.addOptional(self.base.options.minor_subsystem_version);
......@@ -185,15 +186,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
185186 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
186187 }
187188 if (self.base.options.lto) {
188 switch (self.base.options.optimize_mode) {
189 switch (optimize_mode) {
189190 .Debug => {},
190191 .ReleaseSmall => try argv.append("-OPT:lldlto=2"),
191192 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),
192193 }
193194 }
194195 if (self.base.options.output_mode == .Exe) {
195 const stack_size = self.base.options.stack_size_override orelse 16777216;
196 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
196 try argv.append(try allocPrint(arena, "-STACK:{d}", .{self.base.stack_size}));
197197 }
198198 if (self.base.options.image_base_override) |image_base| {
199199 try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{image_base}));
......@@ -232,10 +232,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
232232 if (!self.base.options.dynamicbase) {
233233 try argv.append("-dynamicbase:NO");
234234 }
235 if (self.base.options.allow_shlib_undefined) |allow_shlib_undefined| {
236 if (allow_shlib_undefined) {
237 try argv.append("-FORCE:UNRESOLVED");
238 }
235 if (self.base.allow_shlib_undefined) {
236 try argv.append("-FORCE:UNRESOLVED");
239237 }
240238
241239 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
......@@ -419,7 +417,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
419417 try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib"));
420418
421419 for (mingw.always_link_libs) |name| {
422 if (!self.base.options.system_libs.contains(name)) {
420 if (!self.base.comp.system_libs.contains(name)) {
423421 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});
424422 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));
425423 }
......@@ -429,7 +427,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
429427 .Dynamic => "",
430428 .Static => "lib",
431429 };
432 const d_str = switch (self.base.options.optimize_mode) {
430 const d_str = switch (optimize_mode) {
433431 .Debug => "d",
434432 else => "",
435433 };
......@@ -489,8 +487,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
489487 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
490488 }
491489
492 try argv.ensureUnusedCapacity(self.base.options.system_libs.count());
493 for (self.base.options.system_libs.keys()) |key| {
490 try argv.ensureUnusedCapacity(self.base.comp.system_libs.count());
491 for (self.base.comp.system_libs.keys()) |key| {
494492 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
495493 if (comp.crt_files.get(lib_basename)) |crt_file| {
496494 argv.appendAssumeCapacity(crt_file.full_object_path);
......@@ -516,7 +514,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
516514 return error.DllImportLibraryNotFound;
517515 }
518516
519 if (self.base.options.verbose_link) {
517 if (self.base.comp.verbose_link) {
520518 // Skip over our own name so that the LLD linker name is the first argv item.
521519 Compilation.dump_argv(argv.items[1..]);
522520 }
src/link/Elf.zig+169-153
......@@ -206,7 +206,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
206206 assert(target.ofmt == .elf);
207207
208208 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
209 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
209 const use_llvm = options.comp.config.use_llvm;
210 const opt_zcu = options.comp.module;
211 const output_mode = options.comp.config.output_mode;
212 const link_mode = options.comp.config.link_mode;
210213
211214 const self = try createEmpty(arena, options);
212215 errdefer self.base.destroy();
......@@ -216,8 +219,8 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
216219 return self;
217220 }
218221
219 const is_obj = options.output_mode == .Obj;
220 const is_obj_or_ar = is_obj or (options.output_mode == .Lib and options.link_mode == .Static);
222 const is_obj = output_mode == .Obj;
223 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .Static);
221224
222225 const sub_path = if (!use_lld) options.emit.sub_path else p: {
223226 // Open a temporary object file, not the final output file because we
......@@ -229,10 +232,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
229232 break :p o_file_path;
230233 };
231234
232 self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{
235 self.base.file = try options.emit.directory.handle.createFile(sub_path, .{
233236 .truncate = false,
234237 .read = true,
235 .mode = link.determineMode(options),
238 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
236239 });
237240
238241 const gpa = options.comp.gpa;
......@@ -292,24 +295,34 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
292295 });
293296 }
294297
295 if (options.module != null and !options.use_llvm) {
296 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
297 self.files.set(index, .{ .zig_object = .{
298 .index = index,
299 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
300 options.module.?.main_mod.root_src_path,
301 )}),
302 } });
303 self.zig_object_index = index;
304 try self.zigObjectPtr().?.init(self);
305 try self.initMetadata();
298 if (opt_zcu) |zcu| {
299 if (!use_llvm) {
300 const index: File.Index = @intCast(try self.files.addOne(gpa));
301 self.files.set(index, .{ .zig_object = .{
302 .index = index,
303 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
304 zcu.main_mod.root_src_path,
305 )}),
306 } });
307 self.zig_object_index = index;
308 try self.zigObjectPtr().?.init(self);
309 try self.initMetadata(.{
310 .symbol_count_hint = options.symbol_count_hint,
311 .program_code_size_hint = options.program_code_size_hint,
312 });
313 }
306314 }
307315
308316 return self;
309317}
310318
311319pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
320 const use_llvm = options.comp.config.use_llvm;
321 const optimize_mode = options.comp.root_mod.optimize_mode;
312322 const target = options.comp.root_mod.resolved_target.result;
323 const output_mode = options.comp.config.output_mode;
324 const link_mode = options.comp.config.link_mode;
325 const is_native_os = options.comp.root_mod.resolved_target.is_native_os;
313326 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
314327 0...32 => .p32,
315328 33...64 => .p64,
......@@ -322,7 +335,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
322335 .sparc64 => 0x2000,
323336 else => 0x1000,
324337 };
325 const is_dyn_lib = options.output_mode == .Lib and options.link_mode == .Dynamic;
338 const is_dyn_lib = output_mode == .Lib and link_mode == .Dynamic;
326339 const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic)
327340 elf.VER_NDX_GLOBAL
328341 else
......@@ -333,13 +346,23 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
333346 .tag = .elf,
334347 .comp = options.comp,
335348 .emit = options.emit,
349 .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj),
350 .stack_size = options.stack_size orelse 16777216,
351 .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os,
336352 .file = null,
353 .disable_lld_caching = options.disable_lld_caching,
354 .build_id = options.build_id,
355 .rpath_list = options.rpath_list,
356 .force_undefined_symbols = options.force_undefined_symbols,
357 .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
358 .function_sections = options.function_sections,
359 .data_sections = options.data_sections,
337360 },
338361 .ptr_width = ptr_width,
339362 .page_size = page_size,
340363 .default_sym_version = default_sym_version,
341364 };
342 if (options.use_llvm and options.comp.config.have_zcu) {
365 if (use_llvm and options.comp.config.have_zcu) {
343366 self.llvm_object = try LlvmObject.create(arena, options);
344367 }
345368
......@@ -504,8 +527,13 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
504527 return start;
505528}
506529
530pub const InitMetadataOptions = struct {
531 symbol_count_hint: u64,
532 program_code_size_hint: u64,
533};
534
507535/// TODO move to ZigObject
508pub fn initMetadata(self: *Elf) !void {
536pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
509537 const gpa = self.base.comp.gpa;
510538 const ptr_size = self.ptrWidthBytes();
511539 const target = self.base.comp.root_mod.resolved_target.result;
......@@ -515,7 +543,7 @@ pub fn initMetadata(self: *Elf) !void {
515543
516544 const fillSection = struct {
517545 fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {
518 if (elf_file.isRelocatable()) {
546 if (elf_file.base.isRelocatable()) {
519547 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);
520548 shdr.sh_offset = off;
521549 shdr.sh_size = size;
......@@ -530,9 +558,9 @@ pub fn initMetadata(self: *Elf) !void {
530558
531559 comptime assert(number_of_zig_segments == 5);
532560
533 if (!self.isRelocatable()) {
561 if (!self.base.isRelocatable()) {
534562 if (self.phdr_zig_load_re_index == null) {
535 const filesz = self.base.options.program_code_size_hint;
563 const filesz = options.program_code_size_hint;
536564 const off = self.findFreeSpace(filesz, self.page_size);
537565 self.phdr_zig_load_re_index = try self.addPhdr(.{
538566 .type = elf.PT_LOAD,
......@@ -549,7 +577,7 @@ pub fn initMetadata(self: *Elf) !void {
549577 // We really only need ptr alignment but since we are using PROGBITS, linux requires
550578 // page align.
551579 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
552 const filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
580 const filesz = @as(u64, ptr_size) * options.symbol_count_hint;
553581 const off = self.findFreeSpace(filesz, alignment);
554582 self.phdr_zig_got_index = try self.addPhdr(.{
555583 .type = elf.PT_LOAD,
......@@ -613,8 +641,8 @@ pub fn initMetadata(self: *Elf) !void {
613641 .offset = std.math.maxInt(u64),
614642 });
615643 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
616 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
617 if (self.isRelocatable()) {
644 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
645 if (self.base.isRelocatable()) {
618646 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
619647 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
620648 .shndx = rela_shndx,
......@@ -630,7 +658,7 @@ pub fn initMetadata(self: *Elf) !void {
630658 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
631659 }
632660
633 if (self.zig_got_section_index == null and !self.isRelocatable()) {
661 if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
634662 self.zig_got_section_index = try self.addSection(.{
635663 .name = ".got.zig",
636664 .type = elf.SHT_PROGBITS,
......@@ -661,7 +689,7 @@ pub fn initMetadata(self: *Elf) !void {
661689 });
662690 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
663691 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
664 if (self.isRelocatable()) {
692 if (self.base.isRelocatable()) {
665693 const rela_shndx = try self.addRelaShdr(
666694 ".rela.data.rel.ro.zig",
667695 self.zig_data_rel_ro_section_index.?,
......@@ -690,7 +718,7 @@ pub fn initMetadata(self: *Elf) !void {
690718 });
691719 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
692720 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
693 if (self.isRelocatable()) {
721 if (self.base.isRelocatable()) {
694722 const rela_shndx = try self.addRelaShdr(
695723 ".rela.data.zig",
696724 self.zig_data_section_index.?,
......@@ -930,13 +958,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16) void {
930958}
931959
932960pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
933 if (self.base.options.emit == null) {
934 if (self.llvm_object) |llvm_object| {
935 try llvm_object.flushModule(comp, prog_node);
936 }
937 return;
938 }
939 const use_lld = build_options.have_llvm and self.base.options.use_lld;
961 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
940962 if (use_lld) {
941963 return self.linkWithLLD(comp, prog_node);
942964 }
......@@ -950,7 +972,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
950972 if (self.llvm_object) |llvm_object| {
951973 try llvm_object.flushModule(comp, prog_node);
952974
953 const use_lld = build_options.have_llvm and self.base.options.use_lld;
975 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
954976 if (use_lld) return;
955977 }
956978
......@@ -959,13 +981,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
959981 sub_prog_node.activate();
960982 defer sub_prog_node.end();
961983
962 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
984 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
963985 defer arena_allocator.deinit();
964986 const arena = arena_allocator.allocator();
965987
966988 const target = self.base.comp.root_mod.resolved_target.result;
967 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
968 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
989 const link_mode = self.base.comp.config.link_mode;
990 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
991 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
969992 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
970993 if (fs.path.dirname(full_out_path)) |dirname| {
971994 break :blk try fs.path.join(arena, &.{ dirname, path });
......@@ -973,10 +996,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
973996 break :blk path;
974997 }
975998 } else null;
976 const gc_sections = self.base.options.gc_sections orelse false;
999 const gc_sections = self.base.gc_sections;
9771000
9781001 // --verbose-link
979 if (self.base.options.verbose_link) try self.dumpArgv(comp);
1002 if (self.base.comp.verbose_link) try self.dumpArgv(comp);
9801003
9811004 const csu = try CsuObjects.init(arena, self.base.options, comp);
9821005 const compiler_rt_path: ?[]const u8 = blk: {
......@@ -986,8 +1009,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
9861009 };
9871010
9881011 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
989 if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
990 if (self.isObject()) return self.flushObject(comp, module_obj_path);
1012 if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
1013 if (self.base.isObject()) return self.flushObject(comp, module_obj_path);
9911014
9921015 // Here we will parse input positional and library files (if referenced).
9931016 // This will roughly match in any linker backend we support.
......@@ -1011,7 +1034,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10111034 if (module_obj_path) |path| try positionals.append(.{ .path = path });
10121035
10131036 // rpaths
1014 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);
1037 var rpath_table = std.StringArrayHashMap(void).init(gpa);
10151038 defer rpath_table.deinit();
10161039
10171040 for (self.base.options.rpath_list) |rpath| {
......@@ -1019,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10191042 }
10201043
10211044 if (self.base.options.each_lib_rpath) {
1022 var test_path = std.ArrayList(u8).init(self.base.allocator);
1045 var test_path = std.ArrayList(u8).init(gpa);
10231046 defer test_path.deinit();
10241047 for (self.base.options.lib_dirs) |lib_dir_path| {
1025 for (self.base.options.system_libs.keys()) |link_lib| {
1048 for (self.base.comp.system_libs.keys()) |link_lib| {
10261049 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
10271050 continue;
10281051 _ = try rpath_table.put(lib_dir_path, {});
......@@ -1064,8 +1087,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10641087
10651088 var system_libs = std.ArrayList(SystemLib).init(arena);
10661089
1067 try system_libs.ensureUnusedCapacity(self.base.options.system_libs.values().len);
1068 for (self.base.options.system_libs.values()) |lib_info| {
1090 try system_libs.ensureUnusedCapacity(self.base.comp.system_libs.values().len);
1091 for (self.base.comp.system_libs.values()) |lib_info| {
10691092 system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
10701093 }
10711094
......@@ -1127,7 +1150,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11271150 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
11281151 });
11291152 } else if (target.isMusl()) {
1130 const path = try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1153 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
11311154 .Static => "libc.a",
11321155 .Dynamic => "libc.so",
11331156 });
......@@ -1224,7 +1247,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12241247 if (self.entry_index == null) {
12251248 const entry: ?[]const u8 = entry: {
12261249 if (self.base.options.entry) |entry| break :entry entry;
1227 if (!self.isDynLib()) break :entry "_start";
1250 if (!self.base.isDynLib()) break :entry "_start";
12281251 break :entry null;
12291252 };
12301253 self.entry_index = if (entry) |name| self.globalByName(name) else null;
......@@ -1301,7 +1324,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13011324 try self.writeAtoms();
13021325 try self.writeSyntheticSections();
13031326
1304 if (self.entry_index == null and self.isExe()) {
1327 if (self.entry_index == null and self.base.isExe()) {
13051328 log.debug("flushing. no_entry_point_found = true", .{});
13061329 self.error_flags.no_entry_point_found = true;
13071330 } else {
......@@ -1531,13 +1554,15 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)
15311554
15321555/// --verbose-link output
15331556fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1534 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
1557 const gpa = self.base.comp.gpa;
1558 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
15351559 defer arena_allocator.deinit();
15361560 const arena = arena_allocator.allocator();
15371561
15381562 const target = self.base.comp.root_mod.resolved_target.result;
1539 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
1540 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
1563 const link_mode = self.base.comp.config.link_mode;
1564 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
1565 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
15411566 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
15421567 if (fs.path.dirname(full_out_path)) |dirname| {
15431568 break :blk try fs.path.join(arena, &.{ dirname, path });
......@@ -1545,7 +1570,6 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15451570 break :blk path;
15461571 }
15471572 } else null;
1548 const gc_sections = self.base.options.gc_sections orelse false;
15491573
15501574 const csu = try CsuObjects.init(arena, self.base.options, comp);
15511575 const compiler_rt_path: ?[]const u8 = blk: {
......@@ -1558,20 +1582,20 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15581582
15591583 try argv.append("zig");
15601584
1561 if (self.isStaticLib()) {
1585 if (self.base.isStaticLib()) {
15621586 try argv.append("ar");
15631587 } else {
15641588 try argv.append("ld");
15651589 }
15661590
1567 if (self.isObject()) {
1591 if (self.base.isObject()) {
15681592 try argv.append("-r");
15691593 }
15701594
15711595 try argv.append("-o");
15721596 try argv.append(full_out_path);
15731597
1574 if (self.isRelocatable()) {
1598 if (self.base.isRelocatable()) {
15751599 for (self.base.options.objects) |obj| {
15761600 try argv.append(obj.path);
15771601 }
......@@ -1591,7 +1615,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15911615 }
15921616 }
15931617
1594 if (self.isDynLib()) {
1618 if (self.base.isDynLib()) {
15951619 if (self.base.options.soname) |name| {
15961620 try argv.append("-soname");
15971621 try argv.append(name);
......@@ -1624,16 +1648,16 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
16241648 }
16251649 }
16261650
1627 if (self.base.options.stack_size_override) |ss| {
1628 try argv.append("-z");
1629 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
1630 }
1651 try argv.appendSlice(&.{
1652 "-z",
1653 try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),
1654 });
16311655
16321656 if (self.base.options.image_base_override) |image_base| {
16331657 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
16341658 }
16351659
1636 if (gc_sections) {
1660 if (self.base.gc_sections) {
16371661 try argv.append("--gc-sections");
16381662 }
16391663
......@@ -1666,11 +1690,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
16661690
16671691 if (self.isStatic()) {
16681692 try argv.append("-static");
1669 } else if (self.isDynLib()) {
1693 } else if (self.base.isDynLib()) {
16701694 try argv.append("-shared");
16711695 }
16721696
1673 if (self.base.options.pie and self.isExe()) {
1697 if (self.base.options.pie and self.base.isExe()) {
16741698 try argv.append("-pie");
16751699 }
16761700
......@@ -1741,11 +1765,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
17411765 // Shared libraries.
17421766 // Worst-case, we need an --as-needed argument for every lib, as well
17431767 // as one before and one after.
1744 try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
1768 try argv.ensureUnusedCapacity(self.base.comp.system_libs.keys().len * 2 + 2);
17451769 argv.appendAssumeCapacity("--as-needed");
17461770 var as_needed = true;
17471771
1748 for (self.base.options.system_libs.values()) |lib_info| {
1772 for (self.base.comp.system_libs.values()) |lib_info| {
17491773 const lib_as_needed = !lib_info.needed;
17501774 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
17511775 0b00, 0b11 => {},
......@@ -1780,7 +1804,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
17801804 // libc dep
17811805 if (self.base.options.link_libc) {
17821806 if (self.base.options.libc_installation != null) {
1783 const needs_grouping = self.base.options.link_mode == .Static;
1807 const needs_grouping = link_mode == .Static;
17841808 if (needs_grouping) try argv.append("--start-group");
17851809 try argv.appendSlice(target_util.libcFullLinkFlags(target));
17861810 if (needs_grouping) try argv.append("--end-group");
......@@ -1793,7 +1817,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
17931817 }
17941818 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
17951819 } else if (target.isMusl()) {
1796 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1820 try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {
17971821 .Static => "libc.a",
17981822 .Dynamic => "libc.so",
17991823 }));
......@@ -2006,6 +2030,7 @@ fn accessLibPath(
20062030 lib_name: []const u8,
20072031 link_mode: ?std.builtin.LinkMode,
20082032) !bool {
2033 const gpa = self.base.comp.gpa;
20092034 const sep = fs.path.sep_str;
20102035 const target = self.base.comp.root_mod.resolved_target.result;
20112036 test_path.clearRetainingCapacity();
......@@ -2021,7 +2046,7 @@ fn accessLibPath(
20212046 suffix,
20222047 });
20232048 if (checked_paths) |cpaths| {
2024 try cpaths.append(try self.base.allocator.dupe(u8, test_path.items));
2049 try cpaths.append(try gpa.dupe(u8, test_path.items));
20252050 }
20262051 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
20272052 error.FileNotFound => return false,
......@@ -2150,7 +2175,7 @@ fn markImportsExports(self: *Elf) void {
21502175 }
21512176 if (file_ptr.index() == file_index) {
21522177 global.flags.@"export" = true;
2153 if (elf_file.isDynLib() and vis != .PROTECTED) {
2178 if (elf_file.base.isDynLib() and vis != .PROTECTED) {
21542179 global.flags.import = true;
21552180 }
21562181 }
......@@ -2158,7 +2183,7 @@ fn markImportsExports(self: *Elf) void {
21582183 }
21592184 }.mark;
21602185
2161 if (!self.isDynLib()) {
2186 if (!self.base.isDynLib()) {
21622187 for (self.shared_objects.items) |index| {
21632188 for (self.file(index).?.globals()) |global_index| {
21642189 const global = self.symbol(global_index);
......@@ -2274,12 +2299,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
22742299 const tracy = trace(@src());
22752300 defer tracy.end();
22762301
2277 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
2302 const gpa = self.base.comp.gpa;
2303 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
22782304 defer arena_allocator.deinit();
22792305 const arena = arena_allocator.allocator();
22802306
2281 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
2282 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
2307 const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
2308 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
22832309
22842310 // If there is no Zig code to compile, then we should skip flushing the output file because it
22852311 // will not be part of the linker line anyway.
......@@ -2298,16 +2324,15 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
22982324 sub_prog_node.context.refresh();
22992325 defer sub_prog_node.end();
23002326
2301 const is_obj = self.base.options.output_mode == .Obj;
2302 const is_lib = self.base.options.output_mode == .Lib;
2303 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
2304 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
2327 const output_mode = self.base.comp.config.output_mode;
2328 const is_obj = output_mode == .Obj;
2329 const is_lib = output_mode == .Lib;
2330 const link_mode = self.base.comp.config.link_mode;
2331 const is_dyn_lib = link_mode == .Dynamic and is_lib;
2332 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
23052333 const have_dynamic_linker = self.base.options.link_libc and
2306 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
2334 link_mode == .Dynamic and is_exe_or_dyn_lib;
23072335 const target = self.base.comp.root_mod.resolved_target.result;
2308 const gc_sections = self.base.options.gc_sections orelse !is_obj;
2309 const stack_size = self.base.options.stack_size_override orelse 16777216;
2310 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
23112336 const compiler_rt_path: ?[]const u8 = blk: {
23122337 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
23132338 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
......@@ -2354,7 +2379,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
23542379 // installation sources because they are always a product of the compiler version + target information.
23552380 man.hash.addOptionalBytes(self.base.options.entry);
23562381 man.hash.addOptional(self.base.options.image_base_override);
2357 man.hash.add(gc_sections);
2382 man.hash.add(self.base.gc_sections);
23582383 man.hash.addOptional(self.base.options.sort_section);
23592384 man.hash.add(self.base.options.eh_frame_hdr);
23602385 man.hash.add(self.base.options.emit_relocs);
......@@ -2362,9 +2387,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
23622387 man.hash.addListOfBytes(self.base.options.lib_dirs);
23632388 man.hash.addListOfBytes(self.base.options.rpath_list);
23642389 man.hash.add(self.base.options.each_lib_rpath);
2365 if (self.base.options.output_mode == .Exe) {
2366 man.hash.add(stack_size);
2367 man.hash.add(self.base.options.build_id);
2390 if (output_mode == .Exe) {
2391 man.hash.add(self.base.stack_size);
2392 man.hash.add(self.base.build_id);
23682393 }
23692394 man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys());
23702395 man.hash.add(self.base.options.skip_linker_dependencies);
......@@ -2390,9 +2415,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
23902415 }
23912416 man.hash.addOptionalBytes(self.base.options.soname);
23922417 man.hash.addOptional(self.base.options.version);
2393 try link.hashAddSystemLibs(&man, self.base.options.system_libs);
2418 try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
23942419 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
2395 man.hash.add(allow_shlib_undefined);
2420 man.hash.add(self.base.allow_shlib_undefined);
23962421 man.hash.add(self.base.options.bind_global_refs_locally);
23972422 man.hash.add(self.base.options.compress_debug_sections);
23982423 man.hash.add(self.base.options.tsan);
......@@ -2432,7 +2457,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
24322457 // copy when generating relocatables. Normally, we would expect `lld -r` to work.
24332458 // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails
24342459 // before even generating the relocatable.
2435 if (self.base.options.output_mode == .Obj and
2460 if (output_mode == .Obj and
24362461 (self.base.options.lto or target.isBpfFreestanding()))
24372462 {
24382463 // In this case we must do a simple file copy
......@@ -2459,7 +2484,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
24592484 }
24602485 } else {
24612486 // Create an LLD command line and invoke it.
2462 var argv = std.ArrayList([]const u8).init(self.base.allocator);
2487 var argv = std.ArrayList([]const u8).init(gpa);
24632488 defer argv.deinit();
24642489 // We will invoke ourselves as a child process to gain access to LLD.
24652490 // This is necessary because LLD does not behave properly as a library -
......@@ -2503,15 +2528,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
25032528 .both => {}, // this is the default
25042529 }
25052530
2506 if (self.base.options.output_mode == .Exe) {
2507 try argv.append("-z");
2508 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}));
2531 if (output_mode == .Exe) {
2532 try argv.appendSlice(&.{
2533 "-z",
2534 try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),
2535 });
25092536
2510 switch (self.base.options.build_id) {
2537 switch (self.base.build_id) {
25112538 .none => {},
25122539 .fast, .uuid, .sha1, .md5 => {
25132540 try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
2514 @tagName(self.base.options.build_id),
2541 @tagName(self.base.build_id),
25152542 }));
25162543 },
25172544 .hexstring => |hs| {
......@@ -2536,7 +2563,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
25362563 try argv.append(arg);
25372564 }
25382565
2539 if (gc_sections) {
2566 if (self.base.gc_sections) {
25402567 try argv.append("--gc-sections");
25412568 }
25422569
......@@ -2615,7 +2642,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
26152642 try argv.append(arg);
26162643 }
26172644
2618 if (self.base.options.link_mode == .Static) {
2645 if (link_mode == .Static) {
26192646 if (target.cpu.arch.isArmOrThumb()) {
26202647 try argv.append("-Bstatic");
26212648 } else {
......@@ -2625,7 +2652,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
26252652 try argv.append("-shared");
26262653 }
26272654
2628 if (self.base.options.pie and self.base.options.output_mode == .Exe) {
2655 if (self.base.options.pie and output_mode == .Exe) {
26292656 try argv.append("-pie");
26302657 }
26312658
......@@ -2648,7 +2675,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
26482675 if (csu.crtbegin) |v| try argv.append(v);
26492676
26502677 // rpaths
2651 var rpath_table = std.StringHashMap(void).init(self.base.allocator);
2678 var rpath_table = std.StringHashMap(void).init(gpa);
26522679 defer rpath_table.deinit();
26532680 for (self.base.options.rpath_list) |rpath| {
26542681 if ((try rpath_table.fetchPut(rpath, {})) == null) {
......@@ -2664,7 +2691,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
26642691 if (self.base.options.each_lib_rpath) {
26652692 var test_path = std.ArrayList(u8).init(arena);
26662693 for (self.base.options.lib_dirs) |lib_dir_path| {
2667 for (self.base.options.system_libs.keys()) |link_lib| {
2694 for (self.base.comp.system_libs.keys()) |link_lib| {
26682695 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
26692696 continue;
26702697 if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
......@@ -2763,8 +2790,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
27632790
27642791 // Shared libraries.
27652792 if (is_exe_or_dyn_lib) {
2766 const system_libs = self.base.options.system_libs.keys();
2767 const system_libs_values = self.base.options.system_libs.values();
2793 const system_libs = self.base.comp.system_libs.keys();
2794 const system_libs_values = self.base.comp.system_libs.values();
27682795
27692796 // Worst-case, we need an --as-needed argument for every lib, as well
27702797 // as one before and one after.
......@@ -2813,7 +2840,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
28132840 self.error_flags.missing_libc = false;
28142841 if (self.base.options.link_libc) {
28152842 if (self.base.options.libc_installation != null) {
2816 const needs_grouping = self.base.options.link_mode == .Static;
2843 const needs_grouping = link_mode == .Static;
28172844 if (needs_grouping) try argv.append("--start-group");
28182845 try argv.appendSlice(target_util.libcFullLinkFlags(target));
28192846 if (needs_grouping) try argv.append("--end-group");
......@@ -2826,7 +2853,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
28262853 }
28272854 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
28282855 } else if (target.isMusl()) {
2829 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
2856 try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {
28302857 .Static => "libc.a",
28312858 .Dynamic => "libc.so",
28322859 }));
......@@ -2847,7 +2874,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
28472874 if (csu.crtend) |v| try argv.append(v);
28482875 if (csu.crtn) |v| try argv.append(v);
28492876
2850 if (allow_shlib_undefined) {
2877 if (self.base.allow_shlib_undefined) {
28512878 try argv.append("--allow-shlib-undefined");
28522879 }
28532880
......@@ -2861,7 +2888,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
28612888 try argv.append("-Bsymbolic");
28622889 }
28632890
2864 if (self.base.options.verbose_link) {
2891 if (self.base.comp.verbose_link) {
28652892 // Skip over our own name so that the LLD linker name is the first argv item.
28662893 Compilation.dump_argv(argv.items[1..]);
28672894 }
......@@ -3087,10 +3114,12 @@ fn writeElfHeader(self: *Elf) !void {
30873114
30883115 assert(index == 16);
30893116
3090 const elf_type: elf.ET = switch (self.base.options.output_mode) {
3117 const output_mode = self.base.comp.config.output_mode;
3118 const link_mode = self.base.comp.config.link_mode;
3119 const elf_type: elf.ET = switch (output_mode) {
30913120 .Exe => if (self.base.options.pie) .DYN else .EXEC,
30923121 .Obj => .REL,
3093 .Lib => switch (self.base.options.link_mode) {
3122 .Lib => switch (link_mode) {
30943123 .Static => @as(elf.ET, .REL),
30953124 .Dynamic => .DYN,
30963125 },
......@@ -3216,7 +3245,6 @@ pub fn updateExports(
32163245 @panic("Attempted to compile for object format that was disabled by build configuration");
32173246 }
32183247 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3219 if (self.base.options.emit == null) return;
32203248 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
32213249}
32223250
......@@ -3280,6 +3308,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
32803308}
32813309
32823310fn allocateLinkerDefinedSymbols(self: *Elf) void {
3311 const link_mode = self.base.comp.config.link_mode;
3312
32833313 // _DYNAMIC
32843314 if (self.dynamic_section_index) |shndx| {
32853315 const shdr = &self.shdrs.items[shndx];
......@@ -3362,7 +3392,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
33623392
33633393 // __rela_iplt_start, __rela_iplt_end
33643394 if (self.rela_dyn_section_index) |shndx| blk: {
3365 if (self.base.options.link_mode != .Static or self.base.options.pie) break :blk;
3395 if (link_mode != .Static or self.base.options.pie) break :blk;
33663396 const shdr = &self.shdrs.items[shndx];
33673397 const end_addr = shdr.sh_addr + shdr.sh_size;
33683398 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
......@@ -3531,7 +3561,7 @@ fn initSyntheticSections(self: *Elf) !void {
35313561 });
35323562 }
35333563
3534 if (self.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) {
3564 if (self.base.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) {
35353565 self.dynstrtab_section_index = try self.addSection(.{
35363566 .name = ".dynstr",
35373567 .flags = elf.SHF_ALLOC,
......@@ -3716,7 +3746,7 @@ fn initSpecialPhdrs(self: *Elf) !void {
37163746 self.phdr_gnu_stack_index = try self.addPhdr(.{
37173747 .type = elf.PT_GNU_STACK,
37183748 .flags = elf.PF_W | elf.PF_R,
3719 .memsz = self.base.options.stack_size_override orelse 0,
3749 .memsz = self.base.stack_size,
37203750 .@"align" = 1,
37213751 });
37223752
......@@ -3822,7 +3852,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
38223852 try self.dynamic.addNeeded(shared_object, self);
38233853 }
38243854
3825 if (self.isDynLib()) {
3855 if (self.base.isDynLib()) {
38263856 if (self.base.options.soname) |soname| {
38273857 try self.dynamic.setSoname(soname, self);
38283858 }
......@@ -3837,8 +3867,9 @@ fn sortDynamicSymtab(self: *Elf) void {
38373867}
38383868
38393869fn setVersionSymtab(self: *Elf) !void {
3870 const gpa = self.base.comp.gpa;
38403871 if (self.versym_section_index == null) return;
3841 try self.versym.resize(self.base.allocator, self.dynsym.count());
3872 try self.versym.resize(gpa, self.dynsym.count());
38423873 self.versym.items[0] = elf.VER_NDX_LOCAL;
38433874 for (self.dynsym.entries.items, 1..) |entry, i| {
38443875 const sym = self.symbol(entry.symbol_index);
......@@ -5597,38 +5628,14 @@ const CsuObjects = struct {
55975628};
55985629
55995630pub fn calcImageBase(self: Elf) u64 {
5600 if (self.isDynLib()) return 0;
5601 if (self.isExe() and self.base.options.pie) return 0;
5631 if (self.base.isDynLib()) return 0;
5632 if (self.base.isExe() and self.base.options.pie) return 0;
56025633 return self.base.options.image_base_override orelse switch (self.ptr_width) {
56035634 .p32 => 0x1000,
56045635 .p64 => 0x1000000,
56055636 };
56065637}
56075638
5608pub fn isStatic(self: Elf) bool {
5609 return self.base.options.link_mode == .Static;
5610}
5611
5612pub fn isObject(self: Elf) bool {
5613 return self.base.options.output_mode == .Obj;
5614}
5615
5616pub fn isExe(self: Elf) bool {
5617 return self.base.options.output_mode == .Exe;
5618}
5619
5620pub fn isStaticLib(self: Elf) bool {
5621 return self.base.options.output_mode == .Lib and self.isStatic();
5622}
5623
5624pub fn isRelocatable(self: Elf) bool {
5625 return self.isObject() or self.isStaticLib();
5626}
5627
5628pub fn isDynLib(self: Elf) bool {
5629 return self.base.options.output_mode == .Lib and !self.isStatic();
5630}
5631
56325639pub fn isZigSection(self: Elf, shndx: u16) bool {
56335640 inline for (&[_]?u16{
56345641 self.zig_text_section_index,
......@@ -5668,8 +5675,9 @@ fn addPhdr(self: *Elf, opts: struct {
56685675 filesz: u64 = 0,
56695676 memsz: u64 = 0,
56705677}) error{OutOfMemory}!u16 {
5678 const gpa = self.base.comp.gpa;
56715679 const index = @as(u16, @intCast(self.phdrs.items.len));
5672 try self.phdrs.append(self.base.allocator, .{
5680 try self.phdrs.append(gpa, .{
56735681 .p_type = opts.type,
56745682 .p_flags = opts.flags,
56755683 .p_offset = opts.offset,
......@@ -5818,8 +5826,9 @@ pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
58185826}
58195827
58205828pub fn addAtom(self: *Elf) !Atom.Index {
5829 const gpa = self.base.comp.gpa;
58215830 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
5822 const atom_ptr = try self.atoms.addOne(self.base.allocator);
5831 const atom_ptr = try self.atoms.addOne(gpa);
58235832 atom_ptr.* = .{ .atom_index = index };
58245833 return index;
58255834}
......@@ -5841,7 +5850,8 @@ pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
58415850}
58425851
58435852pub fn addSymbol(self: *Elf) !Symbol.Index {
5844 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
5853 const gpa = self.base.comp.gpa;
5854 try self.symbols.ensureUnusedCapacity(gpa, 1);
58455855 const index = blk: {
58465856 if (self.symbols_free_list.popOrNull()) |index| {
58475857 log.debug(" (reusing symbol index {d})", .{index});
......@@ -5858,8 +5868,9 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {
58585868}
58595869
58605870pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
5871 const gpa = self.base.comp.gpa;
58615872 const fields = @typeInfo(Symbol.Extra).Struct.fields;
5862 try self.symbols_extra.ensureUnusedCapacity(self.base.allocator, fields.len);
5873 try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len);
58635874 return self.addSymbolExtraAssumeCapacity(extra);
58645875}
58655876
......@@ -5959,8 +5970,9 @@ pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateC
59595970}
59605971
59615972pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index {
5973 const gpa = self.base.comp.gpa;
59625974 const index = @as(ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
5963 _ = try self.comdat_groups.addOne(self.base.allocator);
5975 _ = try self.comdat_groups.addOne(gpa);
59645976 return index;
59655977}
59665978
......@@ -6023,14 +6035,16 @@ const ErrorWithNotes = struct {
60236035};
60246036
60256037pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
6026 try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1);
6038 const gpa = self.base.comp.gpa;
6039 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
60276040 return self.addErrorWithNotesAssumeCapacity(note_count);
60286041}
60296042
60306043fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
6044 const gpa = self.base.comp.gpa;
60316045 const index = self.misc_errors.items.len;
60326046 const err = self.misc_errors.addOneAssumeCapacity();
6033 err.* = .{ .msg = undefined, .notes = try self.base.allocator.alloc(link.File.ErrorMsg, note_count) };
6047 err.* = .{ .msg = undefined, .notes = try gpa.alloc(link.File.ErrorMsg, note_count) };
60346048 return .{ .index = index };
60356049}
60366050
......@@ -6040,9 +6054,10 @@ pub fn getShString(self: Elf, off: u32) [:0]const u8 {
60406054}
60416055
60426056pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
6057 const gpa = self.base.comp.gpa;
60436058 const off = @as(u32, @intCast(self.shstrtab.items.len));
6044 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
6045 self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
6059 try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1);
6060 self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
60466061 return off;
60476062}
60486063
......@@ -6052,9 +6067,10 @@ pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
60526067}
60536068
60546069pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
6070 const gpa = self.base.comp.gpa;
60556071 const off = @as(u32, @intCast(self.dynstrtab.items.len));
6056 try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
6057 self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
6072 try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1);
6073 self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
60586074 return off;
60596075}
60606076
src/link/Elf/ZigObject.zig+56-45
......@@ -76,7 +76,7 @@ pub const symbol_mask: u32 = 0x7fffffff;
7676pub const SHN_ATOM: u16 = 0x100;
7777
7878pub fn init(self: *ZigObject, elf_file: *Elf) !void {
79 const gpa = elf_file.base.allocator;
79 const gpa = elf_file.base.comp.gpa;
8080
8181 try self.atoms.append(gpa, 0); // null input section
8282 try self.relocs.append(gpa, .{}); // null relocs section
......@@ -96,7 +96,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
9696 esym.st_shndx = elf.SHN_ABS;
9797 symbol_ptr.esym_index = esym_index;
9898
99 if (!elf_file.base.options.strip) {
99 if (elf_file.base.debug_format != .strip) {
100100 self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32);
101101 }
102102}
......@@ -155,13 +155,13 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
155155pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
156156 // Handle any lazy symbols that were emitted by incremental compilation.
157157 if (self.lazy_syms.getPtr(.none)) |metadata| {
158 const module = elf_file.base.options.module.?;
158 const zcu = elf_file.base.comp.module.?;
159159
160160 // Most lazy symbols can be updated on first use, but
161161 // anyerror needs to wait for everything to be flushed.
162162 if (metadata.text_state != .unused) self.updateLazySymbol(
163163 elf_file,
164 link.File.LazySymbol.initDecl(.code, null, module),
164 link.File.LazySymbol.initDecl(.code, null, zcu),
165165 metadata.text_symbol_index,
166166 ) catch |err| return switch (err) {
167167 error.CodegenFail => error.FlushFailure,
......@@ -169,7 +169,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
169169 };
170170 if (metadata.rodata_state != .unused) self.updateLazySymbol(
171171 elf_file,
172 link.File.LazySymbol.initDecl(.const_data, null, module),
172 link.File.LazySymbol.initDecl(.const_data, null, zcu),
173173 metadata.rodata_symbol_index,
174174 ) catch |err| return switch (err) {
175175 error.CodegenFail => error.FlushFailure,
......@@ -182,7 +182,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
182182 }
183183
184184 if (self.dwarf) |*dw| {
185 try dw.flushModule(elf_file.base.options.module.?);
185 const zcu = elf_file.base.comp.module.?;
186 try dw.flushModule(zcu);
186187
187188 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
188189 // extracted from input object files correctly.
......@@ -195,7 +196,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
195196 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
196197 const low_pc = text_shdr.sh_addr;
197198 const high_pc = text_shdr.sh_addr + text_shdr.sh_size;
198 try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);
199 try dw.writeDbgInfoHeader(zcu, low_pc, high_pc);
199200 self.debug_info_header_dirty = false;
200201 }
201202
......@@ -268,7 +269,7 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
268269}
269270
270271pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
271 const gpa = elf_file.base.allocator;
272 const gpa = elf_file.base.comp.gpa;
272273 const atom_index = try elf_file.addAtom();
273274 const symbol_index = try elf_file.addSymbol();
274275 const esym_index = try self.addLocalEsym(gpa);
......@@ -411,6 +412,7 @@ pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void {
411412}
412413
413414pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
415 const gpa = elf_file.base.comp.gpa;
414416 for (self.atoms.items) |atom_index| {
415417 const atom = elf_file.atom(atom_index) orelse continue;
416418 if (!atom.flags.alive) continue;
......@@ -421,7 +423,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
421423 // Perhaps it would make sense to save the code until flushModule where we
422424 // would free all of generated code?
423425 const code = try self.codeAlloc(elf_file, atom_index);
424 defer elf_file.base.allocator.free(code);
426 defer gpa.free(code);
425427 try atom.scanRelocs(elf_file, code, undefs);
426428 } else try atom.scanRelocs(elf_file, null, undefs);
427429 }
......@@ -447,7 +449,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
447449/// We need this so that we can write to an archive.
448450/// TODO implement writing ZigObject data directly to a buffer instead.
449451pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
450 const gpa = elf_file.base.allocator;
452 const gpa = elf_file.base.comp.gpa;
451453 const shsize: u64 = switch (elf_file.ptr_width) {
452454 .p32 => @sizeOf(elf.Elf32_Shdr),
453455 .p64 => @sizeOf(elf.Elf64_Shdr),
......@@ -465,7 +467,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
465467}
466468
467469pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
468 const gpa = elf_file.base.allocator;
470 const gpa = elf_file.base.comp.gpa;
469471
470472 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
471473
......@@ -508,7 +510,7 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
508510 const out_shdr = elf_file.shdrs.items[out_shndx];
509511 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
510512
511 const gpa = elf_file.base.allocator;
513 const gpa = elf_file.base.comp.gpa;
512514 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
513515 try sec.atom_list.append(gpa, atom_index);
514516 }
......@@ -602,7 +604,7 @@ pub fn asFile(self: *ZigObject) File {
602604/// Returns atom's code.
603605/// Caller owns the memory.
604606pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
605 const gpa = elf_file.base.allocator;
607 const gpa = elf_file.base.comp.gpa;
606608 const atom = elf_file.atom(atom_index).?;
607609 assert(atom.file_index == self.index);
608610 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
......@@ -668,8 +670,8 @@ pub fn lowerAnonDecl(
668670 explicit_alignment: InternPool.Alignment,
669671 src_loc: Module.SrcLoc,
670672) !codegen.Result {
671 const gpa = elf_file.base.allocator;
672 const mod = elf_file.base.options.module.?;
673 const gpa = elf_file.base.comp.gpa;
674 const mod = elf_file.base.comp.module.?;
673675 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
674676 const decl_alignment = switch (explicit_alignment) {
675677 .none => ty.abiAlignment(mod),
......@@ -716,8 +718,8 @@ pub fn getOrCreateMetadataForLazySymbol(
716718 elf_file: *Elf,
717719 lazy_sym: link.File.LazySymbol,
718720) !Symbol.Index {
719 const gpa = elf_file.base.allocator;
720 const mod = elf_file.base.options.module.?;
721 const gpa = elf_file.base.comp.gpa;
722 const mod = elf_file.base.comp.module.?;
721723 const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
722724 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
723725 if (!gop.found_existing) gop.value_ptr.* = .{};
......@@ -752,25 +754,28 @@ pub fn getOrCreateMetadataForLazySymbol(
752754}
753755
754756fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {
757 const gpa = elf_file.base.comp.gpa;
755758 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
756759 for (unnamed_consts.items) |sym_index| {
757760 self.freeDeclMetadata(elf_file, sym_index);
758761 }
759 unnamed_consts.clearAndFree(elf_file.base.allocator);
762 unnamed_consts.clearAndFree(gpa);
760763}
761764
762765fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
763766 _ = self;
767 const gpa = elf_file.base.comp.gpa;
764768 const sym = elf_file.symbol(sym_index);
765769 sym.atom(elf_file).?.free(elf_file);
766770 log.debug("adding %{d} to local symbols free list", .{sym_index});
767 elf_file.symbols_free_list.append(elf_file.base.allocator, sym_index) catch {};
771 elf_file.symbols_free_list.append(gpa, sym_index) catch {};
768772 elf_file.symbols.items[sym_index] = .{};
769773 // TODO free GOT entry here
770774}
771775
772776pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {
773 const mod = elf_file.base.options.module.?;
777 const gpa = elf_file.base.comp.gpa;
778 const mod = elf_file.base.comp.module.?;
774779 const decl = mod.declPtr(decl_index);
775780
776781 log.debug("freeDecl {*}", .{decl});
......@@ -780,7 +785,7 @@ pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclInd
780785 const sym_index = kv.value.symbol_index;
781786 self.freeDeclMetadata(elf_file, sym_index);
782787 self.freeUnnamedConsts(elf_file, decl_index);
783 kv.value.exports.deinit(elf_file.base.allocator);
788 kv.value.exports.deinit(gpa);
784789 }
785790
786791 if (self.dwarf) |*dw| {
......@@ -793,15 +798,16 @@ pub fn getOrCreateMetadataForDecl(
793798 elf_file: *Elf,
794799 decl_index: InternPool.DeclIndex,
795800) !Symbol.Index {
796 const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index);
801 const gpa = elf_file.base.comp.gpa;
802 const gop = try self.decls.getOrPut(gpa, decl_index);
797803 if (!gop.found_existing) {
798 const single_threaded = elf_file.base.options.single_threaded;
804 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
799805 const symbol_index = try self.addAtom(elf_file);
800 const mod = elf_file.base.options.module.?;
806 const mod = elf_file.base.comp.module.?;
801807 const decl = mod.declPtr(decl_index);
802808 const sym = elf_file.symbol(symbol_index);
803809 if (decl.getOwnedVariable(mod)) |variable| {
804 if (variable.is_threadlocal and !single_threaded) {
810 if (variable.is_threadlocal and any_non_single_threaded) {
805811 sym.flags.is_tls = true;
806812 }
807813 }
......@@ -820,13 +826,13 @@ fn getDeclShdrIndex(
820826 code: []const u8,
821827) error{OutOfMemory}!u16 {
822828 _ = self;
823 const mod = elf_file.base.options.module.?;
824 const single_threaded = elf_file.base.options.single_threaded;
829 const mod = elf_file.base.comp.module.?;
830 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
825831 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
826832 .Fn => elf_file.zig_text_section_index.?,
827833 else => blk: {
828834 if (decl.getOwnedVariable(mod)) |variable| {
829 if (variable.is_threadlocal and !single_threaded) {
835 if (variable.is_threadlocal and any_non_single_threaded) {
830836 const is_all_zeroes = for (code) |byte| {
831837 if (byte != 0) break false;
832838 } else true;
......@@ -846,9 +852,12 @@ fn getDeclShdrIndex(
846852 }
847853 if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?;
848854 if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
849 const mode = elf_file.base.options.optimize_mode;
850 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;
851 break :blk elf_file.zig_bss_section_index.?;
855 // TODO: get the optimize_mode from the Module that owns the decl instead
856 // of using the root module here.
857 break :blk switch (elf_file.base.comp.root_mod.optimize_mode) {
858 .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
859 .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
860 };
852861 }
853862 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
854863 // intrusive check for all zeroes than this?
......@@ -873,8 +882,8 @@ fn updateDeclCode(
873882 code: []const u8,
874883 stt_bits: u8,
875884) !void {
876 const gpa = elf_file.base.allocator;
877 const mod = elf_file.base.options.module.?;
885 const gpa = elf_file.base.comp.gpa;
886 const mod = elf_file.base.comp.module.?;
878887 const decl = mod.declPtr(decl_index);
879888 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
880889
......@@ -971,8 +980,8 @@ fn updateTlv(
971980 shndx: u16,
972981 code: []const u8,
973982) !void {
974 const gpa = elf_file.base.allocator;
975 const mod = elf_file.base.options.module.?;
983 const gpa = elf_file.base.comp.gpa;
984 const mod = elf_file.base.comp.module.?;
976985 const decl = mod.declPtr(decl_index);
977986 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
978987
......@@ -1026,6 +1035,7 @@ pub fn updateFunc(
10261035 const tracy = trace(@src());
10271036 defer tracy.end();
10281037
1038 const gpa = elf_file.base.comp.gpa;
10291039 const func = mod.funcInfo(func_index);
10301040 const decl_index = func.owner_decl;
10311041 const decl = mod.declPtr(decl_index);
......@@ -1034,7 +1044,7 @@ pub fn updateFunc(
10341044 self.freeUnnamedConsts(elf_file, decl_index);
10351045 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
10361046
1037 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
1047 var code_buffer = std.ArrayList(u8).init(gpa);
10381048 defer code_buffer.deinit();
10391049
10401050 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
......@@ -1117,7 +1127,8 @@ pub fn updateDecl(
11171127 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
11181128 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
11191129
1120 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
1130 const gpa = elf_file.base.comp.gpa;
1131 var code_buffer = std.ArrayList(u8).init(gpa);
11211132 defer code_buffer.deinit();
11221133
11231134 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
......@@ -1179,8 +1190,8 @@ fn updateLazySymbol(
11791190 sym: link.File.LazySymbol,
11801191 symbol_index: Symbol.Index,
11811192) !void {
1182 const gpa = elf_file.base.allocator;
1183 const mod = elf_file.base.options.module.?;
1193 const gpa = elf_file.base.comp.gpa;
1194 const mod = elf_file.base.comp.module.?;
11841195
11851196 var required_alignment: InternPool.Alignment = .none;
11861197 var code_buffer = std.ArrayList(u8).init(gpa);
......@@ -1261,8 +1272,8 @@ pub fn lowerUnnamedConst(
12611272 typed_value: TypedValue,
12621273 decl_index: InternPool.DeclIndex,
12631274) !u32 {
1264 const gpa = elf_file.base.allocator;
1265 const mod = elf_file.base.options.module.?;
1275 const gpa = elf_file.base.comp.gpa;
1276 const mod = elf_file.base.comp.module.?;
12661277 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
12671278 if (!gop.found_existing) {
12681279 gop.value_ptr.* = .{};
......@@ -1308,7 +1319,7 @@ fn lowerConst(
13081319 output_section_index: u16,
13091320 src_loc: Module.SrcLoc,
13101321) !LowerConstResult {
1311 const gpa = elf_file.base.allocator;
1322 const gpa = elf_file.base.comp.gpa;
13121323
13131324 var code_buffer = std.ArrayList(u8).init(gpa);
13141325 defer code_buffer.deinit();
......@@ -1364,7 +1375,7 @@ pub fn updateExports(
13641375 const tracy = trace(@src());
13651376 defer tracy.end();
13661377
1367 const gpa = elf_file.base.allocator;
1378 const gpa = elf_file.base.comp.gpa;
13681379 const metadata = switch (exported) {
13691380 .decl_index => |decl_index| blk: {
13701381 _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
......@@ -1467,7 +1478,7 @@ pub fn deleteDeclExport(
14671478 name: InternPool.NullTerminatedString,
14681479) void {
14691480 const metadata = self.decls.getPtr(decl_index) orelse return;
1470 const mod = elf_file.base.options.module.?;
1481 const mod = elf_file.base.comp.module.?;
14711482 const exp_name = mod.intern_pool.stringToSlice(name);
14721483 const esym_index = metadata.@"export"(self, exp_name) orelse return;
14731484 log.debug("deleting export '{s}'", .{exp_name});
......@@ -1485,7 +1496,7 @@ pub fn deleteDeclExport(
14851496
14861497pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
14871498 _ = lib_name;
1488 const gpa = elf_file.base.allocator;
1499 const gpa = elf_file.base.comp.gpa;
14891500 const off = try self.strtab.insert(gpa, name);
14901501 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
14911502 if (!lookup_gop.found_existing) {
src/link/MachO.zig+94-51
......@@ -144,6 +144,35 @@ tlv_table: TlvSymbolTable = .{},
144144hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
145145
146146darwin_sdk_layout: ?SdkLayout,
147/// Size of the __PAGEZERO segment.
148pagezero_vmsize: u64,
149/// Minimum space for future expansion of the load commands.
150headerpad_size: u32,
151/// Set enough space as if all paths were MATPATHLEN.
152headerpad_max_install_names: bool,
153/// Remove dylibs that are unreachable by the entry point or exported symbols.
154dead_strip_dylibs: bool,
155frameworks: []const Framework,
156/// Install name for the dylib.
157/// TODO: unify with soname
158install_name: ?[]const u8,
159/// Path to entitlements file.
160entitlements: ?[]const u8,
161
162/// When adding a new field, remember to update `hashAddFrameworks`.
163pub const Framework = struct {
164 needed: bool = false,
165 weak: bool = false,
166 path: []const u8,
167};
168
169pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
170 for (hm) |value| {
171 man.hash.add(value.needed);
172 man.hash.add(value.weak);
173 _ = try man.addFile(value.path, null);
174 }
175}
147176
148177/// The filesystem layout of darwin SDK elements.
149178pub const SdkLayout = enum {
......@@ -156,12 +185,14 @@ pub const SdkLayout = enum {
156185pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
157186 if (build_options.only_c) unreachable;
158187 const target = options.comp.root_mod.resolved_target.result;
188 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
189 const use_llvm = options.comp.config.use_llvm;
159190 assert(target.ofmt == .macho);
160191
161192 const gpa = options.comp.gpa;
162193 const emit = options.emit;
163194 const mode: Mode = mode: {
164 if (options.use_llvm or options.module == null or options.cache_mode == .whole)
195 if (use_llvm or options.module == null or options.cache_mode == .whole)
165196 break :mode .zld;
166197 break :mode .incremental;
167198 };
......@@ -192,7 +223,11 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
192223 const file = try emit.directory.handle.createFile(sub_path, .{
193224 .truncate = false,
194225 .read = true,
195 .mode = link.determineMode(options),
226 .mode = link.File.determineMode(
227 use_lld,
228 options.comp.config.output_mode,
229 options.comp.config.link_mode,
230 ),
196231 });
197232 self.base.file = file;
198233
......@@ -242,21 +277,37 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
242277
243278pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {
244279 const self = try arena.create(MachO);
280 const optimize_mode = options.comp.root_mod.optimize_mode;
281 const use_llvm = options.comp.config.use_llvm;
245282
246283 self.* = .{
247284 .base = .{
248285 .tag = .macho,
249286 .comp = options.comp,
250287 .emit = options.emit,
288 .gc_sections = options.gc_sections orelse (optimize_mode != .Debug),
289 .stack_size = options.stack_size orelse 16777216,
290 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
251291 .file = null,
292 .disable_lld_caching = options.disable_lld_caching,
293 .build_id = options.build_id,
294 .rpath_list = options.rpath_list,
295 .force_undefined_symbols = options.force_undefined_symbols,
296 .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
297 .function_sections = options.function_sections,
298 .data_sections = options.data_sections,
252299 },
253 .mode = if (options.use_llvm or options.module == null or options.cache_mode == .whole)
300 .mode = if (use_llvm or options.module == null or options.cache_mode == .whole)
254301 .zld
255302 else
256303 .incremental,
304 .pagezero_vmsize = options.pagezero_size orelse default_pagezero_vmsize,
305 .headerpad_size = options.headerpad_size orelse default_headerpad_size,
306 .headerpad_max_install_names = options.headerpad_max_install_names,
307 .dead_strip_dylibs = options.dead_strip_dylibs,
257308 };
258309
259 if (options.use_llvm and options.module != null) {
310 if (use_llvm and options.module != null) {
260311 self.llvm_object = try LlvmObject.create(arena, options);
261312 }
262313
......@@ -267,8 +318,9 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {
267318
268319pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
269320 const gpa = self.base.comp.gpa;
321 const output_mode = self.base.comp.config.output_mode;
270322
271 if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) {
323 if (output_mode == .Lib and self.base.options.link_mode == .Static) {
272324 if (build_options.have_llvm) {
273325 return self.base.linkAsArchive(comp, prog_node);
274326 } else {
......@@ -303,6 +355,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
303355 sub_prog_node.activate();
304356 defer sub_prog_node.end();
305357
358 const output_mode = self.base.comp.config.output_mode;
306359 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
307360
308361 if (self.lazy_syms.getPtr(.none)) |metadata| {
......@@ -335,7 +388,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
335388 }
336389
337390 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
338 try self.resolveLibSystem(arena, comp, &.{}, &libs);
391 try self.resolveLibSystem(arena, comp, &libs);
339392
340393 const id_symlink_basename = "link.id";
341394
......@@ -446,7 +499,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
446499 try self.createDyldPrivateAtom();
447500 try self.writeStubHelperPreamble();
448501
449 if (self.base.options.output_mode == .Exe and self.getEntryPoint() != null) {
502 if (output_mode == .Exe and self.getEntryPoint() != null) {
450503 const global = self.getEntryPoint().?;
451504 if (self.getSymbol(global).undf()) {
452505 // We do one additional check here in case the entry point was found in one of the dylibs.
......@@ -517,8 +570,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
517570 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
518571 // where the code signature goes into.
519572 var codesig = CodeSignature.init(getPageSize(self.base.options.target.cpu.arch));
520 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
521 if (self.base.options.entitlements) |path| {
573 codesig.code_directory.ident = self.base.emit.sub_path;
574 if (self.entitlements) |path| {
522575 try codesig.addEntitlements(gpa, path);
523576 }
524577 try self.writeCodeSignaturePadding(&codesig);
......@@ -536,7 +589,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
536589 try lc_writer.writeStruct(self.dysymtab_cmd);
537590 try load_commands.writeDylinkerLC(lc_writer);
538591
539 switch (self.base.options.output_mode) {
592 switch (output_mode) {
540593 .Exe => blk: {
541594 const seg_id = self.header_segment_cmd_index.?;
542595 const seg = self.segments.items[seg_id];
......@@ -552,7 +605,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
552605
553606 try lc_writer.writeStruct(macho.entry_point_command{
554607 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),
555 .stacksize = self.base.options.stack_size_override orelse 0,
608 .stacksize = self.base.stack_size,
556609 });
557610 },
558611 .Lib => if (self.base.options.link_mode == .Dynamic) {
......@@ -591,7 +644,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
591644
592645 if (codesig) |*csig| {
593646 try self.writeCodeSignature(comp, csig); // code signing always comes last
594 const emit = self.base.options.emit.?;
647 const emit = self.base.emit;
595648 try invalidateKernelCache(emit.directory.handle, emit.sub_path);
596649 }
597650
......@@ -642,34 +695,20 @@ pub fn resolveLibSystem(
642695 self: *MachO,
643696 arena: Allocator,
644697 comp: *Compilation,
645 search_dirs: []const []const u8,
646698 out_libs: anytype,
647699) !void {
648 const gpa = self.base.comp.gpa;
649 var tmp_arena_allocator = std.heap.ArenaAllocator.init(gpa);
650 defer tmp_arena_allocator.deinit();
651 const tmp_arena = tmp_arena_allocator.allocator();
652
653 var test_path = std.ArrayList(u8).init(tmp_arena);
654 var checked_paths = std.ArrayList([]const u8).init(tmp_arena);
700 var test_path = std.ArrayList(u8).init(arena);
701 var checked_paths = std.ArrayList([]const u8).init(arena);
655702
656703 success: {
657 for (search_dirs) |dir| if (try accessLibPath(
658 tmp_arena,
659 &test_path,
660 &checked_paths,
661 dir,
662 "libSystem",
663 )) break :success;
664
665704 if (self.base.options.darwin_sdk_layout) |sdk_layout| switch (sdk_layout) {
666705 .sdk => {
667 const dir = try fs.path.join(tmp_arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" });
668 if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
706 const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" });
707 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
669708 },
670709 .vendored => {
671 const dir = try comp.zig_lib_directory.join(tmp_arena, &[_][]const u8{ "libc", "darwin" });
672 if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
710 const dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "darwin" });
711 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
673712 },
674713 };
675714
......@@ -1082,7 +1121,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts, ctx: *ParseErr
10821121 try self.dylibs.append(gpa, dylib);
10831122
10841123 const should_link_dylib_even_if_unreachable = blk: {
1085 if (self.base.options.dead_strip_dylibs and !dylib_options.needed) break :blk false;
1124 if (self.dead_strip_dylibs and !dylib_options.needed) break :blk false;
10861125 break :blk !(dylib_options.dependent or self.referenced_dylibs.contains(gop.value_ptr.*));
10871126 };
10881127
......@@ -1597,7 +1636,8 @@ fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: S
15971636}
15981637
15991638pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {
1600 if (self.base.options.output_mode != .Exe) return;
1639 const output_mode = self.base.comp.config.output_mode;
1640 if (output_mode != .Exe) return;
16011641
16021642 const gpa = self.base.comp.gpa;
16031643 const sym_index = try self.allocateSymbol();
......@@ -1647,10 +1687,11 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {
16471687}
16481688
16491689pub fn resolveSymbols(self: *MachO) !void {
1690 const output_mode = self.base.comp.config.output_mode;
16501691 // We add the specified entrypoint as the first unresolved symbols so that
16511692 // we search for it in libraries should there be no object files specified
16521693 // on the linker line.
1653 if (self.base.options.output_mode == .Exe) {
1694 if (output_mode == .Exe) {
16541695 const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
16551696 _ = try self.addUndefined(entry_name, .{});
16561697 }
......@@ -1867,9 +1908,10 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
18671908}
18681909
18691910fn resolveSymbolsAtLoading(self: *MachO) !void {
1870 const is_lib = self.base.options.output_mode == .Lib;
1911 const output_mode = self.base.comp.config.output_mode;
1912 const is_lib = output_mode == .Lib;
18711913 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
1872 const allow_undef = is_dyn_lib and (self.base.options.allow_shlib_undefined orelse false);
1914 const allow_undef = is_dyn_lib and self.base.allow_shlib_undefined;
18731915
18741916 var next_sym: usize = 0;
18751917 while (next_sym < self.unresolved.count()) {
......@@ -2674,12 +2716,12 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {
26742716 const val = decl.val;
26752717 const mod = self.base.options.module.?;
26762718 const zig_ty = ty.zigTypeTag(mod);
2677 const mode = self.base.options.optimize_mode;
2678 const single_threaded = self.base.options.single_threaded;
2719 const any_non_single_threaded = self.base.comp.config.any_non_single_threaded;
2720 const optimize_mode = self.base.comp.root_mod.optimize_mode;
26792721 const sect_id: u8 = blk: {
26802722 // TODO finish and audit this function
26812723 if (val.isUndefDeep(mod)) {
2682 if (mode == .ReleaseFast or mode == .ReleaseSmall) {
2724 if (optimize_mode == .ReleaseFast or optimize_mode == .ReleaseSmall) {
26832725 @panic("TODO __DATA,__bss");
26842726 } else {
26852727 break :blk self.data_section_index.?;
......@@ -2687,7 +2729,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {
26872729 }
26882730
26892731 if (val.getVariable(mod)) |variable| {
2690 if (variable.is_threadlocal and !single_threaded) {
2732 if (variable.is_threadlocal and any_non_single_threaded) {
26912733 break :blk self.thread_data_section_index.?;
26922734 }
26932735 break :blk self.data_section_index.?;
......@@ -2796,8 +2838,6 @@ pub fn updateExports(
27962838 if (self.llvm_object) |llvm_object|
27972839 return llvm_object.updateExports(mod, exported, exports);
27982840
2799 if (self.base.options.emit == null) return;
2800
28012841 const tracy = trace(@src());
28022842 defer tracy.end();
28032843
......@@ -3093,7 +3133,7 @@ fn populateMissingMetadata(self: *MachO) !void {
30933133 if (self.header_segment_cmd_index == null) {
30943134 // The first __TEXT segment is immovable and covers MachO header and load commands.
30953135 self.header_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));
3096 const ideal_size = @max(self.base.options.headerpad_size orelse 0, default_headerpad_size);
3136 const ideal_size = self.headerpad_size;
30973137 const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), getPageSize(cpu_arch));
30983138
30993139 log.debug("found __TEXT segment (header-only) free space 0x{x} to 0x{x}", .{ 0, needed_size });
......@@ -3222,13 +3262,13 @@ fn populateMissingMetadata(self: *MachO) !void {
32223262}
32233263
32243264fn calcPagezeroSize(self: *MachO) u64 {
3225 const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;
3265 const output_mode = self.base.comp.config.output_mode;
32263266 const page_size = getPageSize(self.base.options.target.cpu.arch);
3227 const aligned_pagezero_vmsize = mem.alignBackward(u64, pagezero_vmsize, page_size);
3228 if (self.base.options.output_mode == .Lib) return 0;
3267 const aligned_pagezero_vmsize = mem.alignBackward(u64, self.pagezero_vmsize, page_size);
3268 if (output_mode == .Lib) return 0;
32293269 if (aligned_pagezero_vmsize == 0) return 0;
3230 if (aligned_pagezero_vmsize != pagezero_vmsize) {
3231 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
3270 if (aligned_pagezero_vmsize != self.pagezero_vmsize) {
3271 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{self.pagezero_vmsize});
32323272 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
32333273 }
32343274 return aligned_pagezero_vmsize;
......@@ -4685,6 +4725,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
46854725}
46864726
46874727pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void {
4728 const output_mode = self.base.comp.config.output_mode;
46884729 const seg_id = self.header_segment_cmd_index.?;
46894730 const seg = self.segments.items[seg_id];
46904731 const offset = self.codesig_cmd.dataoff;
......@@ -4698,7 +4739,7 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod
46984739 .exec_seg_base = seg.fileoff,
46994740 .exec_seg_limit = seg.filesize,
47004741 .file_size = offset,
4701 .output_mode = self.base.options.output_mode,
4742 .output_mode = output_mode,
47024743 }, buffer.writer());
47034744 assert(buffer.items.len == code_sig.size());
47044745
......@@ -4712,6 +4753,8 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod
47124753
47134754/// Writes Mach-O file header.
47144755pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
4756 const output_mode = self.base.comp.config.output_mode;
4757
47154758 var header: macho.mach_header_64 = .{};
47164759 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
47174760
......@@ -4727,7 +4770,7 @@ pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
47274770 else => unreachable,
47284771 }
47294772
4730 switch (self.base.options.output_mode) {
4773 switch (output_mode) {
47314774 .Exe => {
47324775 header.filetype = macho.MH_EXECUTE;
47334776 },
src/link/MachO/zld.zig+73-86
......@@ -6,20 +6,21 @@ pub fn linkWithZld(
66 const tracy = trace(@src());
77 defer tracy.end();
88
9 const gpa = macho_file.base.allocator;
10 const options = &macho_file.base.options;
11 const target = options.target;
9 const gpa = macho_file.base.comp.gpa;
10 const target = macho_file.base.comp.root_mod.resolved_target.result;
11 const emit = macho_file.base.emit;
1212
1313 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
1414 defer arena_allocator.deinit();
1515 const arena = arena_allocator.allocator();
1616
17 const directory = options.emit.?.directory; // Just an alias to make it shorter to type.
18 const full_out_path = try directory.join(arena, &[_][]const u8{options.emit.?.sub_path});
17 const directory = emit.directory; // Just an alias to make it shorter to type.
18 const full_out_path = try directory.join(arena, &[_][]const u8{emit.?.sub_path});
19 const opt_zcu = macho_file.base.comp.module;
1920
2021 // If there is no Zig code to compile, then we should skip flushing the output file because it
2122 // will not be part of the linker line anyway.
22 const module_obj_path: ?[]const u8 = if (options.module != null) blk: {
23 const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: {
2324 try macho_file.flushModule(comp, prog_node);
2425
2526 if (fs.path.dirname(full_out_path)) |dirname| {
......@@ -34,22 +35,24 @@ pub fn linkWithZld(
3435 sub_prog_node.context.refresh();
3536 defer sub_prog_node.end();
3637
38 const output_mode = macho_file.base.comp.config.output_mode;
39 const link_mode = macho_file.base.comp.config.link_mode;
3740 const cpu_arch = target.cpu.arch;
38 const is_lib = options.output_mode == .Lib;
39 const is_dyn_lib = options.link_mode == .Dynamic and is_lib;
40 const is_exe_or_dyn_lib = is_dyn_lib or options.output_mode == .Exe;
41 const stack_size = options.stack_size_override orelse 0;
42 const is_debug_build = options.optimize_mode == .Debug;
43 const gc_sections = options.gc_sections orelse !is_debug_build;
41 const is_lib = output_mode == .Lib;
42 const is_dyn_lib = link_mode == .Dynamic and is_lib;
43 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
44 const stack_size = macho_file.base.stack_size;
4445
4546 const id_symlink_basename = "zld.id";
4647
4748 var man: Cache.Manifest = undefined;
48 defer if (!options.disable_lld_caching) man.deinit();
49 defer if (!macho_file.base.disable_lld_caching) man.deinit();
4950
5051 var digest: [Cache.hex_digest_len]u8 = undefined;
5152
52 if (!options.disable_lld_caching) {
53 const objects = macho_file.base.comp.objects;
54
55 if (!macho_file.base.disable_lld_caching) {
5356 man = comp.cache_parent.obtain();
5457
5558 // We are about to obtain this lock, so here we give other processes a chance first.
......@@ -57,7 +60,7 @@ pub fn linkWithZld(
5760
5861 comptime assert(Compilation.link_hash_implementation_version == 10);
5962
60 for (options.objects) |obj| {
63 for (objects) |obj| {
6164 _ = try man.addFile(obj.path, null);
6265 man.hash.add(obj.must_link);
6366 }
......@@ -68,24 +71,22 @@ pub fn linkWithZld(
6871 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
6972 // installation sources because they are always a product of the compiler version + target information.
7073 man.hash.add(stack_size);
71 man.hash.addOptional(options.pagezero_size);
72 man.hash.addOptional(options.headerpad_size);
73 man.hash.add(options.headerpad_max_install_names);
74 man.hash.add(gc_sections);
75 man.hash.add(options.dead_strip_dylibs);
76 man.hash.add(options.strip);
77 man.hash.addListOfBytes(options.lib_dirs);
78 man.hash.addListOfBytes(options.framework_dirs);
79 try link.hashAddFrameworks(&man, options.frameworks);
80 man.hash.addListOfBytes(options.rpath_list);
74 man.hash.addOptional(macho_file.pagezero_vmsize);
75 man.hash.addOptional(macho_file.headerpad_size);
76 man.hash.add(macho_file.headerpad_max_install_names);
77 man.hash.add(macho_file.base.gc_sections);
78 man.hash.add(macho_file.dead_strip_dylibs);
79 man.hash.add(macho_file.base.comp.root_mod.strip);
80 try MachO.hashAddFrameworks(&man, macho_file.frameworks);
81 man.hash.addListOfBytes(macho_file.rpath_list);
8182 if (is_dyn_lib) {
82 man.hash.addOptionalBytes(options.install_name);
83 man.hash.addOptional(options.version);
83 man.hash.addOptionalBytes(macho_file.install_name);
84 man.hash.addOptional(comp.version);
8485 }
85 try link.hashAddSystemLibs(&man, options.system_libs);
86 man.hash.addOptionalBytes(options.sysroot);
87 man.hash.addListOfBytes(options.force_undefined_symbols.keys());
88 try man.addOptionalFile(options.entitlements);
86 try link.hashAddSystemLibs(&man, comp.system_libs);
87 man.hash.addOptionalBytes(comp.sysroot);
88 man.hash.addListOfBytes(macho_file.base.force_undefined_symbols.keys());
89 try man.addOptionalFile(macho_file.entitlements);
8990
9091 // We don't actually care whether it's a cache hit or miss; we just
9192 // need the digest and the lock.
......@@ -125,13 +126,13 @@ pub fn linkWithZld(
125126 };
126127 }
127128
128 if (options.output_mode == .Obj) {
129 if (output_mode == .Obj) {
129130 // LLD's MachO driver does not support the equivalent of `-r` so we do a simple file copy
130131 // here. TODO: think carefully about how we can avoid this redundant operation when doing
131132 // build-obj. See also the corresponding TODO in linkAsArchive.
132133 const the_object_path = blk: {
133 if (options.objects.len != 0) {
134 break :blk options.objects[0].path;
134 if (objects.len != 0) {
135 break :blk objects[0].path;
135136 }
136137
137138 if (comp.c_object_table.count() != 0)
......@@ -150,7 +151,7 @@ pub fn linkWithZld(
150151 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
151152 }
152153 } else {
153 const sub_path = options.emit.?.sub_path;
154 const sub_path = emit.?.sub_path;
154155
155156 const old_file = macho_file.base.file; // TODO is this needed at all?
156157 defer macho_file.base.file = old_file;
......@@ -158,7 +159,7 @@ pub fn linkWithZld(
158159 const file = try directory.handle.createFile(sub_path, .{
159160 .truncate = true,
160161 .read = true,
161 .mode = link.determineMode(options.*),
162 .mode = link.File.determineMode(false, output_mode, link_mode),
162163 });
163164 defer file.close();
164165 macho_file.base.file = file;
......@@ -175,8 +176,8 @@ pub fn linkWithZld(
175176
176177 // Positional arguments to the linker such as object files and static archives.
177178 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
178 try positionals.ensureUnusedCapacity(options.objects.len);
179 positionals.appendSliceAssumeCapacity(options.objects);
179 try positionals.ensureUnusedCapacity(objects.len);
180 positionals.appendSliceAssumeCapacity(objects);
180181
181182 for (comp.c_object_table.keys()) |key| {
182183 try positionals.append(.{ .path = key.status.success.object_path });
......@@ -190,7 +191,7 @@ pub fn linkWithZld(
190191 if (comp.compiler_rt_obj) |obj| try positionals.append(.{ .path = obj.full_object_path });
191192
192193 // libc++ dep
193 if (options.link_libcpp) {
194 if (comp.config.link_libcpp) {
194195 try positionals.ensureUnusedCapacity(2);
195196 positionals.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
196197 positionals.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
......@@ -199,23 +200,23 @@ pub fn linkWithZld(
199200 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
200201
201202 {
202 const vals = options.system_libs.values();
203 const vals = comp.system_libs.values();
203204 try libs.ensureUnusedCapacity(vals.len);
204205 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);
205206 }
206207
207208 {
208 try libs.ensureUnusedCapacity(options.frameworks.len);
209 for (options.frameworks) |v| libs.putAssumeCapacity(v.path, .{
209 try libs.ensureUnusedCapacity(macho_file.frameworks.len);
210 for (macho_file.frameworks) |v| libs.putAssumeCapacity(v.path, .{
210211 .needed = v.needed,
211212 .weak = v.weak,
212213 .path = v.path,
213214 });
214215 }
215216
216 try macho_file.resolveLibSystem(arena, comp, options.lib_dirs, &libs);
217 try macho_file.resolveLibSystem(arena, comp, &libs);
217218
218 if (options.verbose_link) {
219 if (comp.verbose_link) {
219220 var argv = std.ArrayList([]const u8).init(arena);
220221
221222 try argv.append("zig");
......@@ -228,14 +229,14 @@ pub fn linkWithZld(
228229 if (is_dyn_lib) {
229230 try argv.append("-dylib");
230231
231 if (options.install_name) |install_name| {
232 if (macho_file.install_name) |install_name| {
232233 try argv.append("-install_name");
233234 try argv.append(install_name);
234235 }
235236 }
236237
237238 {
238 const platform = Platform.fromTarget(options.target);
239 const platform = Platform.fromTarget(target);
239240 try argv.append("-platform_version");
240241 try argv.append(@tagName(platform.os_tag));
241242 try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version}));
......@@ -248,44 +249,39 @@ pub fn linkWithZld(
248249 }
249250 }
250251
251 if (options.sysroot) |syslibroot| {
252 if (macho_file.sysroot) |syslibroot| {
252253 try argv.append("-syslibroot");
253254 try argv.append(syslibroot);
254255 }
255256
256 for (options.rpath_list) |rpath| {
257 for (macho_file.rpath_list) |rpath| {
257258 try argv.append("-rpath");
258259 try argv.append(rpath);
259260 }
260261
261 if (options.pagezero_size) |pagezero_size| {
262 try argv.append("-pagezero_size");
263 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));
264 }
265
266 if (options.headerpad_size) |headerpad_size| {
267 try argv.append("-headerpad_size");
268 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{headerpad_size}));
269 }
262 try argv.appendSlice(&.{
263 "-pagezero_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_size}),
264 "-headerpad_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.headerpad_size}),
265 });
270266
271 if (options.headerpad_max_install_names) {
267 if (macho_file.headerpad_max_install_names) {
272268 try argv.append("-headerpad_max_install_names");
273269 }
274270
275 if (gc_sections) {
271 if (macho_file.base.gc_sections) {
276272 try argv.append("-dead_strip");
277273 }
278274
279 if (options.dead_strip_dylibs) {
275 if (macho_file.dead_strip_dylibs) {
280276 try argv.append("-dead_strip_dylibs");
281277 }
282278
283 if (options.entry) |entry| {
279 if (comp.config.entry) |entry| {
284280 try argv.append("-e");
285281 try argv.append(entry);
286282 }
287283
288 for (options.objects) |obj| {
284 for (objects) |obj| {
289285 if (obj.must_link) {
290286 try argv.append("-force_load");
291287 }
......@@ -303,7 +299,7 @@ pub fn linkWithZld(
303299 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
304300 if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);
305301
306 if (options.link_libcpp) {
302 if (comp.config.link_libcpp) {
307303 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
308304 try argv.append(comp.libcxx_static_lib.?.full_object_path);
309305 }
......@@ -313,8 +309,8 @@ pub fn linkWithZld(
313309
314310 try argv.append("-lSystem");
315311
316 for (options.system_libs.keys()) |l_name| {
317 const info = options.system_libs.get(l_name).?;
312 for (comp.system_libs.keys()) |l_name| {
313 const info = comp.system_libs.get(l_name).?;
318314 const arg = if (info.needed)
319315 try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name})
320316 else if (info.weak)
......@@ -324,11 +320,7 @@ pub fn linkWithZld(
324320 try argv.append(arg);
325321 }
326322
327 for (options.lib_dirs) |lib_dir| {
328 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
329 }
330
331 for (options.frameworks) |framework| {
323 for (macho_file.frameworks) |framework| {
332324 const name = std.fs.path.stem(framework.path);
333325 const arg = if (framework.needed)
334326 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
......@@ -339,11 +331,7 @@ pub fn linkWithZld(
339331 try argv.append(arg);
340332 }
341333
342 for (options.framework_dirs) |framework_dir| {
343 try argv.append(try std.fmt.allocPrint(arena, "-F{s}", .{framework_dir}));
344 }
345
346 if (is_dyn_lib and (options.allow_shlib_undefined orelse false)) {
334 if (is_dyn_lib and macho_file.base.allow_shlib_undefined) {
347335 try argv.append("-undefined");
348336 try argv.append("dynamic_lookup");
349337 }
......@@ -412,7 +400,7 @@ pub fn linkWithZld(
412400 };
413401 }
414402
415 if (gc_sections) {
403 if (macho_file.base.gc_sections) {
416404 try dead_strip.gcAtoms(macho_file);
417405 }
418406
......@@ -519,7 +507,7 @@ pub fn linkWithZld(
519507 // where the code signature goes into.
520508 var codesig = CodeSignature.init(MachO.getPageSize(cpu_arch));
521509 codesig.code_directory.ident = fs.path.basename(full_out_path);
522 if (options.entitlements) |path| {
510 if (macho_file.entitlements) |path| {
523511 try codesig.addEntitlements(gpa, path);
524512 }
525513 try macho_file.writeCodeSignaturePadding(&codesig);
......@@ -539,7 +527,7 @@ pub fn linkWithZld(
539527 try lc_writer.writeStruct(macho_file.dysymtab_cmd);
540528 try load_commands.writeDylinkerLC(lc_writer);
541529
542 switch (macho_file.base.options.output_mode) {
530 switch (output_mode) {
543531 .Exe => blk: {
544532 const seg_id = macho_file.header_segment_cmd_index.?;
545533 const seg = macho_file.segments.items[seg_id];
......@@ -555,10 +543,10 @@ pub fn linkWithZld(
555543
556544 try lc_writer.writeStruct(macho.entry_point_command{
557545 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),
558 .stacksize = macho_file.base.options.stack_size_override orelse 0,
546 .stacksize = macho_file.base.stack_size,
559547 });
560548 },
561 .Lib => if (macho_file.base.options.link_mode == .Dynamic) {
549 .Lib => if (link_mode == .Dynamic) {
562550 try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer);
563551 },
564552 else => {},
......@@ -598,11 +586,11 @@ pub fn linkWithZld(
598586
599587 if (codesig) |*csig| {
600588 try macho_file.writeCodeSignature(comp, csig); // code signing always comes last
601 try MachO.invalidateKernelCache(directory.handle, macho_file.base.options.emit.?.sub_path);
589 try MachO.invalidateKernelCache(directory.handle, macho_file.base.emit.sub_path);
602590 }
603591 }
604592
605 if (!options.disable_lld_caching) {
593 if (!macho_file.base.disable_lld_caching) {
606594 // Update the file with the digest. If it fails we can continue; it only
607595 // means that the next invocation will have an unnecessary cache miss.
608596 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
......@@ -622,12 +610,11 @@ pub fn linkWithZld(
622610
623611fn createSegments(macho_file: *MachO) !void {
624612 const gpa = macho_file.base.allocator;
625 const pagezero_vmsize = macho_file.base.options.pagezero_size orelse MachO.default_pagezero_vmsize;
626613 const page_size = MachO.getPageSize(macho_file.base.options.target.cpu.arch);
627 const aligned_pagezero_vmsize = mem.alignBackward(u64, pagezero_vmsize, page_size);
614 const aligned_pagezero_vmsize = mem.alignBackward(u64, macho_file.pagezero_vmsize, page_size);
628615 if (macho_file.base.options.output_mode != .Lib and aligned_pagezero_vmsize > 0) {
629 if (aligned_pagezero_vmsize != pagezero_vmsize) {
630 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
616 if (aligned_pagezero_vmsize != macho_file.pagezero_vmsize) {
617 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{macho_file.pagezero_vmsize});
631618 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
632619 }
633620 macho_file.pagezero_segment_cmd_index = @intCast(macho_file.segments.items.len);
src/link/NvPtx.zig+29-19
......@@ -24,46 +24,56 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
2424
2525base: link.File,
2626llvm_object: *LlvmObject,
27ptx_file_name: []const u8,
2827
29pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
30 if (!options.use_llvm) return error.PtxArchNotSupported;
28pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx {
29 if (build_options.only_c) unreachable;
3130
32 if (!options.target.cpu.arch.isNvptx()) return error.PtxArchNotSupported;
31 const target = options.comp.root_mod.resolved_target.result;
32 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
33 const use_llvm = options.comp.config.use_llvm;
3334
34 switch (options.target.os.tag) {
35 assert(use_llvm); // Caught by Compilation.Config.resolve.
36 assert(!use_lld); // Caught by Compilation.Config.resolve.
37 assert(target.cpu.arch.isNvptx()); // Caught by Compilation.Config.resolve.
38
39 switch (target.os.tag) {
3540 // TODO: does it also work with nvcl ?
3641 .cuda => {},
3742 else => return error.PtxArchNotSupported,
3843 }
3944
40 const llvm_object = try LlvmObject.create(gpa, options);
41 const nvptx = try gpa.create(NvPtx);
45 const llvm_object = try LlvmObject.create(arena, options);
46 const nvptx = try arena.create(NvPtx);
4247 nvptx.* = .{
4348 .base = .{
4449 .tag = .nvptx,
45 .options = options,
50 .comp = options.comp,
51 .emit = options.emit,
52 .gc_sections = options.gc_sections orelse false,
53 .stack_size = options.stack_size orelse 0,
54 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
4655 .file = null,
47 .allocator = gpa,
56 .disable_lld_caching = options.disable_lld_caching,
57 .build_id = options.build_id,
58 .rpath_list = options.rpath_list,
59 .force_undefined_symbols = options.force_undefined_symbols,
60 .function_sections = options.function_sections,
61 .data_sections = options.data_sections,
4862 },
4963 .llvm_object = llvm_object,
50 .ptx_file_name = try std.mem.join(gpa, "", &[_][]const u8{ options.root_name, ".ptx" }),
5164 };
5265
5366 return nvptx;
5467}
5568
56pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {
57 if (!options.use_llvm) return error.PtxArchNotSupported;
58 assert(options.target.ofmt == .nvptx);
59
60 log.debug("Opening .ptx target file {s}", .{sub_path});
61 return createEmpty(allocator, options);
69pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx {
70 const target = options.comp.root_mod.resolved_target.result;
71 assert(target.ofmt == .nvptx);
72 return createEmpty(arena, options);
6273}
6374
6475pub fn deinit(self: *NvPtx) void {
65 self.llvm_object.destroy(self.base.allocator);
66 self.base.allocator.free(self.ptx_file_name);
76 self.llvm_object.deinit();
6777}
6878
6979pub fn updateFunc(self: *NvPtx, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
......@@ -110,7 +120,7 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No
110120 comp.emit_asm = .{
111121 // 'null' means using the default cache dir: zig-cache/o/...
112122 .directory = null,
113 .basename = self.ptx_file_name,
123 .basename = self.base.emit.sub_path,
114124 };
115125 defer {
116126 comp.bin_file.options.emit = outfile;
src/link/Plan9.zig+89-63
......@@ -318,12 +318,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 {
318318 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
319319 };
320320 // a / will always be in a file path
321 try self.file_segments.put(self.base.allocator, "/", 1);
321 try self.file_segments.put(gpa, "/", 1);
322322 return self;
323323}
324324
325325fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !void {
326 const gpa = self.base.allocator;
326 const gpa = self.base.comp.gpa;
327327 const mod = self.base.options.module.?;
328328 const decl = mod.declPtr(decl_index);
329329 const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope(mod));
......@@ -379,6 +379,7 @@ fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !voi
379379}
380380
381381fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void {
382 const gpa = self.base.comp.gpa;
382383 const sep = std.fs.path.sep;
383384 var it = std.mem.tokenizeScalar(u8, path, sep);
384385 while (it.next()) |component| {
......@@ -386,7 +387,7 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi
386387 try a.writer().writeInt(u16, num, .big);
387388 } else {
388389 self.file_segments_i += 1;
389 try self.file_segments.put(self.base.allocator, component, self.file_segments_i);
390 try self.file_segments.put(gpa, component, self.file_segments_i);
390391 try a.writer().writeInt(u16, self.file_segments_i, .big);
391392 }
392393 }
......@@ -397,6 +398,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
397398 @panic("Attempted to compile for object format that was disabled by build configuration");
398399 }
399400
401 const gpa = self.base.comp.gpa;
400402 const func = mod.funcInfo(func_index);
401403 const decl_index = func.owner_decl;
402404 const decl = mod.declPtr(decl_index);
......@@ -404,10 +406,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
404406
405407 const atom_idx = try self.seeDecl(decl_index);
406408
407 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
409 var code_buffer = std.ArrayList(u8).init(gpa);
408410 defer code_buffer.deinit();
409411 var dbg_info_output: DebugInfoOutput = .{
410 .dbg_line = std.ArrayList(u8).init(self.base.allocator),
412 .dbg_line = std.ArrayList(u8).init(gpa),
411413 .start_line = null,
412414 .end_line = undefined,
413415 .pcop_change_index = null,
......@@ -448,14 +450,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
448450}
449451
450452pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
453 const gpa = self.base.comp.gpa;
451454 _ = try self.seeDecl(decl_index);
452 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
455 var code_buffer = std.ArrayList(u8).init(gpa);
453456 defer code_buffer.deinit();
454457
455458 const mod = self.base.options.module.?;
456459 const decl = mod.declPtr(decl_index);
457460
458 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
461 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
459462 if (!gop.found_existing) {
460463 gop.value_ptr.* = .{};
461464 }
......@@ -465,7 +468,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
465468
466469 const index = unnamed_consts.items.len;
467470 // name is freed when the unnamed const is freed
468 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });
471 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
469472
470473 const sym_index = try self.allocateSymbolIndex();
471474 const new_atom_idx = try self.createAtom();
......@@ -498,17 +501,18 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
498501 },
499502 };
500503 // duped_code is freed when the unnamed const is freed
501 const duped_code = try self.base.allocator.dupe(u8, code);
502 errdefer self.base.allocator.free(duped_code);
504 const duped_code = try gpa.dupe(u8, code);
505 errdefer gpa.free(duped_code);
503506 const new_atom = self.getAtomPtr(new_atom_idx);
504507 new_atom.* = info;
505508 new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } };
506 try unnamed_consts.append(self.base.allocator, new_atom_idx);
509 try unnamed_consts.append(gpa, new_atom_idx);
507510 // we return the new_atom_idx to codegen
508511 return new_atom_idx;
509512}
510513
511514pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) !void {
515 const gpa = self.base.comp.gpa;
512516 const decl = mod.declPtr(decl_index);
513517
514518 if (decl.isExtern(mod)) {
......@@ -517,7 +521,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
517521 }
518522 const atom_idx = try self.seeDecl(decl_index);
519523
520 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
524 var code_buffer = std.ArrayList(u8).init(gpa);
521525 defer code_buffer.deinit();
522526 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
523527 // TODO we need the symbol index for symbol in the table of locals for the containing atom
......@@ -535,16 +539,17 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
535539 return;
536540 },
537541 };
538 try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1);
539 const duped_code = try self.base.allocator.dupe(u8, code);
542 try self.data_decl_table.ensureUnusedCapacity(gpa, 1);
543 const duped_code = try gpa.dupe(u8, code);
540544 self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } };
541545 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {
542 self.base.allocator.free(old_entry.value);
546 gpa.free(old_entry.value);
543547 }
544548 return self.updateFinish(decl_index);
545549}
546550/// called at the end of update{Decl,Func}
547551fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
552 const gpa = self.base.comp.gpa;
548553 const mod = self.base.options.module.?;
549554 const decl = mod.declPtr(decl_index);
550555 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);
......@@ -558,7 +563,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
558563 const sym: aout.Sym = .{
559564 .value = undefined, // the value of stuff gets filled in in flushModule
560565 .type = atom.type,
561 .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),
566 .name = try gpa.dupe(u8, mod.intern_pool.stringToSlice(decl.name)),
562567 };
563568
564569 if (atom.sym_index) |s| {
......@@ -571,10 +576,11 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
571576}
572577
573578fn allocateSymbolIndex(self: *Plan9) !usize {
579 const gpa = self.base.comp.gpa;
574580 if (self.syms_index_free_list.popOrNull()) |i| {
575581 return i;
576582 } else {
577 _ = try self.syms.addOne(self.base.allocator);
583 _ = try self.syms.addOne(gpa);
578584 return self.syms.items.len - 1;
579585 }
580586}
......@@ -589,7 +595,8 @@ fn allocateGotIndex(self: *Plan9) usize {
589595}
590596
591597pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
592 assert(!self.base.options.use_lld);
598 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
599 assert(!use_lld);
593600
594601 switch (self.base.options.effectiveOutputMode()) {
595602 .Exe => {},
......@@ -650,7 +657,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
650657 @panic("Attempted to compile for object format that was disabled by build configuration");
651658 }
652659
653 _ = comp;
660 const gpa = comp.gpa;
661
654662 const tracy = trace(@src());
655663 defer tracy.end();
656664
......@@ -691,12 +699,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
691699 const atom_count = self.atomCount();
692700 assert(self.got_len == atom_count + self.got_index_free_list.items.len);
693701 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
694 var got_table = try self.base.allocator.alloc(u8, got_size);
695 defer self.base.allocator.free(got_table);
702 var got_table = try gpa.alloc(u8, got_size);
703 defer gpa.free(got_table);
696704
697705 // + 4 for header, got, symbols, linecountinfo
698 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());
699 defer self.base.allocator.free(iovecs);
706 var iovecs = try gpa.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());
707 defer gpa.free(iovecs);
700708
701709 const file = self.base.file.?;
702710
......@@ -709,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
709717 var iovecs_i: usize = 1;
710718 var text_i: u64 = 0;
711719
712 var linecountinfo = std.ArrayList(u8).init(self.base.allocator);
720 var linecountinfo = std.ArrayList(u8).init(gpa);
713721 defer linecountinfo.deinit();
714722 // text
715723 {
......@@ -901,10 +909,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
901909 }
902910 }
903911 }
904 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
912 var sym_buf = std.ArrayList(u8).init(gpa);
905913 try self.writeSyms(&sym_buf);
906914 const syms = try sym_buf.toOwnedSlice();
907 defer self.base.allocator.free(syms);
915 defer gpa.free(syms);
908916 assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls
909917 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
910918 iovecs_i += 1;
......@@ -985,6 +993,7 @@ fn addDeclExports(
985993 decl_index: InternPool.DeclIndex,
986994 exports: []const *Module.Export,
987995) !void {
996 const gpa = self.base.comp.gpa;
988997 const metadata = self.decls.getPtr(decl_index).?;
989998 const atom = self.getAtom(metadata.index);
990999
......@@ -994,7 +1003,7 @@ fn addDeclExports(
9941003 if (exp.opts.section.unwrap()) |section_name| {
9951004 if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) {
9961005 try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
997 self.base.allocator,
1006 gpa,
9981007 mod.declPtr(decl_index).srcLoc(mod),
9991008 "plan9 does not support extra sections",
10001009 .{},
......@@ -1005,19 +1014,20 @@ fn addDeclExports(
10051014 const sym = .{
10061015 .value = atom.offset.?,
10071016 .type = atom.type.toGlobal(),
1008 .name = try self.base.allocator.dupe(u8, exp_name),
1017 .name = try gpa.dupe(u8, exp_name),
10091018 };
10101019
10111020 if (metadata.getExport(self, exp_name)) |i| {
10121021 self.syms.items[i] = sym;
10131022 } else {
1014 try self.syms.append(self.base.allocator, sym);
1015 try metadata.exports.append(self.base.allocator, self.syms.items.len - 1);
1023 try self.syms.append(gpa, sym);
1024 try metadata.exports.append(gpa, self.syms.items.len - 1);
10161025 }
10171026 }
10181027}
10191028
10201029pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1030 const gpa = self.base.comp.gpa;
10211031 // TODO audit the lifetimes of decls table entries. It's possible to get
10221032 // freeDecl without any updateDecl in between.
10231033 // However that is planned to change, see the TODO comment in Module.zig
......@@ -1029,17 +1039,17 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
10291039 const symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?;
10301040 var submap = symidx_and_submap.functions;
10311041 if (submap.fetchSwapRemove(decl_index)) |removed_entry| {
1032 self.base.allocator.free(removed_entry.value.code);
1033 self.base.allocator.free(removed_entry.value.lineinfo);
1042 gpa.free(removed_entry.value.code);
1043 gpa.free(removed_entry.value.lineinfo);
10341044 }
10351045 if (submap.count() == 0) {
10361046 self.syms.items[symidx_and_submap.sym_index] = aout.Sym.undefined_symbol;
1037 self.syms_index_free_list.append(self.base.allocator, symidx_and_submap.sym_index) catch {};
1038 submap.deinit(self.base.allocator);
1047 self.syms_index_free_list.append(gpa, symidx_and_submap.sym_index) catch {};
1048 submap.deinit(gpa);
10391049 }
10401050 } else {
10411051 if (self.data_decl_table.fetchSwapRemove(decl_index)) |removed_entry| {
1042 self.base.allocator.free(removed_entry.value);
1052 gpa.free(removed_entry.value);
10431053 }
10441054 }
10451055 if (self.decls.fetchRemove(decl_index)) |const_kv| {
......@@ -1047,35 +1057,36 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
10471057 const atom = self.getAtom(kv.value.index);
10481058 if (atom.got_index) |i| {
10491059 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
1050 self.got_index_free_list.append(self.base.allocator, i) catch {};
1060 self.got_index_free_list.append(gpa, i) catch {};
10511061 }
10521062 if (atom.sym_index) |i| {
1053 self.syms_index_free_list.append(self.base.allocator, i) catch {};
1063 self.syms_index_free_list.append(gpa, i) catch {};
10541064 self.syms.items[i] = aout.Sym.undefined_symbol;
10551065 }
1056 kv.value.exports.deinit(self.base.allocator);
1066 kv.value.exports.deinit(gpa);
10571067 }
10581068 self.freeUnnamedConsts(decl_index);
10591069 {
10601070 const atom_index = self.decls.get(decl_index).?.index;
10611071 const relocs = self.relocs.getPtr(atom_index) orelse return;
1062 relocs.clearAndFree(self.base.allocator);
1072 relocs.clearAndFree(gpa);
10631073 assert(self.relocs.remove(atom_index));
10641074 }
10651075}
10661076fn freeUnnamedConsts(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1077 const gpa = self.base.comp.gpa;
10671078 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
10681079 for (unnamed_consts.items) |atom_idx| {
10691080 const atom = self.getAtom(atom_idx);
1070 self.base.allocator.free(self.syms.items[atom.sym_index.?].name);
1081 gpa.free(self.syms.items[atom.sym_index.?].name);
10711082 self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol;
1072 self.syms_index_free_list.append(self.base.allocator, atom.sym_index.?) catch {};
1083 self.syms_index_free_list.append(gpa, atom.sym_index.?) catch {};
10731084 }
1074 unnamed_consts.clearAndFree(self.base.allocator);
1085 unnamed_consts.clearAndFree(gpa);
10751086}
10761087
10771088fn createAtom(self: *Plan9) !Atom.Index {
1078 const gpa = self.base.allocator;
1089 const gpa = self.base.comp.gpa;
10791090 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
10801091 const atom = try self.atoms.addOne(gpa);
10811092 atom.* = .{
......@@ -1089,7 +1100,8 @@ fn createAtom(self: *Plan9) !Atom.Index {
10891100}
10901101
10911102pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index {
1092 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1103 const gpa = self.base.comp.gpa;
1104 const gop = try self.decls.getOrPut(gpa, decl_index);
10931105 if (!gop.found_existing) {
10941106 const index = try self.createAtom();
10951107 self.getAtomPtr(index).got_index = self.allocateGotIndex();
......@@ -1134,7 +1146,8 @@ pub fn updateExports(
11341146}
11351147
11361148pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
1137 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(self.base.options.module.?));
1149 const gpa = self.base.comp.gpa;
1150 const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(self.base.options.module.?));
11381151 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
11391152
11401153 if (!gop.found_existing) gop.value_ptr.* = .{};
......@@ -1160,7 +1173,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.In
11601173}
11611174
11621175fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void {
1163 const gpa = self.base.allocator;
1176 const gpa = self.base.comp.gpa;
11641177 const mod = self.base.options.module.?;
11651178
11661179 var required_alignment: InternPool.Alignment = .none;
......@@ -1206,8 +1219,8 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
12061219 },
12071220 };
12081221 // duped_code is freed when the atom is freed
1209 const duped_code = try self.base.allocator.dupe(u8, code);
1210 errdefer self.base.allocator.free(duped_code);
1222 const duped_code = try gpa.dupe(u8, code);
1223 errdefer gpa.free(duped_code);
12111224 self.getAtomPtr(atom_index).code = .{
12121225 .code_ptr = duped_code.ptr,
12131226 .other = .{ .code_len = duped_code.len },
......@@ -1215,13 +1228,13 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
12151228}
12161229
12171230pub fn deinit(self: *Plan9) void {
1218 const gpa = self.base.allocator;
1231 const gpa = self.base.comp.gpa;
12191232 {
12201233 var it = self.relocs.valueIterator();
12211234 while (it.next()) |relocs| {
1222 relocs.deinit(self.base.allocator);
1235 relocs.deinit(gpa);
12231236 }
1224 self.relocs.deinit(self.base.allocator);
1237 self.relocs.deinit(gpa);
12251238 }
12261239 // free the unnamed consts
12271240 var it_unc = self.unnamed_const_atoms.iterator();
......@@ -1280,24 +1293,36 @@ pub fn deinit(self: *Plan9) void {
12801293 }
12811294}
12821295
1283pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
1284 if (options.use_llvm)
1285 return error.LLVMBackendDoesNotSupportPlan9;
1286 assert(options.target.ofmt == .plan9);
1296pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 {
1297 if (build_options.only_c) unreachable;
1298
1299 const target = options.comp.root_mod.resolved_target.result;
1300 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
1301 const use_llvm = options.comp.config.use_llvm;
12871302
1288 const self = try createEmpty(allocator, options);
1303 assert(!use_llvm); // Caught by Compilation.Config.resolve.
1304 assert(!use_lld); // Caught by Compilation.Config.resolve.
1305 assert(target.ofmt == .plan9);
1306
1307 const self = try createEmpty(arena, options);
12891308 errdefer self.base.destroy();
12901309
1291 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
1310 const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{
12921311 .read = true,
1293 .mode = link.determineMode(options),
1312 .mode = link.File.determineMode(
1313 use_lld,
1314 options.comp.config.output_mode,
1315 options.comp.config.link_mode,
1316 ),
12941317 });
12951318 errdefer file.close();
12961319 self.base.file = file;
12971320
1298 self.bases = defaultBaseAddrs(options.target.cpu.arch);
1321 self.bases = defaultBaseAddrs(target.cpu.arch);
1322
1323 const gpa = options.comp.gpa;
12991324
1300 try self.syms.appendSlice(self.base.allocator, &.{
1325 try self.syms.appendSlice(gpa, &.{
13011326 // we include the global offset table to make it easier for debugging
13021327 .{
13031328 .value = self.getAddr(0, .d), // the global offset table starts at 0
......@@ -1490,7 +1515,7 @@ pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.S
14901515 // be used by more than one function, however, its address is being used so we need
14911516 // to put it in some location.
14921517 // ...
1493 const gpa = self.base.allocator;
1518 const gpa = self.base.comp.gpa;
14941519 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
14951520 const mod = self.base.options.module.?;
14961521 if (!gop.found_existing) {
......@@ -1538,11 +1563,12 @@ pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: li
15381563}
15391564
15401565pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {
1541 const gop = try self.relocs.getOrPut(self.base.allocator, parent_index);
1566 const gpa = self.base.comp.gpa;
1567 const gop = try self.relocs.getOrPut(gpa, parent_index);
15421568 if (!gop.found_existing) {
15431569 gop.value_ptr.* = .{};
15441570 }
1545 try gop.value_ptr.append(self.base.allocator, reloc);
1571 try gop.value_ptr.append(gpa, reloc);
15461572}
15471573
15481574pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom {
src/link/SpirV.zig+36-23
......@@ -47,48 +47,65 @@ base: link.File,
4747
4848object: codegen.Object,
4949
50pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
51 const self = try gpa.create(SpirV);
50pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
51 const gpa = options.comp.gpa;
52 const target = options.comp.root_mod.resolved_target.result;
53
54 const self = try arena.create(SpirV);
5255 self.* = .{
5356 .base = .{
5457 .tag = .spirv,
55 .options = options,
58 .comp = options.comp,
59 .emit = options.emit,
60 .gc_sections = options.gc_sections orelse false,
61 .stack_size = options.stack_size orelse 0,
62 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
5663 .file = null,
57 .allocator = gpa,
64 .disable_lld_caching = options.disable_lld_caching,
65 .build_id = options.build_id,
66 .rpath_list = options.rpath_list,
67 .force_undefined_symbols = options.force_undefined_symbols,
68 .function_sections = options.function_sections,
69 .data_sections = options.data_sections,
5870 },
5971 .object = codegen.Object.init(gpa),
6072 };
6173 errdefer self.deinit();
6274
63 // TODO: Figure out where to put all of these
64 switch (options.target.cpu.arch) {
75 switch (target.cpu.arch) {
6576 .spirv32, .spirv64 => {},
66 else => return error.TODOArchNotSupported,
77 else => unreachable, // Caught by Compilation.Config.resolve.
6778 }
6879
69 switch (options.target.os.tag) {
80 switch (target.os.tag) {
7081 .opencl, .glsl450, .vulkan => {},
71 else => return error.TODOOsNotSupported,
82 else => unreachable, // Caught by Compilation.Config.resolve.
7283 }
7384
74 if (options.target.abi != .none) {
75 return error.TODOAbiNotSupported;
76 }
85 assert(target.abi != .none); // Caught by Compilation.Config.resolve.
7786
7887 return self;
7988}
8089
81pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {
82 assert(options.target.ofmt == .spirv);
90pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
91 if (build_options.only_c) unreachable;
92
93 const target = options.comp.root_mod.resolved_target.result;
94 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
95 const use_llvm = options.comp.config.use_llvm;
8396
84 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.
85 if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
97 assert(!use_llvm); // Caught by Compilation.Config.resolve.
98 assert(!use_lld); // Caught by Compilation.Config.resolve.
99 assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve.
86100
87 const spirv = try createEmpty(allocator, options);
101 const spirv = try createEmpty(arena, options);
88102 errdefer spirv.base.destroy();
89103
90104 // TODO: read the file and keep valid parts instead of truncating
91 const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
105 const file = try options.emit.?.directory.handle.createFile(options.emit.sub_path, .{
106 .truncate = true,
107 .read = true,
108 });
92109 spirv.base.file = file;
93110 return spirv;
94111}
......@@ -150,11 +167,7 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void {
150167}
151168
152169pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
153 if (build_options.have_llvm and self.base.options.use_lld) {
154 return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
155 } else {
156 return self.flushModule(comp, prog_node);
157 }
170 return self.flushModule(comp, prog_node);
158171}
159172
160173pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
src/link/Wasm.zig+398-321
......@@ -191,6 +191,9 @@ synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
191191/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
192192anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
193193
194import_table: bool,
195export_table: bool,
196
194197pub const Alignment = types.Alignment;
195198
196199pub const Segment = struct {
......@@ -363,63 +366,71 @@ pub const StringTable = struct {
363366 }
364367};
365368
366pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
367 assert(options.target.ofmt == .wasm);
369pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
370 if (build_options.only_c) unreachable;
371 const gpa = options.comp.gpa;
372 const target = options.comp.root_mod.resolved_target.result;
373 assert(target.ofmt == .wasm);
368374
369 if (options.use_llvm and options.use_lld) {
370 return createEmpty(allocator, options);
371 }
375 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
376 const use_llvm = options.comp.config.use_llvm;
377 const output_mode = options.comp.config.output_mode;
372378
373 const wasm_bin = try createEmpty(allocator, options);
374 errdefer wasm_bin.base.destroy();
379 const wasm = try createEmpty(arena, options);
380 errdefer wasm.base.destroy();
375381
376 // We are not using LLD at this point, so ensure we set the intermediary basename
377 if (build_options.have_llvm and options.use_llvm and options.module != null) {
378 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
379 // we also want to put the intermediary object file in the cache while the
380 // main emit directory is the cwd.
381 wasm_bin.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
382 options.emit.?.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
383 });
382 if (use_lld and use_llvm) {
383 // LLVM emits the object file; LLD links it into the final product.
384 return wasm;
384385 }
385386
387 const sub_path = if (!use_lld) options.emit.sub_path else p: {
388 // Open a temporary object file, not the final output file because we
389 // want to link with LLD.
390 const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{
391 options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch),
392 });
393 wasm.base.intermediary_basename = o_file_path;
394 break :p o_file_path;
395 };
396
386397 // TODO: read the file and keep valid parts instead of truncating
387398 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
388399 .truncate = true,
389400 .read = true,
390401 .mode = if (fs.has_executable_bit)
391 if (options.target.os.tag == .wasi and options.output_mode == .Exe)
402 if (target.os.tag == .wasi and output_mode == .Exe)
392403 fs.File.default_mode | 0b001_000_000
393404 else
394405 fs.File.default_mode
395406 else
396407 0,
397408 });
398 wasm_bin.base.file = file;
399 wasm_bin.name = sub_path;
409 wasm.base.file = file;
410 wasm.name = sub_path;
400411
401412 // create stack pointer symbol
402413 {
403 const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global);
404 const symbol = loc.getSymbol(wasm_bin);
414 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
415 const symbol = loc.getSymbol(wasm);
405416 // For object files we will import the stack pointer symbol
406 if (options.output_mode == .Obj) {
417 if (output_mode == .Obj) {
407418 symbol.setUndefined(true);
408 symbol.index = @as(u32, @intCast(wasm_bin.imported_globals_count));
409 wasm_bin.imported_globals_count += 1;
410 try wasm_bin.imports.putNoClobber(
411 allocator,
419 symbol.index = @intCast(wasm.imported_globals_count);
420 wasm.imported_globals_count += 1;
421 try wasm.imports.putNoClobber(
422 gpa,
412423 loc,
413424 .{
414 .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
425 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
415426 .name = symbol.name,
416427 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
417428 },
418429 );
419430 } else {
420 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
431 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
421432 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
422 const global = try wasm_bin.wasm_globals.addOne(allocator);
433 const global = try wasm.wasm_globals.addOne(gpa);
423434 global.* = .{
424435 .global_type = .{
425436 .valtype = .i32,
......@@ -432,25 +443,25 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
432443
433444 // create indirect function pointer symbol
434445 {
435 const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);
436 const symbol = loc.getSymbol(wasm_bin);
446 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
447 const symbol = loc.getSymbol(wasm);
437448 const table: std.wasm.Table = .{
438449 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
439450 .reftype = .funcref,
440451 };
441 if (options.output_mode == .Obj or options.import_table) {
452 if (output_mode == .Obj or options.import_table) {
442453 symbol.setUndefined(true);
443 symbol.index = @intCast(wasm_bin.imported_tables_count);
444 wasm_bin.imported_tables_count += 1;
445 try wasm_bin.imports.put(allocator, loc, .{
446 .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),
454 symbol.index = @intCast(wasm.imported_tables_count);
455 wasm.imported_tables_count += 1;
456 try wasm.imports.put(gpa, loc, .{
457 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
447458 .name = symbol.name,
448459 .kind = .{ .table = table },
449460 });
450461 } else {
451 symbol.index = @as(u32, @intCast(wasm_bin.imported_tables_count + wasm_bin.tables.items.len));
452 try wasm_bin.tables.append(allocator, table);
453 if (options.export_table) {
462 symbol.index = @as(u32, @intCast(wasm.imported_tables_count + wasm.tables.items.len));
463 try wasm.tables.append(gpa, table);
464 if (wasm.export_table) {
454465 symbol.setFlag(.WASM_SYM_EXPORTED);
455466 } else {
456467 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
......@@ -460,8 +471,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
460471
461472 // create __wasm_call_ctors
462473 {
463 const loc = try wasm_bin.createSyntheticSymbol("__wasm_call_ctors", .function);
464 const symbol = loc.getSymbol(wasm_bin);
474 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
475 const symbol = loc.getSymbol(wasm);
465476 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
466477 // we do not know the function index until after we merged all sections.
467478 // Therefore we set `symbol.index` and create its corresponding references
......@@ -469,67 +480,76 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
469480 }
470481
471482 // shared-memory symbols for TLS support
472 if (wasm_bin.base.options.shared_memory) {
483 if (wasm.base.options.shared_memory) {
473484 {
474 const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global);
475 const symbol = loc.getSymbol(wasm_bin);
485 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
486 const symbol = loc.getSymbol(wasm);
476487 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
477 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
478 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
488 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
489 try wasm.wasm_globals.append(gpa, .{
479490 .global_type = .{ .valtype = .i32, .mutable = true },
480491 .init = .{ .i32_const = undefined },
481492 });
482493 }
483494 {
484 const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global);
485 const symbol = loc.getSymbol(wasm_bin);
495 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
496 const symbol = loc.getSymbol(wasm);
486497 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
487 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
488 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
498 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
499 try wasm.wasm_globals.append(gpa, .{
489500 .global_type = .{ .valtype = .i32, .mutable = false },
490501 .init = .{ .i32_const = undefined },
491502 });
492503 }
493504 {
494 const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global);
495 const symbol = loc.getSymbol(wasm_bin);
505 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
506 const symbol = loc.getSymbol(wasm);
496507 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
497 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);
498 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{
508 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
509 try wasm.wasm_globals.append(gpa, .{
499510 .global_type = .{ .valtype = .i32, .mutable = false },
500511 .init = .{ .i32_const = undefined },
501512 });
502513 }
503514 {
504 const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function);
505 const symbol = loc.getSymbol(wasm_bin);
515 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
516 const symbol = loc.getSymbol(wasm);
506517 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
507518 }
508519 }
509520
510 // if (!options.strip and options.module != null) {
511 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, .dwarf32);
512 // try wasm_bin.initDebugSections();
513 // }
514
515 return wasm_bin;
521 return wasm;
516522}
517523
518pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
519 const wasm = try gpa.create(Wasm);
520 errdefer gpa.destroy(wasm);
524pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
525 const use_llvm = options.comp.config.use_llvm;
526 const output_mode = options.comp.config.output_mode;
527
528 const wasm = try arena.create(Wasm);
521529 wasm.* = .{
522530 .base = .{
523531 .tag = .wasm,
524 .options = options,
532 .comp = options.comp,
533 .emit = options.emit,
534 .gc_sections = options.gc_sections orelse (output_mode != .Obj),
535 .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB
536 .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
525537 .file = null,
526 .allocator = gpa,
538 .disable_lld_caching = options.disable_lld_caching,
539 .build_id = options.build_id,
540 .rpath_list = options.rpath_list,
541 .force_undefined_symbols = options.force_undefined_symbols,
542 .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
543 .function_sections = options.function_sections,
544 .data_sections = options.data_sections,
527545 },
528546 .name = undefined,
547 .import_table = options.import_table,
548 .export_table = options.export_table,
529549 };
530550
531 if (options.use_llvm) {
532 wasm.llvm_object = try LlvmObject.create(gpa, options);
551 if (use_llvm) {
552 wasm.llvm_object = try LlvmObject.create(arena, options);
533553 }
534554 return wasm;
535555}
......@@ -537,22 +557,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
537557/// For a given name, creates a new global synthetic symbol.
538558/// Leaves index undefined and the default flags (0).
539559fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {
540 const name_offset = try wasm.string_table.put(wasm.base.allocator, name);
560 const gpa = wasm.base.comp.gpa;
561 const name_offset = try wasm.string_table.put(gpa, name);
541562 return wasm.createSyntheticSymbolOffset(name_offset, tag);
542563}
543564
544565fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
545566 const sym_index = @as(u32, @intCast(wasm.symbols.items.len));
546567 const loc: SymbolLoc = .{ .index = sym_index, .file = null };
547 try wasm.symbols.append(wasm.base.allocator, .{
568 const gpa = wasm.base.comp.gpa;
569 try wasm.symbols.append(gpa, .{
548570 .name = name_offset,
549571 .flags = 0,
550572 .tag = tag,
551573 .index = undefined,
552574 .virtual_address = undefined,
553575 });
554 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {});
555 try wasm.globals.put(wasm.base.allocator, name_offset, loc);
576 try wasm.resolved_symbols.putNoClobber(gpa, loc, {});
577 try wasm.globals.put(gpa, name_offset, loc);
556578 return loc;
557579}
558580
......@@ -589,12 +611,13 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
589611 const file = try fs.cwd().openFile(path, .{});
590612 errdefer file.close();
591613
592 var object = Object.create(wasm.base.allocator, file, path, null) catch |err| switch (err) {
614 const gpa = wasm.base.comp.gpa;
615 var object = Object.create(gpa, file, path, null) catch |err| switch (err) {
593616 error.InvalidMagicByte, error.NotObjectFile => return false,
594617 else => |e| return e,
595618 };
596 errdefer object.deinit(wasm.base.allocator);
597 try wasm.objects.append(wasm.base.allocator, object);
619 errdefer object.deinit(gpa);
620 try wasm.objects.append(gpa, object);
598621 return true;
599622}
600623
......@@ -602,7 +625,8 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
602625/// When the index was not found, a new `Atom` will be created, and its index will be returned.
603626/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
604627pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index {
605 const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index);
628 const gpa = wasm.base.comp.gpa;
629 const gop = try wasm.decls.getOrPut(gpa, decl_index);
606630 if (!gop.found_existing) {
607631 const atom_index = try wasm.createAtom();
608632 gop.value_ptr.* = atom_index;
......@@ -611,18 +635,19 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At
611635 const mod = wasm.base.options.module.?;
612636 const decl = mod.declPtr(decl_index);
613637 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
614 symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name);
638 symbol.name = try wasm.string_table.put(gpa, full_name);
615639 }
616640 return gop.value_ptr.*;
617641}
618642
619643/// Creates a new empty `Atom` and returns its `Atom.Index`
620644fn createAtom(wasm: *Wasm) !Atom.Index {
621 const index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
622 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
645 const gpa = wasm.base.comp.gpa;
646 const index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
647 const atom = try wasm.managed_atoms.addOne(gpa);
623648 atom.* = Atom.empty;
624649 atom.sym_index = try wasm.allocateSymbol();
625 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, .{ .file = null, .index = atom.sym_index }, index);
650 try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = atom.sym_index }, index);
626651
627652 return index;
628653}
......@@ -644,6 +669,8 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
644669/// When false, it will only link with object files that contain symbols that
645670/// are referenced by other object files or Zig code.
646671fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
672 const gpa = wasm.base.comp.gpa;
673
647674 const file = try fs.cwd().openFile(path, .{});
648675 errdefer file.close();
649676
......@@ -651,25 +678,25 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
651678 .file = file,
652679 .name = path,
653680 };
654 archive.parse(wasm.base.allocator) catch |err| switch (err) {
681 archive.parse(gpa) catch |err| switch (err) {
655682 error.EndOfStream, error.NotArchive => {
656 archive.deinit(wasm.base.allocator);
683 archive.deinit(gpa);
657684 return false;
658685 },
659686 else => |e| return e,
660687 };
661688
662689 if (!force_load) {
663 errdefer archive.deinit(wasm.base.allocator);
664 try wasm.archives.append(wasm.base.allocator, archive);
690 errdefer archive.deinit(gpa);
691 try wasm.archives.append(gpa, archive);
665692 return true;
666693 }
667 defer archive.deinit(wasm.base.allocator);
694 defer archive.deinit(gpa);
668695
669696 // In this case we must force link all embedded object files within the archive
670697 // We loop over all symbols, and then group them by offset as the offset
671698 // notates where the object file starts.
672 var offsets = std.AutoArrayHashMap(u32, void).init(wasm.base.allocator);
699 var offsets = std.AutoArrayHashMap(u32, void).init(gpa);
673700 defer offsets.deinit();
674701 for (archive.toc.values()) |symbol_offsets| {
675702 for (symbol_offsets.items) |sym_offset| {
......@@ -678,8 +705,8 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
678705 }
679706
680707 for (offsets.keys()) |file_offset| {
681 const object = try wasm.objects.addOne(wasm.base.allocator);
682 object.* = try archive.parseObject(wasm.base.allocator, file_offset);
708 const object = try wasm.objects.addOne(gpa);
709 object.* = try archive.parseObject(gpa, file_offset);
683710 }
684711
685712 return true;
......@@ -695,6 +722,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool {
695722}
696723
697724fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
725 const gpa = wasm.base.comp.gpa;
698726 const object: Object = wasm.objects.items[object_index];
699727 log.debug("Resolving symbols in object: '{s}'", .{object.name});
700728
......@@ -708,7 +736,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
708736 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
709737 continue;
710738 }
711 const sym_name_index = try wasm.string_table.put(wasm.base.allocator, sym_name);
739 const sym_name_index = try wasm.string_table.put(gpa, sym_name);
712740
713741 if (symbol.isLocal()) {
714742 if (symbol.isUndefined()) {
......@@ -716,17 +744,17 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
716744 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });
717745 return error.UndefinedLocal;
718746 }
719 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});
747 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
720748 continue;
721749 }
722750
723 const maybe_existing = try wasm.globals.getOrPut(wasm.base.allocator, sym_name_index);
751 const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index);
724752 if (!maybe_existing.found_existing) {
725753 maybe_existing.value_ptr.* = location;
726 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});
754 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
727755
728756 if (symbol.isUndefined()) {
729 try wasm.undefs.putNoClobber(wasm.base.allocator, sym_name_index, location);
757 try wasm.undefs.putNoClobber(gpa, sym_name_index, location);
730758 }
731759 continue;
732760 }
......@@ -753,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
753781 return error.SymbolCollision;
754782 }
755783
756 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);
784 try wasm.discarded.put(gpa, location, existing_loc);
757785 continue; // Do not overwrite defined symbols with undefined symbols
758786 }
759787
......@@ -791,7 +819,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
791819 }
792820
793821 // both undefined so skip overwriting existing symbol and discard the new symbol
794 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);
822 try wasm.discarded.put(gpa, location, existing_loc);
795823 continue;
796824 }
797825
......@@ -822,7 +850,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
822850 // symbol is weak and the new one isn't, in which case we *do* overwrite it.
823851 if (existing_sym.isWeak() and symbol.isWeak()) blk: {
824852 if (existing_sym.isUndefined() and !symbol.isUndefined()) break :blk;
825 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);
853 try wasm.discarded.put(gpa, location, existing_loc);
826854 continue;
827855 }
828856
......@@ -830,10 +858,10 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
830858 log.debug("Overwriting symbol '{s}'", .{sym_name});
831859 log.debug(" old definition in '{s}'", .{existing_file_path});
832860 log.debug(" new definition in '{s}'", .{object.name});
833 try wasm.discarded.putNoClobber(wasm.base.allocator, existing_loc, location);
861 try wasm.discarded.putNoClobber(gpa, existing_loc, location);
834862 maybe_existing.value_ptr.* = location;
835 try wasm.globals.put(wasm.base.allocator, sym_name_index, location);
836 try wasm.resolved_symbols.put(wasm.base.allocator, location, {});
863 try wasm.globals.put(gpa, sym_name_index, location);
864 try wasm.resolved_symbols.put(gpa, location, {});
837865 assert(wasm.resolved_symbols.swapRemove(existing_loc));
838866 if (existing_sym.isUndefined()) {
839867 _ = wasm.undefs.swapRemove(sym_name_index);
......@@ -842,6 +870,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
842870}
843871
844872fn resolveSymbolsInArchives(wasm: *Wasm) !void {
873 const gpa = wasm.base.comp.gpa;
845874 if (wasm.archives.items.len == 0) return;
846875
847876 log.debug("Resolving symbols in archives", .{});
......@@ -860,9 +889,9 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
860889 // Symbol is found in unparsed object file within current archive.
861890 // Parse object and and resolve symbols again before we check remaining
862891 // undefined symbols.
863 const object_file_index = @as(u16, @intCast(wasm.objects.items.len));
864 const object = try archive.parseObject(wasm.base.allocator, offset.items[0]);
865 try wasm.objects.append(wasm.base.allocator, object);
892 const object_file_index: u16 = @intCast(wasm.objects.items.len);
893 const object = try archive.parseObject(gpa, offset.items[0]);
894 try wasm.objects.append(gpa, object);
866895 try wasm.resolveSymbolsInObject(object_file_index);
867896
868897 // continue loop for any remaining undefined symbols that still exist
......@@ -880,6 +909,8 @@ fn writeI32Const(writer: anytype, val: u32) !void {
880909}
881910
882911fn setupInitMemoryFunction(wasm: *Wasm) !void {
912 const gpa = wasm.base.comp.gpa;
913
883914 // Passive segments are used to avoid memory being reinitialized on each
884915 // thread's instantiation. These passive segments are initialized and
885916 // dropped in __wasm_init_memory, which is registered as the start function
......@@ -896,7 +927,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
896927 break :address loc.getSymbol(wasm).virtual_address;
897928 } else 0;
898929
899 var function_body = std.ArrayList(u8).init(wasm.base.allocator);
930 var function_body = std.ArrayList(u8).init(gpa);
900931 defer function_body.deinit();
901932 const writer = function_body.writer();
902933
......@@ -1040,6 +1071,8 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
10401071/// Constructs a synthetic function that performs runtime relocations for
10411072/// TLS symbols. This function is called by `__wasm_init_tls`.
10421073fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1074 const gpa = wasm.base.comp.gpa;
1075
10431076 // When we have TLS GOT entries and shared memory is enabled,
10441077 // we must perform runtime relocations or else we don't create the function.
10451078 if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) {
......@@ -1047,7 +1080,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
10471080 }
10481081
10491082 // const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs");
1050 var function_body = std.ArrayList(u8).init(wasm.base.allocator);
1083 var function_body = std.ArrayList(u8).init(gpa);
10511084 defer function_body.deinit();
10521085 const writer = function_body.writer();
10531086
......@@ -1221,10 +1254,12 @@ fn validateFeatures(
12211254/// if one or multiple undefined references exist. When none exist, the symbol will
12221255/// not be created, ensuring we don't unneccesarily emit unreferenced symbols.
12231256fn resolveLazySymbols(wasm: *Wasm) !void {
1257 const gpa = wasm.base.comp.gpa;
1258
12241259 if (wasm.string_table.getOffset("__heap_base")) |name_offset| {
12251260 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
12261261 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1227 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1262 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
12281263 _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.
12291264 }
12301265 }
......@@ -1232,7 +1267,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
12321267 if (wasm.string_table.getOffset("__heap_end")) |name_offset| {
12331268 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
12341269 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1235 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1270 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
12361271 _ = wasm.resolved_symbols.swapRemove(loc);
12371272 }
12381273 }
......@@ -1241,12 +1276,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
12411276 if (wasm.string_table.getOffset("__tls_base")) |name_offset| {
12421277 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
12431278 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
1244 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1279 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
12451280 _ = wasm.resolved_symbols.swapRemove(kv.value);
12461281 const symbol = loc.getSymbol(wasm);
12471282 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
12481283 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
1249 try wasm.wasm_globals.append(wasm.base.allocator, .{
1284 try wasm.wasm_globals.append(gpa, .{
12501285 .global_type = .{ .valtype = .i32, .mutable = true },
12511286 .init = .{ .i32_const = undefined },
12521287 });
......@@ -1256,7 +1291,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
12561291 if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| {
12571292 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
12581293 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
1259 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1294 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
12601295 _ = wasm.resolved_symbols.swapRemove(kv.value);
12611296 }
12621297 }
......@@ -1292,8 +1327,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
12921327}
12931328
12941329pub fn deinit(wasm: *Wasm) void {
1295 const gpa = wasm.base.allocator;
1296 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
1330 const gpa = wasm.base.comp.gpa;
1331 if (wasm.llvm_object) |llvm_object| llvm_object.deinit();
12971332
12981333 for (wasm.func_types.items) |*func_type| {
12991334 func_type.deinit(gpa);
......@@ -1378,7 +1413,9 @@ pub fn deinit(wasm: *Wasm) void {
13781413/// Allocates a new symbol and returns its index.
13791414/// Will re-use slots when a symbol was freed at an earlier stage.
13801415pub fn allocateSymbol(wasm: *Wasm) !u32 {
1381 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
1416 const gpa = wasm.base.comp.gpa;
1417
1418 try wasm.symbols.ensureUnusedCapacity(gpa, 1);
13821419 const symbol: Symbol = .{
13831420 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls
13841421 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
......@@ -1404,6 +1441,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:
14041441 const tracy = trace(@src());
14051442 defer tracy.end();
14061443
1444 const gpa = wasm.base.comp.gpa;
14071445 const func = mod.funcInfo(func_index);
14081446 const decl_index = func.owner_decl;
14091447 const decl = mod.declPtr(decl_index);
......@@ -1414,7 +1452,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:
14141452 // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
14151453 // defer if (decl_state) |*ds| ds.deinit();
14161454
1417 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
1455 var code_writer = std.ArrayList(u8).init(gpa);
14181456 defer code_writer.deinit();
14191457 // const result = try codegen.generateFunction(
14201458 // &wasm.base,
......@@ -1477,6 +1515,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !
14771515 return;
14781516 }
14791517
1518 const gpa = wasm.base.comp.gpa;
14801519 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
14811520 const atom = wasm.getAtomPtr(atom_index);
14821521 atom.clear();
......@@ -1489,7 +1528,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !
14891528 }
14901529 const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
14911530
1492 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
1531 var code_writer = std.ArrayList(u8).init(gpa);
14931532 defer code_writer.deinit();
14941533
14951534 const res = try codegen.generateSymbol(
......@@ -1528,16 +1567,17 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De
15281567}
15291568
15301569fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void {
1570 const gpa = wasm.base.comp.gpa;
15311571 const mod = wasm.base.options.module.?;
15321572 const decl = mod.declPtr(decl_index);
15331573 const atom_index = wasm.decls.get(decl_index).?;
15341574 const atom = wasm.getAtomPtr(atom_index);
15351575 const symbol = &wasm.symbols.items[atom.sym_index];
15361576 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1537 symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name);
1577 symbol.name = try wasm.string_table.put(gpa, full_name);
15381578 symbol.tag = symbol_tag;
1539 try atom.code.appendSlice(wasm.base.allocator, code);
1540 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
1579 try atom.code.appendSlice(gpa, code);
1580 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
15411581
15421582 atom.size = @intCast(code.len);
15431583 if (code.len == 0) return;
......@@ -1591,6 +1631,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
15911631/// Returns the symbol index of the local
15921632/// The given `decl` is the parent decl whom owns the constant.
15931633pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
1634 const gpa = wasm.base.comp.gpa;
15941635 const mod = wasm.base.options.module.?;
15951636 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
15961637 const decl = mod.declPtr(decl_index);
......@@ -1599,14 +1640,14 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec
15991640 const parent_atom = wasm.getAtom(parent_atom_index);
16001641 const local_index = parent_atom.locals.items.len;
16011642 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1602 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{
1643 const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{
16031644 fqn, local_index,
16041645 });
1605 defer wasm.base.allocator.free(name);
1646 defer gpa.free(name);
16061647
16071648 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
16081649 .ok => |atom_index| {
1609 try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index);
1650 try wasm.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index);
16101651 return wasm.getAtom(atom_index).getSymbolIndex().?;
16111652 },
16121653 .fail => |em| {
......@@ -1623,24 +1664,25 @@ const LowerConstResult = union(enum) {
16231664};
16241665
16251666fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
1667 const gpa = wasm.base.comp.gpa;
16261668 const mod = wasm.base.options.module.?;
16271669
16281670 // Create and initialize a new local symbol and atom
16291671 const atom_index = try wasm.createAtom();
1630 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
1672 var value_bytes = std.ArrayList(u8).init(gpa);
16311673 defer value_bytes.deinit();
16321674
16331675 const code = code: {
16341676 const atom = wasm.getAtomPtr(atom_index);
16351677 atom.alignment = tv.ty.abiAlignment(mod);
16361678 wasm.symbols.items[atom.sym_index] = .{
1637 .name = try wasm.string_table.put(wasm.base.allocator, name),
1679 .name = try wasm.string_table.put(gpa, name),
16381680 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
16391681 .tag = .data,
16401682 .index = undefined,
16411683 .virtual_address = undefined,
16421684 };
1643 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
1685 try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {});
16441686
16451687 const result = try codegen.generateSymbol(
16461688 &wasm.base,
......@@ -1663,7 +1705,7 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src
16631705
16641706 const atom = wasm.getAtomPtr(atom_index);
16651707 atom.size = @intCast(code.len);
1666 try atom.code.appendSlice(wasm.base.allocator, code);
1708 try atom.code.appendSlice(gpa, code);
16671709 return .{ .ok = atom_index };
16681710}
16691711
......@@ -1673,8 +1715,9 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src
16731715/// and then returns the index to it.
16741716pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {
16751717 _ = lib_name;
1676 const name_index = try wasm.string_table.put(wasm.base.allocator, name);
1677 const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index);
1718 const gpa = wasm.base.comp.gpa;
1719 const name_index = try wasm.string_table.put(gpa, name);
1720 const gop = try wasm.globals.getOrPut(gpa, name_index);
16781721 if (gop.found_existing) {
16791722 return gop.value_ptr.*.index;
16801723 }
......@@ -1691,14 +1734,14 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3
16911734
16921735 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: {
16931736 const index: u32 = @intCast(wasm.symbols.items.len);
1694 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
1737 try wasm.symbols.ensureUnusedCapacity(gpa, 1);
16951738 wasm.symbols.items.len += 1;
16961739 break :blk index;
16971740 };
16981741 wasm.symbols.items[sym_index] = symbol;
16991742 gop.value_ptr.* = .{ .index = sym_index, .file = null };
1700 try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {});
1701 try wasm.undefs.putNoClobber(wasm.base.allocator, name_index, gop.value_ptr.*);
1743 try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {});
1744 try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*);
17021745 return sym_index;
17031746}
17041747
......@@ -1709,6 +1752,7 @@ pub fn getDeclVAddr(
17091752 decl_index: InternPool.DeclIndex,
17101753 reloc_info: link.File.RelocInfo,
17111754) !u64 {
1755 const gpa = wasm.base.comp.gpa;
17121756 const mod = wasm.base.options.module.?;
17131757 const decl = mod.declPtr(decl_index);
17141758
......@@ -1725,17 +1769,17 @@ pub fn getDeclVAddr(
17251769 // as function pointers are not allowed to be stored inside the data section.
17261770 // They are instead stored in a function table which are called by index.
17271771 try wasm.addTableFunction(target_symbol_index);
1728 try atom.relocs.append(wasm.base.allocator, .{
1772 try atom.relocs.append(gpa, .{
17291773 .index = target_symbol_index,
1730 .offset = @as(u32, @intCast(reloc_info.offset)),
1774 .offset = @intCast(reloc_info.offset),
17311775 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
17321776 });
17331777 } else {
1734 try atom.relocs.append(wasm.base.allocator, .{
1778 try atom.relocs.append(gpa, .{
17351779 .index = target_symbol_index,
1736 .offset = @as(u32, @intCast(reloc_info.offset)),
1780 .offset = @intCast(reloc_info.offset),
17371781 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1738 .addend = @as(i32, @intCast(reloc_info.addend)),
1782 .addend = @intCast(reloc_info.addend),
17391783 });
17401784 }
17411785 // we do not know the final address at this point,
......@@ -1751,7 +1795,8 @@ pub fn lowerAnonDecl(
17511795 explicit_alignment: Alignment,
17521796 src_loc: Module.SrcLoc,
17531797) !codegen.Result {
1754 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
1798 const gpa = wasm.base.comp.gpa;
1799 const gop = try wasm.anon_decls.getOrPut(gpa, decl_val);
17551800 if (!gop.found_existing) {
17561801 const mod = wasm.base.options.module.?;
17571802 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
......@@ -1779,6 +1824,7 @@ pub fn lowerAnonDecl(
17791824}
17801825
17811826pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1827 const gpa = wasm.base.comp.gpa;
17821828 const atom_index = wasm.anon_decls.get(decl_val).?;
17831829 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
17841830
......@@ -1793,17 +1839,17 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
17931839 // as function pointers are not allowed to be stored inside the data section.
17941840 // They are instead stored in a function table which are called by index.
17951841 try wasm.addTableFunction(target_symbol_index);
1796 try parent_atom.relocs.append(wasm.base.allocator, .{
1842 try parent_atom.relocs.append(gpa, .{
17971843 .index = target_symbol_index,
1798 .offset = @as(u32, @intCast(reloc_info.offset)),
1844 .offset = @intCast(reloc_info.offset),
17991845 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
18001846 });
18011847 } else {
1802 try parent_atom.relocs.append(wasm.base.allocator, .{
1848 try parent_atom.relocs.append(gpa, .{
18031849 .index = target_symbol_index,
1804 .offset = @as(u32, @intCast(reloc_info.offset)),
1850 .offset = @intCast(reloc_info.offset),
18051851 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1806 .addend = @as(i32, @intCast(reloc_info.addend)),
1852 .addend = @intCast(reloc_info.addend),
18071853 });
18081854 }
18091855
......@@ -1840,8 +1886,6 @@ pub fn updateExports(
18401886 }
18411887 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
18421888
1843 if (wasm.base.options.emit == null) return;
1844
18451889 const decl_index = switch (exported) {
18461890 .decl_index => |i| i,
18471891 .value => |val| {
......@@ -1880,7 +1924,7 @@ pub fn updateExports(
18801924 };
18811925 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);
18821926 const exported_atom = wasm.getAtom(exported_atom_index);
1883 const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name));
1927 const export_name = try wasm.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name));
18841928 const sym_loc = exported_atom.symbolLoc();
18851929 const symbol = sym_loc.getSymbol(wasm);
18861930 symbol.setGlobal(true);
......@@ -1915,7 +1959,7 @@ pub fn updateExports(
19151959
19161960 if (!existing_sym.isUndefined()) blk: {
19171961 if (symbol.isWeak()) {
1918 try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc);
1962 try wasm.discarded.put(gpa, existing_loc, sym_loc);
19191963 continue; // to-be-exported symbol is weak, so we keep the existing symbol
19201964 }
19211965
......@@ -1939,18 +1983,18 @@ pub fn updateExports(
19391983 }
19401984
19411985 // in this case the existing symbol must be replaced either because it's weak or undefined.
1942 try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc);
1986 try wasm.discarded.put(gpa, existing_loc, sym_loc);
19431987 _ = wasm.imports.remove(existing_loc);
19441988 _ = wasm.undefs.swapRemove(existing_sym.name);
19451989 }
19461990
19471991 // Ensure the symbol will be exported using the given name
19481992 if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) {
1949 try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name);
1993 try wasm.export_names.put(gpa, sym_loc, export_name);
19501994 }
19511995
19521996 try wasm.globals.put(
1953 wasm.base.allocator,
1997 gpa,
19541998 export_name,
19551999 sym_loc,
19562000 );
......@@ -1959,18 +2003,19 @@ pub fn updateExports(
19592003
19602004pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
19612005 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
2006 const gpa = wasm.base.comp.gpa;
19622007 const mod = wasm.base.options.module.?;
19632008 const decl = mod.declPtr(decl_index);
19642009 const atom_index = wasm.decls.get(decl_index).?;
19652010 const atom = wasm.getAtomPtr(atom_index);
1966 wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};
2011 wasm.symbols_free_list.append(gpa, atom.sym_index) catch {};
19672012 _ = wasm.decls.remove(decl_index);
19682013 wasm.symbols.items[atom.sym_index].tag = .dead;
19692014 for (atom.locals.items) |local_atom_index| {
19702015 const local_atom = wasm.getAtom(local_atom_index);
19712016 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
19722017 local_symbol.tag = .dead; // also for any local symbol
1973 wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {};
2018 wasm.symbols_free_list.append(gpa, local_atom.sym_index) catch {};
19742019 assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc()));
19752020 assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));
19762021 }
......@@ -1999,8 +2044,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
19992044
20002045/// Appends a new entry to the indirect function table
20012046pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {
2002 const index = @as(u32, @intCast(wasm.function_table.count()));
2003 try wasm.function_table.put(wasm.base.allocator, .{ .file = null, .index = symbol_index }, index);
2047 const gpa = wasm.base.comp.gpa;
2048 const index: u32 = @intCast(wasm.function_table.count());
2049 try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index);
20042050}
20052051
20062052/// Assigns indexes to all indirect functions.
......@@ -2019,7 +2065,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
20192065 }
20202066 }
20212067
2022 if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) {
2068 if (wasm.import_table or wasm.base.options.output_mode == .Obj) {
20232069 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
20242070 const import = wasm.imports.getPtr(sym_loc).?;
20252071 import.kind.table.limits.min = index - 1; // we start at index 1.
......@@ -2048,6 +2094,7 @@ pub fn addOrUpdateImport(
20482094 /// is asserted instead.
20492095 type_index: ?u32,
20502096) !void {
2097 const gpa = wasm.base.comp.gpa;
20512098 assert(symbol_index != 0);
20522099 // For the import name, we use the decl's name, rather than the fully qualified name
20532100 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same
......@@ -2055,11 +2102,11 @@ pub fn addOrUpdateImport(
20552102 const mangle_name = lib_name != null and
20562103 !std.mem.eql(u8, lib_name.?, "c");
20572104 const full_name = if (mangle_name) full_name: {
2058 break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? });
2105 break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? });
20592106 } else name;
2060 defer if (mangle_name) wasm.base.allocator.free(full_name);
2107 defer if (mangle_name) gpa.free(full_name);
20612108
2062 const decl_name_index = try wasm.string_table.put(wasm.base.allocator, full_name);
2109 const decl_name_index = try wasm.string_table.put(gpa, full_name);
20632110 const symbol: *Symbol = &wasm.symbols.items[symbol_index];
20642111 symbol.setUndefined(true);
20652112 symbol.setGlobal(true);
......@@ -2068,12 +2115,12 @@ pub fn addOrUpdateImport(
20682115 // we specified a specific name for the symbol that does not match the import name
20692116 symbol.setFlag(.WASM_SYM_EXPLICIT_NAME);
20702117 }
2071 const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index);
2118 const global_gop = try wasm.globals.getOrPut(gpa, decl_name_index);
20722119 if (!global_gop.found_existing) {
20732120 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };
20742121 global_gop.value_ptr.* = loc;
2075 try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});
2076 try wasm.undefs.putNoClobber(wasm.base.allocator, decl_name_index, loc);
2122 try wasm.resolved_symbols.put(gpa, loc, {});
2123 try wasm.undefs.putNoClobber(gpa, decl_name_index, loc);
20772124 } else if (global_gop.value_ptr.*.index != symbol_index) {
20782125 // We are not updating a symbol, but found an existing global
20792126 // symbol with the same name. This means we always favor the
......@@ -2081,21 +2128,21 @@ pub fn addOrUpdateImport(
20812128 // We can also skip storing the import as we will not output
20822129 // this symbol.
20832130 return wasm.discarded.put(
2084 wasm.base.allocator,
2131 gpa,
20852132 .{ .file = null, .index = symbol_index },
20862133 global_gop.value_ptr.*,
20872134 );
20882135 }
20892136
20902137 if (type_index) |ty_index| {
2091 const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null });
2138 const gop = try wasm.imports.getOrPut(gpa, .{ .index = symbol_index, .file = null });
20922139 const module_name = if (lib_name) |l_name| blk: {
20932140 break :blk l_name;
20942141 } else wasm.host_name;
20952142 if (!gop.found_existing) {
20962143 gop.value_ptr.* = .{
2097 .module_name = try wasm.string_table.put(wasm.base.allocator, module_name),
2098 .name = try wasm.string_table.put(wasm.base.allocator, name),
2144 .module_name = try wasm.string_table.put(gpa, module_name),
2145 .name = try wasm.string_table.put(gpa, name),
20992146 .kind = .{ .function = ty_index },
21002147 };
21012148 }
......@@ -2132,10 +2179,10 @@ const Kind = union(enum) {
21322179
21332180/// Parses an Atom and inserts its metadata into the corresponding sections.
21342181fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2182 const gpa = wasm.base.comp.gpa;
21352183 const atom = wasm.getAtomPtr(atom_index);
21362184 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
2137 const do_garbage_collect = wasm.base.options.gc_sections orelse
2138 (wasm.base.options.output_mode != .Obj);
2185 const do_garbage_collect = wasm.base.gc_sections;
21392186
21402187 if (symbol.isDead() and do_garbage_collect) {
21412188 // Prevent unreferenced symbols from being parsed.
......@@ -2147,7 +2194,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
21472194 const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count);
21482195 const type_index = wasm.atom_types.get(atom_index).?;
21492196 try wasm.functions.putNoClobber(
2150 wasm.base.allocator,
2197 gpa,
21512198 .{ .file = null, .index = index },
21522199 .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index },
21532200 );
......@@ -2156,7 +2203,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
21562203
21572204 if (wasm.code_section_index == null) {
21582205 wasm.code_section_index = @intCast(wasm.segments.items.len);
2159 try wasm.segments.append(wasm.base.allocator, .{
2206 try wasm.segments.append(gpa, .{
21602207 .alignment = atom.alignment,
21612208 .size = atom.size,
21622209 .offset = 0,
......@@ -2167,11 +2214,11 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
21672214 break :result wasm.code_section_index.?;
21682215 },
21692216 .data => result: {
2170 const segment_name = try std.mem.concat(wasm.base.allocator, u8, &.{
2217 const segment_name = try std.mem.concat(gpa, u8, &.{
21712218 kind.segmentName(),
21722219 wasm.string_table.get(symbol.name),
21732220 });
2174 errdefer wasm.base.allocator.free(segment_name);
2221 errdefer gpa.free(segment_name);
21752222 const segment_info: types.Segment = .{
21762223 .name = segment_name,
21772224 .alignment = atom.alignment,
......@@ -2188,14 +2235,14 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
21882235 }
21892236
21902237 const should_merge = wasm.base.options.output_mode != .Obj;
2191 const gop = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(should_merge));
2238 const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge));
21922239 if (gop.found_existing) {
21932240 const index = gop.value_ptr.*;
21942241 wasm.segments.items[index].size += atom.size;
21952242
21962243 symbol.index = @intCast(wasm.segment_info.getIndex(index).?);
21972244 // segment info already exists, so free its memory
2198 wasm.base.allocator.free(segment_name);
2245 gpa.free(segment_name);
21992246 break :result index;
22002247 } else {
22012248 const index: u32 = @intCast(wasm.segments.items.len);
......@@ -2203,7 +2250,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
22032250 if (wasm.base.options.shared_memory) {
22042251 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
22052252 }
2206 try wasm.segments.append(wasm.base.allocator, .{
2253 try wasm.segments.append(gpa, .{
22072254 .alignment = atom.alignment,
22082255 .size = 0,
22092256 .offset = 0,
......@@ -2212,7 +2259,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
22122259 gop.value_ptr.* = index;
22132260
22142261 const info_index: u32 = @intCast(wasm.segment_info.count());
2215 try wasm.segment_info.put(wasm.base.allocator, index, segment_info);
2262 try wasm.segment_info.put(gpa, index, segment_info);
22162263 symbol.index = info_index;
22172264 break :result index;
22182265 }
......@@ -2228,6 +2275,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
22282275/// From a given index, append the given `Atom` at the back of the linked list.
22292276/// Simply inserts it into the map of atoms when it doesn't exist yet.
22302277pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
2278 const gpa = wasm.base.comp.gpa;
22312279 const atom = wasm.getAtomPtr(atom_index);
22322280 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
22332281 const last = wasm.getAtomPtr(last_index_ptr.*);
......@@ -2235,7 +2283,7 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void
22352283 atom.prev = last_index_ptr.*;
22362284 last_index_ptr.* = atom_index;
22372285 } else {
2238 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index);
2286 try wasm.atoms.putNoClobber(gpa, index, atom_index);
22392287 }
22402288}
22412289
......@@ -2363,12 +2411,13 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
23632411}
23642412
23652413fn sortDataSegments(wasm: *Wasm) !void {
2414 const gpa = wasm.base.comp.gpa;
23662415 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
2367 try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count());
2368 errdefer new_mapping.deinit(wasm.base.allocator);
2416 try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());
2417 errdefer new_mapping.deinit(gpa);
23692418
2370 const keys = try wasm.base.allocator.dupe([]const u8, wasm.data_segments.keys());
2371 defer wasm.base.allocator.free(keys);
2419 const keys = try gpa.dupe([]const u8, wasm.data_segments.keys());
2420 defer gpa.free(keys);
23722421
23732422 const SortContext = struct {
23742423 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
......@@ -2388,7 +2437,7 @@ fn sortDataSegments(wasm: *Wasm) !void {
23882437 const segment_index = wasm.data_segments.get(key).?;
23892438 new_mapping.putAssumeCapacity(key, segment_index);
23902439 }
2391 wasm.data_segments.deinit(wasm.base.allocator);
2440 wasm.data_segments.deinit(gpa);
23922441 wasm.data_segments = new_mapping;
23932442}
23942443
......@@ -2401,8 +2450,9 @@ fn sortDataSegments(wasm: *Wasm) !void {
24012450/// original functions and their types. We need to know the type to verify it doesn't
24022451/// contain any parameters.
24032452fn setupInitFunctions(wasm: *Wasm) !void {
2453 const gpa = wasm.base.comp.gpa;
24042454 for (wasm.objects.items, 0..) |object, file_index| {
2405 try wasm.init_funcs.ensureUnusedCapacity(wasm.base.allocator, object.init_funcs.len);
2455 try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len);
24062456 for (object.init_funcs) |init_func| {
24072457 const symbol = object.symtable[init_func.symbol_index];
24082458 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {
......@@ -2439,6 +2489,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
24392489/// Generates an atom containing the global error set' size.
24402490/// This will only be generated if the symbol exists.
24412491fn setupErrorsLen(wasm: *Wasm) !void {
2492 const gpa = wasm.base.comp.gpa;
24422493 const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;
24432494
24442495 const errors_len = wasm.base.options.module.?.global_error_set.count();
......@@ -2456,19 +2507,19 @@ fn setupErrorsLen(wasm: *Wasm) !void {
24562507 prev_atom.next = atom.next;
24572508 atom.prev = null;
24582509 }
2459 atom.deinit(wasm.base.allocator);
2510 atom.deinit(gpa);
24602511 break :blk index;
24612512 } else new_atom: {
24622513 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
2463 try wasm.symbol_atom.put(wasm.base.allocator, loc, atom_index);
2464 try wasm.managed_atoms.append(wasm.base.allocator, undefined);
2514 try wasm.symbol_atom.put(gpa, loc, atom_index);
2515 try wasm.managed_atoms.append(gpa, undefined);
24652516 break :new_atom atom_index;
24662517 };
24672518 const atom = wasm.getAtomPtr(atom_index);
24682519 atom.* = Atom.empty;
24692520 atom.sym_index = loc.index;
24702521 atom.size = 2;
2471 try atom.code.writer(wasm.base.allocator).writeInt(u16, @intCast(errors_len), .little);
2522 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
24722523
24732524 try wasm.parseAtom(atom_index, .{ .data = .read_only });
24742525}
......@@ -2480,16 +2531,17 @@ fn setupErrorsLen(wasm: *Wasm) !void {
24802531/// references to the function stored in the symbol have been finalized so we end
24812532/// up calling the resolved function.
24822533fn initializeCallCtorsFunction(wasm: *Wasm) !void {
2534 const gpa = wasm.base.comp.gpa;
24832535 // No code to emit, so also no ctors to call
24842536 if (wasm.code_section_index == null) {
24852537 // Make sure to remove it from the resolved symbols so we do not emit
24862538 // it within any section. TODO: Remove this once we implement garbage collection.
24872539 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
2488 std.debug.assert(wasm.resolved_symbols.swapRemove(loc));
2540 assert(wasm.resolved_symbols.swapRemove(loc));
24892541 return;
24902542 }
24912543
2492 var function_body = std.ArrayList(u8).init(wasm.base.allocator);
2544 var function_body = std.ArrayList(u8).init(gpa);
24932545 defer function_body.deinit();
24942546 const writer = function_body.writer();
24952547
......@@ -2531,6 +2583,7 @@ fn createSyntheticFunction(
25312583 func_ty: std.wasm.Type,
25322584 function_body: *std.ArrayList(u8),
25332585) !void {
2586 const gpa = wasm.base.comp.gpa;
25342587 const loc = wasm.findGlobalSymbol(symbol_name) orelse
25352588 try wasm.createSyntheticSymbol(symbol_name, .function);
25362589 const symbol = loc.getSymbol(wasm);
......@@ -2541,7 +2594,7 @@ fn createSyntheticFunction(
25412594 // create function with above type
25422595 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));
25432596 try wasm.functions.putNoClobber(
2544 wasm.base.allocator,
2597 gpa,
25452598 .{ .file = null, .index = func_index },
25462599 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },
25472600 );
......@@ -2549,7 +2602,7 @@ fn createSyntheticFunction(
25492602
25502603 // create the atom that will be output into the final binary
25512604 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
2552 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
2605 const atom = try wasm.managed_atoms.addOne(gpa);
25532606 atom.* = .{
25542607 .size = @as(u32, @intCast(function_body.items.len)),
25552608 .offset = 0,
......@@ -2562,7 +2615,7 @@ fn createSyntheticFunction(
25622615 .original_offset = 0,
25632616 };
25642617 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
2565 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
2618 try wasm.symbol_atom.putNoClobber(gpa, loc, atom_index);
25662619
25672620 // `allocateAtoms` has already been called, set the atom's offset manually.
25682621 // This is fine to do manually as we insert the atom at the very end.
......@@ -2582,10 +2635,11 @@ pub fn createFunction(
25822635 function_body: *std.ArrayList(u8),
25832636 relocations: *std.ArrayList(Relocation),
25842637) !u32 {
2638 const gpa = wasm.base.comp.gpa;
25852639 const loc = try wasm.createSyntheticSymbol(symbol_name, .function);
25862640
2587 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
2588 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
2641 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
2642 const atom = try wasm.managed_atoms.addOne(gpa);
25892643 atom.* = .{
25902644 .size = @intCast(function_body.items.len),
25912645 .offset = 0,
......@@ -2607,9 +2661,9 @@ pub fn createFunction(
26072661 break :idx index;
26082662 };
26092663 try wasm.appendAtomAtIndex(section_index, atom_index);
2610 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
2611 try wasm.atom_types.put(wasm.base.allocator, atom_index, try wasm.putOrGetFuncType(func_ty));
2612 try wasm.synthetic_functions.append(wasm.base.allocator, atom_index);
2664 try wasm.symbol_atom.putNoClobber(gpa, loc, atom_index);
2665 try wasm.atom_types.put(gpa, atom_index, try wasm.putOrGetFuncType(func_ty));
2666 try wasm.synthetic_functions.append(gpa, atom_index);
26132667
26142668 return loc.index;
26152669}
......@@ -2622,9 +2676,11 @@ fn setupStartSection(wasm: *Wasm) !void {
26222676}
26232677
26242678fn initializeTLSFunction(wasm: *Wasm) !void {
2679 const gpa = wasm.base.comp.gpa;
2680
26252681 if (!wasm.base.options.shared_memory) return;
26262682
2627 var function_body = std.ArrayList(u8).init(wasm.base.allocator);
2683 var function_body = std.ArrayList(u8).init(gpa);
26282684 defer function_body.deinit();
26292685 const writer = function_body.writer();
26302686
......@@ -2684,6 +2740,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
26842740}
26852741
26862742fn setupImports(wasm: *Wasm) !void {
2743 const gpa = wasm.base.comp.gpa;
26872744 log.debug("Merging imports", .{});
26882745 var discarded_it = wasm.discarded.keyIterator();
26892746 while (discarded_it.next()) |discarded| {
......@@ -2718,12 +2775,12 @@ fn setupImports(wasm: *Wasm) !void {
27182775 // We copy the import to a new import to ensure the names contain references
27192776 // to the internal string table, rather than of the object file.
27202777 const new_imp: types.Import = .{
2721 .module_name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.module_name)),
2722 .name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.name)),
2778 .module_name = try wasm.string_table.put(gpa, object.string_table.get(import.module_name)),
2779 .name = try wasm.string_table.put(gpa, object.string_table.get(import.name)),
27232780 .kind = import.kind,
27242781 };
27252782 // TODO: De-duplicate imports when they contain the same names and type
2726 try wasm.imports.putNoClobber(wasm.base.allocator, symbol_loc, new_imp);
2783 try wasm.imports.putNoClobber(gpa, symbol_loc, new_imp);
27272784 }
27282785
27292786 // Assign all indexes of the imports to their representing symbols
......@@ -2764,7 +2821,9 @@ fn setupImports(wasm: *Wasm) !void {
27642821/// Takes the global, function and table section from each linked object file
27652822/// and merges it into a single section for each.
27662823fn mergeSections(wasm: *Wasm) !void {
2767 var removed_duplicates = std.ArrayList(SymbolLoc).init(wasm.base.allocator);
2824 const gpa = wasm.base.comp.gpa;
2825
2826 var removed_duplicates = std.ArrayList(SymbolLoc).init(gpa);
27682827 defer removed_duplicates.deinit();
27692828
27702829 for (wasm.resolved_symbols.keys()) |sym_loc| {
......@@ -2791,7 +2850,7 @@ fn mergeSections(wasm: *Wasm) !void {
27912850 switch (symbol.tag) {
27922851 .function => {
27932852 const gop = try wasm.functions.getOrPut(
2794 wasm.base.allocator,
2853 gpa,
27952854 .{ .file = sym_loc.file, .index = symbol.index },
27962855 );
27972856 if (gop.found_existing) {
......@@ -2800,7 +2859,7 @@ fn mergeSections(wasm: *Wasm) !void {
28002859 // we only emit a single function, instead of duplicates.
28012860 symbol.unmark();
28022861 try wasm.discarded.putNoClobber(
2803 wasm.base.allocator,
2862 gpa,
28042863 sym_loc,
28052864 .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index },
28062865 );
......@@ -2813,12 +2872,12 @@ fn mergeSections(wasm: *Wasm) !void {
28132872 .global => {
28142873 const original_global = object.globals[index];
28152874 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;
2816 try wasm.wasm_globals.append(wasm.base.allocator, original_global);
2875 try wasm.wasm_globals.append(gpa, original_global);
28172876 },
28182877 .table => {
28192878 const original_table = object.tables[index];
28202879 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;
2821 try wasm.tables.append(wasm.base.allocator, original_table);
2880 try wasm.tables.append(gpa, original_table);
28222881 },
28232882 else => unreachable,
28242883 }
......@@ -2838,10 +2897,11 @@ fn mergeSections(wasm: *Wasm) !void {
28382897/// 'types' section, while assigning the type index to the representing
28392898/// section (import, export, function).
28402899fn mergeTypes(wasm: *Wasm) !void {
2900 const gpa = wasm.base.comp.gpa;
28412901 // A map to track which functions have already had their
28422902 // type inserted. If we do this for the same function multiple times,
28432903 // it will be overwritten with the incorrect type.
2844 var dirty = std.AutoHashMap(u32, void).init(wasm.base.allocator);
2904 var dirty = std.AutoHashMap(u32, void).init(gpa);
28452905 try dirty.ensureUnusedCapacity(@as(u32, @intCast(wasm.functions.count())));
28462906 defer dirty.deinit();
28472907
......@@ -2873,6 +2933,7 @@ fn mergeTypes(wasm: *Wasm) !void {
28732933}
28742934
28752935fn setupExports(wasm: *Wasm) !void {
2936 const gpa = wasm.base.comp.gpa;
28762937 if (wasm.base.options.output_mode == .Obj) return;
28772938 log.debug("Building exports from symbols", .{});
28782939
......@@ -2903,11 +2964,11 @@ fn setupExports(wasm: *Wasm) !void {
29032964 const sym_name = sym_loc.getName(wasm);
29042965 const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: {
29052966 if (sym_loc.file == null) break :blk symbol.name;
2906 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
2967 break :blk try wasm.string_table.put(gpa, sym_name);
29072968 };
29082969 const exp: types.Export = if (symbol.tag == .data) exp: {
29092970 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
2910 try wasm.wasm_globals.append(wasm.base.allocator, .{
2971 try wasm.wasm_globals.append(gpa, .{
29112972 .global_type = .{ .valtype = .i32, .mutable = false },
29122973 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },
29132974 });
......@@ -2926,7 +2987,7 @@ fn setupExports(wasm: *Wasm) !void {
29262987 wasm.string_table.get(exp.name),
29272988 exp.index,
29282989 });
2929 try wasm.exports.append(wasm.base.allocator, exp);
2990 try wasm.exports.append(gpa, exp);
29302991 }
29312992
29322993 log.debug("Completed building exports. Total count: ({d})", .{wasm.exports.items.len});
......@@ -2957,8 +3018,6 @@ fn setupStart(wasm: *Wasm) !void {
29573018fn setupMemory(wasm: *Wasm) !void {
29583019 log.debug("Setting up memory layout", .{});
29593020 const page_size = std.wasm.page_size; // 64kb
2960 // Use the user-provided stack size or else we use 1MB by default
2961 const stack_size = wasm.base.options.stack_size_override orelse page_size * 16;
29623021 const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention
29633022 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
29643023
......@@ -2974,7 +3033,7 @@ fn setupMemory(wasm: *Wasm) !void {
29743033
29753034 if (place_stack_first and !is_obj) {
29763035 memory_ptr = stack_alignment.forward(memory_ptr);
2977 memory_ptr += stack_size;
3036 memory_ptr += wasm.base.stack_size;
29783037 // We always put the stack pointer global at index 0
29793038 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
29803039 }
......@@ -3021,7 +3080,7 @@ fn setupMemory(wasm: *Wasm) !void {
30213080
30223081 if (!place_stack_first and !is_obj) {
30233082 memory_ptr = stack_alignment.forward(memory_ptr);
3024 memory_ptr += stack_size;
3083 memory_ptr += wasm.base.stack_size;
30253084 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
30263085 }
30273086
......@@ -3088,29 +3147,30 @@ fn setupMemory(wasm: *Wasm) !void {
30883147/// index of the segment within the final data section. When the segment does not yet
30893148/// exist, a new one will be initialized and appended. The new index will be returned in that case.
30903149pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
3150 const gpa = wasm.base.comp.gpa;
30913151 const object: Object = wasm.objects.items[object_index];
30923152 const symbol = object.symtable[symbol_index];
3093 const index = @as(u32, @intCast(wasm.segments.items.len));
3153 const index: u32 = @intCast(wasm.segments.items.len);
30943154
30953155 switch (symbol.tag) {
30963156 .data => {
30973157 const segment_info = object.segment_info[symbol.index];
30983158 const merge_segment = wasm.base.options.output_mode != .Obj;
3099 const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
3159 const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
31003160 if (!result.found_existing) {
31013161 result.value_ptr.* = index;
31023162 var flags: u32 = 0;
31033163 if (wasm.base.options.shared_memory) {
31043164 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
31053165 }
3106 try wasm.segments.append(wasm.base.allocator, .{
3166 try wasm.segments.append(gpa, .{
31073167 .alignment = .@"1",
31083168 .size = 0,
31093169 .offset = 0,
31103170 .flags = flags,
31113171 });
3112 try wasm.segment_info.putNoClobber(wasm.base.allocator, index, .{
3113 .name = try wasm.base.allocator.dupe(u8, segment_info.name),
3172 try wasm.segment_info.putNoClobber(gpa, index, .{
3173 .name = try gpa.dupe(u8, segment_info.name),
31143174 .alignment = segment_info.alignment,
31153175 .flags = segment_info.flags,
31163176 });
......@@ -3183,7 +3243,8 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3
31833243
31843244/// Appends a new segment with default field values
31853245fn appendDummySegment(wasm: *Wasm) !void {
3186 try wasm.segments.append(wasm.base.allocator, .{
3246 const gpa = wasm.base.comp.gpa;
3247 try wasm.segments.append(gpa, .{
31873248 .alignment = .@"1",
31883249 .size = 0,
31893250 .offset = 0,
......@@ -3203,6 +3264,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
32033264 // and then return said symbol's index. The final table will be populated
32043265 // during `flush` when we know all possible error names.
32053266
3267 const gpa = wasm.base.comp.gpa;
32063268 const atom_index = try wasm.createAtom();
32073269 const atom = wasm.getAtomPtr(atom_index);
32083270 const slice_ty = Type.slice_const_u8_sentinel_0;
......@@ -3210,7 +3272,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
32103272 atom.alignment = slice_ty.abiAlignment(mod);
32113273 const sym_index = atom.sym_index;
32123274
3213 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table");
3275 const sym_name = try wasm.string_table.put(gpa, "__zig_err_name_table");
32143276 const symbol = &wasm.symbols.items[sym_index];
32153277 symbol.* = .{
32163278 .name = sym_name,
......@@ -3222,7 +3284,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
32223284 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
32233285 symbol.mark();
32243286
3225 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
3287 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
32263288
32273289 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
32283290 wasm.error_table_symbol = sym_index;
......@@ -3234,6 +3296,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
32343296/// This creates a table that consists of pointers and length to each error name.
32353297/// The table is what is being pointed to within the runtime bodies that are generated.
32363298fn populateErrorNameTable(wasm: *Wasm) !void {
3299 const gpa = wasm.base.comp.gpa;
32373300 const symbol_index = wasm.error_table_symbol orelse return;
32383301 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
32393302
......@@ -3243,7 +3306,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
32433306 const names_atom_index = try wasm.createAtom();
32443307 const names_atom = wasm.getAtomPtr(names_atom_index);
32453308 names_atom.alignment = .@"1";
3246 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
3309 const sym_name = try wasm.string_table.put(gpa, "__zig_err_names");
32473310 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
32483311 names_symbol.* = .{
32493312 .name = sym_name,
......@@ -3269,10 +3332,10 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
32693332 const slice_ty = Type.slice_const_u8_sentinel_0;
32703333 const offset = @as(u32, @intCast(atom.code.items.len));
32713334 // first we create the data for the slice of the name
3272 try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated
3273 try atom.code.writer(wasm.base.allocator).writeInt(u32, len - 1, .little);
3335 try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated
3336 try atom.code.writer(gpa).writeInt(u32, len - 1, .little);
32743337 // create relocation to the error name
3275 try atom.relocs.append(wasm.base.allocator, .{
3338 try atom.relocs.append(gpa, .{
32763339 .index = names_atom.sym_index,
32773340 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
32783341 .offset = offset,
......@@ -3282,7 +3345,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
32823345 addend += len;
32833346
32843347 // as we updated the error name table, we now store the actual name within the names atom
3285 try names_atom.code.ensureUnusedCapacity(wasm.base.allocator, len);
3348 try names_atom.code.ensureUnusedCapacity(gpa, len);
32863349 names_atom.code.appendSliceAssumeCapacity(error_name);
32873350 names_atom.code.appendAssumeCapacity(0);
32883351
......@@ -3291,8 +3354,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
32913354 names_atom.size = addend;
32923355
32933356 const name_loc = names_atom.symbolLoc();
3294 try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});
3295 try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index);
3357 try wasm.resolved_symbols.put(gpa, name_loc, {});
3358 try wasm.symbol_atom.put(gpa, name_loc, names_atom_index);
32963359
32973360 // link the atoms with the rest of the binary so they can be allocated
32983361 // and relocations will be performed.
......@@ -3304,7 +3367,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
33043367/// This initializes the index, appends a new segment,
33053368/// and finally, creates a managed `Atom`.
33063369pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {
3307 const new_index = @as(u32, @intCast(wasm.segments.items.len));
3370 const gpa = wasm.base.comp.gpa;
3371 const new_index: u32 = @intCast(wasm.segments.items.len);
33083372 index.* = new_index;
33093373 try wasm.appendDummySegment();
33103374
......@@ -3312,7 +3376,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
33123376 const atom = wasm.getAtomPtr(atom_index);
33133377 wasm.symbols.items[atom.sym_index] = .{
33143378 .tag = .section,
3315 .name = try wasm.string_table.put(wasm.base.allocator, name),
3379 .name = try wasm.string_table.put(gpa, name),
33163380 .index = 0,
33173381 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
33183382 };
......@@ -3322,8 +3386,10 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
33223386}
33233387
33243388fn resetState(wasm: *Wasm) void {
3389 const gpa = wasm.base.comp.gpa;
3390
33253391 for (wasm.segment_info.values()) |segment_info| {
3326 wasm.base.allocator.free(segment_info.name);
3392 gpa.free(segment_info.name);
33273393 }
33283394
33293395 var atom_it = wasm.decls.valueIterator();
......@@ -3358,16 +3424,12 @@ fn resetState(wasm: *Wasm) void {
33583424}
33593425
33603426pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
3361 if (wasm.base.options.emit == null) {
3362 if (wasm.llvm_object) |llvm_object| {
3363 return try llvm_object.flushModule(comp, prog_node);
3364 }
3365 return;
3366 }
3427 const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld;
3428 const use_llvm = wasm.base.comp.config.use_llvm;
33673429
3368 if (build_options.have_llvm and wasm.base.options.use_lld) {
3430 if (use_lld) {
33693431 return wasm.linkWithLLD(comp, prog_node);
3370 } else if (wasm.base.options.use_llvm and !wasm.base.options.use_lld) {
3432 } else if (use_llvm and !use_lld) {
33713433 return wasm.linkWithZld(comp, prog_node);
33723434 } else {
33733435 return wasm.flushModule(comp, prog_node);
......@@ -3379,21 +3441,22 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
33793441 const tracy = trace(@src());
33803442 defer tracy.end();
33813443
3382 const gpa = wasm.base.allocator;
3383 const options = wasm.base.options;
3444 const gpa = wasm.base.comp.gpa;
33843445
33853446 // Used for all temporary memory allocated during flushin
33863447 var arena_instance = std.heap.ArenaAllocator.init(gpa);
33873448 defer arena_instance.deinit();
33883449 const arena = arena_instance.allocator();
33893450
3390 const directory = options.emit.?.directory; // Just an alias to make it shorter to type.
3391 const full_out_path = try directory.join(arena, &[_][]const u8{options.emit.?.sub_path});
3451 const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
3452 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
3453 const opt_zcu = wasm.base.comp.module;
3454 const use_llvm = wasm.base.comp.config.use_llvm;
33923455
33933456 // If there is no Zig code to compile, then we should skip flushing the output file because it
33943457 // will not be part of the linker line anyway.
3395 const module_obj_path: ?[]const u8 = if (options.module != null) blk: {
3396 assert(options.use_llvm); // `linkWithZld` should never be called when the Wasm backend is used
3458 const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: {
3459 assert(use_llvm); // `linkWithZld` should never be called when the Wasm backend is used
33973460 try wasm.flushModule(comp, prog_node);
33983461
33993462 if (fs.path.dirname(full_out_path)) |dirname| {
......@@ -3416,12 +3479,14 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34163479 const id_symlink_basename = "zld.id";
34173480
34183481 var man: Cache.Manifest = undefined;
3419 defer if (!options.disable_lld_caching) man.deinit();
3482 defer if (!wasm.base.disable_lld_caching) man.deinit();
34203483 var digest: [Cache.hex_digest_len]u8 = undefined;
34213484
3485 const objects = wasm.base.comp.objects;
3486
34223487 // NOTE: The following section must be maintained to be equal
34233488 // as the section defined in `linkWithLLD`
3424 if (!options.disable_lld_caching) {
3489 if (!wasm.base.disable_lld_caching) {
34253490 man = comp.cache_parent.obtain();
34263491
34273492 // We are about to obtain this lock, so here we give other processes a chance first.
......@@ -3429,7 +3494,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34293494
34303495 comptime assert(Compilation.link_hash_implementation_version == 10);
34313496
3432 for (options.objects) |obj| {
3497 for (objects) |obj| {
34333498 _ = try man.addFile(obj.path, null);
34343499 man.hash.add(obj.must_link);
34353500 }
......@@ -3438,19 +3503,19 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34383503 }
34393504 try man.addOptionalFile(module_obj_path);
34403505 try man.addOptionalFile(compiler_rt_path);
3441 man.hash.addOptionalBytes(options.entry);
3442 man.hash.addOptional(options.stack_size_override);
3443 man.hash.add(wasm.base.options.build_id);
3444 man.hash.add(options.import_memory);
3445 man.hash.add(options.import_table);
3446 man.hash.add(options.export_table);
3447 man.hash.addOptional(options.initial_memory);
3448 man.hash.addOptional(options.max_memory);
3449 man.hash.add(options.shared_memory);
3450 man.hash.addOptional(options.global_base);
3451 man.hash.add(options.export_symbol_names.len);
3506 man.hash.addOptionalBytes(wasm.base.comp.config.entry);
3507 man.hash.add(wasm.base.stack_size);
3508 man.hash.add(wasm.base.build_id);
3509 man.hash.add(wasm.base.comp.config.import_memory);
3510 man.hash.add(wasm.base.comp.config.shared_memory);
3511 man.hash.add(wasm.import_table);
3512 man.hash.add(wasm.export_table);
3513 man.hash.addOptional(wasm.initial_memory);
3514 man.hash.addOptional(wasm.max_memory);
3515 man.hash.addOptional(wasm.global_base);
3516 man.hash.add(wasm.export_symbol_names.len);
34523517 // strip does not need to go into the linker hash because it is part of the hash namespace
3453 for (options.export_symbol_names) |symbol_name| {
3518 for (wasm.export_symbol_names) |symbol_name| {
34543519 man.hash.addBytes(symbol_name);
34553520 }
34563521
......@@ -3485,30 +3550,36 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34853550
34863551 // Positional arguments to the linker such as object files and static archives.
34873552 var positionals = std.ArrayList([]const u8).init(arena);
3488 try positionals.ensureUnusedCapacity(options.objects.len);
3553 try positionals.ensureUnusedCapacity(objects.len);
3554
3555 const target = wasm.base.comp.root_mod.resolved_target.result;
3556 const output_mode = wasm.base.comp.config.output_mode;
3557 const link_mode = wasm.base.comp.config.link_mode;
3558 const link_libc = wasm.base.comp.config.link_libc;
3559 const link_libcpp = wasm.base.comp.config.link_libcpp;
3560 const wasi_exec_model = wasm.base.comp.config.wasi_exec_model;
34893561
34903562 // When the target os is WASI, we allow linking with WASI-LIBC
3491 if (options.target.os.tag == .wasi) {
3492 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or
3493 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);
3563 if (target.os.tag == .wasi) {
3564 const is_exe_or_dyn_lib = output_mode == .Exe or
3565 (output_mode == .Lib and link_mode == .Dynamic);
34943566 if (is_exe_or_dyn_lib) {
3495 const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs;
3496 for (wasi_emulated_libs) |crt_file| {
3567 for (wasm.wasi_emulated_libs) |crt_file| {
34973568 try positionals.append(try comp.get_libc_crt_file(
34983569 arena,
34993570 wasi_libc.emulatedLibCRFileLibName(crt_file),
35003571 ));
35013572 }
35023573
3503 if (wasm.base.options.link_libc) {
3574 if (link_libc) {
35043575 try positionals.append(try comp.get_libc_crt_file(
35053576 arena,
3506 wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model),
3577 wasi_libc.execModelCrtFileFullName(wasi_exec_model),
35073578 ));
35083579 try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));
35093580 }
35103581
3511 if (wasm.base.options.link_libcpp) {
3582 if (link_libcpp) {
35123583 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
35133584 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
35143585 }
......@@ -3519,7 +3590,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
35193590 try positionals.append(path);
35203591 }
35213592
3522 for (options.objects) |object| {
3593 for (objects) |object| {
35233594 try positionals.append(object.path);
35243595 }
35253596
......@@ -3562,7 +3633,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
35623633 try wasm.setupExports();
35633634 try wasm.writeToFile(enabled_features, emit_features_count, arena);
35643635
3565 if (!wasm.base.options.disable_lld_caching) {
3636 if (!wasm.base.disable_lld_caching) {
35663637 // Update the file with the digest. If it fails we can continue; it only
35673638 // means that the next invocation will have an unnecessary cache miss.
35683639 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
......@@ -3594,15 +3665,18 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
35943665 try wasm.populateErrorNameTable();
35953666
35963667 // Used for all temporary memory allocated during flushin
3597 var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator);
3668 const gpa = wasm.base.comp.gpa;
3669 var arena_instance = std.heap.ArenaAllocator.init(gpa);
35983670 defer arena_instance.deinit();
35993671 const arena = arena_instance.allocator();
36003672
3673 const objects = wasm.base.comp.objects;
3674
36013675 // Positional arguments to the linker such as object files and static archives.
36023676 var positionals = std.ArrayList([]const u8).init(arena);
3603 try positionals.ensureUnusedCapacity(wasm.base.options.objects.len);
3677 try positionals.ensureUnusedCapacity(objects.len);
36043678
3605 for (wasm.base.options.objects) |object| {
3679 for (objects) |object| {
36063680 positionals.appendAssumeCapacity(object.path);
36073681 }
36083682
......@@ -3711,6 +3785,10 @@ fn writeToFile(
37113785 feature_count: u32,
37123786 arena: Allocator,
37133787) !void {
3788 const gpa = wasm.base.comp.gpa;
3789 const use_llvm = wasm.base.comp.config.use_llvm;
3790 const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld;
3791
37143792 // Size of each section header
37153793 const header_size = 5 + 1;
37163794 // The amount of sections that will be written
......@@ -3719,9 +3797,9 @@ fn writeToFile(
37193797 var code_section_index: ?u32 = null;
37203798 // Index of the data section. Used to tell relocation table where the section lives.
37213799 var data_section_index: ?u32 = null;
3722 const is_obj = wasm.base.options.output_mode == .Obj or (!wasm.base.options.use_llvm and wasm.base.options.use_lld);
3800 const is_obj = wasm.base.options.output_mode == .Obj or (!use_llvm and use_lld);
37233801
3724 var binary_bytes = std.ArrayList(u8).init(wasm.base.allocator);
3802 var binary_bytes = std.ArrayList(u8).init(gpa);
37253803 defer binary_bytes.deinit();
37263804 const binary_writer = binary_bytes.writer();
37273805
......@@ -3774,8 +3852,8 @@ fn writeToFile(
37743852 if (import_memory) {
37753853 const mem_name = if (is_obj) "__linear_memory" else "memory";
37763854 const mem_imp: types.Import = .{
3777 .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name),
3778 .name = try wasm.string_table.put(wasm.base.allocator, mem_name),
3855 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
3856 .name = try wasm.string_table.put(gpa, mem_name),
37793857 .kind = .{ .memory = wasm.memories.limits },
37803858 };
37813859 try wasm.emitImport(binary_writer, mem_imp);
......@@ -3955,7 +4033,7 @@ fn writeToFile(
39554033 var atom_index = wasm.atoms.get(code_index).?;
39564034
39574035 // The code section must be sorted in line with the function order.
3958 var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
4036 var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(gpa, wasm.functions.count());
39594037 defer sorted_atoms.deinit();
39604038
39614039 while (true) {
......@@ -3966,7 +4044,7 @@ fn writeToFile(
39664044 sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions
39674045 atom_index = atom.prev orelse break;
39684046 }
3969 std.debug.assert(wasm.functions.count() == sorted_atoms.items.len);
4047 assert(wasm.functions.count() == sorted_atoms.items.len);
39704048
39714049 const atom_sort_fn = struct {
39724050 fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool {
......@@ -4086,7 +4164,7 @@ fn writeToFile(
40864164 if (!wasm.base.options.strip) {
40874165 // The build id must be computed on the main sections only,
40884166 // so we have to do it now, before the debug sections.
4089 switch (wasm.base.options.build_id) {
4167 switch (wasm.base.build_id) {
40904168 .none => {},
40914169 .fast => {
40924170 var id: [16]u8 = undefined;
......@@ -4121,7 +4199,7 @@ fn writeToFile(
41214199 // try dwarf.writeDbgLineHeader();
41224200 // }
41234201
4124 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);
4202 var debug_bytes = std.ArrayList(u8).init(gpa);
41254203 defer debug_bytes.deinit();
41264204
41274205 const DebugSection = struct {
......@@ -4362,8 +4440,10 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
43624440}
43634441
43644442fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {
4443 const gpa = wasm.base.comp.gpa;
4444
43654445 // We must emit subsection size, so first write to a temporary list
4366 var section_list = std.ArrayList(u8).init(wasm.base.allocator);
4446 var section_list = std.ArrayList(u8).init(gpa);
43674447 defer section_list.deinit();
43684448 const sub_writer = section_list.writer();
43694449
......@@ -4445,12 +4525,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
44454525 const tracy = trace(@src());
44464526 defer tracy.end();
44474527
4448 var arena_allocator = std.heap.ArenaAllocator.init(wasm.base.allocator);
4528 const gpa = wasm.base.comp.gpa;
4529 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
44494530 defer arena_allocator.deinit();
44504531 const arena = arena_allocator.allocator();
44514532
4452 const directory = wasm.base.options.emit.?.directory; // Just an alias to make it shorter to type.
4453 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.options.emit.?.sub_path});
4533 const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
4534 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
44544535
44554536 // If there is no Zig code to compile, then we should skip flushing the output file because it
44564537 // will not be part of the linker line anyway.
......@@ -4481,11 +4562,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
44814562 const id_symlink_basename = "lld.id";
44824563
44834564 var man: Cache.Manifest = undefined;
4484 defer if (!wasm.base.options.disable_lld_caching) man.deinit();
4565 defer if (!wasm.base.disable_lld_caching) man.deinit();
44854566
44864567 var digest: [Cache.hex_digest_len]u8 = undefined;
44874568
4488 if (!wasm.base.options.disable_lld_caching) {
4569 if (!wasm.base.disable_lld_caching) {
44894570 man = comp.cache_parent.obtain();
44904571
44914572 // We are about to obtain this lock, so here we give other processes a chance first.
......@@ -4502,13 +4583,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
45024583 }
45034584 try man.addOptionalFile(module_obj_path);
45044585 try man.addOptionalFile(compiler_rt_path);
4505 man.hash.addOptionalBytes(wasm.base.options.entry);
4506 man.hash.addOptional(wasm.base.options.stack_size_override);
4507 man.hash.add(wasm.base.options.build_id);
4586 man.hash.addOptionalBytes(wasm.base.comp.config.entry);
4587 man.hash.add(wasm.base.stack_size);
4588 man.hash.add(wasm.base.build_id);
45084589 man.hash.add(wasm.base.options.import_memory);
45094590 man.hash.add(wasm.base.options.export_memory);
4510 man.hash.add(wasm.base.options.import_table);
4511 man.hash.add(wasm.base.options.export_table);
4591 man.hash.add(wasm.import_table);
4592 man.hash.add(wasm.export_table);
45124593 man.hash.addOptional(wasm.base.options.initial_memory);
45134594 man.hash.addOptional(wasm.base.options.max_memory);
45144595 man.hash.add(wasm.base.options.shared_memory);
......@@ -4573,7 +4654,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
45734654 }
45744655 } else {
45754656 // Create an LLD command line and invoke it.
4576 var argv = std.ArrayList([]const u8).init(wasm.base.allocator);
4657 var argv = std.ArrayList([]const u8).init(gpa);
45774658 defer argv.deinit();
45784659 // We will invoke ourselves as a child process to gain access to LLD.
45794660 // This is necessary because LLD does not behave properly as a library -
......@@ -4598,22 +4679,20 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
45984679 try argv.append("--export-memory");
45994680 }
46004681
4601 if (wasm.base.options.import_table) {
4602 assert(!wasm.base.options.export_table);
4682 if (wasm.import_table) {
4683 assert(!wasm.export_table);
46034684 try argv.append("--import-table");
46044685 }
46054686
4606 if (wasm.base.options.export_table) {
4607 assert(!wasm.base.options.import_table);
4687 if (wasm.export_table) {
4688 assert(!wasm.import_table);
46084689 try argv.append("--export-table");
46094690 }
46104691
4611 if (wasm.base.options.gc_sections) |gc| {
4612 // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly
4613 // specified it as garbage collection is enabled by default.
4614 if (!gc) {
4615 try argv.append("--no-gc-sections");
4616 }
4692 // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly
4693 // specified it as garbage collection is enabled by default.
4694 if (!wasm.base.gc_sections) {
4695 try argv.append("--no-gc-sections");
46174696 }
46184697
46194698 if (wasm.base.options.strip) {
......@@ -4662,12 +4741,10 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
46624741 try argv.append("--no-entry");
46634742 }
46644743
4665 // Increase the default stack size to a more reasonable value of 1MB instead of
4666 // the default of 1 Wasm page being 64KB, unless overridden by the user.
4667 try argv.append("-z");
4668 const stack_size = wasm.base.options.stack_size_override orelse std.wasm.page_size * 16;
4669 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
4670 try argv.append(arg);
4744 try argv.appendSlice(&.{
4745 "-z",
4746 try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}),
4747 });
46714748
46724749 if (wasm.base.options.import_symbols) {
46734750 try argv.append("--allow-undefined");
......@@ -4681,7 +4758,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
46814758 }
46824759
46834760 // XXX - TODO: add when wasm-ld supports --build-id.
4684 // if (wasm.base.options.build_id) {
4761 // if (wasm.base.build_id) {
46854762 // try argv.append("--build-id=tree");
46864763 // }
46874764
......@@ -4695,8 +4772,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
46954772 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or
46964773 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);
46974774 if (is_exe_or_dyn_lib) {
4698 const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs;
4699 for (wasi_emulated_libs) |crt_file| {
4775 for (wasm.wasi_emulated_libs) |crt_file| {
47004776 try argv.append(try comp.get_libc_crt_file(
47014777 arena,
47024778 wasi_libc.emulatedLibCRFileLibName(crt_file),
......@@ -4753,7 +4829,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
47534829 try argv.append(p);
47544830 }
47554831
4756 if (wasm.base.options.verbose_link) {
4832 if (wasm.base.comp.verbose_link) {
47574833 // Skip over our own name so that the LLD linker name is the first argv item.
47584834 Compilation.dump_argv(argv.items[1..]);
47594835 }
......@@ -4838,7 +4914,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
48384914 }
48394915 }
48404916
4841 if (!wasm.base.options.disable_lld_caching) {
4917 if (!wasm.base.disable_lld_caching) {
48424918 // Update the file with the digest. If it fails we can continue; it only
48434919 // means that the next invocation will have an unnecessary cache miss.
48444920 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
......@@ -5113,14 +5189,15 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
51135189 if (wasm.getTypeIndex(func_type)) |index| {
51145190 return index;
51155191 }
5192 const gpa = wasm.base.comp.gpa;
51165193
51175194 // functype does not exist.
5118 const index = @as(u32, @intCast(wasm.func_types.items.len));
5119 const params = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.params);
5120 errdefer wasm.base.allocator.free(params);
5121 const returns = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.returns);
5122 errdefer wasm.base.allocator.free(returns);
5123 try wasm.func_types.append(wasm.base.allocator, .{
5195 const index: u32 = @intCast(wasm.func_types.items.len);
5196 const params = try gpa.dupe(std.wasm.Valtype, func_type.params);
5197 errdefer gpa.free(params);
5198 const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns);
5199 errdefer gpa.free(returns);
5200 try wasm.func_types.append(gpa, .{
51245201 .params = params,
51255202 .returns = returns,
51265203 });
......@@ -5131,9 +5208,10 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
51315208/// Asserts declaration has an associated `Atom`.
51325209/// Returns the index into the list of types.
51335210pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {
5211 const gpa = wasm.base.comp.gpa;
51345212 const atom_index = wasm.decls.get(decl_index).?;
51355213 const index = try wasm.putOrGetFuncType(func_type);
5136 try wasm.atom_types.put(wasm.base.allocator, atom_index, index);
5214 try wasm.atom_types.put(gpa, atom_index, index);
51375215 return index;
51385216}
51395217
......@@ -5142,8 +5220,7 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
51425220fn markReferences(wasm: *Wasm) !void {
51435221 const tracy = trace(@src());
51445222 defer tracy.end();
5145 const do_garbage_collect = wasm.base.options.gc_sections orelse
5146 (wasm.base.options.output_mode != .Obj);
5223 const do_garbage_collect = wasm.base.gc_sections;
51475224
51485225 for (wasm.resolved_symbols.keys()) |sym_loc| {
51495226 const sym = sym_loc.getSymbol(wasm);
src/main.zig+21-23
......@@ -842,7 +842,7 @@ fn buildOutputType(
842842 var linker_print_gc_sections: bool = false;
843843 var linker_print_icf_sections: bool = false;
844844 var linker_print_map: bool = false;
845 var linker_opt_bisect_limit: i32 = -1;
845 var llvm_opt_bisect_limit: c_int = -1;
846846 var linker_z_nocopyreloc = false;
847847 var linker_z_nodelete = false;
848848 var linker_z_notext = false;
......@@ -859,7 +859,7 @@ fn buildOutputType(
859859 var linker_module_definition_file: ?[]const u8 = null;
860860 var test_no_exec = false;
861861 var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{};
862 var stack_size_override: ?u64 = null;
862 var stack_size: ?u64 = null;
863863 var image_base_override: ?u64 = null;
864864 var link_eh_frame_hdr = false;
865865 var link_emit_relocs = false;
......@@ -892,7 +892,7 @@ fn buildOutputType(
892892 var contains_res_file: bool = false;
893893 var reference_trace: ?u32 = null;
894894 var pdb_out_path: ?[]const u8 = null;
895 var dwarf_format: ?std.dwarf.Format = null;
895 var debug_format: ?link.File.DebugFormat = null;
896896 var error_limit: ?Module.ErrorInt = null;
897897 var want_structured_cfg: ?bool = null;
898898 // These are before resolving sysroot.
......@@ -1129,10 +1129,7 @@ fn buildOutputType(
11291129 } else if (mem.eql(u8, arg, "--force_undefined")) {
11301130 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
11311131 } else if (mem.eql(u8, arg, "--stack")) {
1132 const next_arg = args_iter.nextOrFatal();
1133 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
1134 fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) });
1135 };
1132 stack_size = parseStackSize(args_iter.nextOrFatal());
11361133 } else if (mem.eql(u8, arg, "--image-base")) {
11371134 const next_arg = args_iter.nextOrFatal();
11381135 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
......@@ -1487,9 +1484,9 @@ fn buildOutputType(
14871484 } else if (mem.eql(u8, arg, "-fno-strip")) {
14881485 mod_opts.strip = false;
14891486 } else if (mem.eql(u8, arg, "-gdwarf32")) {
1490 dwarf_format = .@"32";
1487 debug_format = .{ .dwarf = .@"32" };
14911488 } else if (mem.eql(u8, arg, "-gdwarf64")) {
1492 dwarf_format = .@"64";
1489 debug_format = .{ .dwarf = .@"64" };
14931490 } else if (mem.eql(u8, arg, "-fformatted-panics")) {
14941491 formatted_panics = true;
14951492 } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {
......@@ -1511,7 +1508,9 @@ fn buildOutputType(
15111508 } else if (mem.eql(u8, arg, "-fno-builtin")) {
15121509 no_builtin = true;
15131510 } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) {
1514 linker_opt_bisect_limit = std.math.lossyCast(i32, parseIntSuffix(arg, "-fopt-bisect-limit=".len));
1511 const next_arg = arg["-fopt-bisect-limit=".len..];
1512 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
1513 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
15151514 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
15161515 link_eh_frame_hdr = true;
15171516 } else if (mem.eql(u8, arg, "--dynamicbase")) {
......@@ -1994,11 +1993,11 @@ fn buildOutputType(
19941993 },
19951994 .gdwarf32 => {
19961995 mod_opts.strip = false;
1997 dwarf_format = .@"32";
1996 debug_format = .{ .dwarf = .@"32" };
19981997 },
19991998 .gdwarf64 => {
20001999 mod_opts.strip = false;
2001 dwarf_format = .@"64";
2000 debug_format = .{ .dwarf = .@"64" };
20022001 },
20032002 .sanitize => {
20042003 if (mem.eql(u8, it.only_arg, "undefined")) {
......@@ -2257,10 +2256,7 @@ fn buildOutputType(
22572256 } else if (mem.eql(u8, z_arg, "norelro")) {
22582257 linker_z_relro = false;
22592258 } else if (mem.startsWith(u8, z_arg, "stack-size=")) {
2260 const next_arg = z_arg["stack-size=".len..];
2261 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
2262 fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) });
2263 };
2259 stack_size = parseStackSize(z_arg["stack-size=".len..]);
22642260 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
22652261 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
22662262 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
......@@ -2285,10 +2281,7 @@ fn buildOutputType(
22852281 } else if (mem.eql(u8, arg, "-u")) {
22862282 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});
22872283 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {
2288 const stack_size = linker_args_it.nextOrFatal();
2289 stack_size_override = std.fmt.parseUnsigned(u64, stack_size, 0) catch |err| {
2290 fatal("unable to parse stack size override '{s}': {s}", .{ stack_size, @errorName(err) });
2291 };
2284 stack_size = parseStackSize(linker_args_it.nextOrFatal());
22922285 } else if (mem.eql(u8, arg, "--image-base")) {
22932286 const image_base = linker_args_it.nextOrFatal();
22942287 image_base_override = std.fmt.parseUnsigned(u64, image_base, 0) catch |err| {
......@@ -3407,7 +3400,7 @@ fn buildOutputType(
34073400 .linker_print_gc_sections = linker_print_gc_sections,
34083401 .linker_print_icf_sections = linker_print_icf_sections,
34093402 .linker_print_map = linker_print_map,
3410 .linker_opt_bisect_limit = linker_opt_bisect_limit,
3403 .llvm_opt_bisect_limit = llvm_opt_bisect_limit,
34113404 .linker_global_base = linker_global_base,
34123405 .linker_export_symbol_names = linker_export_symbol_names.items,
34133406 .linker_z_nocopyreloc = linker_z_nocopyreloc,
......@@ -3430,7 +3423,7 @@ fn buildOutputType(
34303423 .link_eh_frame_hdr = link_eh_frame_hdr,
34313424 .link_emit_relocs = link_emit_relocs,
34323425 .force_undefined_symbols = force_undefined_symbols,
3433 .stack_size_override = stack_size_override,
3426 .stack_size = stack_size,
34343427 .image_base_override = image_base_override,
34353428 .formatted_panics = formatted_panics,
34363429 .function_sections = function_sections,
......@@ -3459,7 +3452,7 @@ fn buildOutputType(
34593452 .test_runner_path = test_runner_path,
34603453 .disable_lld_caching = !output_to_cache,
34613454 .subsystem = subsystem,
3462 .dwarf_format = dwarf_format,
3455 .debug_format = debug_format,
34633456 .debug_compile_errors = debug_compile_errors,
34643457 .enable_link_snapshots = enable_link_snapshots,
34653458 .install_name = install_name,
......@@ -7688,3 +7681,8 @@ fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target {
76887681 return std.zig.system.resolveTargetQuery(target_query) catch |err|
76897682 fatal("unable to resolve target: {s}", .{@errorName(err)});
76907683}
7684
7685fn parseStackSize(s: []const u8) u64 {
7686 return std.fmt.parseUnsigned(u64, s, 0) catch |err|
7687 fatal("unable to parse stack size '{s}': {s}", .{ s, @errorName(err) });
7688}
src/musl.zig+1-1
......@@ -226,7 +226,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
226226 .is_native_abi = false,
227227 .self_exe_path = comp.self_exe_path,
228228 .verbose_cc = comp.verbose_cc,
229 .verbose_link = comp.bin_file.options.verbose_link,
229 .verbose_link = comp.verbose_link,
230230 .verbose_air = comp.verbose_air,
231231 .verbose_llvm_ir = comp.verbose_llvm_ir,
232232 .verbose_cimport = comp.verbose_cimport,
src/target.zig+8
......@@ -323,6 +323,14 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool {
323323 };
324324}
325325
326/// The set of targets that Zig supports using LLD to link for.
327pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
328 return switch (ofmt) {
329 .elf, .coff, .wasm => true,
330 else => false,
331 };
332}
333
326334/// The set of targets that our own self-hosted backends have robust support for.
327335/// Used to select between LLVM backend and self-hosted backend when compiling in
328336/// debug mode. A given target should only return true here if it is passing greater