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,...@@ -69,6 +69,8 @@ root_name: [:0]const u8,
69cache_mode: CacheMode,69cache_mode: CacheMode,
70include_compiler_rt: bool,70include_compiler_rt: bool,
71objects: []Compilation.LinkObject,71objects: []Compilation.LinkObject,
72/// Needed only for passing -F args to clang.
73framework_dirs: []const []const u8,
72/// These are *always* dynamically linked. Static libraries will be74/// These are *always* dynamically linked. Static libraries will be
73/// provided as positional arguments.75/// provided as positional arguments.
74system_libs: std.StringArrayHashMapUnmanaged(SystemLib),76system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
...@@ -133,6 +135,7 @@ verbose_llvm_ir: ?[]const u8,...@@ -133,6 +135,7 @@ verbose_llvm_ir: ?[]const u8,
133verbose_llvm_bc: ?[]const u8,135verbose_llvm_bc: ?[]const u8,
134verbose_cimport: bool,136verbose_cimport: bool,
135verbose_llvm_cpu_features: bool,137verbose_llvm_cpu_features: bool,
138verbose_link: bool,
136disable_c_depfile: bool,139disable_c_depfile: bool,
137time_report: bool,140time_report: bool,
138stack_report: bool,141stack_report: bool,
...@@ -220,6 +223,8 @@ emit_llvm_bc: ?EmitLoc,...@@ -220,6 +223,8 @@ emit_llvm_bc: ?EmitLoc,
220work_queue_wait_group: WaitGroup = .{},223work_queue_wait_group: WaitGroup = .{},
221astgen_wait_group: WaitGroup = .{},224astgen_wait_group: WaitGroup = .{},
222225
226llvm_opt_bisect_limit: c_int,
227
223pub const Emit = struct {228pub const Emit = struct {
224 /// Where the output will go.229 /// Where the output will go.
225 directory: Directory,230 directory: Directory,
...@@ -340,7 +345,7 @@ const Job = union(enum) {...@@ -340,7 +345,7 @@ const Job = union(enum) {
340 /// one of WASI libc static objects345 /// one of WASI libc static objects
341 wasi_libc_crt_file: wasi_libc.CRTFile,346 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`.
344 windows_import_lib: usize,349 windows_import_lib: usize,
345};350};
346351
...@@ -819,6 +824,20 @@ pub const cache_helpers = struct {...@@ -819,6 +824,20 @@ pub const cache_helpers = struct {
819 addEmitLoc(hh, optional_emit_loc orelse return);824 addEmitLoc(hh, optional_emit_loc orelse return);
820 }825 }
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
822 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {841 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {
823 _ = try self.addFile(c_source.src_path, null);842 _ = try self.addFile(c_source.src_path, null);
824 // Hash the extra flags, with special care to call addFile for file parameters.843 // Hash the extra flags, with special care to call addFile for file parameters.
...@@ -846,7 +865,7 @@ pub const ClangPreprocessorMode = enum {...@@ -846,7 +865,7 @@ pub const ClangPreprocessorMode = enum {
846 stdout,865 stdout,
847};866};
848867
849pub const Framework = link.Framework;868pub const Framework = link.File.MachO.Framework;
850pub const SystemLib = link.SystemLib;869pub const SystemLib = link.SystemLib;
851pub const CacheMode = link.CacheMode;870pub const CacheMode = link.CacheMode;
852871
...@@ -952,7 +971,7 @@ pub const InitOptions = struct {...@@ -952,7 +971,7 @@ pub const InitOptions = struct {
952 linker_print_gc_sections: bool = false,971 linker_print_gc_sections: bool = false,
953 linker_print_icf_sections: bool = false,972 linker_print_icf_sections: bool = false,
954 linker_print_map: bool = false,973 linker_print_map: bool = false,
955 linker_opt_bisect_limit: i32 = -1,974 llvm_opt_bisect_limit: i32 = -1,
956 each_lib_rpath: ?bool = null,975 each_lib_rpath: ?bool = null,
957 build_id: ?std.zig.BuildId = null,976 build_id: ?std.zig.BuildId = null,
958 disable_c_depfile: bool = false,977 disable_c_depfile: bool = false,
...@@ -994,7 +1013,7 @@ pub const InitOptions = struct {...@@ -994,7 +1013,7 @@ pub const InitOptions = struct {
994 hash_style: link.HashStyle = .both,1013 hash_style: link.HashStyle = .both,
995 entry: ?[]const u8 = null,1014 entry: ?[]const u8 = null,
996 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{},1015 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{},
997 stack_size_override: ?u64 = null,1016 stack_size: ?u64 = null,
998 image_base_override: ?u64 = null,1017 image_base_override: ?u64 = null,
999 version: ?std.SemanticVersion = null,1018 version: ?std.SemanticVersion = null,
1000 compatibility_version: ?std.SemanticVersion = null,1019 compatibility_version: ?std.SemanticVersion = null,
...@@ -1007,7 +1026,7 @@ pub const InitOptions = struct {...@@ -1007,7 +1026,7 @@ pub const InitOptions = struct {
1007 test_name_prefix: ?[]const u8 = null,1026 test_name_prefix: ?[]const u8 = null,
1008 test_runner_path: ?[]const u8 = null,1027 test_runner_path: ?[]const u8 = null,
1009 subsystem: ?std.Target.SubSystem = null,1028 subsystem: ?std.Target.SubSystem = null,
1010 dwarf_format: ?std.dwarf.Format = null,1029 debug_format: ?link.File.DebugFormat = null,
1011 /// (Zig compiler development) Enable dumping linker's state as JSON.1030 /// (Zig compiler development) Enable dumping linker's state as JSON.
1012 enable_link_snapshots: bool = false,1031 enable_link_snapshots: bool = false,
1013 /// (Darwin) Install name of the dylib1032 /// (Darwin) Install name of the dylib
...@@ -1297,7 +1316,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1297,7 +1316,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1297 cache.hash.add(options.config.link_libcpp);1316 cache.hash.add(options.config.link_libcpp);
1298 cache.hash.add(options.config.link_libunwind);1317 cache.hash.add(options.config.link_libunwind);
1299 cache.hash.add(output_mode);1318 cache.hash.add(output_mode);
1300 cache.hash.addOptional(options.dwarf_format);1319 cache_helpers.addOptionalDebugFormat(&cache.hash, options.debug_format);
1301 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);1320 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
1302 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);1321 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
1303 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs);1322 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs);
...@@ -1596,6 +1615,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1596,6 +1615,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1596 .verbose_llvm_bc = options.verbose_llvm_bc,1615 .verbose_llvm_bc = options.verbose_llvm_bc,
1597 .verbose_cimport = options.verbose_cimport,1616 .verbose_cimport = options.verbose_cimport,
1598 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,1617 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
1618 .verbose_link = options.verbose_link,
1599 .disable_c_depfile = options.disable_c_depfile,1619 .disable_c_depfile = options.disable_c_depfile,
1600 .owned_link_dir = owned_link_dir,1620 .owned_link_dir = owned_link_dir,
1601 .color = options.color,1621 .color = options.color,
...@@ -1617,6 +1637,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1617,6 +1637,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1617 .libc_installation = libc_dirs.libc_installation,1637 .libc_installation = libc_dirs.libc_installation,
1618 .include_compiler_rt = include_compiler_rt,1638 .include_compiler_rt = include_compiler_rt,
1619 .objects = options.link_objects,1639 .objects = options.link_objects,
1640 .framework_dirs = options.framework_dirs,
1641 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
1620 };1642 };
16211643
1622 if (bin_file_emit) |emit| {1644 if (bin_file_emit) |emit| {
...@@ -1636,7 +1658,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1636,7 +1658,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1636 .z_max_page_size = options.linker_z_max_page_size,1658 .z_max_page_size = options.linker_z_max_page_size,
1637 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,1659 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
1638 .frameworks = options.frameworks,1660 .frameworks = options.frameworks,
1639 .framework_dirs = options.framework_dirs,
1640 .wasi_emulated_libs = options.wasi_emulated_libs,1661 .wasi_emulated_libs = options.wasi_emulated_libs,
1641 .lib_dirs = options.lib_dirs,1662 .lib_dirs = options.lib_dirs,
1642 .rpath_list = options.rpath_list,1663 .rpath_list = options.rpath_list,
...@@ -1659,13 +1680,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1659,13 +1680,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1659 .print_gc_sections = options.linker_print_gc_sections,1680 .print_gc_sections = options.linker_print_gc_sections,
1660 .print_icf_sections = options.linker_print_icf_sections,1681 .print_icf_sections = options.linker_print_icf_sections,
1661 .print_map = options.linker_print_map,1682 .print_map = options.linker_print_map,
1662 .opt_bisect_limit = options.linker_opt_bisect_limit,
1663 .tsaware = options.linker_tsaware,1683 .tsaware = options.linker_tsaware,
1664 .nxcompat = options.linker_nxcompat,1684 .nxcompat = options.linker_nxcompat,
1665 .dynamicbase = options.linker_dynamicbase,1685 .dynamicbase = options.linker_dynamicbase,
1666 .major_subsystem_version = options.major_subsystem_version,1686 .major_subsystem_version = options.major_subsystem_version,
1667 .minor_subsystem_version = options.minor_subsystem_version,1687 .minor_subsystem_version = options.minor_subsystem_version,
1668 .stack_size_override = options.stack_size_override,1688 .stack_size = options.stack_size,
1669 .image_base_override = options.image_base_override,1689 .image_base_override = options.image_base_override,
1670 .version_script = options.version_script,1690 .version_script = options.version_script,
1671 .gc_sections = options.linker_gc_sections,1691 .gc_sections = options.linker_gc_sections,
...@@ -1674,7 +1694,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1674,7 +1694,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1674 .rdynamic = options.rdynamic,1694 .rdynamic = options.rdynamic,
1675 .soname = options.soname,1695 .soname = options.soname,
1676 .compatibility_version = options.compatibility_version,1696 .compatibility_version = options.compatibility_version,
1677 .verbose_link = options.verbose_link,
1678 .dll_export_fns = dll_export_fns,1697 .dll_export_fns = dll_export_fns,
1679 .skip_linker_dependencies = options.skip_linker_dependencies,1698 .skip_linker_dependencies = options.skip_linker_dependencies,
1680 .parent_compilation_link_libc = options.parent_compilation_link_libc,1699 .parent_compilation_link_libc = options.parent_compilation_link_libc,
...@@ -1682,7 +1701,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1682,7 +1701,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1682 .build_id = build_id,1701 .build_id = build_id,
1683 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,1702 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
1684 .subsystem = options.subsystem,1703 .subsystem = options.subsystem,
1685 .dwarf_format = options.dwarf_format,1704 .debug_format = options.debug_format,
1686 .hash_style = options.hash_style,1705 .hash_style = options.hash_style,
1687 .enable_link_snapshots = options.enable_link_snapshots,1706 .enable_link_snapshots = options.enable_link_snapshots,
1688 .install_name = options.install_name,1707 .install_name = options.install_name,
...@@ -1826,7 +1845,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1826,7 +1845,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18261845
1827 // When linking mingw-w64 there are some import libs we always need.1846 // When linking mingw-w64 there are some import libs we always need.
1828 for (mingw.always_link_libs) |name| {1847 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, .{
1830 .needed = false,1849 .needed = false,
1831 .weak = false,1850 .weak = false,
1832 .path = null,1851 .path = null,
...@@ -1835,7 +1854,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1835,7 +1854,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1835 }1854 }
1836 // Generate Windows import libs.1855 // Generate Windows import libs.
1837 if (target.os.tag == .windows) {1856 if (target.os.tag == .windows) {
1838 const count = comp.bin_file.options.system_libs.count();1857 const count = comp.system_libs.count();
1839 try comp.work_queue.ensureUnusedCapacity(count);1858 try comp.work_queue.ensureUnusedCapacity(count);
1840 for (0..count) |i| {1859 for (0..count) |i| {
1841 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });1860 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });
...@@ -2450,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2450,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2450 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);2469 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
2451 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);2470 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);
2454 man.hash.addOptional(comp.bin_file.options.image_base_override);2473 man.hash.addOptional(comp.bin_file.options.image_base_override);
2455 man.hash.addOptional(comp.bin_file.options.gc_sections);2474 man.hash.addOptional(comp.bin_file.options.gc_sections);
2456 man.hash.add(comp.bin_file.options.eh_frame_hdr);2475 man.hash.add(comp.bin_file.options.eh_frame_hdr);
...@@ -2460,7 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2460,7 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2460 man.hash.addListOfBytes(comp.bin_file.options.rpath_list);2479 man.hash.addListOfBytes(comp.bin_file.options.rpath_list);
2461 man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys());2480 man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys());
2462 man.hash.add(comp.bin_file.options.each_lib_rpath);2481 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);
2464 man.hash.add(comp.bin_file.options.skip_linker_dependencies);2483 man.hash.add(comp.bin_file.options.skip_linker_dependencies);
2465 man.hash.add(comp.bin_file.options.z_nodelete);2484 man.hash.add(comp.bin_file.options.z_nodelete);
2466 man.hash.add(comp.bin_file.options.z_notext);2485 man.hash.add(comp.bin_file.options.z_notext);
...@@ -2488,9 +2507,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2488,9 +2507,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2488 }2507 }
2489 man.hash.addOptionalBytes(comp.bin_file.options.soname);2508 man.hash.addOptionalBytes(comp.bin_file.options.soname);
2490 man.hash.addOptional(comp.bin_file.options.version);2509 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);
2492 man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys());2511 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);
2494 man.hash.add(comp.bin_file.options.bind_global_refs_locally);2513 man.hash.add(comp.bin_file.options.bind_global_refs_locally);
2495 man.hash.add(comp.bin_file.options.tsan);2514 man.hash.add(comp.bin_file.options.tsan);
2496 man.hash.addOptionalBytes(comp.bin_file.options.sysroot);2515 man.hash.addOptionalBytes(comp.bin_file.options.sysroot);
...@@ -2505,7 +2524,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2505,7 +2524,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2505 man.hash.addOptional(comp.bin_file.options.global_base);2524 man.hash.addOptional(comp.bin_file.options.global_base);
25062525
2507 // Mach-O specific stuff2526 // Mach-O specific stuff
2508 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);2527 man.hash.addListOfBytes(comp.framework_dirs);
2509 try link.hashAddFrameworks(man, comp.bin_file.options.frameworks);2528 try link.hashAddFrameworks(man, comp.bin_file.options.frameworks);
2510 try man.addOptionalFile(comp.bin_file.options.entitlements);2529 try man.addOptionalFile(comp.bin_file.options.entitlements);
2511 man.hash.addOptional(comp.bin_file.options.pagezero_size);2530 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...@@ -3561,7 +3580,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3561 const named_frame = tracy.namedFrame("windows_import_lib");3580 const named_frame = tracy.namedFrame("windows_import_lib");
3562 defer named_frame.end();3581 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];
3565 mingw.buildImportLib(comp, link_lib) catch |err| {3584 mingw.buildImportLib(comp, link_lib) catch |err| {
3566 // TODO Surface more error details.3585 // TODO Surface more error details.
3567 comp.lockAndSetMiscFailure(3586 comp.lockAndSetMiscFailure(
...@@ -4964,7 +4983,7 @@ pub fn addCCArgs(...@@ -4964,7 +4983,7 @@ pub fn addCCArgs(
4964 try argv.appendSlice(&.{ "-iframework", framework_dir });4983 try argv.appendSlice(&.{ "-iframework", framework_dir });
4965 }4984 }
49664985
4967 for (comp.bin_file.options.framework_dirs) |framework_dir| {4986 for (comp.framework_dirs) |framework_dir| {
4968 try argv.appendSlice(&.{ "-F", framework_dir });4987 try argv.appendSlice(&.{ "-F", framework_dir });
4969 }4988 }
49704989
...@@ -5219,22 +5238,21 @@ pub fn addCCArgs(...@@ -5219,22 +5238,21 @@ pub fn addCCArgs(
5219 },5238 },
5220 }5239 }
52215240
5222 if (!comp.bin_file.options.strip) {5241 try argv.ensureUnusedCapacity(2);
5223 switch (target.ofmt) {5242 switch (comp.bin_file.debug_format) {
5224 .coff => {5243 .strip => {},
5225 // -g is required here because -gcodeview doesn't trigger debug info5244 .code_view => {
5226 // generation, it only changes the type of information generated.5245 // -g is required here because -gcodeview doesn't trigger debug info
5227 try argv.appendSlice(&.{ "-g", "-gcodeview" });5246 // generation, it only changes the type of information generated.
5228 },5247 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" });
5229 .elf, .macho => {5248 },
5230 try argv.append("-gdwarf-4");5249 .dwarf => |f| {
5231 if (comp.bin_file.options.dwarf_format) |f| switch (f) {5250 argv.appendAssumeCapacity("-gdwarf-4");
5232 .@"32" => try argv.append("-gdwarf32"),5251 switch (f) {
5233 .@"64" => try argv.append("-gdwarf64"),5252 .@"32" => argv.appendAssumeCapacity("-gdwarf32"),
5234 };5253 .@"64" => argv.appendAssumeCapacity("-gdwarf64"),
5235 },5254 }
5236 else => try argv.append("-g"),5255 },
5237 }
5238 }5256 }
52395257
5240 if (target_util.llvmMachineAbi(target)) |mabi| {5258 if (target_util.llvmMachineAbi(target)) |mabi| {
...@@ -6306,7 +6324,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -6306,7 +6324,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
6306 // This happens when an `extern "foo"` function is referenced.6324 // This happens when an `extern "foo"` function is referenced.
6307 // If we haven't seen this library yet and we're targeting Windows, we need6325 // If we haven't seen this library yet and we're targeting Windows, we need
6308 // to queue up a work item to produce the DLL import library for this.6326 // 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);
6310 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {6328 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
6311 gop.value_ptr.* = .{6329 gop.value_ptr.* = .{
6312 .needed = true,6330 .needed = true,
...@@ -6314,7 +6332,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -6314,7 +6332,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
6314 .path = null,6332 .path = null,
6315 };6333 };
6316 try comp.work_queue.writeItem(.{6334 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,
6318 });6336 });
6319 }6337 }
6320}6338}
src/Compilation/Config.zig+24-12
...@@ -137,7 +137,11 @@ pub fn resolve(options: Options) !Config {...@@ -137,7 +137,11 @@ pub fn resolve(options: Options) !Config {
137 const use_llvm = b: {137 const use_llvm = b: {
138 // If emitting to LLVM bitcode object format, must use LLVM backend.138 // If emitting to LLVM bitcode object format, must use LLVM backend.
139 if (options.emit_llvm_ir or options.emit_llvm_bc) {139 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
141 break :b true;145 break :b true;
142 }146 }
143147
...@@ -147,6 +151,12 @@ pub fn resolve(options: Options) !Config {...@@ -147,6 +151,12 @@ pub fn resolve(options: Options) !Config {
147 break :b false;151 break :b false;
148 }152 }
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
150 if (options.use_llvm) |x| break :b x;160 if (options.use_llvm) |x| break :b x;
151161
152 // If we have no zig code to compile, no need for LLVM.162 // If we have no zig code to compile, no need for LLVM.
...@@ -166,16 +176,23 @@ pub fn resolve(options: Options) !Config {...@@ -166,16 +176,23 @@ pub fn resolve(options: Options) !Config {
166 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);176 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
167 };177 };
168178
169 if (!use_lib_llvm and use_llvm and options.emit_bin) {179 if (options.emit_bin) {
170 // Explicit request to use LLVM to produce an object file, but without180 if (!use_lib_llvm and use_llvm) {
171 // using LLVM libraries. Impossible.181 // Explicit request to use LLVM to produce an object file, but without
172 return error.EmittingBinaryRequiresLlvmLibrary;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 }
173 }190 }
174191
175 // Make a decision on whether to use LLD or our own linker.192 // Make a decision on whether to use LLD or our own linker.
176 const use_lld = b: {193 const use_lld = b: {
177 if (target.isDarwin()) {194 if (!target_util.hasLldSupport(target.ofmt)) {
178 if (options.use_lld == true) return error.LldIncompatibleOs;195 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
179 break :b false;196 break :b false;
180 }197 }
181198
...@@ -184,11 +201,6 @@ pub fn resolve(options: Options) !Config {...@@ -184,11 +201,6 @@ pub fn resolve(options: Options) !Config {
184 break :b false;201 break :b false;
185 }202 }
186203
187 if (target.ofmt == .c) {
188 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
189 break :b false;
190 }
191
192 if (options.lto == true) {204 if (options.lto == true) {
193 if (options.use_lld == false) return error.LtoRequiresLld;205 if (options.use_lld == false) return error.LtoRequiresLld;
194 break :b true;206 break :b true;
src/codegen/llvm.zig+44-30
...@@ -854,15 +854,21 @@ pub const Object = struct {...@@ -854,15 +854,21 @@ pub const Object = struct {
854 pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);854 pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);
855855
856 pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object {856 pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object {
857 const gpa = options.comp.gpa;857 if (build_options.only_c) unreachable;
858 const llvm_target_triple = try targetTriple(arena, options.target);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
860 var builder = try Builder.init(.{866 var builder = try Builder.init(.{
861 .allocator = gpa,867 .allocator = gpa,
862 .use_lib_llvm = options.use_lib_llvm,868 .use_lib_llvm = comp.config.use_lib_llvm,
863 .strip = options.strip or !options.use_lib_llvm, // TODO869 .strip = strip or !comp.config.use_lib_llvm, // TODO
864 .name = options.root_name,870 .name = comp.root_name,
865 .target = options.target,871 .target = target,
866 .triple = llvm_target_triple,872 .triple = llvm_target_triple,
867 });873 });
868 errdefer builder.deinit();874 errdefer builder.deinit();
...@@ -870,10 +876,18 @@ pub const Object = struct {...@@ -870,10 +876,18 @@ pub const Object = struct {
870 var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined;876 var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined;
871 var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined;877 var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined;
872 if (builder.useLibLlvm()) {878 if (builder.useLibLlvm()) {
873 if (!options.strip) {879 debug_info: {
874 switch (options.target.ofmt) {880 const debug_format = options.debug_format orelse b: {
875 .coff => builder.llvm.module.?.addModuleCodeViewFlag(),881 if (strip) break :b .strip;
876 else => builder.llvm.module.?.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"),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"),
877 }891 }
878 builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true);892 builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true);
879893
...@@ -892,8 +906,8 @@ pub const Object = struct {...@@ -892,8 +906,8 @@ pub const Object = struct {
892 // TODO: the only concern I have with this is WASI as either host or target, should906 // TODO: the only concern I have with this is WASI as either host or target, should
893 // we leave the paths as relative then?907 // we leave the paths as relative then?
894 const compile_unit_dir_z = blk: {908 const compile_unit_dir_z = blk: {
895 if (options.module) |mod| m: {909 if (comp.module) |zcu| m: {
896 const d = try mod.root_mod.root.joinStringZ(arena, "");910 const d = try zcu.root_mod.root.joinStringZ(arena, "");
897 if (d.len == 0) break :m;911 if (d.len == 0) break :m;
898 if (std.fs.path.isAbsolute(d)) break :blk d;912 if (std.fs.path.isAbsolute(d)) break :blk d;
899 break :blk std.fs.realpathAlloc(arena, d) catch d;913 break :blk std.fs.realpathAlloc(arena, d) catch d;
...@@ -903,9 +917,9 @@ pub const Object = struct {...@@ -903,9 +917,9 @@ pub const Object = struct {
903917
904 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(918 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
905 DW.LANG.C99,919 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),
907 producer.slice(&builder).?,921 producer.slice(&builder).?,
908 options.optimize_mode != .Debug,922 optimize_mode != .Debug,
909 "", // flags923 "", // flags
910 0, // runtime version924 0, // runtime version
911 "", // split name925 "", // split name
...@@ -914,19 +928,19 @@ pub const Object = struct {...@@ -914,19 +928,19 @@ pub const Object = struct {
914 );928 );
915 }929 }
916930
917 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)931 const opt_level: llvm.CodeGenOptLevel = if (optimize_mode == .Debug)
918 .None932 .None
919 else933 else
920 .Aggressive;934 .Aggressive;
921935
922 const reloc_mode: llvm.RelocMode = if (options.pic)936 const reloc_mode: llvm.RelocMode = if (pic)
923 .PIC937 .PIC
924 else if (options.link_mode == .Dynamic)938 else if (comp.config.link_mode == .Dynamic)
925 llvm.RelocMode.DynamicNoPIC939 llvm.RelocMode.DynamicNoPIC
926 else940 else
927 .Static;941 .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) {
930 .default => .Default,944 .default => .Default,
931 .tiny => .Tiny,945 .tiny => .Tiny,
932 .small => .Small,946 .small => .Small,
...@@ -941,15 +955,15 @@ pub const Object = struct {...@@ -941,15 +955,15 @@ pub const Object = struct {
941 target_machine = llvm.TargetMachine.create(955 target_machine = llvm.TargetMachine.create(
942 builder.llvm.target.?,956 builder.llvm.target.?,
943 builder.target_triple.slice(&builder).?,957 builder.target_triple.slice(&builder).?,
944 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,958 if (target.cpu.model.llvm_name) |s| s.ptr else null,
945 options.llvm_cpu_features,959 comp.root_mod.resolved_target.llvm_cpu_features.?,
946 opt_level,960 opt_level,
947 reloc_mode,961 reloc_mode,
948 code_model,962 code_model,
949 options.function_sections,963 options.function_sections orelse false,
950 options.data_sections,964 options.data_sections orelse false,
951 float_abi,965 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,
953 );967 );
954 errdefer target_machine.dispose();968 errdefer target_machine.dispose();
955969
...@@ -958,15 +972,15 @@ pub const Object = struct {...@@ -958,15 +972,15 @@ pub const Object = struct {
958972
959 builder.llvm.module.?.setModuleDataLayout(target_data);973 builder.llvm.module.?.setModuleDataLayout(target_data);
960974
961 if (options.pic) builder.llvm.module.?.setModulePICLevel();975 if (pic) builder.llvm.module.?.setModulePICLevel();
962 if (options.pie) builder.llvm.module.?.setModulePIELevel();976 if (comp.config.pie) builder.llvm.module.?.setModulePIELevel();
963 if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);977 if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);
964978
965 if (options.opt_bisect_limit >= 0) {979 if (comp.llvm_opt_bisect_limit >= 0) {
966 builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit));980 builder.llvm.context.setOptBisectLimit(comp.llvm_opt_bisect_limit);
967 }981 }
968982
969 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }});983 builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }});
970 if (std.debug.runtime_safety) {984 if (std.debug.runtime_safety) {
971 const rep = target_data.stringRep();985 const rep = target_data.stringRep();
972 defer llvm.disposeMessage(rep);986 defer llvm.disposeMessage(rep);
...@@ -981,13 +995,13 @@ pub const Object = struct {...@@ -981,13 +995,13 @@ pub const Object = struct {
981 obj.* = .{995 obj.* = .{
982 .gpa = gpa,996 .gpa = gpa,
983 .builder = builder,997 .builder = builder,
984 .module = options.module.?,998 .module = comp.module.?,
985 .di_map = .{},999 .di_map = .{},
986 .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO1000 .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO
987 .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null,1001 .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null,
988 .target_machine = target_machine,1002 .target_machine = target_machine,
989 .target_data = target_data,1003 .target_data = target_data,
990 .target = options.target,1004 .target = target,
991 .decl_map = .{},1005 .decl_map = .{},
992 .anon_decl_map = .{},1006 .anon_decl_map = .{},
993 .named_enum_map = .{},1007 .named_enum_map = .{},
src/link.zig+84-49
...@@ -32,13 +32,6 @@ pub const SystemLib = struct {...@@ -32,13 +32,6 @@ pub const SystemLib = struct {
32 path: ?[]const u8,32 path: ?[]const u8,
33};33};
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
42pub const SortSection = enum { name, alignment };35pub const SortSection = enum { name, alignment };
4336
44pub const CacheMode = enum { incremental, whole };37pub const CacheMode = enum { incremental, whole };
...@@ -56,14 +49,6 @@ pub fn hashAddSystemLibs(...@@ -56,14 +49,6 @@ pub fn hashAddSystemLibs(
56 }49 }
57}50}
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
67pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;52pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
6853
69pub const HashStyle = enum { sysv, gnu, both };54pub const HashStyle = enum { sysv, gnu, both };
...@@ -81,6 +66,19 @@ pub const File = struct {...@@ -81,6 +66,19 @@ pub const File = struct {
81 /// When linking with LLD, this linker code will output an object file only at66 /// When linking with LLD, this linker code will output an object file only at
82 /// this location, and then this path can be placed on the LLD linker line.67 /// this location, and then this path can be placed on the LLD linker line.
83 intermediary_basename: ?[]const u8 = null,68 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
85 /// Prevents other processes from clobbering files in the output directory83 /// Prevents other processes from clobbering files in the output directory
86 /// of this linking operation.84 /// of this linking operation.
...@@ -88,6 +86,12 @@ pub const File = struct {...@@ -88,6 +86,12 @@ pub const File = struct {
8886
89 child_pid: ?std.ChildProcess.Id = null,87 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
91 pub const OpenOptions = struct {95 pub const OpenOptions = struct {
92 comp: *Compilation,96 comp: *Compilation,
93 emit: Compilation.Emit,97 emit: Compilation.Emit,
...@@ -97,7 +101,7 @@ pub const File = struct {...@@ -97,7 +101,7 @@ pub const File = struct {
97101
98 /// Virtual address of the entry point procedure relative to image base.102 /// Virtual address of the entry point procedure relative to image base.
99 entry_addr: ?u64,103 entry_addr: ?u64,
100 stack_size_override: ?u64,104 stack_size: ?u64,
101 image_base_override: ?u64,105 image_base_override: ?u64,
102 function_sections: bool,106 function_sections: bool,
103 data_sections: bool,107 data_sections: bool,
...@@ -128,7 +132,6 @@ pub const File = struct {...@@ -128,7 +132,6 @@ pub const File = struct {
128 max_memory: ?u64,132 max_memory: ?u64,
129 export_symbol_names: []const []const u8,133 export_symbol_names: []const []const u8,
130 global_base: ?u64,134 global_base: ?u64,
131 verbose_link: bool,
132 dll_export_fns: bool,135 dll_export_fns: bool,
133 skip_linker_dependencies: bool,136 skip_linker_dependencies: bool,
134 parent_compilation_link_libc: bool,137 parent_compilation_link_libc: bool,
...@@ -139,7 +142,7 @@ pub const File = struct {...@@ -139,7 +142,7 @@ pub const File = struct {
139 sort_section: ?SortSection,142 sort_section: ?SortSection,
140 major_subsystem_version: ?u32,143 major_subsystem_version: ?u32,
141 minor_subsystem_version: ?u32,144 minor_subsystem_version: ?u32,
142 gc_sections: ?bool = null,145 gc_sections: ?bool,
143 allow_shlib_undefined: ?bool,146 allow_shlib_undefined: ?bool,
144 subsystem: ?std.Target.SubSystem,147 subsystem: ?std.Target.SubSystem,
145 version_script: ?[]const u8,148 version_script: ?[]const u8,
...@@ -147,11 +150,7 @@ pub const File = struct {...@@ -147,11 +150,7 @@ pub const File = struct {
147 print_gc_sections: bool,150 print_gc_sections: bool,
148 print_icf_sections: bool,151 print_icf_sections: bool,
149 print_map: bool,152 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.
155 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),154 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
156 /// Use a wrapper function for symbol. Any undefined reference to symbol155 /// Use a wrapper function for symbol. Any undefined reference to symbol
157 /// will be resolved to __wrap_symbol. Any undefined reference to156 /// will be resolved to __wrap_symbol. Any undefined reference to
...@@ -163,7 +162,7 @@ pub const File = struct {...@@ -163,7 +162,7 @@ pub const File = struct {
163162
164 compatibility_version: ?std.SemanticVersion,163 compatibility_version: ?std.SemanticVersion,
165164
166 dwarf_format: ?std.dwarf.Format,165 debug_format: ?DebugFormat,
167166
168 // TODO: remove this. libraries are resolved by the frontend.167 // TODO: remove this. libraries are resolved by the frontend.
169 lib_dirs: []const []const u8,168 lib_dirs: []const []const u8,
...@@ -184,8 +183,7 @@ pub const File = struct {...@@ -184,8 +183,7 @@ pub const File = struct {
184 headerpad_max_install_names: bool,183 headerpad_max_install_names: bool,
185 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols184 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
186 dead_strip_dylibs: bool,185 dead_strip_dylibs: bool,
187 framework_dirs: []const []const u8,186 frameworks: []const MachO.Framework,
188 frameworks: []const Framework,
189 darwin_sdk_layout: ?MachO.SdkLayout,187 darwin_sdk_layout: ?MachO.SdkLayout,
190188
191 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative189 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
...@@ -228,7 +226,7 @@ pub const File = struct {...@@ -228,7 +226,7 @@ pub const File = struct {
228 .coff, .elf, .macho, .plan9, .wasm => {226 .coff, .elf, .macho, .plan9, .wasm => {
229 if (build_options.only_c) unreachable;227 if (build_options.only_c) unreachable;
230 if (base.file != null) return;228 if (base.file != null) return;
231 const emit = base.options.emit orelse return;229 const emit = base.emit;
232 if (base.child_pid) |pid| {230 if (base.child_pid) |pid| {
233 if (builtin.os.tag == .windows) {231 if (builtin.os.tag == .windows) {
234 base.cast(Coff).?.ptraceAttach(pid) catch |err| {232 base.cast(Coff).?.ptraceAttach(pid) catch |err| {
...@@ -256,10 +254,13 @@ pub const File = struct {...@@ -256,10 +254,13 @@ pub const File = struct {
256 }254 }
257 }255 }
258 }256 }
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;
259 base.file = try emit.directory.handle.createFile(emit.sub_path, .{260 base.file = try emit.directory.handle.createFile(emit.sub_path, .{
260 .truncate = false,261 .truncate = false,
261 .read = true,262 .read = true,
262 .mode = determineMode(base.options),263 .mode = determineMode(use_lld, output_mode, link_mode),
263 });264 });
264 },265 },
265 .c, .spirv, .nvptx => {},266 .c, .spirv, .nvptx => {},
...@@ -267,9 +268,13 @@ pub const File = struct {...@@ -267,9 +268,13 @@ pub const File = struct {
267 }268 }
268269
269 pub fn makeExecutable(base: *File) !void {270 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) {
271 .Obj => return,276 .Obj => return,
272 .Lib => switch (base.options.link_mode) {277 .Lib => switch (link_mode) {
273 .Static => return,278 .Static => return,
274 .Dynamic => {},279 .Dynamic => {},
275 },280 },
...@@ -278,7 +283,6 @@ pub const File = struct {...@@ -278,7 +283,6 @@ pub const File = struct {
278 switch (base.tag) {283 switch (base.tag) {
279 .elf => if (base.file) |f| {284 .elf => if (base.file) |f| {
280 if (build_options.only_c) unreachable;285 if (build_options.only_c) unreachable;
281 const use_lld = build_options.have_llvm and base.options.use_lld;
282 if (base.intermediary_basename != null and use_lld) {286 if (base.intermediary_basename != null and use_lld) {
283 // The file we have open is not the final file that we want to287 // The file we have open is not the final file that we want to
284 // make executable, so we don't have to close it.288 // make executable, so we don't have to close it.
...@@ -596,7 +600,7 @@ pub const File = struct {...@@ -596,7 +600,7 @@ pub const File = struct {
596 return @fieldParentPtr(C, "base", base).flush(comp, prog_node);600 return @fieldParentPtr(C, "base", base).flush(comp, prog_node);
597 }601 }
598 if (comp.clang_preprocessor_mode == .yes) {602 if (comp.clang_preprocessor_mode == .yes) {
599 const emit = base.options.emit orelse return; // -fno-emit-bin603 const emit = base.emit;
600 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)604 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
601 // Until then, we do `lld -r -o output.o input.o` even though the output is the same605 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
602 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file606 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
...@@ -610,8 +614,10 @@ pub const File = struct {...@@ -610,8 +614,10 @@ pub const File = struct {
610 return;614 return;
611 }615 }
612616
613 const use_lld = build_options.have_llvm and base.options.use_lld;617 const use_lld = build_options.have_llvm and base.comp.config.use_lld;
614 if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static) {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) {
615 return base.linkAsArchive(comp, prog_node);621 return base.linkAsArchive(comp, prog_node);
616 }622 }
617 switch (base.tag) {623 switch (base.tag) {
...@@ -845,8 +851,6 @@ pub const File = struct {...@@ -845,8 +851,6 @@ pub const File = struct {
845 }851 }
846852
847 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {853 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
848 const emit = base.options.emit orelse return;
849
850 const tracy = trace(@src());854 const tracy = trace(@src());
851 defer tracy.end();855 defer tracy.end();
852856
...@@ -854,22 +858,23 @@ pub const File = struct {...@@ -854,22 +858,23 @@ pub const File = struct {
854 defer arena_allocator.deinit();858 defer arena_allocator.deinit();
855 const arena = arena_allocator.allocator();859 const arena = arena_allocator.allocator();
856860
857 const directory = emit.directory; // Just an alias to make it shorter to type.861 const directory = base.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});862 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
859 const full_out_path_z = try arena.dupeZ(u8, full_out_path);863 const full_out_path_z = try arena.dupeZ(u8, full_out_path);
864 const opt_zcu = base.comp.module;
860865
861 // If there is no Zig code to compile, then we should skip flushing the output file866 // If there is no Zig code to compile, then we should skip flushing the output file
862 // because it will not be part of the linker line anyway.867 // 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: {
864 try base.flushModule(comp, prog_node);869 try base.flushModule(comp, prog_node);
865870
866 const dirname = fs.path.dirname(full_out_path_z) orelse ".";871 const dirname = fs.path.dirname(full_out_path_z) orelse ".";
867 break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? });872 break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? });
868 } else null;873 } 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)
873 comp.compiler_rt_obj.?.full_object_path878 comp.compiler_rt_obj.?.full_object_path
874 else879 else
875 null;880 null;
...@@ -881,17 +886,19 @@ pub const File = struct {...@@ -881,17 +886,19 @@ pub const File = struct {
881 const id_symlink_basename = "llvm-ar.id";886 const id_symlink_basename = "llvm-ar.id";
882887
883 var man: Cache.Manifest = undefined;888 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
886 var digest: [Cache.hex_digest_len]u8 = undefined;893 var digest: [Cache.hex_digest_len]u8 = undefined;
887894
888 if (!base.options.disable_lld_caching) {895 if (!base.disable_lld_caching) {
889 man = comp.cache_parent.obtain();896 man = comp.cache_parent.obtain();
890897
891 // We are about to obtain this lock, so here we give other processes a chance first.898 // We are about to obtain this lock, so here we give other processes a chance first.
892 base.releaseLock();899 base.releaseLock();
893900
894 for (base.options.objects) |obj| {901 for (objects) |obj| {
895 _ = try man.addFile(obj.path, null);902 _ = try man.addFile(obj.path, null);
896 man.hash.add(obj.must_link);903 man.hash.add(obj.must_link);
897 man.hash.add(obj.loption);904 man.hash.add(obj.loption);
...@@ -904,7 +911,7 @@ pub const File = struct {...@@ -904,7 +911,7 @@ pub const File = struct {
904 _ = try man.addFile(key.status.success.res_path, null);911 _ = try man.addFile(key.status.success.res_path, null);
905 }912 }
906 }913 }
907 try man.addOptionalFile(module_obj_path);914 try man.addOptionalFile(zcu_obj_path);
908 try man.addOptionalFile(compiler_rt_path);915 try man.addOptionalFile(compiler_rt_path);
909916
910 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.917 // 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 {...@@ -934,11 +941,11 @@ pub const File = struct {
934 }941 }
935942
936 const win32_resource_table_len = if (build_options.only_core_functionality) 0 else comp.win32_resource_table.count();943 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;
938 var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files);945 var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files);
939 defer object_files.deinit();946 defer object_files.deinit();
940947
941 for (base.options.objects) |obj| {948 for (objects) |obj| {
942 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));949 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));
943 }950 }
944 for (comp.c_object_table.keys()) |key| {951 for (comp.c_object_table.keys()) |key| {
...@@ -949,14 +956,14 @@ pub const File = struct {...@@ -949,14 +956,14 @@ pub const File = struct {
949 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));956 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
950 }957 }
951 }958 }
952 if (module_obj_path) |p| {959 if (zcu_obj_path) |p| {
953 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));960 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
954 }961 }
955 if (compiler_rt_path) |p| {962 if (compiler_rt_path) |p| {
956 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));963 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
957 }964 }
958965
959 if (base.options.verbose_link) {966 if (comp.verbose_link) {
960 std.debug.print("ar rcs {s}", .{full_out_path_z});967 std.debug.print("ar rcs {s}", .{full_out_path_z});
961 for (object_files.items) |arg| {968 for (object_files.items) |arg| {
962 std.debug.print(" {s}", .{arg});969 std.debug.print(" {s}", .{arg});
...@@ -972,7 +979,7 @@ pub const File = struct {...@@ -972,7 +979,7 @@ pub const File = struct {
972 const bad = llvm_bindings.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_tag);979 const bad = llvm_bindings.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_tag);
973 if (bad) return error.UnableToWriteArchive;980 if (bad) return error.UnableToWriteArchive;
974981
975 if (!base.options.disable_lld_caching) {982 if (!base.disable_lld_caching) {
976 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {983 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
977 log.warn("failed to save archive hash digest file: {s}", .{@errorName(err)});984 log.warn("failed to save archive hash digest file: {s}", .{@errorName(err)});
978 };985 };
...@@ -1090,6 +1097,34 @@ pub const File = struct {...@@ -1090,6 +1097,34 @@ pub const File = struct {
1090 }1097 }
1091 }1098 }
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
1093 pub const C = @import("link/C.zig");1128 pub const C = @import("link/C.zig");
1094 pub const Coff = @import("link/Coff.zig");1129 pub const Coff = @import("link/Coff.zig");
1095 pub const Plan9 = @import("link/Plan9.zig");1130 pub const Plan9 = @import("link/Plan9.zig");
src/link/C.zig+34-20
...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;...@@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
5const fs = std.fs;5const fs = std.fs;
66
7const C = @This();7const C = @This();
8const build_options = @import("build_options");
8const Module = @import("../Module.zig");9const Module = @import("../Module.zig");
9const InternPool = @import("../InternPool.zig");10const InternPool = @import("../InternPool.zig");
10const Alignment = InternPool.Alignment;11const Alignment = InternPool.Alignment;
...@@ -91,28 +92,40 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {...@@ -91,28 +92,40 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
91 };92 };
92}93}
9394
94pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C {95pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C {
95 assert(options.target.ofmt == .c);96 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;101 // These are caught by `Compilation.Config.resolve`.
98 if (options.use_lld) return error.LLDHasNoCBackend;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, .{
101 // Truncation is done on `flush`.108 // Truncation is done on `flush`.
102 .truncate = false,109 .truncate = false,
103 .mode = link.determineMode(options),110 .mode = link.determineMode(options),
104 });111 });
105 errdefer file.close();112 errdefer file.close();
106113
107 const c_file = try gpa.create(C);114 const c_file = try arena.create(C);
108 errdefer gpa.destroy(c_file);
109115
110 c_file.* = .{116 c_file.* = .{
111 .base = .{117 .base = .{
112 .tag = .c,118 .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,
114 .file = file,124 .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,
116 },129 },
117 };130 };
118131
...@@ -120,7 +133,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C...@@ -120,7 +133,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
120}133}
121134
122pub fn deinit(self: *C) void {135pub fn deinit(self: *C) void {
123 const gpa = self.base.allocator;136 const gpa = self.base.comp.gpa;
124137
125 for (self.decl_table.values()) |*db| {138 for (self.decl_table.values()) |*db| {
126 db.deinit(gpa);139 db.deinit(gpa);
...@@ -141,7 +154,7 @@ pub fn deinit(self: *C) void {...@@ -141,7 +154,7 @@ pub fn deinit(self: *C) void {
141}154}
142155
143pub fn freeDecl(self: *C, decl_index: InternPool.DeclIndex) void {156pub fn freeDecl(self: *C, decl_index: InternPool.DeclIndex) void {
144 const gpa = self.base.allocator;157 const gpa = self.base.comp.gpa;
145 if (self.decl_table.fetchSwapRemove(decl_index)) |kv| {158 if (self.decl_table.fetchSwapRemove(decl_index)) |kv| {
146 var decl_block = kv.value;159 var decl_block = kv.value;
147 decl_block.deinit(gpa);160 decl_block.deinit(gpa);
...@@ -155,7 +168,7 @@ pub fn updateFunc(...@@ -155,7 +168,7 @@ pub fn updateFunc(
155 air: Air,168 air: Air,
156 liveness: Liveness,169 liveness: Liveness,
157) !void {170) !void {
158 const gpa = self.base.allocator;171 const gpa = self.base.comp.gpa;
159172
160 const func = module.funcInfo(func_index);173 const func = module.funcInfo(func_index);
161 const decl_index = func.owner_decl;174 const decl_index = func.owner_decl;
...@@ -223,7 +236,7 @@ pub fn updateFunc(...@@ -223,7 +236,7 @@ pub fn updateFunc(
223}236}
224237
225fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {238fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
226 const gpa = self.base.allocator;239 const gpa = self.base.comp.gpa;
227 const anon_decl = self.anon_decls.keys()[i];240 const anon_decl = self.anon_decls.keys()[i];
228241
229 const fwd_decl = &self.fwd_decl_buf;242 const fwd_decl = &self.fwd_decl_buf;
...@@ -285,7 +298,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: InternPool.DeclIndex) !...@@ -285,7 +298,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: InternPool.DeclIndex) !
285 const tracy = trace(@src());298 const tracy = trace(@src());
286 defer tracy.end();299 defer tracy.end();
287300
288 const gpa = self.base.allocator;301 const gpa = self.base.comp.gpa;
289302
290 const gop = try self.decl_table.getOrPut(gpa, decl_index);303 const gop = try self.decl_table.getOrPut(gpa, decl_index);
291 if (!gop.found_existing) {304 if (!gop.found_existing) {
...@@ -352,7 +365,8 @@ pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void...@@ -352,7 +365,8 @@ pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void
352}365}
353366
354fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {367fn 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);
356 errdefer defines.deinit();370 errdefer defines.deinit();
357 const writer = defines.writer();371 const writer = defines.writer();
358 switch (target.abi) {372 switch (target.abi) {
...@@ -371,7 +385,7 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -371,7 +385,7 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
371 sub_prog_node.activate();385 sub_prog_node.activate();
372 defer sub_prog_node.end();386 defer sub_prog_node.end();
373387
374 const gpa = self.base.allocator;388 const gpa = self.base.comp.gpa;
375 const module = self.base.options.module.?;389 const module = self.base.options.module.?;
376390
377 {391 {
...@@ -520,7 +534,7 @@ fn flushCTypes(...@@ -520,7 +534,7 @@ fn flushCTypes(
520 pass: codegen.DeclGen.Pass,534 pass: codegen.DeclGen.Pass,
521 decl_ctypes: codegen.CType.Store,535 decl_ctypes: codegen.CType.Store,
522) FlushDeclError!void {536) FlushDeclError!void {
523 const gpa = self.base.allocator;537 const gpa = self.base.comp.gpa;
524 const mod = self.base.options.module.?;538 const mod = self.base.options.module.?;
525539
526 const decl_ctypes_len = decl_ctypes.count();540 const decl_ctypes_len = decl_ctypes.count();
...@@ -601,7 +615,7 @@ fn flushCTypes(...@@ -601,7 +615,7 @@ fn flushCTypes(
601}615}
602616
603fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {617fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
604 const gpa = self.base.allocator;618 const gpa = self.base.comp.gpa;
605619
606 const fwd_decl = &self.lazy_fwd_decl_buf;620 const fwd_decl = &self.lazy_fwd_decl_buf;
607 const code = &self.lazy_code_buf;621 const code = &self.lazy_code_buf;
...@@ -643,7 +657,7 @@ fn flushLazyFn(...@@ -643,7 +657,7 @@ fn flushLazyFn(
643 ctypes: *codegen.CType.Store,657 ctypes: *codegen.CType.Store,
644 lazy_fn: codegen.LazyFnMap.Entry,658 lazy_fn: codegen.LazyFnMap.Entry,
645) FlushDeclError!void {659) FlushDeclError!void {
646 const gpa = self.base.allocator;660 const gpa = self.base.comp.gpa;
647661
648 const fwd_decl = &self.lazy_fwd_decl_buf;662 const fwd_decl = &self.lazy_fwd_decl_buf;
649 const code = &self.lazy_code_buf;663 const code = &self.lazy_code_buf;
...@@ -683,7 +697,7 @@ fn flushLazyFn(...@@ -683,7 +697,7 @@ fn flushLazyFn(
683}697}
684698
685fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {699fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
686 const gpa = self.base.allocator;700 const gpa = self.base.comp.gpa;
687 try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(lazy_fns.count()));701 try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(lazy_fns.count()));
688702
689 var it = lazy_fns.iterator();703 var it = lazy_fns.iterator();
...@@ -702,7 +716,7 @@ fn flushDeclBlock(...@@ -702,7 +716,7 @@ fn flushDeclBlock(
702 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),716 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
703 extern_symbol_name: InternPool.OptionalNullTerminatedString,717 extern_symbol_name: InternPool.OptionalNullTerminatedString,
704) FlushDeclError!void {718) FlushDeclError!void {
705 const gpa = self.base.allocator;719 const gpa = self.base.comp.gpa;
706 try self.flushLazyFns(f, decl_block.lazy_fns);720 try self.flushLazyFns(f, decl_block.lazy_fns);
707 try f.all_buffers.ensureUnusedCapacity(gpa, 1);721 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
708 fwd_decl: {722 fwd_decl: {
src/link/Coff.zig+14-11
...@@ -232,7 +232,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {...@@ -232,7 +232,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {
232 errdefer self.base.destroy();232 errdefer self.base.destroy();
233233
234 const use_lld = build_options.have_llvm and options.comp.config.use_lld;234 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
237 if (use_lld and use_llvm) {237 if (use_lld and use_llvm) {
238 // LLVM emits the object file; LLD links it into the final product.238 // 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 {...@@ -353,6 +353,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {
353353
354pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {354pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {
355 const target = options.comp.root_mod.resolved_target.result;355 const target = options.comp.root_mod.resolved_target.result;
356 const optimize_mode = options.comp.root_mod.optimize_mode;
356 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {357 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
357 0...32 => .p32,358 0...32 => .p32,
358 33...64 => .p64,359 33...64 => .p64,
...@@ -367,14 +368,24 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {...@@ -367,14 +368,24 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {
367 .tag = .coff,368 .tag = .coff,
368 .comp = options.comp,369 .comp = options.comp,
369 .emit = options.emit,370 .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,
370 .file = null,374 .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,
371 },382 },
372 .ptr_width = ptr_width,383 .ptr_width = ptr_width,
373 .page_size = page_size,384 .page_size = page_size,
374 .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory),385 .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory),
375 };386 };
376387
377 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;388 const use_llvm = options.comp.config.use_llvm;
378 if (use_llvm and options.comp.config.have_zcu) {389 if (use_llvm and options.comp.config.have_zcu) {
379 self.llvm_object = try LlvmObject.create(arena, options);390 self.llvm_object = try LlvmObject.create(arena, options);
380 }391 }
...@@ -1494,8 +1505,6 @@ pub fn updateExports(...@@ -1494,8 +1505,6 @@ pub fn updateExports(
14941505
1495 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);1506 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
14961507
1497 if (self.base.options.emit == null) return;
1498
1499 const gpa = self.base.comp.gpa;1508 const gpa = self.base.comp.gpa;
15001509
1501 const metadata = switch (exported) {1510 const metadata = switch (exported) {
...@@ -1645,13 +1654,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {...@@ -1645,13 +1654,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
1645}1654}
16461655
1647pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {1656pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
1648 if (self.base.options.emit == null) {1657 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
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;
1655 if (use_lld) {1658 if (use_lld) {
1656 return lld.linkWithLLD(self, comp, prog_node);1659 return lld.linkWithLLD(self, comp, prog_node);
1657 }1660 }
src/link/Coff/lld.zig+15-17
...@@ -25,8 +25,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -25,8 +25,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
25 defer arena_allocator.deinit();25 defer arena_allocator.deinit();
26 const arena = arena_allocator.allocator();26 const arena = arena_allocator.allocator();
2727
28 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.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.options.emit.?.sub_path});29 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
3030
31 // If there is no Zig code to compile, then we should skip flushing the output file because it31 // If there is no Zig code to compile, then we should skip flushing the output file because it
32 // will not be part of the linker line anyway.32 // 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...@@ -50,6 +50,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
50 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;50 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
51 const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib;51 const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib;
52 const target = self.base.options.target;52 const target = self.base.options.target;
53 const optimize_mode = self.base.comp.root_mod.optimize_mode;
5354
54 // See link/Elf.zig for comments on how this mechanism works.55 // See link/Elf.zig for comments on how this mechanism works.
55 const id_symlink_basename = "lld.id";56 const id_symlink_basename = "lld.id";
...@@ -79,7 +80,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -79,7 +80,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
79 }80 }
80 try man.addOptionalFile(module_obj_path);81 try man.addOptionalFile(module_obj_path);
81 man.hash.addOptionalBytes(self.base.options.entry);82 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);
83 man.hash.addOptional(self.base.options.image_base_override);84 man.hash.addOptional(self.base.options.image_base_override);
84 man.hash.addListOfBytes(self.base.options.lib_dirs);85 man.hash.addListOfBytes(self.base.options.lib_dirs);
85 man.hash.add(self.base.options.skip_linker_dependencies);86 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...@@ -93,14 +94,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
93 }94 }
94 }95 }
95 }96 }
96 try link.hashAddSystemLibs(&man, self.base.options.system_libs);97 try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
97 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());98 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
98 man.hash.addOptional(self.base.options.subsystem);99 man.hash.addOptional(self.base.options.subsystem);
99 man.hash.add(self.base.options.is_test);100 man.hash.add(self.base.options.is_test);
100 man.hash.add(self.base.options.tsaware);101 man.hash.add(self.base.options.tsaware);
101 man.hash.add(self.base.options.nxcompat);102 man.hash.add(self.base.options.nxcompat);
102 man.hash.add(self.base.options.dynamicbase);103 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);
104 // strip does not need to go into the linker hash because it is part of the hash namespace105 // strip does not need to go into the linker hash because it is part of the hash namespace
105 man.hash.addOptional(self.base.options.major_subsystem_version);106 man.hash.addOptional(self.base.options.major_subsystem_version);
106 man.hash.addOptional(self.base.options.minor_subsystem_version);107 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...@@ -185,15 +186,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
185 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));186 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
186 }187 }
187 if (self.base.options.lto) {188 if (self.base.options.lto) {
188 switch (self.base.options.optimize_mode) {189 switch (optimize_mode) {
189 .Debug => {},190 .Debug => {},
190 .ReleaseSmall => try argv.append("-OPT:lldlto=2"),191 .ReleaseSmall => try argv.append("-OPT:lldlto=2"),
191 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),192 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),
192 }193 }
193 }194 }
194 if (self.base.options.output_mode == .Exe) {195 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}", .{self.base.stack_size}));
196 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
197 }197 }
198 if (self.base.options.image_base_override) |image_base| {198 if (self.base.options.image_base_override) |image_base| {
199 try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{image_base}));199 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...@@ -232,10 +232,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
232 if (!self.base.options.dynamicbase) {232 if (!self.base.options.dynamicbase) {
233 try argv.append("-dynamicbase:NO");233 try argv.append("-dynamicbase:NO");
234 }234 }
235 if (self.base.options.allow_shlib_undefined) |allow_shlib_undefined| {235 if (self.base.allow_shlib_undefined) {
236 if (allow_shlib_undefined) {236 try argv.append("-FORCE:UNRESOLVED");
237 try argv.append("-FORCE:UNRESOLVED");
238 }
239 }237 }
240238
241 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));239 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...@@ -419,7 +417,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
419 try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib"));417 try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib"));
420418
421 for (mingw.always_link_libs) |name| {419 for (mingw.always_link_libs) |name| {
422 if (!self.base.options.system_libs.contains(name)) {420 if (!self.base.comp.system_libs.contains(name)) {
423 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});421 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});
424 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));422 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));
425 }423 }
...@@ -429,7 +427,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -429,7 +427,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
429 .Dynamic => "",427 .Dynamic => "",
430 .Static => "lib",428 .Static => "lib",
431 };429 };
432 const d_str = switch (self.base.options.optimize_mode) {430 const d_str = switch (optimize_mode) {
433 .Debug => "d",431 .Debug => "d",
434 else => "",432 else => "",
435 };433 };
...@@ -489,8 +487,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -489,8 +487,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
489 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);487 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
490 }488 }
491489
492 try argv.ensureUnusedCapacity(self.base.options.system_libs.count());490 try argv.ensureUnusedCapacity(self.base.comp.system_libs.count());
493 for (self.base.options.system_libs.keys()) |key| {491 for (self.base.comp.system_libs.keys()) |key| {
494 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});492 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
495 if (comp.crt_files.get(lib_basename)) |crt_file| {493 if (comp.crt_files.get(lib_basename)) |crt_file| {
496 argv.appendAssumeCapacity(crt_file.full_object_path);494 argv.appendAssumeCapacity(crt_file.full_object_path);
...@@ -516,7 +514,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -516,7 +514,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
516 return error.DllImportLibraryNotFound;514 return error.DllImportLibraryNotFound;
517 }515 }
518516
519 if (self.base.options.verbose_link) {517 if (self.base.comp.verbose_link) {
520 // Skip over our own name so that the LLD linker name is the first argv item.518 // Skip over our own name so that the LLD linker name is the first argv item.
521 Compilation.dump_argv(argv.items[1..]);519 Compilation.dump_argv(argv.items[1..]);
522 }520 }
src/link/Elf.zig+169-153
...@@ -206,7 +206,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {...@@ -206,7 +206,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
206 assert(target.ofmt == .elf);206 assert(target.ofmt == .elf);
207207
208 const use_lld = build_options.have_llvm and options.comp.config.use_lld;208 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
211 const self = try createEmpty(arena, options);214 const self = try createEmpty(arena, options);
212 errdefer self.base.destroy();215 errdefer self.base.destroy();
...@@ -216,8 +219,8 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {...@@ -216,8 +219,8 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
216 return self;219 return self;
217 }220 }
218221
219 const is_obj = options.output_mode == .Obj;222 const is_obj = output_mode == .Obj;
220 const is_obj_or_ar = is_obj or (options.output_mode == .Lib and options.link_mode == .Static);223 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .Static);
221224
222 const sub_path = if (!use_lld) options.emit.sub_path else p: {225 const sub_path = if (!use_lld) options.emit.sub_path else p: {
223 // Open a temporary object file, not the final output file because we226 // 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 {...@@ -229,10 +232,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
229 break :p o_file_path;232 break :p o_file_path;
230 };233 };
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, .{
233 .truncate = false,236 .truncate = false,
234 .read = true,237 .read = true,
235 .mode = link.determineMode(options),238 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
236 });239 });
237240
238 const gpa = options.comp.gpa;241 const gpa = options.comp.gpa;
...@@ -292,24 +295,34 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {...@@ -292,24 +295,34 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
292 });295 });
293 }296 }
294297
295 if (options.module != null and !options.use_llvm) {298 if (opt_zcu) |zcu| {
296 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));299 if (!use_llvm) {
297 self.files.set(index, .{ .zig_object = .{300 const index: File.Index = @intCast(try self.files.addOne(gpa));
298 .index = index,301 self.files.set(index, .{ .zig_object = .{
299 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(302 .index = index,
300 options.module.?.main_mod.root_src_path,303 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
301 )}),304 zcu.main_mod.root_src_path,
302 } });305 )}),
303 self.zig_object_index = index;306 } });
304 try self.zigObjectPtr().?.init(self);307 self.zig_object_index = index;
305 try self.initMetadata();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 }
306 }314 }
307315
308 return self;316 return self;
309}317}
310318
311pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {319pub 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;
312 const target = options.comp.root_mod.resolved_target.result;322 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;
313 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {326 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
314 0...32 => .p32,327 0...32 => .p32,
315 33...64 => .p64,328 33...64 => .p64,
...@@ -322,7 +335,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {...@@ -322,7 +335,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
322 .sparc64 => 0x2000,335 .sparc64 => 0x2000,
323 else => 0x1000,336 else => 0x1000,
324 };337 };
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;
326 const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic)339 const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic)
327 elf.VER_NDX_GLOBAL340 elf.VER_NDX_GLOBAL
328 else341 else
...@@ -333,13 +346,23 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {...@@ -333,13 +346,23 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
333 .tag = .elf,346 .tag = .elf,
334 .comp = options.comp,347 .comp = options.comp,
335 .emit = options.emit,348 .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,
336 .file = null,352 .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,
337 },360 },
338 .ptr_width = ptr_width,361 .ptr_width = ptr_width,
339 .page_size = page_size,362 .page_size = page_size,
340 .default_sym_version = default_sym_version,363 .default_sym_version = default_sym_version,
341 };364 };
342 if (options.use_llvm and options.comp.config.have_zcu) {365 if (use_llvm and options.comp.config.have_zcu) {
343 self.llvm_object = try LlvmObject.create(arena, options);366 self.llvm_object = try LlvmObject.create(arena, options);
344 }367 }
345368
...@@ -504,8 +527,13 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {...@@ -504,8 +527,13 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
504 return start;527 return start;
505}528}
506529
530pub const InitMetadataOptions = struct {
531 symbol_count_hint: u64,
532 program_code_size_hint: u64,
533};
534
507/// TODO move to ZigObject535/// TODO move to ZigObject
508pub fn initMetadata(self: *Elf) !void {536pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
509 const gpa = self.base.comp.gpa;537 const gpa = self.base.comp.gpa;
510 const ptr_size = self.ptrWidthBytes();538 const ptr_size = self.ptrWidthBytes();
511 const target = self.base.comp.root_mod.resolved_target.result;539 const target = self.base.comp.root_mod.resolved_target.result;
...@@ -515,7 +543,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -515,7 +543,7 @@ pub fn initMetadata(self: *Elf) !void {
515543
516 const fillSection = struct {544 const fillSection = struct {
517 fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {545 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()) {
519 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);547 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);
520 shdr.sh_offset = off;548 shdr.sh_offset = off;
521 shdr.sh_size = size;549 shdr.sh_size = size;
...@@ -530,9 +558,9 @@ pub fn initMetadata(self: *Elf) !void {...@@ -530,9 +558,9 @@ pub fn initMetadata(self: *Elf) !void {
530558
531 comptime assert(number_of_zig_segments == 5);559 comptime assert(number_of_zig_segments == 5);
532560
533 if (!self.isRelocatable()) {561 if (!self.base.isRelocatable()) {
534 if (self.phdr_zig_load_re_index == null) {562 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;
536 const off = self.findFreeSpace(filesz, self.page_size);564 const off = self.findFreeSpace(filesz, self.page_size);
537 self.phdr_zig_load_re_index = try self.addPhdr(.{565 self.phdr_zig_load_re_index = try self.addPhdr(.{
538 .type = elf.PT_LOAD,566 .type = elf.PT_LOAD,
...@@ -549,7 +577,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -549,7 +577,7 @@ pub fn initMetadata(self: *Elf) !void {
549 // We really only need ptr alignment but since we are using PROGBITS, linux requires577 // We really only need ptr alignment but since we are using PROGBITS, linux requires
550 // page align.578 // page align.
551 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);579 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;
553 const off = self.findFreeSpace(filesz, alignment);581 const off = self.findFreeSpace(filesz, alignment);
554 self.phdr_zig_got_index = try self.addPhdr(.{582 self.phdr_zig_got_index = try self.addPhdr(.{
555 .type = elf.PT_LOAD,583 .type = elf.PT_LOAD,
...@@ -613,8 +641,8 @@ pub fn initMetadata(self: *Elf) !void {...@@ -613,8 +641,8 @@ pub fn initMetadata(self: *Elf) !void {
613 .offset = std.math.maxInt(u64),641 .offset = std.math.maxInt(u64),
614 });642 });
615 const shdr = &self.shdrs.items[self.zig_text_section_index.?];643 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);644 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
617 if (self.isRelocatable()) {645 if (self.base.isRelocatable()) {
618 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);646 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
619 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{647 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
620 .shndx = rela_shndx,648 .shndx = rela_shndx,
...@@ -630,7 +658,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -630,7 +658,7 @@ pub fn initMetadata(self: *Elf) !void {
630 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});658 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
631 }659 }
632660
633 if (self.zig_got_section_index == null and !self.isRelocatable()) {661 if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
634 self.zig_got_section_index = try self.addSection(.{662 self.zig_got_section_index = try self.addSection(.{
635 .name = ".got.zig",663 .name = ".got.zig",
636 .type = elf.SHT_PROGBITS,664 .type = elf.SHT_PROGBITS,
...@@ -661,7 +689,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -661,7 +689,7 @@ pub fn initMetadata(self: *Elf) !void {
661 });689 });
662 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];690 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
663 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);691 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
664 if (self.isRelocatable()) {692 if (self.base.isRelocatable()) {
665 const rela_shndx = try self.addRelaShdr(693 const rela_shndx = try self.addRelaShdr(
666 ".rela.data.rel.ro.zig",694 ".rela.data.rel.ro.zig",
667 self.zig_data_rel_ro_section_index.?,695 self.zig_data_rel_ro_section_index.?,
...@@ -690,7 +718,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -690,7 +718,7 @@ pub fn initMetadata(self: *Elf) !void {
690 });718 });
691 const shdr = &self.shdrs.items[self.zig_data_section_index.?];719 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
692 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);720 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
693 if (self.isRelocatable()) {721 if (self.base.isRelocatable()) {
694 const rela_shndx = try self.addRelaShdr(722 const rela_shndx = try self.addRelaShdr(
695 ".rela.data.zig",723 ".rela.data.zig",
696 self.zig_data_section_index.?,724 self.zig_data_section_index.?,
...@@ -930,13 +958,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16) void {...@@ -930,13 +958,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16) void {
930}958}
931959
932pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {960pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
933 if (self.base.options.emit == null) {961 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
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;
940 if (use_lld) {962 if (use_lld) {
941 return self.linkWithLLD(comp, prog_node);963 return self.linkWithLLD(comp, prog_node);
942 }964 }
...@@ -950,7 +972,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -950,7 +972,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
950 if (self.llvm_object) |llvm_object| {972 if (self.llvm_object) |llvm_object| {
951 try llvm_object.flushModule(comp, prog_node);973 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;
954 if (use_lld) return;976 if (use_lld) return;
955 }977 }
956978
...@@ -959,13 +981,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -959,13 +981,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
959 sub_prog_node.activate();981 sub_prog_node.activate();
960 defer sub_prog_node.end();982 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);
963 defer arena_allocator.deinit();985 defer arena_allocator.deinit();
964 const arena = arena_allocator.allocator();986 const arena = arena_allocator.allocator();
965987
966 const target = self.base.comp.root_mod.resolved_target.result;988 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.989 const link_mode = self.base.comp.config.link_mode;
968 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});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});
969 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {992 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
970 if (fs.path.dirname(full_out_path)) |dirname| {993 if (fs.path.dirname(full_out_path)) |dirname| {
971 break :blk try fs.path.join(arena, &.{ dirname, path });994 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...@@ -973,10 +996,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
973 break :blk path;996 break :blk path;
974 }997 }
975 } else null;998 } else null;
976 const gc_sections = self.base.options.gc_sections orelse false;999 const gc_sections = self.base.gc_sections;
9771000
978 // --verbose-link1001 // --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
981 const csu = try CsuObjects.init(arena, self.base.options, comp);1004 const csu = try CsuObjects.init(arena, self.base.options, comp);
982 const compiler_rt_path: ?[]const u8 = blk: {1005 const compiler_rt_path: ?[]const u8 = blk: {
...@@ -986,8 +1009,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -986,8 +1009,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
986 };1009 };
9871010
988 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);1011 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
989 if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);1012 if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
990 if (self.isObject()) return self.flushObject(comp, module_obj_path);1013 if (self.base.isObject()) return self.flushObject(comp, module_obj_path);
9911014
992 // Here we will parse input positional and library files (if referenced).1015 // Here we will parse input positional and library files (if referenced).
993 // This will roughly match in any linker backend we support.1016 // 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...@@ -1011,7 +1034,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1011 if (module_obj_path) |path| try positionals.append(.{ .path = path });1034 if (module_obj_path) |path| try positionals.append(.{ .path = path });
10121035
1013 // rpaths1036 // rpaths
1014 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);1037 var rpath_table = std.StringArrayHashMap(void).init(gpa);
1015 defer rpath_table.deinit();1038 defer rpath_table.deinit();
10161039
1017 for (self.base.options.rpath_list) |rpath| {1040 for (self.base.options.rpath_list) |rpath| {
...@@ -1019,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1019,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1019 }1042 }
10201043
1021 if (self.base.options.each_lib_rpath) {1044 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);
1023 defer test_path.deinit();1046 defer test_path.deinit();
1024 for (self.base.options.lib_dirs) |lib_dir_path| {1047 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| {
1026 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))1049 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
1027 continue;1050 continue;
1028 _ = try rpath_table.put(lib_dir_path, {});1051 _ = try rpath_table.put(lib_dir_path, {});
...@@ -1064,8 +1087,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1064,8 +1087,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10641087
1065 var system_libs = std.ArrayList(SystemLib).init(arena);1088 var system_libs = std.ArrayList(SystemLib).init(arena);
10661089
1067 try system_libs.ensureUnusedCapacity(self.base.options.system_libs.values().len);1090 try system_libs.ensureUnusedCapacity(self.base.comp.system_libs.values().len);
1068 for (self.base.options.system_libs.values()) |lib_info| {1091 for (self.base.comp.system_libs.values()) |lib_info| {
1069 system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });1092 system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
1070 }1093 }
10711094
...@@ -1127,7 +1150,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1127,7 +1150,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1127 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),1150 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
1128 });1151 });
1129 } else if (target.isMusl()) {1152 } 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) {
1131 .Static => "libc.a",1154 .Static => "libc.a",
1132 .Dynamic => "libc.so",1155 .Dynamic => "libc.so",
1133 });1156 });
...@@ -1224,7 +1247,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1224,7 +1247,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1224 if (self.entry_index == null) {1247 if (self.entry_index == null) {
1225 const entry: ?[]const u8 = entry: {1248 const entry: ?[]const u8 = entry: {
1226 if (self.base.options.entry) |entry| break :entry entry;1249 if (self.base.options.entry) |entry| break :entry entry;
1227 if (!self.isDynLib()) break :entry "_start";1250 if (!self.base.isDynLib()) break :entry "_start";
1228 break :entry null;1251 break :entry null;
1229 };1252 };
1230 self.entry_index = if (entry) |name| self.globalByName(name) else null;1253 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...@@ -1301,7 +1324,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1301 try self.writeAtoms();1324 try self.writeAtoms();
1302 try self.writeSyntheticSections();1325 try self.writeSyntheticSections();
13031326
1304 if (self.entry_index == null and self.isExe()) {1327 if (self.entry_index == null and self.base.isExe()) {
1305 log.debug("flushing. no_entry_point_found = true", .{});1328 log.debug("flushing. no_entry_point_found = true", .{});
1306 self.error_flags.no_entry_point_found = true;1329 self.error_flags.no_entry_point_found = true;
1307 } else {1330 } else {
...@@ -1531,13 +1554,15 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)...@@ -1531,13 +1554,15 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)
15311554
1532/// --verbose-link output1555/// --verbose-link output
1533fn dumpArgv(self: *Elf, comp: *Compilation) !void {1556fn 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);
1535 defer arena_allocator.deinit();1559 defer arena_allocator.deinit();
1536 const arena = arena_allocator.allocator();1560 const arena = arena_allocator.allocator();
15371561
1538 const target = self.base.comp.root_mod.resolved_target.result;1562 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.1563 const link_mode = self.base.comp.config.link_mode;
1540 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});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});
1541 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {1566 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
1542 if (fs.path.dirname(full_out_path)) |dirname| {1567 if (fs.path.dirname(full_out_path)) |dirname| {
1543 break :blk try fs.path.join(arena, &.{ dirname, path });1568 break :blk try fs.path.join(arena, &.{ dirname, path });
...@@ -1545,7 +1570,6 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1545,7 +1570,6 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1545 break :blk path;1570 break :blk path;
1546 }1571 }
1547 } else null;1572 } else null;
1548 const gc_sections = self.base.options.gc_sections orelse false;
15491573
1550 const csu = try CsuObjects.init(arena, self.base.options, comp);1574 const csu = try CsuObjects.init(arena, self.base.options, comp);
1551 const compiler_rt_path: ?[]const u8 = blk: {1575 const compiler_rt_path: ?[]const u8 = blk: {
...@@ -1558,20 +1582,20 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1558,20 +1582,20 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15581582
1559 try argv.append("zig");1583 try argv.append("zig");
15601584
1561 if (self.isStaticLib()) {1585 if (self.base.isStaticLib()) {
1562 try argv.append("ar");1586 try argv.append("ar");
1563 } else {1587 } else {
1564 try argv.append("ld");1588 try argv.append("ld");
1565 }1589 }
15661590
1567 if (self.isObject()) {1591 if (self.base.isObject()) {
1568 try argv.append("-r");1592 try argv.append("-r");
1569 }1593 }
15701594
1571 try argv.append("-o");1595 try argv.append("-o");
1572 try argv.append(full_out_path);1596 try argv.append(full_out_path);
15731597
1574 if (self.isRelocatable()) {1598 if (self.base.isRelocatable()) {
1575 for (self.base.options.objects) |obj| {1599 for (self.base.options.objects) |obj| {
1576 try argv.append(obj.path);1600 try argv.append(obj.path);
1577 }1601 }
...@@ -1591,7 +1615,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1591,7 +1615,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1591 }1615 }
1592 }1616 }
15931617
1594 if (self.isDynLib()) {1618 if (self.base.isDynLib()) {
1595 if (self.base.options.soname) |name| {1619 if (self.base.options.soname) |name| {
1596 try argv.append("-soname");1620 try argv.append("-soname");
1597 try argv.append(name);1621 try argv.append(name);
...@@ -1624,16 +1648,16 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1624,16 +1648,16 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1624 }1648 }
1625 }1649 }
16261650
1627 if (self.base.options.stack_size_override) |ss| {1651 try argv.appendSlice(&.{
1628 try argv.append("-z");1652 "-z",
1629 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));1653 try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),
1630 }1654 });
16311655
1632 if (self.base.options.image_base_override) |image_base| {1656 if (self.base.options.image_base_override) |image_base| {
1633 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));1657 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1634 }1658 }
16351659
1636 if (gc_sections) {1660 if (self.base.gc_sections) {
1637 try argv.append("--gc-sections");1661 try argv.append("--gc-sections");
1638 }1662 }
16391663
...@@ -1666,11 +1690,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1666,11 +1690,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
16661690
1667 if (self.isStatic()) {1691 if (self.isStatic()) {
1668 try argv.append("-static");1692 try argv.append("-static");
1669 } else if (self.isDynLib()) {1693 } else if (self.base.isDynLib()) {
1670 try argv.append("-shared");1694 try argv.append("-shared");
1671 }1695 }
16721696
1673 if (self.base.options.pie and self.isExe()) {1697 if (self.base.options.pie and self.base.isExe()) {
1674 try argv.append("-pie");1698 try argv.append("-pie");
1675 }1699 }
16761700
...@@ -1741,11 +1765,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1741,11 +1765,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1741 // Shared libraries.1765 // Shared libraries.
1742 // Worst-case, we need an --as-needed argument for every lib, as well1766 // Worst-case, we need an --as-needed argument for every lib, as well
1743 // as one before and one after.1767 // 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);
1745 argv.appendAssumeCapacity("--as-needed");1769 argv.appendAssumeCapacity("--as-needed");
1746 var as_needed = true;1770 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| {
1749 const lib_as_needed = !lib_info.needed;1773 const lib_as_needed = !lib_info.needed;
1750 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {1774 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1751 0b00, 0b11 => {},1775 0b00, 0b11 => {},
...@@ -1780,7 +1804,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1780,7 +1804,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1780 // libc dep1804 // libc dep
1781 if (self.base.options.link_libc) {1805 if (self.base.options.link_libc) {
1782 if (self.base.options.libc_installation != null) {1806 if (self.base.options.libc_installation != null) {
1783 const needs_grouping = self.base.options.link_mode == .Static;1807 const needs_grouping = link_mode == .Static;
1784 if (needs_grouping) try argv.append("--start-group");1808 if (needs_grouping) try argv.append("--start-group");
1785 try argv.appendSlice(target_util.libcFullLinkFlags(target));1809 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1786 if (needs_grouping) try argv.append("--end-group");1810 if (needs_grouping) try argv.append("--end-group");
...@@ -1793,7 +1817,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1793,7 +1817,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1793 }1817 }
1794 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));1818 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1795 } else if (target.isMusl()) {1819 } 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) {
1797 .Static => "libc.a",1821 .Static => "libc.a",
1798 .Dynamic => "libc.so",1822 .Dynamic => "libc.so",
1799 }));1823 }));
...@@ -2006,6 +2030,7 @@ fn accessLibPath(...@@ -2006,6 +2030,7 @@ fn accessLibPath(
2006 lib_name: []const u8,2030 lib_name: []const u8,
2007 link_mode: ?std.builtin.LinkMode,2031 link_mode: ?std.builtin.LinkMode,
2008) !bool {2032) !bool {
2033 const gpa = self.base.comp.gpa;
2009 const sep = fs.path.sep_str;2034 const sep = fs.path.sep_str;
2010 const target = self.base.comp.root_mod.resolved_target.result;2035 const target = self.base.comp.root_mod.resolved_target.result;
2011 test_path.clearRetainingCapacity();2036 test_path.clearRetainingCapacity();
...@@ -2021,7 +2046,7 @@ fn accessLibPath(...@@ -2021,7 +2046,7 @@ fn accessLibPath(
2021 suffix,2046 suffix,
2022 });2047 });
2023 if (checked_paths) |cpaths| {2048 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));
2025 }2050 }
2026 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {2051 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
2027 error.FileNotFound => return false,2052 error.FileNotFound => return false,
...@@ -2150,7 +2175,7 @@ fn markImportsExports(self: *Elf) void {...@@ -2150,7 +2175,7 @@ fn markImportsExports(self: *Elf) void {
2150 }2175 }
2151 if (file_ptr.index() == file_index) {2176 if (file_ptr.index() == file_index) {
2152 global.flags.@"export" = true;2177 global.flags.@"export" = true;
2153 if (elf_file.isDynLib() and vis != .PROTECTED) {2178 if (elf_file.base.isDynLib() and vis != .PROTECTED) {
2154 global.flags.import = true;2179 global.flags.import = true;
2155 }2180 }
2156 }2181 }
...@@ -2158,7 +2183,7 @@ fn markImportsExports(self: *Elf) void {...@@ -2158,7 +2183,7 @@ fn markImportsExports(self: *Elf) void {
2158 }2183 }
2159 }.mark;2184 }.mark;
21602185
2161 if (!self.isDynLib()) {2186 if (!self.base.isDynLib()) {
2162 for (self.shared_objects.items) |index| {2187 for (self.shared_objects.items) |index| {
2163 for (self.file(index).?.globals()) |global_index| {2188 for (self.file(index).?.globals()) |global_index| {
2164 const global = self.symbol(global_index);2189 const global = self.symbol(global_index);
...@@ -2274,12 +2299,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2274,12 +2299,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2274 const tracy = trace(@src());2299 const tracy = trace(@src());
2275 defer tracy.end();2300 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);
2278 defer arena_allocator.deinit();2304 defer arena_allocator.deinit();
2279 const arena = arena_allocator.allocator();2305 const arena = arena_allocator.allocator();
22802306
2281 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.2307 const directory = self.base.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});2308 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
22832309
2284 // If there is no Zig code to compile, then we should skip flushing the output file because it2310 // If there is no Zig code to compile, then we should skip flushing the output file because it
2285 // will not be part of the linker line anyway.2311 // 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...@@ -2298,16 +2324,15 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2298 sub_prog_node.context.refresh();2324 sub_prog_node.context.refresh();
2299 defer sub_prog_node.end();2325 defer sub_prog_node.end();
23002326
2301 const is_obj = self.base.options.output_mode == .Obj;2327 const output_mode = self.base.comp.config.output_mode;
2302 const is_lib = self.base.options.output_mode == .Lib;2328 const is_obj = output_mode == .Obj;
2303 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;2329 const is_lib = output_mode == .Lib;
2304 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;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;
2305 const have_dynamic_linker = self.base.options.link_libc and2333 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;
2307 const target = self.base.comp.root_mod.resolved_target.result;2335 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;
2311 const compiler_rt_path: ?[]const u8 = blk: {2336 const compiler_rt_path: ?[]const u8 = blk: {
2312 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;2337 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
2313 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;2338 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...@@ -2354,7 +2379,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2354 // installation sources because they are always a product of the compiler version + target information.2379 // installation sources because they are always a product of the compiler version + target information.
2355 man.hash.addOptionalBytes(self.base.options.entry);2380 man.hash.addOptionalBytes(self.base.options.entry);
2356 man.hash.addOptional(self.base.options.image_base_override);2381 man.hash.addOptional(self.base.options.image_base_override);
2357 man.hash.add(gc_sections);2382 man.hash.add(self.base.gc_sections);
2358 man.hash.addOptional(self.base.options.sort_section);2383 man.hash.addOptional(self.base.options.sort_section);
2359 man.hash.add(self.base.options.eh_frame_hdr);2384 man.hash.add(self.base.options.eh_frame_hdr);
2360 man.hash.add(self.base.options.emit_relocs);2385 man.hash.add(self.base.options.emit_relocs);
...@@ -2362,9 +2387,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2362,9 +2387,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2362 man.hash.addListOfBytes(self.base.options.lib_dirs);2387 man.hash.addListOfBytes(self.base.options.lib_dirs);
2363 man.hash.addListOfBytes(self.base.options.rpath_list);2388 man.hash.addListOfBytes(self.base.options.rpath_list);
2364 man.hash.add(self.base.options.each_lib_rpath);2389 man.hash.add(self.base.options.each_lib_rpath);
2365 if (self.base.options.output_mode == .Exe) {2390 if (output_mode == .Exe) {
2366 man.hash.add(stack_size);2391 man.hash.add(self.base.stack_size);
2367 man.hash.add(self.base.options.build_id);2392 man.hash.add(self.base.build_id);
2368 }2393 }
2369 man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys());2394 man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys());
2370 man.hash.add(self.base.options.skip_linker_dependencies);2395 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...@@ -2390,9 +2415,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2390 }2415 }
2391 man.hash.addOptionalBytes(self.base.options.soname);2416 man.hash.addOptionalBytes(self.base.options.soname);
2392 man.hash.addOptional(self.base.options.version);2417 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);
2394 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());2419 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);
2396 man.hash.add(self.base.options.bind_global_refs_locally);2421 man.hash.add(self.base.options.bind_global_refs_locally);
2397 man.hash.add(self.base.options.compress_debug_sections);2422 man.hash.add(self.base.options.compress_debug_sections);
2398 man.hash.add(self.base.options.tsan);2423 man.hash.add(self.base.options.tsan);
...@@ -2432,7 +2457,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2432,7 +2457,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2432 // copy when generating relocatables. Normally, we would expect `lld -r` to work.2457 // copy when generating relocatables. Normally, we would expect `lld -r` to work.
2433 // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails2458 // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails
2434 // before even generating the relocatable.2459 // before even generating the relocatable.
2435 if (self.base.options.output_mode == .Obj and2460 if (output_mode == .Obj and
2436 (self.base.options.lto or target.isBpfFreestanding()))2461 (self.base.options.lto or target.isBpfFreestanding()))
2437 {2462 {
2438 // In this case we must do a simple file copy2463 // 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...@@ -2459,7 +2484,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2459 }2484 }
2460 } else {2485 } else {
2461 // Create an LLD command line and invoke it.2486 // 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);
2463 defer argv.deinit();2488 defer argv.deinit();
2464 // We will invoke ourselves as a child process to gain access to LLD.2489 // We will invoke ourselves as a child process to gain access to LLD.
2465 // This is necessary because LLD does not behave properly as a library -2490 // 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...@@ -2503,15 +2528,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2503 .both => {}, // this is the default2528 .both => {}, // this is the default
2504 }2529 }
25052530
2506 if (self.base.options.output_mode == .Exe) {2531 if (output_mode == .Exe) {
2507 try argv.append("-z");2532 try argv.appendSlice(&.{
2508 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}));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) {
2511 .none => {},2538 .none => {},
2512 .fast, .uuid, .sha1, .md5 => {2539 .fast, .uuid, .sha1, .md5 => {
2513 try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{2540 try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
2514 @tagName(self.base.options.build_id),2541 @tagName(self.base.build_id),
2515 }));2542 }));
2516 },2543 },
2517 .hexstring => |hs| {2544 .hexstring => |hs| {
...@@ -2536,7 +2563,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2536,7 +2563,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2536 try argv.append(arg);2563 try argv.append(arg);
2537 }2564 }
25382565
2539 if (gc_sections) {2566 if (self.base.gc_sections) {
2540 try argv.append("--gc-sections");2567 try argv.append("--gc-sections");
2541 }2568 }
25422569
...@@ -2615,7 +2642,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2615,7 +2642,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2615 try argv.append(arg);2642 try argv.append(arg);
2616 }2643 }
26172644
2618 if (self.base.options.link_mode == .Static) {2645 if (link_mode == .Static) {
2619 if (target.cpu.arch.isArmOrThumb()) {2646 if (target.cpu.arch.isArmOrThumb()) {
2620 try argv.append("-Bstatic");2647 try argv.append("-Bstatic");
2621 } else {2648 } else {
...@@ -2625,7 +2652,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2625,7 +2652,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2625 try argv.append("-shared");2652 try argv.append("-shared");
2626 }2653 }
26272654
2628 if (self.base.options.pie and self.base.options.output_mode == .Exe) {2655 if (self.base.options.pie and output_mode == .Exe) {
2629 try argv.append("-pie");2656 try argv.append("-pie");
2630 }2657 }
26312658
...@@ -2648,7 +2675,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2648,7 +2675,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2648 if (csu.crtbegin) |v| try argv.append(v);2675 if (csu.crtbegin) |v| try argv.append(v);
26492676
2650 // rpaths2677 // rpaths
2651 var rpath_table = std.StringHashMap(void).init(self.base.allocator);2678 var rpath_table = std.StringHashMap(void).init(gpa);
2652 defer rpath_table.deinit();2679 defer rpath_table.deinit();
2653 for (self.base.options.rpath_list) |rpath| {2680 for (self.base.options.rpath_list) |rpath| {
2654 if ((try rpath_table.fetchPut(rpath, {})) == null) {2681 if ((try rpath_table.fetchPut(rpath, {})) == null) {
...@@ -2664,7 +2691,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2664,7 +2691,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2664 if (self.base.options.each_lib_rpath) {2691 if (self.base.options.each_lib_rpath) {
2665 var test_path = std.ArrayList(u8).init(arena);2692 var test_path = std.ArrayList(u8).init(arena);
2666 for (self.base.options.lib_dirs) |lib_dir_path| {2693 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| {
2668 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))2695 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
2669 continue;2696 continue;
2670 if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {2697 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...@@ -2763,8 +2790,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
27632790
2764 // Shared libraries.2791 // Shared libraries.
2765 if (is_exe_or_dyn_lib) {2792 if (is_exe_or_dyn_lib) {
2766 const system_libs = self.base.options.system_libs.keys();2793 const system_libs = self.base.comp.system_libs.keys();
2767 const system_libs_values = self.base.options.system_libs.values();2794 const system_libs_values = self.base.comp.system_libs.values();
27682795
2769 // Worst-case, we need an --as-needed argument for every lib, as well2796 // Worst-case, we need an --as-needed argument for every lib, as well
2770 // as one before and one after.2797 // as one before and one after.
...@@ -2813,7 +2840,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2813,7 +2840,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2813 self.error_flags.missing_libc = false;2840 self.error_flags.missing_libc = false;
2814 if (self.base.options.link_libc) {2841 if (self.base.options.link_libc) {
2815 if (self.base.options.libc_installation != null) {2842 if (self.base.options.libc_installation != null) {
2816 const needs_grouping = self.base.options.link_mode == .Static;2843 const needs_grouping = link_mode == .Static;
2817 if (needs_grouping) try argv.append("--start-group");2844 if (needs_grouping) try argv.append("--start-group");
2818 try argv.appendSlice(target_util.libcFullLinkFlags(target));2845 try argv.appendSlice(target_util.libcFullLinkFlags(target));
2819 if (needs_grouping) try argv.append("--end-group");2846 if (needs_grouping) try argv.append("--end-group");
...@@ -2826,7 +2853,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2826,7 +2853,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2826 }2853 }
2827 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));2854 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
2828 } else if (target.isMusl()) {2855 } 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) {
2830 .Static => "libc.a",2857 .Static => "libc.a",
2831 .Dynamic => "libc.so",2858 .Dynamic => "libc.so",
2832 }));2859 }));
...@@ -2847,7 +2874,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2847,7 +2874,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2847 if (csu.crtend) |v| try argv.append(v);2874 if (csu.crtend) |v| try argv.append(v);
2848 if (csu.crtn) |v| try argv.append(v);2875 if (csu.crtn) |v| try argv.append(v);
28492876
2850 if (allow_shlib_undefined) {2877 if (self.base.allow_shlib_undefined) {
2851 try argv.append("--allow-shlib-undefined");2878 try argv.append("--allow-shlib-undefined");
2852 }2879 }
28532880
...@@ -2861,7 +2888,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -2861,7 +2888,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
2861 try argv.append("-Bsymbolic");2888 try argv.append("-Bsymbolic");
2862 }2889 }
28632890
2864 if (self.base.options.verbose_link) {2891 if (self.base.comp.verbose_link) {
2865 // Skip over our own name so that the LLD linker name is the first argv item.2892 // Skip over our own name so that the LLD linker name is the first argv item.
2866 Compilation.dump_argv(argv.items[1..]);2893 Compilation.dump_argv(argv.items[1..]);
2867 }2894 }
...@@ -3087,10 +3114,12 @@ fn writeElfHeader(self: *Elf) !void {...@@ -3087,10 +3114,12 @@ fn writeElfHeader(self: *Elf) !void {
30873114
3088 assert(index == 16);3115 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) {
3091 .Exe => if (self.base.options.pie) .DYN else .EXEC,3120 .Exe => if (self.base.options.pie) .DYN else .EXEC,
3092 .Obj => .REL,3121 .Obj => .REL,
3093 .Lib => switch (self.base.options.link_mode) {3122 .Lib => switch (link_mode) {
3094 .Static => @as(elf.ET, .REL),3123 .Static => @as(elf.ET, .REL),
3095 .Dynamic => .DYN,3124 .Dynamic => .DYN,
3096 },3125 },
...@@ -3216,7 +3245,6 @@ pub fn updateExports(...@@ -3216,7 +3245,6 @@ pub fn updateExports(
3216 @panic("Attempted to compile for object format that was disabled by build configuration");3245 @panic("Attempted to compile for object format that was disabled by build configuration");
3217 }3246 }
3218 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);3247 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3219 if (self.base.options.emit == null) return;
3220 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);3248 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
3221}3249}
32223250
...@@ -3280,6 +3308,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {...@@ -3280,6 +3308,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
3280}3308}
32813309
3282fn allocateLinkerDefinedSymbols(self: *Elf) void {3310fn allocateLinkerDefinedSymbols(self: *Elf) void {
3311 const link_mode = self.base.comp.config.link_mode;
3312
3283 // _DYNAMIC3313 // _DYNAMIC
3284 if (self.dynamic_section_index) |shndx| {3314 if (self.dynamic_section_index) |shndx| {
3285 const shdr = &self.shdrs.items[shndx];3315 const shdr = &self.shdrs.items[shndx];
...@@ -3362,7 +3392,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3362,7 +3392,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
33623392
3363 // __rela_iplt_start, __rela_iplt_end3393 // __rela_iplt_start, __rela_iplt_end
3364 if (self.rela_dyn_section_index) |shndx| blk: {3394 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;
3366 const shdr = &self.shdrs.items[shndx];3396 const shdr = &self.shdrs.items[shndx];
3367 const end_addr = shdr.sh_addr + shdr.sh_size;3397 const end_addr = shdr.sh_addr + shdr.sh_size;
3368 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);3398 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
...@@ -3531,7 +3561,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3531,7 +3561,7 @@ fn initSyntheticSections(self: *Elf) !void {
3531 });3561 });
3532 }3562 }
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) {
3535 self.dynstrtab_section_index = try self.addSection(.{3565 self.dynstrtab_section_index = try self.addSection(.{
3536 .name = ".dynstr",3566 .name = ".dynstr",
3537 .flags = elf.SHF_ALLOC,3567 .flags = elf.SHF_ALLOC,
...@@ -3716,7 +3746,7 @@ fn initSpecialPhdrs(self: *Elf) !void {...@@ -3716,7 +3746,7 @@ fn initSpecialPhdrs(self: *Elf) !void {
3716 self.phdr_gnu_stack_index = try self.addPhdr(.{3746 self.phdr_gnu_stack_index = try self.addPhdr(.{
3717 .type = elf.PT_GNU_STACK,3747 .type = elf.PT_GNU_STACK,
3718 .flags = elf.PF_W | elf.PF_R,3748 .flags = elf.PF_W | elf.PF_R,
3719 .memsz = self.base.options.stack_size_override orelse 0,3749 .memsz = self.base.stack_size,
3720 .@"align" = 1,3750 .@"align" = 1,
3721 });3751 });
37223752
...@@ -3822,7 +3852,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {...@@ -3822,7 +3852,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
3822 try self.dynamic.addNeeded(shared_object, self);3852 try self.dynamic.addNeeded(shared_object, self);
3823 }3853 }
38243854
3825 if (self.isDynLib()) {3855 if (self.base.isDynLib()) {
3826 if (self.base.options.soname) |soname| {3856 if (self.base.options.soname) |soname| {
3827 try self.dynamic.setSoname(soname, self);3857 try self.dynamic.setSoname(soname, self);
3828 }3858 }
...@@ -3837,8 +3867,9 @@ fn sortDynamicSymtab(self: *Elf) void {...@@ -3837,8 +3867,9 @@ fn sortDynamicSymtab(self: *Elf) void {
3837}3867}
38383868
3839fn setVersionSymtab(self: *Elf) !void {3869fn setVersionSymtab(self: *Elf) !void {
3870 const gpa = self.base.comp.gpa;
3840 if (self.versym_section_index == null) return;3871 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());
3842 self.versym.items[0] = elf.VER_NDX_LOCAL;3873 self.versym.items[0] = elf.VER_NDX_LOCAL;
3843 for (self.dynsym.entries.items, 1..) |entry, i| {3874 for (self.dynsym.entries.items, 1..) |entry, i| {
3844 const sym = self.symbol(entry.symbol_index);3875 const sym = self.symbol(entry.symbol_index);
...@@ -5597,38 +5628,14 @@ const CsuObjects = struct {...@@ -5597,38 +5628,14 @@ const CsuObjects = struct {
5597};5628};
55985629
5599pub fn calcImageBase(self: Elf) u64 {5630pub fn calcImageBase(self: Elf) u64 {
5600 if (self.isDynLib()) return 0;5631 if (self.base.isDynLib()) return 0;
5601 if (self.isExe() and self.base.options.pie) return 0;5632 if (self.base.isExe() and self.base.options.pie) return 0;
5602 return self.base.options.image_base_override orelse switch (self.ptr_width) {5633 return self.base.options.image_base_override orelse switch (self.ptr_width) {
5603 .p32 => 0x1000,5634 .p32 => 0x1000,
5604 .p64 => 0x1000000,5635 .p64 => 0x1000000,
5605 };5636 };
5606}5637}
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
5632pub fn isZigSection(self: Elf, shndx: u16) bool {5639pub fn isZigSection(self: Elf, shndx: u16) bool {
5633 inline for (&[_]?u16{5640 inline for (&[_]?u16{
5634 self.zig_text_section_index,5641 self.zig_text_section_index,
...@@ -5668,8 +5675,9 @@ fn addPhdr(self: *Elf, opts: struct {...@@ -5668,8 +5675,9 @@ fn addPhdr(self: *Elf, opts: struct {
5668 filesz: u64 = 0,5675 filesz: u64 = 0,
5669 memsz: u64 = 0,5676 memsz: u64 = 0,
5670}) error{OutOfMemory}!u16 {5677}) error{OutOfMemory}!u16 {
5678 const gpa = self.base.comp.gpa;
5671 const index = @as(u16, @intCast(self.phdrs.items.len));5679 const index = @as(u16, @intCast(self.phdrs.items.len));
5672 try self.phdrs.append(self.base.allocator, .{5680 try self.phdrs.append(gpa, .{
5673 .p_type = opts.type,5681 .p_type = opts.type,
5674 .p_flags = opts.flags,5682 .p_flags = opts.flags,
5675 .p_offset = opts.offset,5683 .p_offset = opts.offset,
...@@ -5818,8 +5826,9 @@ pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {...@@ -5818,8 +5826,9 @@ pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
5818}5826}
58195827
5820pub fn addAtom(self: *Elf) !Atom.Index {5828pub fn addAtom(self: *Elf) !Atom.Index {
5829 const gpa = self.base.comp.gpa;
5821 const index = @as(Atom.Index, @intCast(self.atoms.items.len));5830 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);
5823 atom_ptr.* = .{ .atom_index = index };5832 atom_ptr.* = .{ .atom_index = index };
5824 return index;5833 return index;
5825}5834}
...@@ -5841,7 +5850,8 @@ pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {...@@ -5841,7 +5850,8 @@ pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
5841}5850}
58425851
5843pub fn addSymbol(self: *Elf) !Symbol.Index {5852pub 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);
5845 const index = blk: {5855 const index = blk: {
5846 if (self.symbols_free_list.popOrNull()) |index| {5856 if (self.symbols_free_list.popOrNull()) |index| {
5847 log.debug(" (reusing symbol index {d})", .{index});5857 log.debug(" (reusing symbol index {d})", .{index});
...@@ -5858,8 +5868,9 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {...@@ -5858,8 +5868,9 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {
5858}5868}
58595869
5860pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {5870pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
5871 const gpa = self.base.comp.gpa;
5861 const fields = @typeInfo(Symbol.Extra).Struct.fields;5872 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);
5863 return self.addSymbolExtraAssumeCapacity(extra);5874 return self.addSymbolExtraAssumeCapacity(extra);
5864}5875}
58655876
...@@ -5959,8 +5970,9 @@ pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateC...@@ -5959,8 +5970,9 @@ pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateC
5959}5970}
59605971
5961pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index {5972pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index {
5973 const gpa = self.base.comp.gpa;
5962 const index = @as(ComdatGroup.Index, @intCast(self.comdat_groups.items.len));5974 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);
5964 return index;5976 return index;
5965}5977}
59665978
...@@ -6023,14 +6035,16 @@ const ErrorWithNotes = struct {...@@ -6023,14 +6035,16 @@ const ErrorWithNotes = struct {
6023};6035};
60246036
6025pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {6037pub 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);
6027 return self.addErrorWithNotesAssumeCapacity(note_count);6040 return self.addErrorWithNotesAssumeCapacity(note_count);
6028}6041}
60296042
6030fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {6043fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
6044 const gpa = self.base.comp.gpa;
6031 const index = self.misc_errors.items.len;6045 const index = self.misc_errors.items.len;
6032 const err = self.misc_errors.addOneAssumeCapacity();6046 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) };
6034 return .{ .index = index };6048 return .{ .index = index };
6035}6049}
60366050
...@@ -6040,9 +6054,10 @@ pub fn getShString(self: Elf, off: u32) [:0]const u8 {...@@ -6040,9 +6054,10 @@ pub fn getShString(self: Elf, off: u32) [:0]const u8 {
6040}6054}
60416055
6042pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {6056pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
6057 const gpa = self.base.comp.gpa;
6043 const off = @as(u32, @intCast(self.shstrtab.items.len));6058 const off = @as(u32, @intCast(self.shstrtab.items.len));
6044 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);6059 try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1);
6045 self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;6060 self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
6046 return off;6061 return off;
6047}6062}
60486063
...@@ -6052,9 +6067,10 @@ pub fn getDynString(self: Elf, off: u32) [:0]const u8 {...@@ -6052,9 +6067,10 @@ pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
6052}6067}
60536068
6054pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {6069pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
6070 const gpa = self.base.comp.gpa;
6055 const off = @as(u32, @intCast(self.dynstrtab.items.len));6071 const off = @as(u32, @intCast(self.dynstrtab.items.len));
6056 try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);6072 try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1);
6057 self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;6073 self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
6058 return off;6074 return off;
6059}6075}
60606076
src/link/Elf/ZigObject.zig+56-45
...@@ -76,7 +76,7 @@ pub const symbol_mask: u32 = 0x7fffffff;...@@ -76,7 +76,7 @@ pub const symbol_mask: u32 = 0x7fffffff;
76pub const SHN_ATOM: u16 = 0x100;76pub const SHN_ATOM: u16 = 0x100;
7777
78pub fn init(self: *ZigObject, elf_file: *Elf) !void {78pub fn init(self: *ZigObject, elf_file: *Elf) !void {
79 const gpa = elf_file.base.allocator;79 const gpa = elf_file.base.comp.gpa;
8080
81 try self.atoms.append(gpa, 0); // null input section81 try self.atoms.append(gpa, 0); // null input section
82 try self.relocs.append(gpa, .{}); // null relocs section82 try self.relocs.append(gpa, .{}); // null relocs section
...@@ -96,7 +96,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -96,7 +96,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
96 esym.st_shndx = elf.SHN_ABS;96 esym.st_shndx = elf.SHN_ABS;
97 symbol_ptr.esym_index = esym_index;97 symbol_ptr.esym_index = esym_index;
9898
99 if (!elf_file.base.options.strip) {99 if (elf_file.base.debug_format != .strip) {
100 self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32);100 self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32);
101 }101 }
102}102}
...@@ -155,13 +155,13 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -155,13 +155,13 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
155pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {155pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
156 // Handle any lazy symbols that were emitted by incremental compilation.156 // Handle any lazy symbols that were emitted by incremental compilation.
157 if (self.lazy_syms.getPtr(.none)) |metadata| {157 if (self.lazy_syms.getPtr(.none)) |metadata| {
158 const module = elf_file.base.options.module.?;158 const zcu = elf_file.base.comp.module.?;
159159
160 // Most lazy symbols can be updated on first use, but160 // Most lazy symbols can be updated on first use, but
161 // anyerror needs to wait for everything to be flushed.161 // anyerror needs to wait for everything to be flushed.
162 if (metadata.text_state != .unused) self.updateLazySymbol(162 if (metadata.text_state != .unused) self.updateLazySymbol(
163 elf_file,163 elf_file,
164 link.File.LazySymbol.initDecl(.code, null, module),164 link.File.LazySymbol.initDecl(.code, null, zcu),
165 metadata.text_symbol_index,165 metadata.text_symbol_index,
166 ) catch |err| return switch (err) {166 ) catch |err| return switch (err) {
167 error.CodegenFail => error.FlushFailure,167 error.CodegenFail => error.FlushFailure,
...@@ -169,7 +169,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {...@@ -169,7 +169,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
169 };169 };
170 if (metadata.rodata_state != .unused) self.updateLazySymbol(170 if (metadata.rodata_state != .unused) self.updateLazySymbol(
171 elf_file,171 elf_file,
172 link.File.LazySymbol.initDecl(.const_data, null, module),172 link.File.LazySymbol.initDecl(.const_data, null, zcu),
173 metadata.rodata_symbol_index,173 metadata.rodata_symbol_index,
174 ) catch |err| return switch (err) {174 ) catch |err| return switch (err) {
175 error.CodegenFail => error.FlushFailure,175 error.CodegenFail => error.FlushFailure,
...@@ -182,7 +182,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {...@@ -182,7 +182,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
182 }182 }
183183
184 if (self.dwarf) |*dw| {184 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
187 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections188 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
188 // extracted from input object files correctly.189 // extracted from input object files correctly.
...@@ -195,7 +196,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {...@@ -195,7 +196,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
195 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];196 const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?];
196 const low_pc = text_shdr.sh_addr;197 const low_pc = text_shdr.sh_addr;
197 const high_pc = text_shdr.sh_addr + text_shdr.sh_size;198 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);
199 self.debug_info_header_dirty = false;200 self.debug_info_header_dirty = false;
200 }201 }
201202
...@@ -268,7 +269,7 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {...@@ -268,7 +269,7 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
268}269}
269270
270pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {271pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
271 const gpa = elf_file.base.allocator;272 const gpa = elf_file.base.comp.gpa;
272 const atom_index = try elf_file.addAtom();273 const atom_index = try elf_file.addAtom();
273 const symbol_index = try elf_file.addSymbol();274 const symbol_index = try elf_file.addSymbol();
274 const esym_index = try self.addLocalEsym(gpa);275 const esym_index = try self.addLocalEsym(gpa);
...@@ -411,6 +412,7 @@ pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void {...@@ -411,6 +412,7 @@ pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void {
411}412}
412413
413pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {414pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
415 const gpa = elf_file.base.comp.gpa;
414 for (self.atoms.items) |atom_index| {416 for (self.atoms.items) |atom_index| {
415 const atom = elf_file.atom(atom_index) orelse continue;417 const atom = elf_file.atom(atom_index) orelse continue;
416 if (!atom.flags.alive) continue;418 if (!atom.flags.alive) continue;
...@@ -421,7 +423,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -421,7 +423,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
421 // Perhaps it would make sense to save the code until flushModule where we423 // Perhaps it would make sense to save the code until flushModule where we
422 // would free all of generated code?424 // would free all of generated code?
423 const code = try self.codeAlloc(elf_file, atom_index);425 const code = try self.codeAlloc(elf_file, atom_index);
424 defer elf_file.base.allocator.free(code);426 defer gpa.free(code);
425 try atom.scanRelocs(elf_file, code, undefs);427 try atom.scanRelocs(elf_file, code, undefs);
426 } else try atom.scanRelocs(elf_file, null, undefs);428 } else try atom.scanRelocs(elf_file, null, undefs);
427 }429 }
...@@ -447,7 +449,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {...@@ -447,7 +449,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
447/// We need this so that we can write to an archive.449/// We need this so that we can write to an archive.
448/// TODO implement writing ZigObject data directly to a buffer instead.450/// TODO implement writing ZigObject data directly to a buffer instead.
449pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {451pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
450 const gpa = elf_file.base.allocator;452 const gpa = elf_file.base.comp.gpa;
451 const shsize: u64 = switch (elf_file.ptr_width) {453 const shsize: u64 = switch (elf_file.ptr_width) {
452 .p32 => @sizeOf(elf.Elf32_Shdr),454 .p32 => @sizeOf(elf.Elf32_Shdr),
453 .p64 => @sizeOf(elf.Elf64_Shdr),455 .p64 => @sizeOf(elf.Elf64_Shdr),
...@@ -465,7 +467,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {...@@ -465,7 +467,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
465}467}
466468
467pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {469pub 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
470 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);472 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
471473
...@@ -508,7 +510,7 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {...@@ -508,7 +510,7 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
508 const out_shdr = elf_file.shdrs.items[out_shndx];510 const out_shdr = elf_file.shdrs.items[out_shndx];
509 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;511 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;
512 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;514 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
513 try sec.atom_list.append(gpa, atom_index);515 try sec.atom_list.append(gpa, atom_index);
514 }516 }
...@@ -602,7 +604,7 @@ pub fn asFile(self: *ZigObject) File {...@@ -602,7 +604,7 @@ pub fn asFile(self: *ZigObject) File {
602/// Returns atom's code.604/// Returns atom's code.
603/// Caller owns the memory.605/// Caller owns the memory.
604pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {606pub 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;
606 const atom = elf_file.atom(atom_index).?;608 const atom = elf_file.atom(atom_index).?;
607 assert(atom.file_index == self.index);609 assert(atom.file_index == self.index);
608 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];610 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
...@@ -668,8 +670,8 @@ pub fn lowerAnonDecl(...@@ -668,8 +670,8 @@ pub fn lowerAnonDecl(
668 explicit_alignment: InternPool.Alignment,670 explicit_alignment: InternPool.Alignment,
669 src_loc: Module.SrcLoc,671 src_loc: Module.SrcLoc,
670) !codegen.Result {672) !codegen.Result {
671 const gpa = elf_file.base.allocator;673 const gpa = elf_file.base.comp.gpa;
672 const mod = elf_file.base.options.module.?;674 const mod = elf_file.base.comp.module.?;
673 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));675 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
674 const decl_alignment = switch (explicit_alignment) {676 const decl_alignment = switch (explicit_alignment) {
675 .none => ty.abiAlignment(mod),677 .none => ty.abiAlignment(mod),
...@@ -716,8 +718,8 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -716,8 +718,8 @@ pub fn getOrCreateMetadataForLazySymbol(
716 elf_file: *Elf,718 elf_file: *Elf,
717 lazy_sym: link.File.LazySymbol,719 lazy_sym: link.File.LazySymbol,
718) !Symbol.Index {720) !Symbol.Index {
719 const gpa = elf_file.base.allocator;721 const gpa = elf_file.base.comp.gpa;
720 const mod = elf_file.base.options.module.?;722 const mod = elf_file.base.comp.module.?;
721 const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));723 const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
722 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();724 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
723 if (!gop.found_existing) gop.value_ptr.* = .{};725 if (!gop.found_existing) gop.value_ptr.* = .{};
...@@ -752,25 +754,28 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -752,25 +754,28 @@ pub fn getOrCreateMetadataForLazySymbol(
752}754}
753755
754fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {756fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {
757 const gpa = elf_file.base.comp.gpa;
755 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;758 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
756 for (unnamed_consts.items) |sym_index| {759 for (unnamed_consts.items) |sym_index| {
757 self.freeDeclMetadata(elf_file, sym_index);760 self.freeDeclMetadata(elf_file, sym_index);
758 }761 }
759 unnamed_consts.clearAndFree(elf_file.base.allocator);762 unnamed_consts.clearAndFree(gpa);
760}763}
761764
762fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {765fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
763 _ = self;766 _ = self;
767 const gpa = elf_file.base.comp.gpa;
764 const sym = elf_file.symbol(sym_index);768 const sym = elf_file.symbol(sym_index);
765 sym.atom(elf_file).?.free(elf_file);769 sym.atom(elf_file).?.free(elf_file);
766 log.debug("adding %{d} to local symbols free list", .{sym_index});770 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 {};
768 elf_file.symbols.items[sym_index] = .{};772 elf_file.symbols.items[sym_index] = .{};
769 // TODO free GOT entry here773 // TODO free GOT entry here
770}774}
771775
772pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void {776pub 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.?;
774 const decl = mod.declPtr(decl_index);779 const decl = mod.declPtr(decl_index);
775780
776 log.debug("freeDecl {*}", .{decl});781 log.debug("freeDecl {*}", .{decl});
...@@ -780,7 +785,7 @@ pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclInd...@@ -780,7 +785,7 @@ pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclInd
780 const sym_index = kv.value.symbol_index;785 const sym_index = kv.value.symbol_index;
781 self.freeDeclMetadata(elf_file, sym_index);786 self.freeDeclMetadata(elf_file, sym_index);
782 self.freeUnnamedConsts(elf_file, decl_index);787 self.freeUnnamedConsts(elf_file, decl_index);
783 kv.value.exports.deinit(elf_file.base.allocator);788 kv.value.exports.deinit(gpa);
784 }789 }
785790
786 if (self.dwarf) |*dw| {791 if (self.dwarf) |*dw| {
...@@ -793,15 +798,16 @@ pub fn getOrCreateMetadataForDecl(...@@ -793,15 +798,16 @@ pub fn getOrCreateMetadataForDecl(
793 elf_file: *Elf,798 elf_file: *Elf,
794 decl_index: InternPool.DeclIndex,799 decl_index: InternPool.DeclIndex,
795) !Symbol.Index {800) !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);
797 if (!gop.found_existing) {803 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;
799 const symbol_index = try self.addAtom(elf_file);805 const symbol_index = try self.addAtom(elf_file);
800 const mod = elf_file.base.options.module.?;806 const mod = elf_file.base.comp.module.?;
801 const decl = mod.declPtr(decl_index);807 const decl = mod.declPtr(decl_index);
802 const sym = elf_file.symbol(symbol_index);808 const sym = elf_file.symbol(symbol_index);
803 if (decl.getOwnedVariable(mod)) |variable| {809 if (decl.getOwnedVariable(mod)) |variable| {
804 if (variable.is_threadlocal and !single_threaded) {810 if (variable.is_threadlocal and any_non_single_threaded) {
805 sym.flags.is_tls = true;811 sym.flags.is_tls = true;
806 }812 }
807 }813 }
...@@ -820,13 +826,13 @@ fn getDeclShdrIndex(...@@ -820,13 +826,13 @@ fn getDeclShdrIndex(
820 code: []const u8,826 code: []const u8,
821) error{OutOfMemory}!u16 {827) error{OutOfMemory}!u16 {
822 _ = self;828 _ = self;
823 const mod = elf_file.base.options.module.?;829 const mod = elf_file.base.comp.module.?;
824 const single_threaded = elf_file.base.options.single_threaded;830 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
825 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {831 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
826 .Fn => elf_file.zig_text_section_index.?,832 .Fn => elf_file.zig_text_section_index.?,
827 else => blk: {833 else => blk: {
828 if (decl.getOwnedVariable(mod)) |variable| {834 if (decl.getOwnedVariable(mod)) |variable| {
829 if (variable.is_threadlocal and !single_threaded) {835 if (variable.is_threadlocal and any_non_single_threaded) {
830 const is_all_zeroes = for (code) |byte| {836 const is_all_zeroes = for (code) |byte| {
831 if (byte != 0) break false;837 if (byte != 0) break false;
832 } else true;838 } else true;
...@@ -846,9 +852,12 @@ fn getDeclShdrIndex(...@@ -846,9 +852,12 @@ fn getDeclShdrIndex(
846 }852 }
847 if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?;853 if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?;
848 if (Value.fromInterned(variable.init).isUndefDeep(mod)) {854 if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
849 const mode = elf_file.base.options.optimize_mode;855 // TODO: get the optimize_mode from the Module that owns the decl instead
850 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;856 // of using the root module here.
851 break :blk elf_file.zig_bss_section_index.?;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 };
852 }861 }
853 // TODO I blatantly copied the logic from the Wasm linker, but is there a less862 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
854 // intrusive check for all zeroes than this?863 // intrusive check for all zeroes than this?
...@@ -873,8 +882,8 @@ fn updateDeclCode(...@@ -873,8 +882,8 @@ fn updateDeclCode(
873 code: []const u8,882 code: []const u8,
874 stt_bits: u8,883 stt_bits: u8,
875) !void {884) !void {
876 const gpa = elf_file.base.allocator;885 const gpa = elf_file.base.comp.gpa;
877 const mod = elf_file.base.options.module.?;886 const mod = elf_file.base.comp.module.?;
878 const decl = mod.declPtr(decl_index);887 const decl = mod.declPtr(decl_index);
879 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));888 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
880889
...@@ -971,8 +980,8 @@ fn updateTlv(...@@ -971,8 +980,8 @@ fn updateTlv(
971 shndx: u16,980 shndx: u16,
972 code: []const u8,981 code: []const u8,
973) !void {982) !void {
974 const gpa = elf_file.base.allocator;983 const gpa = elf_file.base.comp.gpa;
975 const mod = elf_file.base.options.module.?;984 const mod = elf_file.base.comp.module.?;
976 const decl = mod.declPtr(decl_index);985 const decl = mod.declPtr(decl_index);
977 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));986 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
978987
...@@ -1026,6 +1035,7 @@ pub fn updateFunc(...@@ -1026,6 +1035,7 @@ pub fn updateFunc(
1026 const tracy = trace(@src());1035 const tracy = trace(@src());
1027 defer tracy.end();1036 defer tracy.end();
10281037
1038 const gpa = elf_file.base.comp.gpa;
1029 const func = mod.funcInfo(func_index);1039 const func = mod.funcInfo(func_index);
1030 const decl_index = func.owner_decl;1040 const decl_index = func.owner_decl;
1031 const decl = mod.declPtr(decl_index);1041 const decl = mod.declPtr(decl_index);
...@@ -1034,7 +1044,7 @@ pub fn updateFunc(...@@ -1034,7 +1044,7 @@ pub fn updateFunc(
1034 self.freeUnnamedConsts(elf_file, decl_index);1044 self.freeUnnamedConsts(elf_file, decl_index);
1035 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1045 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);
1038 defer code_buffer.deinit();1048 defer code_buffer.deinit();
10391049
1040 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;1050 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
...@@ -1117,7 +1127,8 @@ pub fn updateDecl(...@@ -1117,7 +1127,8 @@ pub fn updateDecl(
1117 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1127 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1118 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1128 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);
1121 defer code_buffer.deinit();1132 defer code_buffer.deinit();
11221133
1123 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;1134 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
...@@ -1179,8 +1190,8 @@ fn updateLazySymbol(...@@ -1179,8 +1190,8 @@ fn updateLazySymbol(
1179 sym: link.File.LazySymbol,1190 sym: link.File.LazySymbol,
1180 symbol_index: Symbol.Index,1191 symbol_index: Symbol.Index,
1181) !void {1192) !void {
1182 const gpa = elf_file.base.allocator;1193 const gpa = elf_file.base.comp.gpa;
1183 const mod = elf_file.base.options.module.?;1194 const mod = elf_file.base.comp.module.?;
11841195
1185 var required_alignment: InternPool.Alignment = .none;1196 var required_alignment: InternPool.Alignment = .none;
1186 var code_buffer = std.ArrayList(u8).init(gpa);1197 var code_buffer = std.ArrayList(u8).init(gpa);
...@@ -1261,8 +1272,8 @@ pub fn lowerUnnamedConst(...@@ -1261,8 +1272,8 @@ pub fn lowerUnnamedConst(
1261 typed_value: TypedValue,1272 typed_value: TypedValue,
1262 decl_index: InternPool.DeclIndex,1273 decl_index: InternPool.DeclIndex,
1263) !u32 {1274) !u32 {
1264 const gpa = elf_file.base.allocator;1275 const gpa = elf_file.base.comp.gpa;
1265 const mod = elf_file.base.options.module.?;1276 const mod = elf_file.base.comp.module.?;
1266 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);1277 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
1267 if (!gop.found_existing) {1278 if (!gop.found_existing) {
1268 gop.value_ptr.* = .{};1279 gop.value_ptr.* = .{};
...@@ -1308,7 +1319,7 @@ fn lowerConst(...@@ -1308,7 +1319,7 @@ fn lowerConst(
1308 output_section_index: u16,1319 output_section_index: u16,
1309 src_loc: Module.SrcLoc,1320 src_loc: Module.SrcLoc,
1310) !LowerConstResult {1321) !LowerConstResult {
1311 const gpa = elf_file.base.allocator;1322 const gpa = elf_file.base.comp.gpa;
13121323
1313 var code_buffer = std.ArrayList(u8).init(gpa);1324 var code_buffer = std.ArrayList(u8).init(gpa);
1314 defer code_buffer.deinit();1325 defer code_buffer.deinit();
...@@ -1364,7 +1375,7 @@ pub fn updateExports(...@@ -1364,7 +1375,7 @@ pub fn updateExports(
1364 const tracy = trace(@src());1375 const tracy = trace(@src());
1365 defer tracy.end();1376 defer tracy.end();
13661377
1367 const gpa = elf_file.base.allocator;1378 const gpa = elf_file.base.comp.gpa;
1368 const metadata = switch (exported) {1379 const metadata = switch (exported) {
1369 .decl_index => |decl_index| blk: {1380 .decl_index => |decl_index| blk: {
1370 _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1381 _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
...@@ -1467,7 +1478,7 @@ pub fn deleteDeclExport(...@@ -1467,7 +1478,7 @@ pub fn deleteDeclExport(
1467 name: InternPool.NullTerminatedString,1478 name: InternPool.NullTerminatedString,
1468) void {1479) void {
1469 const metadata = self.decls.getPtr(decl_index) orelse return;1480 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.?;
1471 const exp_name = mod.intern_pool.stringToSlice(name);1482 const exp_name = mod.intern_pool.stringToSlice(name);
1472 const esym_index = metadata.@"export"(self, exp_name) orelse return;1483 const esym_index = metadata.@"export"(self, exp_name) orelse return;
1473 log.debug("deleting export '{s}'", .{exp_name});1484 log.debug("deleting export '{s}'", .{exp_name});
...@@ -1485,7 +1496,7 @@ pub fn deleteDeclExport(...@@ -1485,7 +1496,7 @@ pub fn deleteDeclExport(
14851496
1486pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {1497pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
1487 _ = lib_name;1498 _ = lib_name;
1488 const gpa = elf_file.base.allocator;1499 const gpa = elf_file.base.comp.gpa;
1489 const off = try self.strtab.insert(gpa, name);1500 const off = try self.strtab.insert(gpa, name);
1490 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1501 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1491 if (!lookup_gop.found_existing) {1502 if (!lookup_gop.found_existing) {
src/link/MachO.zig+94-51
...@@ -144,6 +144,35 @@ tlv_table: TlvSymbolTable = .{},...@@ -144,6 +144,35 @@ tlv_table: TlvSymbolTable = .{},
144hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},144hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
145145
146darwin_sdk_layout: ?SdkLayout,146darwin_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
148/// The filesystem layout of darwin SDK elements.177/// The filesystem layout of darwin SDK elements.
149pub const SdkLayout = enum {178pub const SdkLayout = enum {
...@@ -156,12 +185,14 @@ pub const SdkLayout = enum {...@@ -156,12 +185,14 @@ pub const SdkLayout = enum {
156pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {185pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
157 if (build_options.only_c) unreachable;186 if (build_options.only_c) unreachable;
158 const target = options.comp.root_mod.resolved_target.result;187 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;
159 assert(target.ofmt == .macho);190 assert(target.ofmt == .macho);
160191
161 const gpa = options.comp.gpa;192 const gpa = options.comp.gpa;
162 const emit = options.emit;193 const emit = options.emit;
163 const mode: Mode = mode: {194 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)
165 break :mode .zld;196 break :mode .zld;
166 break :mode .incremental;197 break :mode .incremental;
167 };198 };
...@@ -192,7 +223,11 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {...@@ -192,7 +223,11 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
192 const file = try emit.directory.handle.createFile(sub_path, .{223 const file = try emit.directory.handle.createFile(sub_path, .{
193 .truncate = false,224 .truncate = false,
194 .read = true,225 .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 ),
196 });231 });
197 self.base.file = file;232 self.base.file = file;
198233
...@@ -242,21 +277,37 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {...@@ -242,21 +277,37 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
242277
243pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {278pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {
244 const self = try arena.create(MachO);279 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
246 self.* = .{283 self.* = .{
247 .base = .{284 .base = .{
248 .tag = .macho,285 .tag = .macho,
249 .comp = options.comp,286 .comp = options.comp,
250 .emit = options.emit,287 .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,
251 .file = null,291 .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,
252 },299 },
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)
254 .zld301 .zld
255 else302 else
256 .incremental,303 .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,
257 };308 };
258309
259 if (options.use_llvm and options.module != null) {310 if (use_llvm and options.module != null) {
260 self.llvm_object = try LlvmObject.create(arena, options);311 self.llvm_object = try LlvmObject.create(arena, options);
261 }312 }
262313
...@@ -267,8 +318,9 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {...@@ -267,8 +318,9 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {
267318
268pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {319pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
269 const gpa = self.base.comp.gpa;320 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) {
272 if (build_options.have_llvm) {324 if (build_options.have_llvm) {
273 return self.base.linkAsArchive(comp, prog_node);325 return self.base.linkAsArchive(comp, prog_node);
274 } else {326 } else {
...@@ -303,6 +355,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -303,6 +355,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
303 sub_prog_node.activate();355 sub_prog_node.activate();
304 defer sub_prog_node.end();356 defer sub_prog_node.end();
305357
358 const output_mode = self.base.comp.config.output_mode;
306 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;359 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
307360
308 if (self.lazy_syms.getPtr(.none)) |metadata| {361 if (self.lazy_syms.getPtr(.none)) |metadata| {
...@@ -335,7 +388,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -335,7 +388,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
335 }388 }
336389
337 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);390 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
338 try self.resolveLibSystem(arena, comp, &.{}, &libs);391 try self.resolveLibSystem(arena, comp, &libs);
339392
340 const id_symlink_basename = "link.id";393 const id_symlink_basename = "link.id";
341394
...@@ -446,7 +499,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -446,7 +499,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
446 try self.createDyldPrivateAtom();499 try self.createDyldPrivateAtom();
447 try self.writeStubHelperPreamble();500 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) {
450 const global = self.getEntryPoint().?;503 const global = self.getEntryPoint().?;
451 if (self.getSymbol(global).undf()) {504 if (self.getSymbol(global).undf()) {
452 // We do one additional check here in case the entry point was found in one of the dylibs.505 // 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...@@ -517,8 +570,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
517 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment570 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
518 // where the code signature goes into.571 // where the code signature goes into.
519 var codesig = CodeSignature.init(getPageSize(self.base.options.target.cpu.arch));572 var codesig = CodeSignature.init(getPageSize(self.base.options.target.cpu.arch));
520 codesig.code_directory.ident = self.base.options.emit.?.sub_path;573 codesig.code_directory.ident = self.base.emit.sub_path;
521 if (self.base.options.entitlements) |path| {574 if (self.entitlements) |path| {
522 try codesig.addEntitlements(gpa, path);575 try codesig.addEntitlements(gpa, path);
523 }576 }
524 try self.writeCodeSignaturePadding(&codesig);577 try self.writeCodeSignaturePadding(&codesig);
...@@ -536,7 +589,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -536,7 +589,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
536 try lc_writer.writeStruct(self.dysymtab_cmd);589 try lc_writer.writeStruct(self.dysymtab_cmd);
537 try load_commands.writeDylinkerLC(lc_writer);590 try load_commands.writeDylinkerLC(lc_writer);
538591
539 switch (self.base.options.output_mode) {592 switch (output_mode) {
540 .Exe => blk: {593 .Exe => blk: {
541 const seg_id = self.header_segment_cmd_index.?;594 const seg_id = self.header_segment_cmd_index.?;
542 const seg = self.segments.items[seg_id];595 const seg = self.segments.items[seg_id];
...@@ -552,7 +605,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -552,7 +605,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
552605
553 try lc_writer.writeStruct(macho.entry_point_command{606 try lc_writer.writeStruct(macho.entry_point_command{
554 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),607 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),
555 .stacksize = self.base.options.stack_size_override orelse 0,608 .stacksize = self.base.stack_size,
556 });609 });
557 },610 },
558 .Lib => if (self.base.options.link_mode == .Dynamic) {611 .Lib => if (self.base.options.link_mode == .Dynamic) {
...@@ -591,7 +644,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -591,7 +644,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
591644
592 if (codesig) |*csig| {645 if (codesig) |*csig| {
593 try self.writeCodeSignature(comp, csig); // code signing always comes last646 try self.writeCodeSignature(comp, csig); // code signing always comes last
594 const emit = self.base.options.emit.?;647 const emit = self.base.emit;
595 try invalidateKernelCache(emit.directory.handle, emit.sub_path);648 try invalidateKernelCache(emit.directory.handle, emit.sub_path);
596 }649 }
597650
...@@ -642,34 +695,20 @@ pub fn resolveLibSystem(...@@ -642,34 +695,20 @@ pub fn resolveLibSystem(
642 self: *MachO,695 self: *MachO,
643 arena: Allocator,696 arena: Allocator,
644 comp: *Compilation,697 comp: *Compilation,
645 search_dirs: []const []const u8,
646 out_libs: anytype,698 out_libs: anytype,
647) !void {699) !void {
648 const gpa = self.base.comp.gpa;700 var test_path = std.ArrayList(u8).init(arena);
649 var tmp_arena_allocator = std.heap.ArenaAllocator.init(gpa);701 var checked_paths = std.ArrayList([]const u8).init(arena);
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);
655702
656 success: {703 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
665 if (self.base.options.darwin_sdk_layout) |sdk_layout| switch (sdk_layout) {704 if (self.base.options.darwin_sdk_layout) |sdk_layout| switch (sdk_layout) {
666 .sdk => {705 .sdk => {
667 const dir = try fs.path.join(tmp_arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" });706 const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" });
668 if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success;707 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
669 },708 },
670 .vendored => {709 .vendored => {
671 const dir = try comp.zig_lib_directory.join(tmp_arena, &[_][]const u8{ "libc", "darwin" });710 const dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "darwin" });
672 if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success;711 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
673 },712 },
674 };713 };
675714
...@@ -1082,7 +1121,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts, ctx: *ParseErr...@@ -1082,7 +1121,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts, ctx: *ParseErr
1082 try self.dylibs.append(gpa, dylib);1121 try self.dylibs.append(gpa, dylib);
10831122
1084 const should_link_dylib_even_if_unreachable = blk: {1123 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;
1086 break :blk !(dylib_options.dependent or self.referenced_dylibs.contains(gop.value_ptr.*));1125 break :blk !(dylib_options.dependent or self.referenced_dylibs.contains(gop.value_ptr.*));
1087 };1126 };
10881127
...@@ -1597,7 +1636,8 @@ fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: S...@@ -1597,7 +1636,8 @@ fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: S
1597}1636}
15981637
1599pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {1638pub 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
1602 const gpa = self.base.comp.gpa;1642 const gpa = self.base.comp.gpa;
1603 const sym_index = try self.allocateSymbol();1643 const sym_index = try self.allocateSymbol();
...@@ -1647,10 +1687,11 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {...@@ -1647,10 +1687,11 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {
1647}1687}
16481688
1649pub fn resolveSymbols(self: *MachO) !void {1689pub fn resolveSymbols(self: *MachO) !void {
1690 const output_mode = self.base.comp.config.output_mode;
1650 // We add the specified entrypoint as the first unresolved symbols so that1691 // We add the specified entrypoint as the first unresolved symbols so that
1651 // we search for it in libraries should there be no object files specified1692 // we search for it in libraries should there be no object files specified
1652 // on the linker line.1693 // on the linker line.
1653 if (self.base.options.output_mode == .Exe) {1694 if (output_mode == .Exe) {
1654 const entry_name = self.base.options.entry orelse load_commands.default_entry_point;1695 const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
1655 _ = try self.addUndefined(entry_name, .{});1696 _ = try self.addUndefined(entry_name, .{});
1656 }1697 }
...@@ -1867,9 +1908,10 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -1867,9 +1908,10 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
1867}1908}
18681909
1869fn resolveSymbolsAtLoading(self: *MachO) !void {1910fn 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;
1871 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;1913 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
1874 var next_sym: usize = 0;1916 var next_sym: usize = 0;
1875 while (next_sym < self.unresolved.count()) {1917 while (next_sym < self.unresolved.count()) {
...@@ -2674,12 +2716,12 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {...@@ -2674,12 +2716,12 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {
2674 const val = decl.val;2716 const val = decl.val;
2675 const mod = self.base.options.module.?;2717 const mod = self.base.options.module.?;
2676 const zig_ty = ty.zigTypeTag(mod);2718 const zig_ty = ty.zigTypeTag(mod);
2677 const mode = self.base.options.optimize_mode;2719 const any_non_single_threaded = self.base.comp.config.any_non_single_threaded;
2678 const single_threaded = self.base.options.single_threaded;2720 const optimize_mode = self.base.comp.root_mod.optimize_mode;
2679 const sect_id: u8 = blk: {2721 const sect_id: u8 = blk: {
2680 // TODO finish and audit this function2722 // TODO finish and audit this function
2681 if (val.isUndefDeep(mod)) {2723 if (val.isUndefDeep(mod)) {
2682 if (mode == .ReleaseFast or mode == .ReleaseSmall) {2724 if (optimize_mode == .ReleaseFast or optimize_mode == .ReleaseSmall) {
2683 @panic("TODO __DATA,__bss");2725 @panic("TODO __DATA,__bss");
2684 } else {2726 } else {
2685 break :blk self.data_section_index.?;2727 break :blk self.data_section_index.?;
...@@ -2687,7 +2729,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {...@@ -2687,7 +2729,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {
2687 }2729 }
26882730
2689 if (val.getVariable(mod)) |variable| {2731 if (val.getVariable(mod)) |variable| {
2690 if (variable.is_threadlocal and !single_threaded) {2732 if (variable.is_threadlocal and any_non_single_threaded) {
2691 break :blk self.thread_data_section_index.?;2733 break :blk self.thread_data_section_index.?;
2692 }2734 }
2693 break :blk self.data_section_index.?;2735 break :blk self.data_section_index.?;
...@@ -2796,8 +2838,6 @@ pub fn updateExports(...@@ -2796,8 +2838,6 @@ pub fn updateExports(
2796 if (self.llvm_object) |llvm_object|2838 if (self.llvm_object) |llvm_object|
2797 return llvm_object.updateExports(mod, exported, exports);2839 return llvm_object.updateExports(mod, exported, exports);
27982840
2799 if (self.base.options.emit == null) return;
2800
2801 const tracy = trace(@src());2841 const tracy = trace(@src());
2802 defer tracy.end();2842 defer tracy.end();
28032843
...@@ -3093,7 +3133,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -3093,7 +3133,7 @@ fn populateMissingMetadata(self: *MachO) !void {
3093 if (self.header_segment_cmd_index == null) {3133 if (self.header_segment_cmd_index == null) {
3094 // The first __TEXT segment is immovable and covers MachO header and load commands.3134 // The first __TEXT segment is immovable and covers MachO header and load commands.
3095 self.header_segment_cmd_index = @as(u8, @intCast(self.segments.items.len));3135 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;
3097 const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), getPageSize(cpu_arch));3137 const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), getPageSize(cpu_arch));
30983138
3099 log.debug("found __TEXT segment (header-only) free space 0x{x} to 0x{x}", .{ 0, needed_size });3139 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 {...@@ -3222,13 +3262,13 @@ fn populateMissingMetadata(self: *MachO) !void {
3222}3262}
32233263
3224fn calcPagezeroSize(self: *MachO) u64 {3264fn 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;
3226 const page_size = getPageSize(self.base.options.target.cpu.arch);3266 const page_size = getPageSize(self.base.options.target.cpu.arch);
3227 const aligned_pagezero_vmsize = mem.alignBackward(u64, pagezero_vmsize, page_size);3267 const aligned_pagezero_vmsize = mem.alignBackward(u64, self.pagezero_vmsize, page_size);
3228 if (self.base.options.output_mode == .Lib) return 0;3268 if (output_mode == .Lib) return 0;
3229 if (aligned_pagezero_vmsize == 0) return 0;3269 if (aligned_pagezero_vmsize == 0) return 0;
3230 if (aligned_pagezero_vmsize != pagezero_vmsize) {3270 if (aligned_pagezero_vmsize != self.pagezero_vmsize) {
3231 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});3271 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{self.pagezero_vmsize});
3232 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});3272 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
3233 }3273 }
3234 return aligned_pagezero_vmsize;3274 return aligned_pagezero_vmsize;
...@@ -4685,6 +4725,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -4685,6 +4725,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
4685}4725}
46864726
4687pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void {4727pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void {
4728 const output_mode = self.base.comp.config.output_mode;
4688 const seg_id = self.header_segment_cmd_index.?;4729 const seg_id = self.header_segment_cmd_index.?;
4689 const seg = self.segments.items[seg_id];4730 const seg = self.segments.items[seg_id];
4690 const offset = self.codesig_cmd.dataoff;4731 const offset = self.codesig_cmd.dataoff;
...@@ -4698,7 +4739,7 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod...@@ -4698,7 +4739,7 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod
4698 .exec_seg_base = seg.fileoff,4739 .exec_seg_base = seg.fileoff,
4699 .exec_seg_limit = seg.filesize,4740 .exec_seg_limit = seg.filesize,
4700 .file_size = offset,4741 .file_size = offset,
4701 .output_mode = self.base.options.output_mode,4742 .output_mode = output_mode,
4702 }, buffer.writer());4743 }, buffer.writer());
4703 assert(buffer.items.len == code_sig.size());4744 assert(buffer.items.len == code_sig.size());
47044745
...@@ -4712,6 +4753,8 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod...@@ -4712,6 +4753,8 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod
47124753
4713/// Writes Mach-O file header.4754/// Writes Mach-O file header.
4714pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {4755pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
4756 const output_mode = self.base.comp.config.output_mode;
4757
4715 var header: macho.mach_header_64 = .{};4758 var header: macho.mach_header_64 = .{};
4716 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;4759 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 {...@@ -4727,7 +4770,7 @@ pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
4727 else => unreachable,4770 else => unreachable,
4728 }4771 }
47294772
4730 switch (self.base.options.output_mode) {4773 switch (output_mode) {
4731 .Exe => {4774 .Exe => {
4732 header.filetype = macho.MH_EXECUTE;4775 header.filetype = macho.MH_EXECUTE;
4733 },4776 },
src/link/MachO/zld.zig+73-86
...@@ -6,20 +6,21 @@ pub fn linkWithZld(...@@ -6,20 +6,21 @@ pub fn linkWithZld(
6 const tracy = trace(@src());6 const tracy = trace(@src());
7 defer tracy.end();7 defer tracy.end();
88
9 const gpa = macho_file.base.allocator;9 const gpa = macho_file.base.comp.gpa;
10 const options = &macho_file.base.options;10 const target = macho_file.base.comp.root_mod.resolved_target.result;
11 const target = options.target;11 const emit = macho_file.base.emit;
1212
13 var arena_allocator = std.heap.ArenaAllocator.init(gpa);13 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
14 defer arena_allocator.deinit();14 defer arena_allocator.deinit();
15 const arena = arena_allocator.allocator();15 const arena = arena_allocator.allocator();
1616
17 const directory = options.emit.?.directory; // Just an alias to make it shorter to type.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{options.emit.?.sub_path});18 const full_out_path = try directory.join(arena, &[_][]const u8{emit.?.sub_path});
19 const opt_zcu = macho_file.base.comp.module;
1920
20 // If there is no Zig code to compile, then we should skip flushing the output file because it21 // If there is no Zig code to compile, then we should skip flushing the output file because it
21 // will not be part of the linker line anyway.22 // 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: {
23 try macho_file.flushModule(comp, prog_node);24 try macho_file.flushModule(comp, prog_node);
2425
25 if (fs.path.dirname(full_out_path)) |dirname| {26 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -34,22 +35,24 @@ pub fn linkWithZld(...@@ -34,22 +35,24 @@ pub fn linkWithZld(
34 sub_prog_node.context.refresh();35 sub_prog_node.context.refresh();
35 defer sub_prog_node.end();36 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;
37 const cpu_arch = target.cpu.arch;40 const cpu_arch = target.cpu.arch;
38 const is_lib = options.output_mode == .Lib;41 const is_lib = output_mode == .Lib;
39 const is_dyn_lib = options.link_mode == .Dynamic and is_lib;42 const is_dyn_lib = link_mode == .Dynamic and is_lib;
40 const is_exe_or_dyn_lib = is_dyn_lib or options.output_mode == .Exe;43 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
41 const stack_size = options.stack_size_override orelse 0;44 const stack_size = macho_file.base.stack_size;
42 const is_debug_build = options.optimize_mode == .Debug;
43 const gc_sections = options.gc_sections orelse !is_debug_build;
4445
45 const id_symlink_basename = "zld.id";46 const id_symlink_basename = "zld.id";
4647
47 var man: Cache.Manifest = undefined;48 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
50 var digest: [Cache.hex_digest_len]u8 = undefined;51 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) {
53 man = comp.cache_parent.obtain();56 man = comp.cache_parent.obtain();
5457
55 // We are about to obtain this lock, so here we give other processes a chance first.58 // We are about to obtain this lock, so here we give other processes a chance first.
...@@ -57,7 +60,7 @@ pub fn linkWithZld(...@@ -57,7 +60,7 @@ pub fn linkWithZld(
5760
58 comptime assert(Compilation.link_hash_implementation_version == 10);61 comptime assert(Compilation.link_hash_implementation_version == 10);
5962
60 for (options.objects) |obj| {63 for (objects) |obj| {
61 _ = try man.addFile(obj.path, null);64 _ = try man.addFile(obj.path, null);
62 man.hash.add(obj.must_link);65 man.hash.add(obj.must_link);
63 }66 }
...@@ -68,24 +71,22 @@ pub fn linkWithZld(...@@ -68,24 +71,22 @@ pub fn linkWithZld(
68 // We can skip hashing libc and libc++ components that we are in charge of building from Zig71 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
69 // installation sources because they are always a product of the compiler version + target information.72 // installation sources because they are always a product of the compiler version + target information.
70 man.hash.add(stack_size);73 man.hash.add(stack_size);
71 man.hash.addOptional(options.pagezero_size);74 man.hash.addOptional(macho_file.pagezero_vmsize);
72 man.hash.addOptional(options.headerpad_size);75 man.hash.addOptional(macho_file.headerpad_size);
73 man.hash.add(options.headerpad_max_install_names);76 man.hash.add(macho_file.headerpad_max_install_names);
74 man.hash.add(gc_sections);77 man.hash.add(macho_file.base.gc_sections);
75 man.hash.add(options.dead_strip_dylibs);78 man.hash.add(macho_file.dead_strip_dylibs);
76 man.hash.add(options.strip);79 man.hash.add(macho_file.base.comp.root_mod.strip);
77 man.hash.addListOfBytes(options.lib_dirs);80 try MachO.hashAddFrameworks(&man, macho_file.frameworks);
78 man.hash.addListOfBytes(options.framework_dirs);81 man.hash.addListOfBytes(macho_file.rpath_list);
79 try link.hashAddFrameworks(&man, options.frameworks);
80 man.hash.addListOfBytes(options.rpath_list);
81 if (is_dyn_lib) {82 if (is_dyn_lib) {
82 man.hash.addOptionalBytes(options.install_name);83 man.hash.addOptionalBytes(macho_file.install_name);
83 man.hash.addOptional(options.version);84 man.hash.addOptional(comp.version);
84 }85 }
85 try link.hashAddSystemLibs(&man, options.system_libs);86 try link.hashAddSystemLibs(&man, comp.system_libs);
86 man.hash.addOptionalBytes(options.sysroot);87 man.hash.addOptionalBytes(comp.sysroot);
87 man.hash.addListOfBytes(options.force_undefined_symbols.keys());88 man.hash.addListOfBytes(macho_file.base.force_undefined_symbols.keys());
88 try man.addOptionalFile(options.entitlements);89 try man.addOptionalFile(macho_file.entitlements);
8990
90 // We don't actually care whether it's a cache hit or miss; we just91 // We don't actually care whether it's a cache hit or miss; we just
91 // need the digest and the lock.92 // need the digest and the lock.
...@@ -125,13 +126,13 @@ pub fn linkWithZld(...@@ -125,13 +126,13 @@ pub fn linkWithZld(
125 };126 };
126 }127 }
127128
128 if (options.output_mode == .Obj) {129 if (output_mode == .Obj) {
129 // LLD's MachO driver does not support the equivalent of `-r` so we do a simple file copy130 // LLD's MachO driver does not support the equivalent of `-r` so we do a simple file copy
130 // here. TODO: think carefully about how we can avoid this redundant operation when doing131 // here. TODO: think carefully about how we can avoid this redundant operation when doing
131 // build-obj. See also the corresponding TODO in linkAsArchive.132 // build-obj. See also the corresponding TODO in linkAsArchive.
132 const the_object_path = blk: {133 const the_object_path = blk: {
133 if (options.objects.len != 0) {134 if (objects.len != 0) {
134 break :blk options.objects[0].path;135 break :blk objects[0].path;
135 }136 }
136137
137 if (comp.c_object_table.count() != 0)138 if (comp.c_object_table.count() != 0)
...@@ -150,7 +151,7 @@ pub fn linkWithZld(...@@ -150,7 +151,7 @@ pub fn linkWithZld(
150 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});151 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
151 }152 }
152 } else {153 } else {
153 const sub_path = options.emit.?.sub_path;154 const sub_path = emit.?.sub_path;
154155
155 const old_file = macho_file.base.file; // TODO is this needed at all?156 const old_file = macho_file.base.file; // TODO is this needed at all?
156 defer macho_file.base.file = old_file;157 defer macho_file.base.file = old_file;
...@@ -158,7 +159,7 @@ pub fn linkWithZld(...@@ -158,7 +159,7 @@ pub fn linkWithZld(
158 const file = try directory.handle.createFile(sub_path, .{159 const file = try directory.handle.createFile(sub_path, .{
159 .truncate = true,160 .truncate = true,
160 .read = true,161 .read = true,
161 .mode = link.determineMode(options.*),162 .mode = link.File.determineMode(false, output_mode, link_mode),
162 });163 });
163 defer file.close();164 defer file.close();
164 macho_file.base.file = file;165 macho_file.base.file = file;
...@@ -175,8 +176,8 @@ pub fn linkWithZld(...@@ -175,8 +176,8 @@ pub fn linkWithZld(
175176
176 // Positional arguments to the linker such as object files and static archives.177 // Positional arguments to the linker such as object files and static archives.
177 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);178 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
178 try positionals.ensureUnusedCapacity(options.objects.len);179 try positionals.ensureUnusedCapacity(objects.len);
179 positionals.appendSliceAssumeCapacity(options.objects);180 positionals.appendSliceAssumeCapacity(objects);
180181
181 for (comp.c_object_table.keys()) |key| {182 for (comp.c_object_table.keys()) |key| {
182 try positionals.append(.{ .path = key.status.success.object_path });183 try positionals.append(.{ .path = key.status.success.object_path });
...@@ -190,7 +191,7 @@ pub fn linkWithZld(...@@ -190,7 +191,7 @@ pub fn linkWithZld(
190 if (comp.compiler_rt_obj) |obj| try positionals.append(.{ .path = obj.full_object_path });191 if (comp.compiler_rt_obj) |obj| try positionals.append(.{ .path = obj.full_object_path });
191192
192 // libc++ dep193 // libc++ dep
193 if (options.link_libcpp) {194 if (comp.config.link_libcpp) {
194 try positionals.ensureUnusedCapacity(2);195 try positionals.ensureUnusedCapacity(2);
195 positionals.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });196 positionals.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
196 positionals.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });197 positionals.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
...@@ -199,23 +200,23 @@ pub fn linkWithZld(...@@ -199,23 +200,23 @@ pub fn linkWithZld(
199 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);200 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
200201
201 {202 {
202 const vals = options.system_libs.values();203 const vals = comp.system_libs.values();
203 try libs.ensureUnusedCapacity(vals.len);204 try libs.ensureUnusedCapacity(vals.len);
204 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);205 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);
205 }206 }
206207
207 {208 {
208 try libs.ensureUnusedCapacity(options.frameworks.len);209 try libs.ensureUnusedCapacity(macho_file.frameworks.len);
209 for (options.frameworks) |v| libs.putAssumeCapacity(v.path, .{210 for (macho_file.frameworks) |v| libs.putAssumeCapacity(v.path, .{
210 .needed = v.needed,211 .needed = v.needed,
211 .weak = v.weak,212 .weak = v.weak,
212 .path = v.path,213 .path = v.path,
213 });214 });
214 }215 }
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) {
219 var argv = std.ArrayList([]const u8).init(arena);220 var argv = std.ArrayList([]const u8).init(arena);
220221
221 try argv.append("zig");222 try argv.append("zig");
...@@ -228,14 +229,14 @@ pub fn linkWithZld(...@@ -228,14 +229,14 @@ pub fn linkWithZld(
228 if (is_dyn_lib) {229 if (is_dyn_lib) {
229 try argv.append("-dylib");230 try argv.append("-dylib");
230231
231 if (options.install_name) |install_name| {232 if (macho_file.install_name) |install_name| {
232 try argv.append("-install_name");233 try argv.append("-install_name");
233 try argv.append(install_name);234 try argv.append(install_name);
234 }235 }
235 }236 }
236237
237 {238 {
238 const platform = Platform.fromTarget(options.target);239 const platform = Platform.fromTarget(target);
239 try argv.append("-platform_version");240 try argv.append("-platform_version");
240 try argv.append(@tagName(platform.os_tag));241 try argv.append(@tagName(platform.os_tag));
241 try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version}));242 try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version}));
...@@ -248,44 +249,39 @@ pub fn linkWithZld(...@@ -248,44 +249,39 @@ pub fn linkWithZld(
248 }249 }
249 }250 }
250251
251 if (options.sysroot) |syslibroot| {252 if (macho_file.sysroot) |syslibroot| {
252 try argv.append("-syslibroot");253 try argv.append("-syslibroot");
253 try argv.append(syslibroot);254 try argv.append(syslibroot);
254 }255 }
255256
256 for (options.rpath_list) |rpath| {257 for (macho_file.rpath_list) |rpath| {
257 try argv.append("-rpath");258 try argv.append("-rpath");
258 try argv.append(rpath);259 try argv.append(rpath);
259 }260 }
260261
261 if (options.pagezero_size) |pagezero_size| {262 try argv.appendSlice(&.{
262 try argv.append("-pagezero_size");263 "-pagezero_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_size}),
263 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));264 "-headerpad_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.headerpad_size}),
264 }265 });
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 }
270266
271 if (options.headerpad_max_install_names) {267 if (macho_file.headerpad_max_install_names) {
272 try argv.append("-headerpad_max_install_names");268 try argv.append("-headerpad_max_install_names");
273 }269 }
274270
275 if (gc_sections) {271 if (macho_file.base.gc_sections) {
276 try argv.append("-dead_strip");272 try argv.append("-dead_strip");
277 }273 }
278274
279 if (options.dead_strip_dylibs) {275 if (macho_file.dead_strip_dylibs) {
280 try argv.append("-dead_strip_dylibs");276 try argv.append("-dead_strip_dylibs");
281 }277 }
282278
283 if (options.entry) |entry| {279 if (comp.config.entry) |entry| {
284 try argv.append("-e");280 try argv.append("-e");
285 try argv.append(entry);281 try argv.append(entry);
286 }282 }
287283
288 for (options.objects) |obj| {284 for (objects) |obj| {
289 if (obj.must_link) {285 if (obj.must_link) {
290 try argv.append("-force_load");286 try argv.append("-force_load");
291 }287 }
...@@ -303,7 +299,7 @@ pub fn linkWithZld(...@@ -303,7 +299,7 @@ pub fn linkWithZld(
303 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);299 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
304 if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);300 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) {
307 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);303 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
308 try argv.append(comp.libcxx_static_lib.?.full_object_path);304 try argv.append(comp.libcxx_static_lib.?.full_object_path);
309 }305 }
...@@ -313,8 +309,8 @@ pub fn linkWithZld(...@@ -313,8 +309,8 @@ pub fn linkWithZld(
313309
314 try argv.append("-lSystem");310 try argv.append("-lSystem");
315311
316 for (options.system_libs.keys()) |l_name| {312 for (comp.system_libs.keys()) |l_name| {
317 const info = options.system_libs.get(l_name).?;313 const info = comp.system_libs.get(l_name).?;
318 const arg = if (info.needed)314 const arg = if (info.needed)
319 try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name})315 try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name})
320 else if (info.weak)316 else if (info.weak)
...@@ -324,11 +320,7 @@ pub fn linkWithZld(...@@ -324,11 +320,7 @@ pub fn linkWithZld(
324 try argv.append(arg);320 try argv.append(arg);
325 }321 }
326322
327 for (options.lib_dirs) |lib_dir| {323 for (macho_file.frameworks) |framework| {
328 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
329 }
330
331 for (options.frameworks) |framework| {
332 const name = std.fs.path.stem(framework.path);324 const name = std.fs.path.stem(framework.path);
333 const arg = if (framework.needed)325 const arg = if (framework.needed)
334 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})326 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
...@@ -339,11 +331,7 @@ pub fn linkWithZld(...@@ -339,11 +331,7 @@ pub fn linkWithZld(
339 try argv.append(arg);331 try argv.append(arg);
340 }332 }
341333
342 for (options.framework_dirs) |framework_dir| {334 if (is_dyn_lib and macho_file.base.allow_shlib_undefined) {
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)) {
347 try argv.append("-undefined");335 try argv.append("-undefined");
348 try argv.append("dynamic_lookup");336 try argv.append("dynamic_lookup");
349 }337 }
...@@ -412,7 +400,7 @@ pub fn linkWithZld(...@@ -412,7 +400,7 @@ pub fn linkWithZld(
412 };400 };
413 }401 }
414402
415 if (gc_sections) {403 if (macho_file.base.gc_sections) {
416 try dead_strip.gcAtoms(macho_file);404 try dead_strip.gcAtoms(macho_file);
417 }405 }
418406
...@@ -519,7 +507,7 @@ pub fn linkWithZld(...@@ -519,7 +507,7 @@ pub fn linkWithZld(
519 // where the code signature goes into.507 // where the code signature goes into.
520 var codesig = CodeSignature.init(MachO.getPageSize(cpu_arch));508 var codesig = CodeSignature.init(MachO.getPageSize(cpu_arch));
521 codesig.code_directory.ident = fs.path.basename(full_out_path);509 codesig.code_directory.ident = fs.path.basename(full_out_path);
522 if (options.entitlements) |path| {510 if (macho_file.entitlements) |path| {
523 try codesig.addEntitlements(gpa, path);511 try codesig.addEntitlements(gpa, path);
524 }512 }
525 try macho_file.writeCodeSignaturePadding(&codesig);513 try macho_file.writeCodeSignaturePadding(&codesig);
...@@ -539,7 +527,7 @@ pub fn linkWithZld(...@@ -539,7 +527,7 @@ pub fn linkWithZld(
539 try lc_writer.writeStruct(macho_file.dysymtab_cmd);527 try lc_writer.writeStruct(macho_file.dysymtab_cmd);
540 try load_commands.writeDylinkerLC(lc_writer);528 try load_commands.writeDylinkerLC(lc_writer);
541529
542 switch (macho_file.base.options.output_mode) {530 switch (output_mode) {
543 .Exe => blk: {531 .Exe => blk: {
544 const seg_id = macho_file.header_segment_cmd_index.?;532 const seg_id = macho_file.header_segment_cmd_index.?;
545 const seg = macho_file.segments.items[seg_id];533 const seg = macho_file.segments.items[seg_id];
...@@ -555,10 +543,10 @@ pub fn linkWithZld(...@@ -555,10 +543,10 @@ pub fn linkWithZld(
555543
556 try lc_writer.writeStruct(macho.entry_point_command{544 try lc_writer.writeStruct(macho.entry_point_command{
557 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),545 .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,
559 });547 });
560 },548 },
561 .Lib => if (macho_file.base.options.link_mode == .Dynamic) {549 .Lib => if (link_mode == .Dynamic) {
562 try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer);550 try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer);
563 },551 },
564 else => {},552 else => {},
...@@ -598,11 +586,11 @@ pub fn linkWithZld(...@@ -598,11 +586,11 @@ pub fn linkWithZld(
598586
599 if (codesig) |*csig| {587 if (codesig) |*csig| {
600 try macho_file.writeCodeSignature(comp, csig); // code signing always comes last588 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);
602 }590 }
603 }591 }
604592
605 if (!options.disable_lld_caching) {593 if (!macho_file.base.disable_lld_caching) {
606 // Update the file with the digest. If it fails we can continue; it only594 // Update the file with the digest. If it fails we can continue; it only
607 // means that the next invocation will have an unnecessary cache miss.595 // means that the next invocation will have an unnecessary cache miss.
608 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {596 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
...@@ -622,12 +610,11 @@ pub fn linkWithZld(...@@ -622,12 +610,11 @@ pub fn linkWithZld(
622610
623fn createSegments(macho_file: *MachO) !void {611fn createSegments(macho_file: *MachO) !void {
624 const gpa = macho_file.base.allocator;612 const gpa = macho_file.base.allocator;
625 const pagezero_vmsize = macho_file.base.options.pagezero_size orelse MachO.default_pagezero_vmsize;
626 const page_size = MachO.getPageSize(macho_file.base.options.target.cpu.arch);613 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);
628 if (macho_file.base.options.output_mode != .Lib and aligned_pagezero_vmsize > 0) {615 if (macho_file.base.options.output_mode != .Lib and aligned_pagezero_vmsize > 0) {
629 if (aligned_pagezero_vmsize != pagezero_vmsize) {616 if (aligned_pagezero_vmsize != macho_file.pagezero_vmsize) {
630 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});617 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{macho_file.pagezero_vmsize});
631 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});618 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
632 }619 }
633 macho_file.pagezero_segment_cmd_index = @intCast(macho_file.segments.items.len);620 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;...@@ -24,46 +24,56 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
2424
25base: link.File,25base: link.File,
26llvm_object: *LlvmObject,26llvm_object: *LlvmObject,
27ptx_file_name: []const u8,
2827
29pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {28pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx {
30 if (!options.use_llvm) return error.PtxArchNotSupported;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) {
35 // TODO: does it also work with nvcl ?40 // TODO: does it also work with nvcl ?
36 .cuda => {},41 .cuda => {},
37 else => return error.PtxArchNotSupported,42 else => return error.PtxArchNotSupported,
38 }43 }
3944
40 const llvm_object = try LlvmObject.create(gpa, options);45 const llvm_object = try LlvmObject.create(arena, options);
41 const nvptx = try gpa.create(NvPtx);46 const nvptx = try arena.create(NvPtx);
42 nvptx.* = .{47 nvptx.* = .{
43 .base = .{48 .base = .{
44 .tag = .nvptx,49 .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,
46 .file = null,55 .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,
48 },62 },
49 .llvm_object = llvm_object,63 .llvm_object = llvm_object,
50 .ptx_file_name = try std.mem.join(gpa, "", &[_][]const u8{ options.root_name, ".ptx" }),
51 };64 };
5265
53 return nvptx;66 return nvptx;
54}67}
5568
56pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {69pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx {
57 if (!options.use_llvm) return error.PtxArchNotSupported;70 const target = options.comp.root_mod.resolved_target.result;
58 assert(options.target.ofmt == .nvptx);71 assert(target.ofmt == .nvptx);
5972 return createEmpty(arena, options);
60 log.debug("Opening .ptx target file {s}", .{sub_path});
61 return createEmpty(allocator, options);
62}73}
6374
64pub fn deinit(self: *NvPtx) void {75pub fn deinit(self: *NvPtx) void {
65 self.llvm_object.destroy(self.base.allocator);76 self.llvm_object.deinit();
66 self.base.allocator.free(self.ptx_file_name);
67}77}
6878
69pub fn updateFunc(self: *NvPtx, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {79pub 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...@@ -110,7 +120,7 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No
110 comp.emit_asm = .{120 comp.emit_asm = .{
111 // 'null' means using the default cache dir: zig-cache/o/...121 // 'null' means using the default cache dir: zig-cache/o/...
112 .directory = null,122 .directory = null,
113 .basename = self.ptx_file_name,123 .basename = self.base.emit.sub_path,
114 };124 };
115 defer {125 defer {
116 comp.bin_file.options.emit = outfile;126 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 {...@@ -318,12 +318,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 {
318 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),318 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
319 };319 };
320 // a / will always be in a file path320 // 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);
322 return self;322 return self;
323}323}
324324
325fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !void {325fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !void {
326 const gpa = self.base.allocator;326 const gpa = self.base.comp.gpa;
327 const mod = self.base.options.module.?;327 const mod = self.base.options.module.?;
328 const decl = mod.declPtr(decl_index);328 const decl = mod.declPtr(decl_index);
329 const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope(mod));329 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...@@ -379,6 +379,7 @@ fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !voi
379}379}
380380
381fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void {381fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void {
382 const gpa = self.base.comp.gpa;
382 const sep = std.fs.path.sep;383 const sep = std.fs.path.sep;
383 var it = std.mem.tokenizeScalar(u8, path, sep);384 var it = std.mem.tokenizeScalar(u8, path, sep);
384 while (it.next()) |component| {385 while (it.next()) |component| {
...@@ -386,7 +387,7 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi...@@ -386,7 +387,7 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi
386 try a.writer().writeInt(u16, num, .big);387 try a.writer().writeInt(u16, num, .big);
387 } else {388 } else {
388 self.file_segments_i += 1;389 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);
390 try a.writer().writeInt(u16, self.file_segments_i, .big);391 try a.writer().writeInt(u16, self.file_segments_i, .big);
391 }392 }
392 }393 }
...@@ -397,6 +398,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -397,6 +398,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
397 @panic("Attempted to compile for object format that was disabled by build configuration");398 @panic("Attempted to compile for object format that was disabled by build configuration");
398 }399 }
399400
401 const gpa = self.base.comp.gpa;
400 const func = mod.funcInfo(func_index);402 const func = mod.funcInfo(func_index);
401 const decl_index = func.owner_decl;403 const decl_index = func.owner_decl;
402 const decl = mod.declPtr(decl_index);404 const decl = mod.declPtr(decl_index);
...@@ -404,10 +406,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -404,10 +406,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
404406
405 const atom_idx = try self.seeDecl(decl_index);407 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);
408 defer code_buffer.deinit();410 defer code_buffer.deinit();
409 var dbg_info_output: DebugInfoOutput = .{411 var dbg_info_output: DebugInfoOutput = .{
410 .dbg_line = std.ArrayList(u8).init(self.base.allocator),412 .dbg_line = std.ArrayList(u8).init(gpa),
411 .start_line = null,413 .start_line = null,
412 .end_line = undefined,414 .end_line = undefined,
413 .pcop_change_index = null,415 .pcop_change_index = null,
...@@ -448,14 +450,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:...@@ -448,14 +450,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
448}450}
449451
450pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {452pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
453 const gpa = self.base.comp.gpa;
451 _ = try self.seeDecl(decl_index);454 _ = 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);
453 defer code_buffer.deinit();456 defer code_buffer.deinit();
454457
455 const mod = self.base.options.module.?;458 const mod = self.base.options.module.?;
456 const decl = mod.declPtr(decl_index);459 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);
459 if (!gop.found_existing) {462 if (!gop.found_existing) {
460 gop.value_ptr.* = .{};463 gop.value_ptr.* = .{};
461 }464 }
...@@ -465,7 +468,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De...@@ -465,7 +468,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
465468
466 const index = unnamed_consts.items.len;469 const index = unnamed_consts.items.len;
467 // name is freed when the unnamed const is freed470 // 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
470 const sym_index = try self.allocateSymbolIndex();473 const sym_index = try self.allocateSymbolIndex();
471 const new_atom_idx = try self.createAtom();474 const new_atom_idx = try self.createAtom();
...@@ -498,17 +501,18 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De...@@ -498,17 +501,18 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
498 },501 },
499 };502 };
500 // duped_code is freed when the unnamed const is freed503 // duped_code is freed when the unnamed const is freed
501 const duped_code = try self.base.allocator.dupe(u8, code);504 const duped_code = try gpa.dupe(u8, code);
502 errdefer self.base.allocator.free(duped_code);505 errdefer gpa.free(duped_code);
503 const new_atom = self.getAtomPtr(new_atom_idx);506 const new_atom = self.getAtomPtr(new_atom_idx);
504 new_atom.* = info;507 new_atom.* = info;
505 new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } };508 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);
507 // we return the new_atom_idx to codegen510 // we return the new_atom_idx to codegen
508 return new_atom_idx;511 return new_atom_idx;
509}512}
510513
511pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) !void {514pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) !void {
515 const gpa = self.base.comp.gpa;
512 const decl = mod.declPtr(decl_index);516 const decl = mod.declPtr(decl_index);
513517
514 if (decl.isExtern(mod)) {518 if (decl.isExtern(mod)) {
...@@ -517,7 +521,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)...@@ -517,7 +521,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
517 }521 }
518 const atom_idx = try self.seeDecl(decl_index);522 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);
521 defer code_buffer.deinit();525 defer code_buffer.deinit();
522 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;526 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
523 // TODO we need the symbol index for symbol in the table of locals for the containing atom527 // 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)...@@ -535,16 +539,17 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
535 return;539 return;
536 },540 },
537 };541 };
538 try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1);542 try self.data_decl_table.ensureUnusedCapacity(gpa, 1);
539 const duped_code = try self.base.allocator.dupe(u8, code);543 const duped_code = try gpa.dupe(u8, code);
540 self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } };544 self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } };
541 if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| {545 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);
543 }547 }
544 return self.updateFinish(decl_index);548 return self.updateFinish(decl_index);
545}549}
546/// called at the end of update{Decl,Func}550/// called at the end of update{Decl,Func}
547fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {551fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
552 const gpa = self.base.comp.gpa;
548 const mod = self.base.options.module.?;553 const mod = self.base.options.module.?;
549 const decl = mod.declPtr(decl_index);554 const decl = mod.declPtr(decl_index);
550 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);555 const is_fn = (decl.ty.zigTypeTag(mod) == .Fn);
...@@ -558,7 +563,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {...@@ -558,7 +563,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
558 const sym: aout.Sym = .{563 const sym: aout.Sym = .{
559 .value = undefined, // the value of stuff gets filled in in flushModule564 .value = undefined, // the value of stuff gets filled in in flushModule
560 .type = atom.type,565 .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)),
562 };567 };
563568
564 if (atom.sym_index) |s| {569 if (atom.sym_index) |s| {
...@@ -571,10 +576,11 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {...@@ -571,10 +576,11 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void {
571}576}
572577
573fn allocateSymbolIndex(self: *Plan9) !usize {578fn allocateSymbolIndex(self: *Plan9) !usize {
579 const gpa = self.base.comp.gpa;
574 if (self.syms_index_free_list.popOrNull()) |i| {580 if (self.syms_index_free_list.popOrNull()) |i| {
575 return i;581 return i;
576 } else {582 } else {
577 _ = try self.syms.addOne(self.base.allocator);583 _ = try self.syms.addOne(gpa);
578 return self.syms.items.len - 1;584 return self.syms.items.len - 1;
579 }585 }
580}586}
...@@ -589,7 +595,8 @@ fn allocateGotIndex(self: *Plan9) usize {...@@ -589,7 +595,8 @@ fn allocateGotIndex(self: *Plan9) usize {
589}595}
590596
591pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {597pub 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
594 switch (self.base.options.effectiveOutputMode()) {601 switch (self.base.options.effectiveOutputMode()) {
595 .Exe => {},602 .Exe => {},
...@@ -650,7 +657,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -650,7 +657,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
650 @panic("Attempted to compile for object format that was disabled by build configuration");657 @panic("Attempted to compile for object format that was disabled by build configuration");
651 }658 }
652659
653 _ = comp;660 const gpa = comp.gpa;
661
654 const tracy = trace(@src());662 const tracy = trace(@src());
655 defer tracy.end();663 defer tracy.end();
656664
...@@ -691,12 +699,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -691,12 +699,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
691 const atom_count = self.atomCount();699 const atom_count = self.atomCount();
692 assert(self.got_len == atom_count + self.got_index_free_list.items.len);700 assert(self.got_len == atom_count + self.got_index_free_list.items.len);
693 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;701 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);702 var got_table = try gpa.alloc(u8, got_size);
695 defer self.base.allocator.free(got_table);703 defer gpa.free(got_table);
696704
697 // + 4 for header, got, symbols, linecountinfo705 // + 4 for header, got, symbols, linecountinfo
698 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());706 var iovecs = try gpa.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());
699 defer self.base.allocator.free(iovecs);707 defer gpa.free(iovecs);
700708
701 const file = self.base.file.?;709 const file = self.base.file.?;
702710
...@@ -709,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -709,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
709 var iovecs_i: usize = 1;717 var iovecs_i: usize = 1;
710 var text_i: u64 = 0;718 var text_i: u64 = 0;
711719
712 var linecountinfo = std.ArrayList(u8).init(self.base.allocator);720 var linecountinfo = std.ArrayList(u8).init(gpa);
713 defer linecountinfo.deinit();721 defer linecountinfo.deinit();
714 // text722 // text
715 {723 {
...@@ -901,10 +909,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -901,10 +909,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
901 }909 }
902 }910 }
903 }911 }
904 var sym_buf = std.ArrayList(u8).init(self.base.allocator);912 var sym_buf = std.ArrayList(u8).init(gpa);
905 try self.writeSyms(&sym_buf);913 try self.writeSyms(&sym_buf);
906 const syms = try sym_buf.toOwnedSlice();914 const syms = try sym_buf.toOwnedSlice();
907 defer self.base.allocator.free(syms);915 defer gpa.free(syms);
908 assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls916 assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls
909 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };917 iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
910 iovecs_i += 1;918 iovecs_i += 1;
...@@ -985,6 +993,7 @@ fn addDeclExports(...@@ -985,6 +993,7 @@ fn addDeclExports(
985 decl_index: InternPool.DeclIndex,993 decl_index: InternPool.DeclIndex,
986 exports: []const *Module.Export,994 exports: []const *Module.Export,
987) !void {995) !void {
996 const gpa = self.base.comp.gpa;
988 const metadata = self.decls.getPtr(decl_index).?;997 const metadata = self.decls.getPtr(decl_index).?;
989 const atom = self.getAtom(metadata.index);998 const atom = self.getAtom(metadata.index);
990999
...@@ -994,7 +1003,7 @@ fn addDeclExports(...@@ -994,7 +1003,7 @@ fn addDeclExports(
994 if (exp.opts.section.unwrap()) |section_name| {1003 if (exp.opts.section.unwrap()) |section_name| {
995 if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) {1004 if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) {
996 try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(1005 try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
997 self.base.allocator,1006 gpa,
998 mod.declPtr(decl_index).srcLoc(mod),1007 mod.declPtr(decl_index).srcLoc(mod),
999 "plan9 does not support extra sections",1008 "plan9 does not support extra sections",
1000 .{},1009 .{},
...@@ -1005,19 +1014,20 @@ fn addDeclExports(...@@ -1005,19 +1014,20 @@ fn addDeclExports(
1005 const sym = .{1014 const sym = .{
1006 .value = atom.offset.?,1015 .value = atom.offset.?,
1007 .type = atom.type.toGlobal(),1016 .type = atom.type.toGlobal(),
1008 .name = try self.base.allocator.dupe(u8, exp_name),1017 .name = try gpa.dupe(u8, exp_name),
1009 };1018 };
10101019
1011 if (metadata.getExport(self, exp_name)) |i| {1020 if (metadata.getExport(self, exp_name)) |i| {
1012 self.syms.items[i] = sym;1021 self.syms.items[i] = sym;
1013 } else {1022 } else {
1014 try self.syms.append(self.base.allocator, sym);1023 try self.syms.append(gpa, sym);
1015 try metadata.exports.append(self.base.allocator, self.syms.items.len - 1);1024 try metadata.exports.append(gpa, self.syms.items.len - 1);
1016 }1025 }
1017 }1026 }
1018}1027}
10191028
1020pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {1029pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1030 const gpa = self.base.comp.gpa;
1021 // TODO audit the lifetimes of decls table entries. It's possible to get1031 // TODO audit the lifetimes of decls table entries. It's possible to get
1022 // freeDecl without any updateDecl in between.1032 // freeDecl without any updateDecl in between.
1023 // However that is planned to change, see the TODO comment in Module.zig1033 // 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 {...@@ -1029,17 +1039,17 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1029 const symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?;1039 const symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?;
1030 var submap = symidx_and_submap.functions;1040 var submap = symidx_and_submap.functions;
1031 if (submap.fetchSwapRemove(decl_index)) |removed_entry| {1041 if (submap.fetchSwapRemove(decl_index)) |removed_entry| {
1032 self.base.allocator.free(removed_entry.value.code);1042 gpa.free(removed_entry.value.code);
1033 self.base.allocator.free(removed_entry.value.lineinfo);1043 gpa.free(removed_entry.value.lineinfo);
1034 }1044 }
1035 if (submap.count() == 0) {1045 if (submap.count() == 0) {
1036 self.syms.items[symidx_and_submap.sym_index] = aout.Sym.undefined_symbol;1046 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 {};1047 self.syms_index_free_list.append(gpa, symidx_and_submap.sym_index) catch {};
1038 submap.deinit(self.base.allocator);1048 submap.deinit(gpa);
1039 }1049 }
1040 } else {1050 } else {
1041 if (self.data_decl_table.fetchSwapRemove(decl_index)) |removed_entry| {1051 if (self.data_decl_table.fetchSwapRemove(decl_index)) |removed_entry| {
1042 self.base.allocator.free(removed_entry.value);1052 gpa.free(removed_entry.value);
1043 }1053 }
1044 }1054 }
1045 if (self.decls.fetchRemove(decl_index)) |const_kv| {1055 if (self.decls.fetchRemove(decl_index)) |const_kv| {
...@@ -1047,35 +1057,36 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {...@@ -1047,35 +1057,36 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1047 const atom = self.getAtom(kv.value.index);1057 const atom = self.getAtom(kv.value.index);
1048 if (atom.got_index) |i| {1058 if (atom.got_index) |i| {
1049 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length1059 // 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 {};
1051 }1061 }
1052 if (atom.sym_index) |i| {1062 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 {};
1054 self.syms.items[i] = aout.Sym.undefined_symbol;1064 self.syms.items[i] = aout.Sym.undefined_symbol;
1055 }1065 }
1056 kv.value.exports.deinit(self.base.allocator);1066 kv.value.exports.deinit(gpa);
1057 }1067 }
1058 self.freeUnnamedConsts(decl_index);1068 self.freeUnnamedConsts(decl_index);
1059 {1069 {
1060 const atom_index = self.decls.get(decl_index).?.index;1070 const atom_index = self.decls.get(decl_index).?.index;
1061 const relocs = self.relocs.getPtr(atom_index) orelse return;1071 const relocs = self.relocs.getPtr(atom_index) orelse return;
1062 relocs.clearAndFree(self.base.allocator);1072 relocs.clearAndFree(gpa);
1063 assert(self.relocs.remove(atom_index));1073 assert(self.relocs.remove(atom_index));
1064 }1074 }
1065}1075}
1066fn freeUnnamedConsts(self: *Plan9, decl_index: InternPool.DeclIndex) void {1076fn freeUnnamedConsts(self: *Plan9, decl_index: InternPool.DeclIndex) void {
1077 const gpa = self.base.comp.gpa;
1067 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;1078 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
1068 for (unnamed_consts.items) |atom_idx| {1079 for (unnamed_consts.items) |atom_idx| {
1069 const atom = self.getAtom(atom_idx);1080 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);
1071 self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol;1082 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 {};
1073 }1084 }
1074 unnamed_consts.clearAndFree(self.base.allocator);1085 unnamed_consts.clearAndFree(gpa);
1075}1086}
10761087
1077fn createAtom(self: *Plan9) !Atom.Index {1088fn createAtom(self: *Plan9) !Atom.Index {
1078 const gpa = self.base.allocator;1089 const gpa = self.base.comp.gpa;
1079 const index = @as(Atom.Index, @intCast(self.atoms.items.len));1090 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
1080 const atom = try self.atoms.addOne(gpa);1091 const atom = try self.atoms.addOne(gpa);
1081 atom.* = .{1092 atom.* = .{
...@@ -1089,7 +1100,8 @@ fn createAtom(self: *Plan9) !Atom.Index {...@@ -1089,7 +1100,8 @@ fn createAtom(self: *Plan9) !Atom.Index {
1089}1100}
10901101
1091pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index {1102pub 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);
1093 if (!gop.found_existing) {1105 if (!gop.found_existing) {
1094 const index = try self.createAtom();1106 const index = try self.createAtom();
1095 self.getAtomPtr(index).got_index = self.allocateGotIndex();1107 self.getAtomPtr(index).got_index = self.allocateGotIndex();
...@@ -1134,7 +1146,8 @@ pub fn updateExports(...@@ -1134,7 +1146,8 @@ pub fn updateExports(
1134}1146}
11351147
1136pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {1148pub 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.?));
1138 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();1151 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
11391152
1140 if (!gop.found_existing) gop.value_ptr.* = .{};1153 if (!gop.found_existing) gop.value_ptr.* = .{};
...@@ -1160,7 +1173,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.In...@@ -1160,7 +1173,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.In
1160}1173}
11611174
1162fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void {1175fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void {
1163 const gpa = self.base.allocator;1176 const gpa = self.base.comp.gpa;
1164 const mod = self.base.options.module.?;1177 const mod = self.base.options.module.?;
11651178
1166 var required_alignment: InternPool.Alignment = .none;1179 var required_alignment: InternPool.Alignment = .none;
...@@ -1206,8 +1219,8 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind...@@ -1206,8 +1219,8 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
1206 },1219 },
1207 };1220 };
1208 // duped_code is freed when the atom is freed1221 // duped_code is freed when the atom is freed
1209 const duped_code = try self.base.allocator.dupe(u8, code);1222 const duped_code = try gpa.dupe(u8, code);
1210 errdefer self.base.allocator.free(duped_code);1223 errdefer gpa.free(duped_code);
1211 self.getAtomPtr(atom_index).code = .{1224 self.getAtomPtr(atom_index).code = .{
1212 .code_ptr = duped_code.ptr,1225 .code_ptr = duped_code.ptr,
1213 .other = .{ .code_len = duped_code.len },1226 .other = .{ .code_len = duped_code.len },
...@@ -1215,13 +1228,13 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind...@@ -1215,13 +1228,13 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
1215}1228}
12161229
1217pub fn deinit(self: *Plan9) void {1230pub fn deinit(self: *Plan9) void {
1218 const gpa = self.base.allocator;1231 const gpa = self.base.comp.gpa;
1219 {1232 {
1220 var it = self.relocs.valueIterator();1233 var it = self.relocs.valueIterator();
1221 while (it.next()) |relocs| {1234 while (it.next()) |relocs| {
1222 relocs.deinit(self.base.allocator);1235 relocs.deinit(gpa);
1223 }1236 }
1224 self.relocs.deinit(self.base.allocator);1237 self.relocs.deinit(gpa);
1225 }1238 }
1226 // free the unnamed consts1239 // free the unnamed consts
1227 var it_unc = self.unnamed_const_atoms.iterator();1240 var it_unc = self.unnamed_const_atoms.iterator();
...@@ -1280,24 +1293,36 @@ pub fn deinit(self: *Plan9) void {...@@ -1280,24 +1293,36 @@ pub fn deinit(self: *Plan9) void {
1280 }1293 }
1281}1294}
12821295
1283pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {1296pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 {
1284 if (options.use_llvm)1297 if (build_options.only_c) unreachable;
1285 return error.LLVMBackendDoesNotSupportPlan9;1298
1286 assert(options.target.ofmt == .plan9);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);
1289 errdefer self.base.destroy();1308 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, .{
1292 .read = true,1311 .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 ),
1294 });1317 });
1295 errdefer file.close();1318 errdefer file.close();
1296 self.base.file = file;1319 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, &.{
1301 // we include the global offset table to make it easier for debugging1326 // we include the global offset table to make it easier for debugging
1302 .{1327 .{
1303 .value = self.getAddr(0, .d), // the global offset table starts at 01328 .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...@@ -1490,7 +1515,7 @@ pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.S
1490 // be used by more than one function, however, its address is being used so we need1515 // be used by more than one function, however, its address is being used so we need
1491 // to put it in some location.1516 // to put it in some location.
1492 // ...1517 // ...
1493 const gpa = self.base.allocator;1518 const gpa = self.base.comp.gpa;
1494 const gop = try self.anon_decls.getOrPut(gpa, decl_val);1519 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
1495 const mod = self.base.options.module.?;1520 const mod = self.base.options.module.?;
1496 if (!gop.found_existing) {1521 if (!gop.found_existing) {
...@@ -1538,11 +1563,12 @@ pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: li...@@ -1538,11 +1563,12 @@ pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: li
1538}1563}
15391564
1540pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {1565pub 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);
1542 if (!gop.found_existing) {1568 if (!gop.found_existing) {
1543 gop.value_ptr.* = .{};1569 gop.value_ptr.* = .{};
1544 }1570 }
1545 try gop.value_ptr.append(self.base.allocator, reloc);1571 try gop.value_ptr.append(gpa, reloc);
1546}1572}
15471573
1548pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom {1574pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom {
src/link/SpirV.zig+36-23
...@@ -47,48 +47,65 @@ base: link.File,...@@ -47,48 +47,65 @@ base: link.File,
4747
48object: codegen.Object,48object: codegen.Object,
4949
50pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {50pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
51 const self = try gpa.create(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);
52 self.* = .{55 self.* = .{
53 .base = .{56 .base = .{
54 .tag = .spirv,57 .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,
56 .file = null,63 .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,
58 },70 },
59 .object = codegen.Object.init(gpa),71 .object = codegen.Object.init(gpa),
60 };72 };
61 errdefer self.deinit();73 errdefer self.deinit();
6274
63 // TODO: Figure out where to put all of these75 switch (target.cpu.arch) {
64 switch (options.target.cpu.arch) {
65 .spirv32, .spirv64 => {},76 .spirv32, .spirv64 => {},
66 else => return error.TODOArchNotSupported,77 else => unreachable, // Caught by Compilation.Config.resolve.
67 }78 }
6879
69 switch (options.target.os.tag) {80 switch (target.os.tag) {
70 .opencl, .glsl450, .vulkan => {},81 .opencl, .glsl450, .vulkan => {},
71 else => return error.TODOOsNotSupported,82 else => unreachable, // Caught by Compilation.Config.resolve.
72 }83 }
7384
74 if (options.target.abi != .none) {85 assert(target.abi != .none); // Caught by Compilation.Config.resolve.
75 return error.TODOAbiNotSupported;
76 }
7786
78 return self;87 return self;
79}88}
8089
81pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {90pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
82 assert(options.target.ofmt == .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.97 assert(!use_llvm); // Caught by Compilation.Config.resolve.
85 if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.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);
88 errdefer spirv.base.destroy();102 errdefer spirv.base.destroy();
89103
90 // TODO: read the file and keep valid parts instead of truncating104 // 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 });
92 spirv.base.file = file;109 spirv.base.file = file;
93 return spirv;110 return spirv;
94}111}
...@@ -150,11 +167,7 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void {...@@ -150,11 +167,7 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void {
150}167}
151168
152pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {169pub 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) {170 return self.flushModule(comp, prog_node);
154 return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
155 } else {
156 return self.flushModule(comp, prog_node);
157 }
158}171}
159172
160pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {173pub 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) = .{},...@@ -191,6 +191,9 @@ synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
191/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.191/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
192anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},192anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
193193
194import_table: bool,
195export_table: bool,
196
194pub const Alignment = types.Alignment;197pub const Alignment = types.Alignment;
195198
196pub const Segment = struct {199pub const Segment = struct {
...@@ -363,63 +366,71 @@ pub const StringTable = struct {...@@ -363,63 +366,71 @@ pub const StringTable = struct {
363 }366 }
364};367};
365368
366pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {369pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
367 assert(options.target.ofmt == .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) {375 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
370 return createEmpty(allocator, options);376 const use_llvm = options.comp.config.use_llvm;
371 }377 const output_mode = options.comp.config.output_mode;
372378
373 const wasm_bin = try createEmpty(allocator, options);379 const wasm = try createEmpty(arena, options);
374 errdefer wasm_bin.base.destroy();380 errdefer wasm.base.destroy();
375381
376 // We are not using LLD at this point, so ensure we set the intermediary basename382 if (use_lld and use_llvm) {
377 if (build_options.have_llvm and options.use_llvm and options.module != null) {383 // LLVM emits the object file; LLD links it into the final product.
378 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,384 return wasm;
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 });
384 }385 }
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
386 // TODO: read the file and keep valid parts instead of truncating397 // TODO: read the file and keep valid parts instead of truncating
387 const file = try options.emit.?.directory.handle.createFile(sub_path, .{398 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
388 .truncate = true,399 .truncate = true,
389 .read = true,400 .read = true,
390 .mode = if (fs.has_executable_bit)401 .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)
392 fs.File.default_mode | 0b001_000_000403 fs.File.default_mode | 0b001_000_000
393 else404 else
394 fs.File.default_mode405 fs.File.default_mode
395 else406 else
396 0,407 0,
397 });408 });
398 wasm_bin.base.file = file;409 wasm.base.file = file;
399 wasm_bin.name = sub_path;410 wasm.name = sub_path;
400411
401 // create stack pointer symbol412 // create stack pointer symbol
402 {413 {
403 const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global);414 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
404 const symbol = loc.getSymbol(wasm_bin);415 const symbol = loc.getSymbol(wasm);
405 // For object files we will import the stack pointer symbol416 // For object files we will import the stack pointer symbol
406 if (options.output_mode == .Obj) {417 if (output_mode == .Obj) {
407 symbol.setUndefined(true);418 symbol.setUndefined(true);
408 symbol.index = @as(u32, @intCast(wasm_bin.imported_globals_count));419 symbol.index = @intCast(wasm.imported_globals_count);
409 wasm_bin.imported_globals_count += 1;420 wasm.imported_globals_count += 1;
410 try wasm_bin.imports.putNoClobber(421 try wasm.imports.putNoClobber(
411 allocator,422 gpa,
412 loc,423 loc,
413 .{424 .{
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),
415 .name = symbol.name,426 .name = symbol.name,
416 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },427 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
417 },428 },
418 );429 );
419 } else {430 } 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);
421 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);432 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);
423 global.* = .{434 global.* = .{
424 .global_type = .{435 .global_type = .{
425 .valtype = .i32,436 .valtype = .i32,
...@@ -432,25 +443,25 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -432,25 +443,25 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
432443
433 // create indirect function pointer symbol444 // create indirect function pointer symbol
434 {445 {
435 const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);446 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
436 const symbol = loc.getSymbol(wasm_bin);447 const symbol = loc.getSymbol(wasm);
437 const table: std.wasm.Table = .{448 const table: std.wasm.Table = .{
438 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`449 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
439 .reftype = .funcref,450 .reftype = .funcref,
440 };451 };
441 if (options.output_mode == .Obj or options.import_table) {452 if (output_mode == .Obj or options.import_table) {
442 symbol.setUndefined(true);453 symbol.setUndefined(true);
443 symbol.index = @intCast(wasm_bin.imported_tables_count);454 symbol.index = @intCast(wasm.imported_tables_count);
444 wasm_bin.imported_tables_count += 1;455 wasm.imported_tables_count += 1;
445 try wasm_bin.imports.put(allocator, loc, .{456 try wasm.imports.put(gpa, loc, .{
446 .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name),457 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
447 .name = symbol.name,458 .name = symbol.name,
448 .kind = .{ .table = table },459 .kind = .{ .table = table },
449 });460 });
450 } else {461 } else {
451 symbol.index = @as(u32, @intCast(wasm_bin.imported_tables_count + wasm_bin.tables.items.len));462 symbol.index = @as(u32, @intCast(wasm.imported_tables_count + wasm.tables.items.len));
452 try wasm_bin.tables.append(allocator, table);463 try wasm.tables.append(gpa, table);
453 if (options.export_table) {464 if (wasm.export_table) {
454 symbol.setFlag(.WASM_SYM_EXPORTED);465 symbol.setFlag(.WASM_SYM_EXPORTED);
455 } else {466 } else {
456 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);467 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
...@@ -460,8 +471,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -460,8 +471,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
460471
461 // create __wasm_call_ctors472 // create __wasm_call_ctors
462 {473 {
463 const loc = try wasm_bin.createSyntheticSymbol("__wasm_call_ctors", .function);474 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
464 const symbol = loc.getSymbol(wasm_bin);475 const symbol = loc.getSymbol(wasm);
465 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);476 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
466 // we do not know the function index until after we merged all sections.477 // we do not know the function index until after we merged all sections.
467 // Therefore we set `symbol.index` and create its corresponding references478 // 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...@@ -469,67 +480,76 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
469 }480 }
470481
471 // shared-memory symbols for TLS support482 // shared-memory symbols for TLS support
472 if (wasm_bin.base.options.shared_memory) {483 if (wasm.base.options.shared_memory) {
473 {484 {
474 const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global);485 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
475 const symbol = loc.getSymbol(wasm_bin);486 const symbol = loc.getSymbol(wasm);
476 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);487 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
477 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);488 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
478 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{489 try wasm.wasm_globals.append(gpa, .{
479 .global_type = .{ .valtype = .i32, .mutable = true },490 .global_type = .{ .valtype = .i32, .mutable = true },
480 .init = .{ .i32_const = undefined },491 .init = .{ .i32_const = undefined },
481 });492 });
482 }493 }
483 {494 {
484 const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global);495 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
485 const symbol = loc.getSymbol(wasm_bin);496 const symbol = loc.getSymbol(wasm);
486 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);497 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
487 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);498 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
488 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{499 try wasm.wasm_globals.append(gpa, .{
489 .global_type = .{ .valtype = .i32, .mutable = false },500 .global_type = .{ .valtype = .i32, .mutable = false },
490 .init = .{ .i32_const = undefined },501 .init = .{ .i32_const = undefined },
491 });502 });
492 }503 }
493 {504 {
494 const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global);505 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
495 const symbol = loc.getSymbol(wasm_bin);506 const symbol = loc.getSymbol(wasm);
496 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);507 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
497 symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len);508 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
498 try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{509 try wasm.wasm_globals.append(gpa, .{
499 .global_type = .{ .valtype = .i32, .mutable = false },510 .global_type = .{ .valtype = .i32, .mutable = false },
500 .init = .{ .i32_const = undefined },511 .init = .{ .i32_const = undefined },
501 });512 });
502 }513 }
503 {514 {
504 const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function);515 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
505 const symbol = loc.getSymbol(wasm_bin);516 const symbol = loc.getSymbol(wasm);
506 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);517 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
507 }518 }
508 }519 }
509520
510 // if (!options.strip and options.module != null) {521 return wasm;
511 // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, .dwarf32);
512 // try wasm_bin.initDebugSections();
513 // }
514
515 return wasm_bin;
516}522}
517523
518pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {524pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
519 const wasm = try gpa.create(Wasm);525 const use_llvm = options.comp.config.use_llvm;
520 errdefer gpa.destroy(wasm);526 const output_mode = options.comp.config.output_mode;
527
528 const wasm = try arena.create(Wasm);
521 wasm.* = .{529 wasm.* = .{
522 .base = .{530 .base = .{
523 .tag = .wasm,531 .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,
525 .file = null,537 .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,
527 },545 },
528 .name = undefined,546 .name = undefined,
547 .import_table = options.import_table,
548 .export_table = options.export_table,
529 };549 };
530550
531 if (options.use_llvm) {551 if (use_llvm) {
532 wasm.llvm_object = try LlvmObject.create(gpa, options);552 wasm.llvm_object = try LlvmObject.create(arena, options);
533 }553 }
534 return wasm;554 return wasm;
535}555}
...@@ -537,22 +557,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {...@@ -537,22 +557,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
537/// For a given name, creates a new global synthetic symbol.557/// For a given name, creates a new global synthetic symbol.
538/// Leaves index undefined and the default flags (0).558/// Leaves index undefined and the default flags (0).
539fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {559fn 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);
541 return wasm.createSyntheticSymbolOffset(name_offset, tag);562 return wasm.createSyntheticSymbolOffset(name_offset, tag);
542}563}
543564
544fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {565fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
545 const sym_index = @as(u32, @intCast(wasm.symbols.items.len));566 const sym_index = @as(u32, @intCast(wasm.symbols.items.len));
546 const loc: SymbolLoc = .{ .index = sym_index, .file = null };567 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, .{
548 .name = name_offset,570 .name = name_offset,
549 .flags = 0,571 .flags = 0,
550 .tag = tag,572 .tag = tag,
551 .index = undefined,573 .index = undefined,
552 .virtual_address = undefined,574 .virtual_address = undefined,
553 });575 });
554 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {});576 try wasm.resolved_symbols.putNoClobber(gpa, loc, {});
555 try wasm.globals.put(wasm.base.allocator, name_offset, loc);577 try wasm.globals.put(gpa, name_offset, loc);
556 return loc;578 return loc;
557}579}
558580
...@@ -589,12 +611,13 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -589,12 +611,13 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
589 const file = try fs.cwd().openFile(path, .{});611 const file = try fs.cwd().openFile(path, .{});
590 errdefer file.close();612 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) {
593 error.InvalidMagicByte, error.NotObjectFile => return false,616 error.InvalidMagicByte, error.NotObjectFile => return false,
594 else => |e| return e,617 else => |e| return e,
595 };618 };
596 errdefer object.deinit(wasm.base.allocator);619 errdefer object.deinit(gpa);
597 try wasm.objects.append(wasm.base.allocator, object);620 try wasm.objects.append(gpa, object);
598 return true;621 return true;
599}622}
600623
...@@ -602,7 +625,8 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {...@@ -602,7 +625,8 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
602/// When the index was not found, a new `Atom` will be created, and its index will be returned.625/// When the index was not found, a new `Atom` will be created, and its index will be returned.
603/// The newly created Atom is empty with default fields as specified by `Atom.empty`.626/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
604pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index {627pub 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);
606 if (!gop.found_existing) {630 if (!gop.found_existing) {
607 const atom_index = try wasm.createAtom();631 const atom_index = try wasm.createAtom();
608 gop.value_ptr.* = atom_index;632 gop.value_ptr.* = atom_index;
...@@ -611,18 +635,19 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At...@@ -611,18 +635,19 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At
611 const mod = wasm.base.options.module.?;635 const mod = wasm.base.options.module.?;
612 const decl = mod.declPtr(decl_index);636 const decl = mod.declPtr(decl_index);
613 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));637 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);
615 }639 }
616 return gop.value_ptr.*;640 return gop.value_ptr.*;
617}641}
618642
619/// Creates a new empty `Atom` and returns its `Atom.Index`643/// Creates a new empty `Atom` and returns its `Atom.Index`
620fn createAtom(wasm: *Wasm) !Atom.Index {644fn createAtom(wasm: *Wasm) !Atom.Index {
621 const index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));645 const gpa = wasm.base.comp.gpa;
622 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);646 const index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
647 const atom = try wasm.managed_atoms.addOne(gpa);
623 atom.* = Atom.empty;648 atom.* = Atom.empty;
624 atom.sym_index = try wasm.allocateSymbol();649 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
627 return index;652 return index;
628}653}
...@@ -644,6 +669,8 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {...@@ -644,6 +669,8 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom {
644/// When false, it will only link with object files that contain symbols that669/// When false, it will only link with object files that contain symbols that
645/// are referenced by other object files or Zig code.670/// are referenced by other object files or Zig code.
646fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {671fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
672 const gpa = wasm.base.comp.gpa;
673
647 const file = try fs.cwd().openFile(path, .{});674 const file = try fs.cwd().openFile(path, .{});
648 errdefer file.close();675 errdefer file.close();
649676
...@@ -651,25 +678,25 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -651,25 +678,25 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
651 .file = file,678 .file = file,
652 .name = path,679 .name = path,
653 };680 };
654 archive.parse(wasm.base.allocator) catch |err| switch (err) {681 archive.parse(gpa) catch |err| switch (err) {
655 error.EndOfStream, error.NotArchive => {682 error.EndOfStream, error.NotArchive => {
656 archive.deinit(wasm.base.allocator);683 archive.deinit(gpa);
657 return false;684 return false;
658 },685 },
659 else => |e| return e,686 else => |e| return e,
660 };687 };
661688
662 if (!force_load) {689 if (!force_load) {
663 errdefer archive.deinit(wasm.base.allocator);690 errdefer archive.deinit(gpa);
664 try wasm.archives.append(wasm.base.allocator, archive);691 try wasm.archives.append(gpa, archive);
665 return true;692 return true;
666 }693 }
667 defer archive.deinit(wasm.base.allocator);694 defer archive.deinit(gpa);
668695
669 // In this case we must force link all embedded object files within the archive696 // In this case we must force link all embedded object files within the archive
670 // We loop over all symbols, and then group them by offset as the offset697 // We loop over all symbols, and then group them by offset as the offset
671 // notates where the object file starts.698 // 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);
673 defer offsets.deinit();700 defer offsets.deinit();
674 for (archive.toc.values()) |symbol_offsets| {701 for (archive.toc.values()) |symbol_offsets| {
675 for (symbol_offsets.items) |sym_offset| {702 for (symbol_offsets.items) |sym_offset| {
...@@ -678,8 +705,8 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -678,8 +705,8 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
678 }705 }
679706
680 for (offsets.keys()) |file_offset| {707 for (offsets.keys()) |file_offset| {
681 const object = try wasm.objects.addOne(wasm.base.allocator);708 const object = try wasm.objects.addOne(gpa);
682 object.* = try archive.parseObject(wasm.base.allocator, file_offset);709 object.* = try archive.parseObject(gpa, file_offset);
683 }710 }
684711
685 return true;712 return true;
...@@ -695,6 +722,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool {...@@ -695,6 +722,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool {
695}722}
696723
697fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {724fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
725 const gpa = wasm.base.comp.gpa;
698 const object: Object = wasm.objects.items[object_index];726 const object: Object = wasm.objects.items[object_index];
699 log.debug("Resolving symbols in object: '{s}'", .{object.name});727 log.debug("Resolving symbols in object: '{s}'", .{object.name});
700728
...@@ -708,7 +736,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -708,7 +736,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
708 if (mem.eql(u8, sym_name, "__indirect_function_table")) {736 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
709 continue;737 continue;
710 }738 }
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
713 if (symbol.isLocal()) {741 if (symbol.isLocal()) {
714 if (symbol.isUndefined()) {742 if (symbol.isUndefined()) {
...@@ -716,17 +744,17 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -716,17 +744,17 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
716 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });744 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });
717 return error.UndefinedLocal;745 return error.UndefinedLocal;
718 }746 }
719 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});747 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
720 continue;748 continue;
721 }749 }
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);
724 if (!maybe_existing.found_existing) {752 if (!maybe_existing.found_existing) {
725 maybe_existing.value_ptr.* = location;753 maybe_existing.value_ptr.* = location;
726 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});754 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
727755
728 if (symbol.isUndefined()) {756 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);
730 }758 }
731 continue;759 continue;
732 }760 }
...@@ -753,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -753,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
753 return error.SymbolCollision;781 return error.SymbolCollision;
754 }782 }
755783
756 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);784 try wasm.discarded.put(gpa, location, existing_loc);
757 continue; // Do not overwrite defined symbols with undefined symbols785 continue; // Do not overwrite defined symbols with undefined symbols
758 }786 }
759787
...@@ -791,7 +819,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -791,7 +819,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
791 }819 }
792820
793 // both undefined so skip overwriting existing symbol and discard the new symbol821 // 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);
795 continue;823 continue;
796 }824 }
797825
...@@ -822,7 +850,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -822,7 +850,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
822 // symbol is weak and the new one isn't, in which case we *do* overwrite it.850 // symbol is weak and the new one isn't, in which case we *do* overwrite it.
823 if (existing_sym.isWeak() and symbol.isWeak()) blk: {851 if (existing_sym.isWeak() and symbol.isWeak()) blk: {
824 if (existing_sym.isUndefined() and !symbol.isUndefined()) break :blk;852 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);
826 continue;854 continue;
827 }855 }
828856
...@@ -830,10 +858,10 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -830,10 +858,10 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
830 log.debug("Overwriting symbol '{s}'", .{sym_name});858 log.debug("Overwriting symbol '{s}'", .{sym_name});
831 log.debug(" old definition in '{s}'", .{existing_file_path});859 log.debug(" old definition in '{s}'", .{existing_file_path});
832 log.debug(" new definition in '{s}'", .{object.name});860 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);
834 maybe_existing.value_ptr.* = location;862 maybe_existing.value_ptr.* = location;
835 try wasm.globals.put(wasm.base.allocator, sym_name_index, location);863 try wasm.globals.put(gpa, sym_name_index, location);
836 try wasm.resolved_symbols.put(wasm.base.allocator, location, {});864 try wasm.resolved_symbols.put(gpa, location, {});
837 assert(wasm.resolved_symbols.swapRemove(existing_loc));865 assert(wasm.resolved_symbols.swapRemove(existing_loc));
838 if (existing_sym.isUndefined()) {866 if (existing_sym.isUndefined()) {
839 _ = wasm.undefs.swapRemove(sym_name_index);867 _ = wasm.undefs.swapRemove(sym_name_index);
...@@ -842,6 +870,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {...@@ -842,6 +870,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
842}870}
843871
844fn resolveSymbolsInArchives(wasm: *Wasm) !void {872fn resolveSymbolsInArchives(wasm: *Wasm) !void {
873 const gpa = wasm.base.comp.gpa;
845 if (wasm.archives.items.len == 0) return;874 if (wasm.archives.items.len == 0) return;
846875
847 log.debug("Resolving symbols in archives", .{});876 log.debug("Resolving symbols in archives", .{});
...@@ -860,9 +889,9 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {...@@ -860,9 +889,9 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
860 // Symbol is found in unparsed object file within current archive.889 // Symbol is found in unparsed object file within current archive.
861 // Parse object and and resolve symbols again before we check remaining890 // Parse object and and resolve symbols again before we check remaining
862 // undefined symbols.891 // undefined symbols.
863 const object_file_index = @as(u16, @intCast(wasm.objects.items.len));892 const object_file_index: u16 = @intCast(wasm.objects.items.len);
864 const object = try archive.parseObject(wasm.base.allocator, offset.items[0]);893 const object = try archive.parseObject(gpa, offset.items[0]);
865 try wasm.objects.append(wasm.base.allocator, object);894 try wasm.objects.append(gpa, object);
866 try wasm.resolveSymbolsInObject(object_file_index);895 try wasm.resolveSymbolsInObject(object_file_index);
867896
868 // continue loop for any remaining undefined symbols that still exist897 // continue loop for any remaining undefined symbols that still exist
...@@ -880,6 +909,8 @@ fn writeI32Const(writer: anytype, val: u32) !void {...@@ -880,6 +909,8 @@ fn writeI32Const(writer: anytype, val: u32) !void {
880}909}
881910
882fn setupInitMemoryFunction(wasm: *Wasm) !void {911fn setupInitMemoryFunction(wasm: *Wasm) !void {
912 const gpa = wasm.base.comp.gpa;
913
883 // Passive segments are used to avoid memory being reinitialized on each914 // Passive segments are used to avoid memory being reinitialized on each
884 // thread's instantiation. These passive segments are initialized and915 // thread's instantiation. These passive segments are initialized and
885 // dropped in __wasm_init_memory, which is registered as the start function916 // dropped in __wasm_init_memory, which is registered as the start function
...@@ -896,7 +927,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -896,7 +927,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
896 break :address loc.getSymbol(wasm).virtual_address;927 break :address loc.getSymbol(wasm).virtual_address;
897 } else 0;928 } else 0;
898929
899 var function_body = std.ArrayList(u8).init(wasm.base.allocator);930 var function_body = std.ArrayList(u8).init(gpa);
900 defer function_body.deinit();931 defer function_body.deinit();
901 const writer = function_body.writer();932 const writer = function_body.writer();
902933
...@@ -1040,6 +1071,8 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {...@@ -1040,6 +1071,8 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
1040/// Constructs a synthetic function that performs runtime relocations for1071/// Constructs a synthetic function that performs runtime relocations for
1041/// TLS symbols. This function is called by `__wasm_init_tls`.1072/// TLS symbols. This function is called by `__wasm_init_tls`.
1042fn setupTLSRelocationsFunction(wasm: *Wasm) !void {1073fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1074 const gpa = wasm.base.comp.gpa;
1075
1043 // When we have TLS GOT entries and shared memory is enabled,1076 // When we have TLS GOT entries and shared memory is enabled,
1044 // we must perform runtime relocations or else we don't create the function.1077 // we must perform runtime relocations or else we don't create the function.
1045 if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) {1078 if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) {
...@@ -1047,7 +1080,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {...@@ -1047,7 +1080,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
1047 }1080 }
10481081
1049 // const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs");1082 // 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);
1051 defer function_body.deinit();1084 defer function_body.deinit();
1052 const writer = function_body.writer();1085 const writer = function_body.writer();
10531086
...@@ -1221,10 +1254,12 @@ fn validateFeatures(...@@ -1221,10 +1254,12 @@ fn validateFeatures(
1221/// if one or multiple undefined references exist. When none exist, the symbol will1254/// if one or multiple undefined references exist. When none exist, the symbol will
1222/// not be created, ensuring we don't unneccesarily emit unreferenced symbols.1255/// not be created, ensuring we don't unneccesarily emit unreferenced symbols.
1223fn resolveLazySymbols(wasm: *Wasm) !void {1256fn resolveLazySymbols(wasm: *Wasm) !void {
1257 const gpa = wasm.base.comp.gpa;
1258
1224 if (wasm.string_table.getOffset("__heap_base")) |name_offset| {1259 if (wasm.string_table.getOffset("__heap_base")) |name_offset| {
1225 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1260 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1226 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);1261 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);
1228 _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.1263 _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations.
1229 }1264 }
1230 }1265 }
...@@ -1232,7 +1267,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1232,7 +1267,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1232 if (wasm.string_table.getOffset("__heap_end")) |name_offset| {1267 if (wasm.string_table.getOffset("__heap_end")) |name_offset| {
1233 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1268 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1234 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);1269 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);
1236 _ = wasm.resolved_symbols.swapRemove(loc);1271 _ = wasm.resolved_symbols.swapRemove(loc);
1237 }1272 }
1238 }1273 }
...@@ -1241,12 +1276,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1241,12 +1276,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1241 if (wasm.string_table.getOffset("__tls_base")) |name_offset| {1276 if (wasm.string_table.getOffset("__tls_base")) |name_offset| {
1242 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1277 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1243 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);1278 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);
1245 _ = wasm.resolved_symbols.swapRemove(kv.value);1280 _ = wasm.resolved_symbols.swapRemove(kv.value);
1246 const symbol = loc.getSymbol(wasm);1281 const symbol = loc.getSymbol(wasm);
1247 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);1282 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
1248 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);1283 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, .{
1250 .global_type = .{ .valtype = .i32, .mutable = true },1285 .global_type = .{ .valtype = .i32, .mutable = true },
1251 .init = .{ .i32_const = undefined },1286 .init = .{ .i32_const = undefined },
1252 });1287 });
...@@ -1256,7 +1291,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1256,7 +1291,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1256 if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| {1291 if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| {
1257 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {1292 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
1258 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);1293 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);
1260 _ = wasm.resolved_symbols.swapRemove(kv.value);1295 _ = wasm.resolved_symbols.swapRemove(kv.value);
1261 }1296 }
1262 }1297 }
...@@ -1292,8 +1327,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {...@@ -1292,8 +1327,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
1292}1327}
12931328
1294pub fn deinit(wasm: *Wasm) void {1329pub fn deinit(wasm: *Wasm) void {
1295 const gpa = wasm.base.allocator;1330 const gpa = wasm.base.comp.gpa;
1296 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);1331 if (wasm.llvm_object) |llvm_object| llvm_object.deinit();
12971332
1298 for (wasm.func_types.items) |*func_type| {1333 for (wasm.func_types.items) |*func_type| {
1299 func_type.deinit(gpa);1334 func_type.deinit(gpa);
...@@ -1378,7 +1413,9 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1378,7 +1413,9 @@ pub fn deinit(wasm: *Wasm) void {
1378/// Allocates a new symbol and returns its index.1413/// Allocates a new symbol and returns its index.
1379/// Will re-use slots when a symbol was freed at an earlier stage.1414/// Will re-use slots when a symbol was freed at an earlier stage.
1380pub fn allocateSymbol(wasm: *Wasm) !u32 {1415pub 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);
1382 const symbol: Symbol = .{1419 const symbol: Symbol = .{
1383 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls1420 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls
1384 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),1421 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
...@@ -1404,6 +1441,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:...@@ -1404,6 +1441,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:
1404 const tracy = trace(@src());1441 const tracy = trace(@src());
1405 defer tracy.end();1442 defer tracy.end();
14061443
1444 const gpa = wasm.base.comp.gpa;
1407 const func = mod.funcInfo(func_index);1445 const func = mod.funcInfo(func_index);
1408 const decl_index = func.owner_decl;1446 const decl_index = func.owner_decl;
1409 const decl = mod.declPtr(decl_index);1447 const decl = mod.declPtr(decl_index);
...@@ -1414,7 +1452,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:...@@ -1414,7 +1452,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air:
1414 // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;1452 // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null;
1415 // defer if (decl_state) |*ds| ds.deinit();1453 // 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);
1418 defer code_writer.deinit();1456 defer code_writer.deinit();
1419 // const result = try codegen.generateFunction(1457 // const result = try codegen.generateFunction(
1420 // &wasm.base,1458 // &wasm.base,
...@@ -1477,6 +1515,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !...@@ -1477,6 +1515,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !
1477 return;1515 return;
1478 }1516 }
14791517
1518 const gpa = wasm.base.comp.gpa;
1480 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);1519 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1481 const atom = wasm.getAtomPtr(atom_index);1520 const atom = wasm.getAtomPtr(atom_index);
1482 atom.clear();1521 atom.clear();
...@@ -1489,7 +1528,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !...@@ -1489,7 +1528,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !
1489 }1528 }
1490 const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;1529 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);
1493 defer code_writer.deinit();1532 defer code_writer.deinit();
14941533
1495 const res = try codegen.generateSymbol(1534 const res = try codegen.generateSymbol(
...@@ -1528,16 +1567,17 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De...@@ -1528,16 +1567,17 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De
1528}1567}
15291568
1530fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void {1569fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void {
1570 const gpa = wasm.base.comp.gpa;
1531 const mod = wasm.base.options.module.?;1571 const mod = wasm.base.options.module.?;
1532 const decl = mod.declPtr(decl_index);1572 const decl = mod.declPtr(decl_index);
1533 const atom_index = wasm.decls.get(decl_index).?;1573 const atom_index = wasm.decls.get(decl_index).?;
1534 const atom = wasm.getAtomPtr(atom_index);1574 const atom = wasm.getAtomPtr(atom_index);
1535 const symbol = &wasm.symbols.items[atom.sym_index];1575 const symbol = &wasm.symbols.items[atom.sym_index];
1536 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1576 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);
1538 symbol.tag = symbol_tag;1578 symbol.tag = symbol_tag;
1539 try atom.code.appendSlice(wasm.base.allocator, code);1579 try atom.code.appendSlice(gpa, code);
1540 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});1580 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
15411581
1542 atom.size = @intCast(code.len);1582 atom.size = @intCast(code.len);
1543 if (code.len == 0) return;1583 if (code.len == 0) return;
...@@ -1591,6 +1631,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {...@@ -1591,6 +1631,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
1591/// Returns the symbol index of the local1631/// Returns the symbol index of the local
1592/// The given `decl` is the parent decl whom owns the constant.1632/// The given `decl` is the parent decl whom owns the constant.
1593pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {1633pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
1634 const gpa = wasm.base.comp.gpa;
1594 const mod = wasm.base.options.module.?;1635 const mod = wasm.base.options.module.?;
1595 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions1636 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
1596 const decl = mod.declPtr(decl_index);1637 const decl = mod.declPtr(decl_index);
...@@ -1599,14 +1640,14 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec...@@ -1599,14 +1640,14 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec
1599 const parent_atom = wasm.getAtom(parent_atom_index);1640 const parent_atom = wasm.getAtom(parent_atom_index);
1600 const local_index = parent_atom.locals.items.len;1641 const local_index = parent_atom.locals.items.len;
1601 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1642 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}", .{
1603 fqn, local_index,1644 fqn, local_index,
1604 });1645 });
1605 defer wasm.base.allocator.free(name);1646 defer gpa.free(name);
16061647
1607 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {1648 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
1608 .ok => |atom_index| {1649 .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);
1610 return wasm.getAtom(atom_index).getSymbolIndex().?;1651 return wasm.getAtom(atom_index).getSymbolIndex().?;
1611 },1652 },
1612 .fail => |em| {1653 .fail => |em| {
...@@ -1623,24 +1664,25 @@ const LowerConstResult = union(enum) {...@@ -1623,24 +1664,25 @@ const LowerConstResult = union(enum) {
1623};1664};
16241665
1625fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {1666fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
1667 const gpa = wasm.base.comp.gpa;
1626 const mod = wasm.base.options.module.?;1668 const mod = wasm.base.options.module.?;
16271669
1628 // Create and initialize a new local symbol and atom1670 // Create and initialize a new local symbol and atom
1629 const atom_index = try wasm.createAtom();1671 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);
1631 defer value_bytes.deinit();1673 defer value_bytes.deinit();
16321674
1633 const code = code: {1675 const code = code: {
1634 const atom = wasm.getAtomPtr(atom_index);1676 const atom = wasm.getAtomPtr(atom_index);
1635 atom.alignment = tv.ty.abiAlignment(mod);1677 atom.alignment = tv.ty.abiAlignment(mod);
1636 wasm.symbols.items[atom.sym_index] = .{1678 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),
1638 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),1680 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
1639 .tag = .data,1681 .tag = .data,
1640 .index = undefined,1682 .index = undefined,
1641 .virtual_address = undefined,1683 .virtual_address = undefined,
1642 };1684 };
1643 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});1685 try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {});
16441686
1645 const result = try codegen.generateSymbol(1687 const result = try codegen.generateSymbol(
1646 &wasm.base,1688 &wasm.base,
...@@ -1663,7 +1705,7 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src...@@ -1663,7 +1705,7 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src
16631705
1664 const atom = wasm.getAtomPtr(atom_index);1706 const atom = wasm.getAtomPtr(atom_index);
1665 atom.size = @intCast(code.len);1707 atom.size = @intCast(code.len);
1666 try atom.code.appendSlice(wasm.base.allocator, code);1708 try atom.code.appendSlice(gpa, code);
1667 return .{ .ok = atom_index };1709 return .{ .ok = atom_index };
1668}1710}
16691711
...@@ -1673,8 +1715,9 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src...@@ -1673,8 +1715,9 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src
1673/// and then returns the index to it.1715/// and then returns the index to it.
1674pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {1716pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 {
1675 _ = lib_name;1717 _ = lib_name;
1676 const name_index = try wasm.string_table.put(wasm.base.allocator, name);1718 const gpa = wasm.base.comp.gpa;
1677 const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index);1719 const name_index = try wasm.string_table.put(gpa, name);
1720 const gop = try wasm.globals.getOrPut(gpa, name_index);
1678 if (gop.found_existing) {1721 if (gop.found_existing) {
1679 return gop.value_ptr.*.index;1722 return gop.value_ptr.*.index;
1680 }1723 }
...@@ -1691,14 +1734,14 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3...@@ -1691,14 +1734,14 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3
16911734
1692 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: {1735 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: {
1693 const index: u32 = @intCast(wasm.symbols.items.len);1736 const index: u32 = @intCast(wasm.symbols.items.len);
1694 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);1737 try wasm.symbols.ensureUnusedCapacity(gpa, 1);
1695 wasm.symbols.items.len += 1;1738 wasm.symbols.items.len += 1;
1696 break :blk index;1739 break :blk index;
1697 };1740 };
1698 wasm.symbols.items[sym_index] = symbol;1741 wasm.symbols.items[sym_index] = symbol;
1699 gop.value_ptr.* = .{ .index = sym_index, .file = null };1742 gop.value_ptr.* = .{ .index = sym_index, .file = null };
1700 try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {});1743 try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {});
1701 try wasm.undefs.putNoClobber(wasm.base.allocator, name_index, gop.value_ptr.*);1744 try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*);
1702 return sym_index;1745 return sym_index;
1703}1746}
17041747
...@@ -1709,6 +1752,7 @@ pub fn getDeclVAddr(...@@ -1709,6 +1752,7 @@ pub fn getDeclVAddr(
1709 decl_index: InternPool.DeclIndex,1752 decl_index: InternPool.DeclIndex,
1710 reloc_info: link.File.RelocInfo,1753 reloc_info: link.File.RelocInfo,
1711) !u64 {1754) !u64 {
1755 const gpa = wasm.base.comp.gpa;
1712 const mod = wasm.base.options.module.?;1756 const mod = wasm.base.options.module.?;
1713 const decl = mod.declPtr(decl_index);1757 const decl = mod.declPtr(decl_index);
17141758
...@@ -1725,17 +1769,17 @@ pub fn getDeclVAddr(...@@ -1725,17 +1769,17 @@ pub fn getDeclVAddr(
1725 // as function pointers are not allowed to be stored inside the data section.1769 // as function pointers are not allowed to be stored inside the data section.
1726 // They are instead stored in a function table which are called by index.1770 // They are instead stored in a function table which are called by index.
1727 try wasm.addTableFunction(target_symbol_index);1771 try wasm.addTableFunction(target_symbol_index);
1728 try atom.relocs.append(wasm.base.allocator, .{1772 try atom.relocs.append(gpa, .{
1729 .index = target_symbol_index,1773 .index = target_symbol_index,
1730 .offset = @as(u32, @intCast(reloc_info.offset)),1774 .offset = @intCast(reloc_info.offset),
1731 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,1775 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1732 });1776 });
1733 } else {1777 } else {
1734 try atom.relocs.append(wasm.base.allocator, .{1778 try atom.relocs.append(gpa, .{
1735 .index = target_symbol_index,1779 .index = target_symbol_index,
1736 .offset = @as(u32, @intCast(reloc_info.offset)),1780 .offset = @intCast(reloc_info.offset),
1737 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,1781 .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),
1739 });1783 });
1740 }1784 }
1741 // we do not know the final address at this point,1785 // we do not know the final address at this point,
...@@ -1751,7 +1795,8 @@ pub fn lowerAnonDecl(...@@ -1751,7 +1795,8 @@ pub fn lowerAnonDecl(
1751 explicit_alignment: Alignment,1795 explicit_alignment: Alignment,
1752 src_loc: Module.SrcLoc,1796 src_loc: Module.SrcLoc,
1753) !codegen.Result {1797) !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);
1755 if (!gop.found_existing) {1800 if (!gop.found_existing) {
1756 const mod = wasm.base.options.module.?;1801 const mod = wasm.base.options.module.?;
1757 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));1802 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
...@@ -1779,6 +1824,7 @@ pub fn lowerAnonDecl(...@@ -1779,6 +1824,7 @@ pub fn lowerAnonDecl(
1779}1824}
17801825
1781pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1826pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1827 const gpa = wasm.base.comp.gpa;
1782 const atom_index = wasm.anon_decls.get(decl_val).?;1828 const atom_index = wasm.anon_decls.get(decl_val).?;
1783 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;1829 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...@@ -1793,17 +1839,17 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
1793 // as function pointers are not allowed to be stored inside the data section.1839 // as function pointers are not allowed to be stored inside the data section.
1794 // They are instead stored in a function table which are called by index.1840 // They are instead stored in a function table which are called by index.
1795 try wasm.addTableFunction(target_symbol_index);1841 try wasm.addTableFunction(target_symbol_index);
1796 try parent_atom.relocs.append(wasm.base.allocator, .{1842 try parent_atom.relocs.append(gpa, .{
1797 .index = target_symbol_index,1843 .index = target_symbol_index,
1798 .offset = @as(u32, @intCast(reloc_info.offset)),1844 .offset = @intCast(reloc_info.offset),
1799 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,1845 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1800 });1846 });
1801 } else {1847 } else {
1802 try parent_atom.relocs.append(wasm.base.allocator, .{1848 try parent_atom.relocs.append(gpa, .{
1803 .index = target_symbol_index,1849 .index = target_symbol_index,
1804 .offset = @as(u32, @intCast(reloc_info.offset)),1850 .offset = @intCast(reloc_info.offset),
1805 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,1851 .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),
1807 });1853 });
1808 }1854 }
18091855
...@@ -1840,8 +1886,6 @@ pub fn updateExports(...@@ -1840,8 +1886,6 @@ pub fn updateExports(
1840 }1886 }
1841 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);1887 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
18421888
1843 if (wasm.base.options.emit == null) return;
1844
1845 const decl_index = switch (exported) {1889 const decl_index = switch (exported) {
1846 .decl_index => |i| i,1890 .decl_index => |i| i,
1847 .value => |val| {1891 .value => |val| {
...@@ -1880,7 +1924,7 @@ pub fn updateExports(...@@ -1880,7 +1924,7 @@ pub fn updateExports(
1880 };1924 };
1881 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);1925 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);
1882 const exported_atom = wasm.getAtom(exported_atom_index);1926 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));
1884 const sym_loc = exported_atom.symbolLoc();1928 const sym_loc = exported_atom.symbolLoc();
1885 const symbol = sym_loc.getSymbol(wasm);1929 const symbol = sym_loc.getSymbol(wasm);
1886 symbol.setGlobal(true);1930 symbol.setGlobal(true);
...@@ -1915,7 +1959,7 @@ pub fn updateExports(...@@ -1915,7 +1959,7 @@ pub fn updateExports(
19151959
1916 if (!existing_sym.isUndefined()) blk: {1960 if (!existing_sym.isUndefined()) blk: {
1917 if (symbol.isWeak()) {1961 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);
1919 continue; // to-be-exported symbol is weak, so we keep the existing symbol1963 continue; // to-be-exported symbol is weak, so we keep the existing symbol
1920 }1964 }
19211965
...@@ -1939,18 +1983,18 @@ pub fn updateExports(...@@ -1939,18 +1983,18 @@ pub fn updateExports(
1939 }1983 }
19401984
1941 // in this case the existing symbol must be replaced either because it's weak or undefined.1985 // 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);
1943 _ = wasm.imports.remove(existing_loc);1987 _ = wasm.imports.remove(existing_loc);
1944 _ = wasm.undefs.swapRemove(existing_sym.name);1988 _ = wasm.undefs.swapRemove(existing_sym.name);
1945 }1989 }
19461990
1947 // Ensure the symbol will be exported using the given name1991 // Ensure the symbol will be exported using the given name
1948 if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) {1992 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);
1950 }1994 }
19511995
1952 try wasm.globals.put(1996 try wasm.globals.put(
1953 wasm.base.allocator,1997 gpa,
1954 export_name,1998 export_name,
1955 sym_loc,1999 sym_loc,
1956 );2000 );
...@@ -1959,18 +2003,19 @@ pub fn updateExports(...@@ -1959,18 +2003,19 @@ pub fn updateExports(
19592003
1960pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {2004pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
1961 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);2005 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
2006 const gpa = wasm.base.comp.gpa;
1962 const mod = wasm.base.options.module.?;2007 const mod = wasm.base.options.module.?;
1963 const decl = mod.declPtr(decl_index);2008 const decl = mod.declPtr(decl_index);
1964 const atom_index = wasm.decls.get(decl_index).?;2009 const atom_index = wasm.decls.get(decl_index).?;
1965 const atom = wasm.getAtomPtr(atom_index);2010 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 {};
1967 _ = wasm.decls.remove(decl_index);2012 _ = wasm.decls.remove(decl_index);
1968 wasm.symbols.items[atom.sym_index].tag = .dead;2013 wasm.symbols.items[atom.sym_index].tag = .dead;
1969 for (atom.locals.items) |local_atom_index| {2014 for (atom.locals.items) |local_atom_index| {
1970 const local_atom = wasm.getAtom(local_atom_index);2015 const local_atom = wasm.getAtom(local_atom_index);
1971 const local_symbol = &wasm.symbols.items[local_atom.sym_index];2016 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
1972 local_symbol.tag = .dead; // also for any local symbol2017 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 {};
1974 assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc()));2019 assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc()));
1975 assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));2020 assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));
1976 }2021 }
...@@ -1999,8 +2044,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {...@@ -1999,8 +2044,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
19992044
2000/// Appends a new entry to the indirect function table2045/// Appends a new entry to the indirect function table
2001pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {2046pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {
2002 const index = @as(u32, @intCast(wasm.function_table.count()));2047 const gpa = wasm.base.comp.gpa;
2003 try wasm.function_table.put(wasm.base.allocator, .{ .file = null, .index = symbol_index }, index);2048 const index: u32 = @intCast(wasm.function_table.count());
2049 try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index);
2004}2050}
20052051
2006/// Assigns indexes to all indirect functions.2052/// Assigns indexes to all indirect functions.
...@@ -2019,7 +2065,7 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -2019,7 +2065,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
2019 }2065 }
2020 }2066 }
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) {
2023 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;2069 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
2024 const import = wasm.imports.getPtr(sym_loc).?;2070 const import = wasm.imports.getPtr(sym_loc).?;
2025 import.kind.table.limits.min = index - 1; // we start at index 1.2071 import.kind.table.limits.min = index - 1; // we start at index 1.
...@@ -2048,6 +2094,7 @@ pub fn addOrUpdateImport(...@@ -2048,6 +2094,7 @@ pub fn addOrUpdateImport(
2048 /// is asserted instead.2094 /// is asserted instead.
2049 type_index: ?u32,2095 type_index: ?u32,
2050) !void {2096) !void {
2097 const gpa = wasm.base.comp.gpa;
2051 assert(symbol_index != 0);2098 assert(symbol_index != 0);
2052 // For the import name, we use the decl's name, rather than the fully qualified name2099 // For the import name, we use the decl's name, rather than the fully qualified name
2053 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same2100 // 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(...@@ -2055,11 +2102,11 @@ pub fn addOrUpdateImport(
2055 const mangle_name = lib_name != null and2102 const mangle_name = lib_name != null and
2056 !std.mem.eql(u8, lib_name.?, "c");2103 !std.mem.eql(u8, lib_name.?, "c");
2057 const full_name = if (mangle_name) full_name: {2104 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.? });
2059 } else name;2106 } 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);
2063 const symbol: *Symbol = &wasm.symbols.items[symbol_index];2110 const symbol: *Symbol = &wasm.symbols.items[symbol_index];
2064 symbol.setUndefined(true);2111 symbol.setUndefined(true);
2065 symbol.setGlobal(true);2112 symbol.setGlobal(true);
...@@ -2068,12 +2115,12 @@ pub fn addOrUpdateImport(...@@ -2068,12 +2115,12 @@ pub fn addOrUpdateImport(
2068 // we specified a specific name for the symbol that does not match the import name2115 // we specified a specific name for the symbol that does not match the import name
2069 symbol.setFlag(.WASM_SYM_EXPLICIT_NAME);2116 symbol.setFlag(.WASM_SYM_EXPLICIT_NAME);
2070 }2117 }
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);
2072 if (!global_gop.found_existing) {2119 if (!global_gop.found_existing) {
2073 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };2120 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };
2074 global_gop.value_ptr.* = loc;2121 global_gop.value_ptr.* = loc;
2075 try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});2122 try wasm.resolved_symbols.put(gpa, loc, {});
2076 try wasm.undefs.putNoClobber(wasm.base.allocator, decl_name_index, loc);2123 try wasm.undefs.putNoClobber(gpa, decl_name_index, loc);
2077 } else if (global_gop.value_ptr.*.index != symbol_index) {2124 } else if (global_gop.value_ptr.*.index != symbol_index) {
2078 // We are not updating a symbol, but found an existing global2125 // We are not updating a symbol, but found an existing global
2079 // symbol with the same name. This means we always favor the2126 // symbol with the same name. This means we always favor the
...@@ -2081,21 +2128,21 @@ pub fn addOrUpdateImport(...@@ -2081,21 +2128,21 @@ pub fn addOrUpdateImport(
2081 // We can also skip storing the import as we will not output2128 // We can also skip storing the import as we will not output
2082 // this symbol.2129 // this symbol.
2083 return wasm.discarded.put(2130 return wasm.discarded.put(
2084 wasm.base.allocator,2131 gpa,
2085 .{ .file = null, .index = symbol_index },2132 .{ .file = null, .index = symbol_index },
2086 global_gop.value_ptr.*,2133 global_gop.value_ptr.*,
2087 );2134 );
2088 }2135 }
20892136
2090 if (type_index) |ty_index| {2137 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 });
2092 const module_name = if (lib_name) |l_name| blk: {2139 const module_name = if (lib_name) |l_name| blk: {
2093 break :blk l_name;2140 break :blk l_name;
2094 } else wasm.host_name;2141 } else wasm.host_name;
2095 if (!gop.found_existing) {2142 if (!gop.found_existing) {
2096 gop.value_ptr.* = .{2143 gop.value_ptr.* = .{
2097 .module_name = try wasm.string_table.put(wasm.base.allocator, module_name),2144 .module_name = try wasm.string_table.put(gpa, module_name),
2098 .name = try wasm.string_table.put(wasm.base.allocator, name),2145 .name = try wasm.string_table.put(gpa, name),
2099 .kind = .{ .function = ty_index },2146 .kind = .{ .function = ty_index },
2100 };2147 };
2101 }2148 }
...@@ -2132,10 +2179,10 @@ const Kind = union(enum) {...@@ -2132,10 +2179,10 @@ const Kind = union(enum) {
21322179
2133/// Parses an Atom and inserts its metadata into the corresponding sections.2180/// Parses an Atom and inserts its metadata into the corresponding sections.
2134fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {2181fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2182 const gpa = wasm.base.comp.gpa;
2135 const atom = wasm.getAtomPtr(atom_index);2183 const atom = wasm.getAtomPtr(atom_index);
2136 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);2184 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
2137 const do_garbage_collect = wasm.base.options.gc_sections orelse2185 const do_garbage_collect = wasm.base.gc_sections;
2138 (wasm.base.options.output_mode != .Obj);
21392186
2140 if (symbol.isDead() and do_garbage_collect) {2187 if (symbol.isDead() and do_garbage_collect) {
2141 // Prevent unreferenced symbols from being parsed.2188 // Prevent unreferenced symbols from being parsed.
...@@ -2147,7 +2194,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2147,7 +2194,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2147 const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count);2194 const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count);
2148 const type_index = wasm.atom_types.get(atom_index).?;2195 const type_index = wasm.atom_types.get(atom_index).?;
2149 try wasm.functions.putNoClobber(2196 try wasm.functions.putNoClobber(
2150 wasm.base.allocator,2197 gpa,
2151 .{ .file = null, .index = index },2198 .{ .file = null, .index = index },
2152 .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index },2199 .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index },
2153 );2200 );
...@@ -2156,7 +2203,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2156,7 +2203,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
21562203
2157 if (wasm.code_section_index == null) {2204 if (wasm.code_section_index == null) {
2158 wasm.code_section_index = @intCast(wasm.segments.items.len);2205 wasm.code_section_index = @intCast(wasm.segments.items.len);
2159 try wasm.segments.append(wasm.base.allocator, .{2206 try wasm.segments.append(gpa, .{
2160 .alignment = atom.alignment,2207 .alignment = atom.alignment,
2161 .size = atom.size,2208 .size = atom.size,
2162 .offset = 0,2209 .offset = 0,
...@@ -2167,11 +2214,11 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2167,11 +2214,11 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2167 break :result wasm.code_section_index.?;2214 break :result wasm.code_section_index.?;
2168 },2215 },
2169 .data => result: {2216 .data => result: {
2170 const segment_name = try std.mem.concat(wasm.base.allocator, u8, &.{2217 const segment_name = try std.mem.concat(gpa, u8, &.{
2171 kind.segmentName(),2218 kind.segmentName(),
2172 wasm.string_table.get(symbol.name),2219 wasm.string_table.get(symbol.name),
2173 });2220 });
2174 errdefer wasm.base.allocator.free(segment_name);2221 errdefer gpa.free(segment_name);
2175 const segment_info: types.Segment = .{2222 const segment_info: types.Segment = .{
2176 .name = segment_name,2223 .name = segment_name,
2177 .alignment = atom.alignment,2224 .alignment = atom.alignment,
...@@ -2188,14 +2235,14 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2188,14 +2235,14 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2188 }2235 }
21892236
2190 const should_merge = wasm.base.options.output_mode != .Obj;2237 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));
2192 if (gop.found_existing) {2239 if (gop.found_existing) {
2193 const index = gop.value_ptr.*;2240 const index = gop.value_ptr.*;
2194 wasm.segments.items[index].size += atom.size;2241 wasm.segments.items[index].size += atom.size;
21952242
2196 symbol.index = @intCast(wasm.segment_info.getIndex(index).?);2243 symbol.index = @intCast(wasm.segment_info.getIndex(index).?);
2197 // segment info already exists, so free its memory2244 // segment info already exists, so free its memory
2198 wasm.base.allocator.free(segment_name);2245 gpa.free(segment_name);
2199 break :result index;2246 break :result index;
2200 } else {2247 } else {
2201 const index: u32 = @intCast(wasm.segments.items.len);2248 const index: u32 = @intCast(wasm.segments.items.len);
...@@ -2203,7 +2250,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2203,7 +2250,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2203 if (wasm.base.options.shared_memory) {2250 if (wasm.base.options.shared_memory) {
2204 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);2251 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
2205 }2252 }
2206 try wasm.segments.append(wasm.base.allocator, .{2253 try wasm.segments.append(gpa, .{
2207 .alignment = atom.alignment,2254 .alignment = atom.alignment,
2208 .size = 0,2255 .size = 0,
2209 .offset = 0,2256 .offset = 0,
...@@ -2212,7 +2259,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2212,7 +2259,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2212 gop.value_ptr.* = index;2259 gop.value_ptr.* = index;
22132260
2214 const info_index: u32 = @intCast(wasm.segment_info.count());2261 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);
2216 symbol.index = info_index;2263 symbol.index = info_index;
2217 break :result index;2264 break :result index;
2218 }2265 }
...@@ -2228,6 +2275,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2228,6 +2275,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2228/// From a given index, append the given `Atom` at the back of the linked list.2275/// From a given index, append the given `Atom` at the back of the linked list.
2229/// Simply inserts it into the map of atoms when it doesn't exist yet.2276/// Simply inserts it into the map of atoms when it doesn't exist yet.
2230pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {2277pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
2278 const gpa = wasm.base.comp.gpa;
2231 const atom = wasm.getAtomPtr(atom_index);2279 const atom = wasm.getAtomPtr(atom_index);
2232 if (wasm.atoms.getPtr(index)) |last_index_ptr| {2280 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
2233 const last = wasm.getAtomPtr(last_index_ptr.*);2281 const last = wasm.getAtomPtr(last_index_ptr.*);
...@@ -2235,7 +2283,7 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void...@@ -2235,7 +2283,7 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void
2235 atom.prev = last_index_ptr.*;2283 atom.prev = last_index_ptr.*;
2236 last_index_ptr.* = atom_index;2284 last_index_ptr.* = atom_index;
2237 } else {2285 } else {
2238 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index);2286 try wasm.atoms.putNoClobber(gpa, index, atom_index);
2239 }2287 }
2240}2288}
22412289
...@@ -2363,12 +2411,13 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {...@@ -2363,12 +2411,13 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
2363}2411}
23642412
2365fn sortDataSegments(wasm: *Wasm) !void {2413fn sortDataSegments(wasm: *Wasm) !void {
2414 const gpa = wasm.base.comp.gpa;
2366 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};2415 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
2367 try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count());2416 try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());
2368 errdefer new_mapping.deinit(wasm.base.allocator);2417 errdefer new_mapping.deinit(gpa);
23692418
2370 const keys = try wasm.base.allocator.dupe([]const u8, wasm.data_segments.keys());2419 const keys = try gpa.dupe([]const u8, wasm.data_segments.keys());
2371 defer wasm.base.allocator.free(keys);2420 defer gpa.free(keys);
23722421
2373 const SortContext = struct {2422 const SortContext = struct {
2374 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {2423 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
...@@ -2388,7 +2437,7 @@ fn sortDataSegments(wasm: *Wasm) !void {...@@ -2388,7 +2437,7 @@ fn sortDataSegments(wasm: *Wasm) !void {
2388 const segment_index = wasm.data_segments.get(key).?;2437 const segment_index = wasm.data_segments.get(key).?;
2389 new_mapping.putAssumeCapacity(key, segment_index);2438 new_mapping.putAssumeCapacity(key, segment_index);
2390 }2439 }
2391 wasm.data_segments.deinit(wasm.base.allocator);2440 wasm.data_segments.deinit(gpa);
2392 wasm.data_segments = new_mapping;2441 wasm.data_segments = new_mapping;
2393}2442}
23942443
...@@ -2401,8 +2450,9 @@ fn sortDataSegments(wasm: *Wasm) !void {...@@ -2401,8 +2450,9 @@ fn sortDataSegments(wasm: *Wasm) !void {
2401/// original functions and their types. We need to know the type to verify it doesn't2450/// original functions and their types. We need to know the type to verify it doesn't
2402/// contain any parameters.2451/// contain any parameters.
2403fn setupInitFunctions(wasm: *Wasm) !void {2452fn setupInitFunctions(wasm: *Wasm) !void {
2453 const gpa = wasm.base.comp.gpa;
2404 for (wasm.objects.items, 0..) |object, file_index| {2454 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);
2406 for (object.init_funcs) |init_func| {2456 for (object.init_funcs) |init_func| {
2407 const symbol = object.symtable[init_func.symbol_index];2457 const symbol = object.symtable[init_func.symbol_index];
2408 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {2458 const ty: std.wasm.Type = if (symbol.isUndefined()) ty: {
...@@ -2439,6 +2489,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -2439,6 +2489,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
2439/// Generates an atom containing the global error set' size.2489/// Generates an atom containing the global error set' size.
2440/// This will only be generated if the symbol exists.2490/// This will only be generated if the symbol exists.
2441fn setupErrorsLen(wasm: *Wasm) !void {2491fn setupErrorsLen(wasm: *Wasm) !void {
2492 const gpa = wasm.base.comp.gpa;
2442 const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;2493 const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;
24432494
2444 const errors_len = wasm.base.options.module.?.global_error_set.count();2495 const errors_len = wasm.base.options.module.?.global_error_set.count();
...@@ -2456,19 +2507,19 @@ fn setupErrorsLen(wasm: *Wasm) !void {...@@ -2456,19 +2507,19 @@ fn setupErrorsLen(wasm: *Wasm) !void {
2456 prev_atom.next = atom.next;2507 prev_atom.next = atom.next;
2457 atom.prev = null;2508 atom.prev = null;
2458 }2509 }
2459 atom.deinit(wasm.base.allocator);2510 atom.deinit(gpa);
2460 break :blk index;2511 break :blk index;
2461 } else new_atom: {2512 } else new_atom: {
2462 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);2513 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
2463 try wasm.symbol_atom.put(wasm.base.allocator, loc, atom_index);2514 try wasm.symbol_atom.put(gpa, loc, atom_index);
2464 try wasm.managed_atoms.append(wasm.base.allocator, undefined);2515 try wasm.managed_atoms.append(gpa, undefined);
2465 break :new_atom atom_index;2516 break :new_atom atom_index;
2466 };2517 };
2467 const atom = wasm.getAtomPtr(atom_index);2518 const atom = wasm.getAtomPtr(atom_index);
2468 atom.* = Atom.empty;2519 atom.* = Atom.empty;
2469 atom.sym_index = loc.index;2520 atom.sym_index = loc.index;
2470 atom.size = 2;2521 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
2473 try wasm.parseAtom(atom_index, .{ .data = .read_only });2524 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2474}2525}
...@@ -2480,16 +2531,17 @@ fn setupErrorsLen(wasm: *Wasm) !void {...@@ -2480,16 +2531,17 @@ fn setupErrorsLen(wasm: *Wasm) !void {
2480/// references to the function stored in the symbol have been finalized so we end2531/// references to the function stored in the symbol have been finalized so we end
2481/// up calling the resolved function.2532/// up calling the resolved function.
2482fn initializeCallCtorsFunction(wasm: *Wasm) !void {2533fn initializeCallCtorsFunction(wasm: *Wasm) !void {
2534 const gpa = wasm.base.comp.gpa;
2483 // No code to emit, so also no ctors to call2535 // No code to emit, so also no ctors to call
2484 if (wasm.code_section_index == null) {2536 if (wasm.code_section_index == null) {
2485 // Make sure to remove it from the resolved symbols so we do not emit2537 // Make sure to remove it from the resolved symbols so we do not emit
2486 // it within any section. TODO: Remove this once we implement garbage collection.2538 // it within any section. TODO: Remove this once we implement garbage collection.
2487 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;2539 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
2488 std.debug.assert(wasm.resolved_symbols.swapRemove(loc));2540 assert(wasm.resolved_symbols.swapRemove(loc));
2489 return;2541 return;
2490 }2542 }
24912543
2492 var function_body = std.ArrayList(u8).init(wasm.base.allocator);2544 var function_body = std.ArrayList(u8).init(gpa);
2493 defer function_body.deinit();2545 defer function_body.deinit();
2494 const writer = function_body.writer();2546 const writer = function_body.writer();
24952547
...@@ -2531,6 +2583,7 @@ fn createSyntheticFunction(...@@ -2531,6 +2583,7 @@ fn createSyntheticFunction(
2531 func_ty: std.wasm.Type,2583 func_ty: std.wasm.Type,
2532 function_body: *std.ArrayList(u8),2584 function_body: *std.ArrayList(u8),
2533) !void {2585) !void {
2586 const gpa = wasm.base.comp.gpa;
2534 const loc = wasm.findGlobalSymbol(symbol_name) orelse2587 const loc = wasm.findGlobalSymbol(symbol_name) orelse
2535 try wasm.createSyntheticSymbol(symbol_name, .function);2588 try wasm.createSyntheticSymbol(symbol_name, .function);
2536 const symbol = loc.getSymbol(wasm);2589 const symbol = loc.getSymbol(wasm);
...@@ -2541,7 +2594,7 @@ fn createSyntheticFunction(...@@ -2541,7 +2594,7 @@ fn createSyntheticFunction(
2541 // create function with above type2594 // create function with above type
2542 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));2595 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));
2543 try wasm.functions.putNoClobber(2596 try wasm.functions.putNoClobber(
2544 wasm.base.allocator,2597 gpa,
2545 .{ .file = null, .index = func_index },2598 .{ .file = null, .index = func_index },
2546 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },2599 .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index },
2547 );2600 );
...@@ -2549,7 +2602,7 @@ fn createSyntheticFunction(...@@ -2549,7 +2602,7 @@ fn createSyntheticFunction(
25492602
2550 // create the atom that will be output into the final binary2603 // create the atom that will be output into the final binary
2551 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));2604 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);
2553 atom.* = .{2606 atom.* = .{
2554 .size = @as(u32, @intCast(function_body.items.len)),2607 .size = @as(u32, @intCast(function_body.items.len)),
2555 .offset = 0,2608 .offset = 0,
...@@ -2562,7 +2615,7 @@ fn createSyntheticFunction(...@@ -2562,7 +2615,7 @@ fn createSyntheticFunction(
2562 .original_offset = 0,2615 .original_offset = 0,
2563 };2616 };
2564 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);2617 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
2567 // `allocateAtoms` has already been called, set the atom's offset manually.2620 // `allocateAtoms` has already been called, set the atom's offset manually.
2568 // This is fine to do manually as we insert the atom at the very end.2621 // This is fine to do manually as we insert the atom at the very end.
...@@ -2582,10 +2635,11 @@ pub fn createFunction(...@@ -2582,10 +2635,11 @@ pub fn createFunction(
2582 function_body: *std.ArrayList(u8),2635 function_body: *std.ArrayList(u8),
2583 relocations: *std.ArrayList(Relocation),2636 relocations: *std.ArrayList(Relocation),
2584) !u32 {2637) !u32 {
2638 const gpa = wasm.base.comp.gpa;
2585 const loc = try wasm.createSyntheticSymbol(symbol_name, .function);2639 const loc = try wasm.createSyntheticSymbol(symbol_name, .function);
25862640
2587 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));2641 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
2588 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);2642 const atom = try wasm.managed_atoms.addOne(gpa);
2589 atom.* = .{2643 atom.* = .{
2590 .size = @intCast(function_body.items.len),2644 .size = @intCast(function_body.items.len),
2591 .offset = 0,2645 .offset = 0,
...@@ -2607,9 +2661,9 @@ pub fn createFunction(...@@ -2607,9 +2661,9 @@ pub fn createFunction(
2607 break :idx index;2661 break :idx index;
2608 };2662 };
2609 try wasm.appendAtomAtIndex(section_index, atom_index);2663 try wasm.appendAtomAtIndex(section_index, atom_index);
2610 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);2664 try wasm.symbol_atom.putNoClobber(gpa, loc, atom_index);
2611 try wasm.atom_types.put(wasm.base.allocator, atom_index, try wasm.putOrGetFuncType(func_ty));2665 try wasm.atom_types.put(gpa, atom_index, try wasm.putOrGetFuncType(func_ty));
2612 try wasm.synthetic_functions.append(wasm.base.allocator, atom_index);2666 try wasm.synthetic_functions.append(gpa, atom_index);
26132667
2614 return loc.index;2668 return loc.index;
2615}2669}
...@@ -2622,9 +2676,11 @@ fn setupStartSection(wasm: *Wasm) !void {...@@ -2622,9 +2676,11 @@ fn setupStartSection(wasm: *Wasm) !void {
2622}2676}
26232677
2624fn initializeTLSFunction(wasm: *Wasm) !void {2678fn initializeTLSFunction(wasm: *Wasm) !void {
2679 const gpa = wasm.base.comp.gpa;
2680
2625 if (!wasm.base.options.shared_memory) return;2681 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);
2628 defer function_body.deinit();2684 defer function_body.deinit();
2629 const writer = function_body.writer();2685 const writer = function_body.writer();
26302686
...@@ -2684,6 +2740,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {...@@ -2684,6 +2740,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
2684}2740}
26852741
2686fn setupImports(wasm: *Wasm) !void {2742fn setupImports(wasm: *Wasm) !void {
2743 const gpa = wasm.base.comp.gpa;
2687 log.debug("Merging imports", .{});2744 log.debug("Merging imports", .{});
2688 var discarded_it = wasm.discarded.keyIterator();2745 var discarded_it = wasm.discarded.keyIterator();
2689 while (discarded_it.next()) |discarded| {2746 while (discarded_it.next()) |discarded| {
...@@ -2718,12 +2775,12 @@ fn setupImports(wasm: *Wasm) !void {...@@ -2718,12 +2775,12 @@ fn setupImports(wasm: *Wasm) !void {
2718 // We copy the import to a new import to ensure the names contain references2775 // We copy the import to a new import to ensure the names contain references
2719 // to the internal string table, rather than of the object file.2776 // to the internal string table, rather than of the object file.
2720 const new_imp: types.Import = .{2777 const new_imp: types.Import = .{
2721 .module_name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.module_name)),2778 .module_name = try wasm.string_table.put(gpa, object.string_table.get(import.module_name)),
2722 .name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.name)),2779 .name = try wasm.string_table.put(gpa, object.string_table.get(import.name)),
2723 .kind = import.kind,2780 .kind = import.kind,
2724 };2781 };
2725 // TODO: De-duplicate imports when they contain the same names and type2782 // 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);
2727 }2784 }
27282785
2729 // Assign all indexes of the imports to their representing symbols2786 // Assign all indexes of the imports to their representing symbols
...@@ -2764,7 +2821,9 @@ fn setupImports(wasm: *Wasm) !void {...@@ -2764,7 +2821,9 @@ fn setupImports(wasm: *Wasm) !void {
2764/// Takes the global, function and table section from each linked object file2821/// Takes the global, function and table section from each linked object file
2765/// and merges it into a single section for each.2822/// and merges it into a single section for each.
2766fn mergeSections(wasm: *Wasm) !void {2823fn 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);
2768 defer removed_duplicates.deinit();2827 defer removed_duplicates.deinit();
27692828
2770 for (wasm.resolved_symbols.keys()) |sym_loc| {2829 for (wasm.resolved_symbols.keys()) |sym_loc| {
...@@ -2791,7 +2850,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2791,7 +2850,7 @@ fn mergeSections(wasm: *Wasm) !void {
2791 switch (symbol.tag) {2850 switch (symbol.tag) {
2792 .function => {2851 .function => {
2793 const gop = try wasm.functions.getOrPut(2852 const gop = try wasm.functions.getOrPut(
2794 wasm.base.allocator,2853 gpa,
2795 .{ .file = sym_loc.file, .index = symbol.index },2854 .{ .file = sym_loc.file, .index = symbol.index },
2796 );2855 );
2797 if (gop.found_existing) {2856 if (gop.found_existing) {
...@@ -2800,7 +2859,7 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2800,7 +2859,7 @@ fn mergeSections(wasm: *Wasm) !void {
2800 // we only emit a single function, instead of duplicates.2859 // we only emit a single function, instead of duplicates.
2801 symbol.unmark();2860 symbol.unmark();
2802 try wasm.discarded.putNoClobber(2861 try wasm.discarded.putNoClobber(
2803 wasm.base.allocator,2862 gpa,
2804 sym_loc,2863 sym_loc,
2805 .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index },2864 .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index },
2806 );2865 );
...@@ -2813,12 +2872,12 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2813,12 +2872,12 @@ fn mergeSections(wasm: *Wasm) !void {
2813 .global => {2872 .global => {
2814 const original_global = object.globals[index];2873 const original_global = object.globals[index];
2815 symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count;2874 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);
2817 },2876 },
2818 .table => {2877 .table => {
2819 const original_table = object.tables[index];2878 const original_table = object.tables[index];
2820 symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count;2879 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);
2822 },2881 },
2823 else => unreachable,2882 else => unreachable,
2824 }2883 }
...@@ -2838,10 +2897,11 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2838,10 +2897,11 @@ fn mergeSections(wasm: *Wasm) !void {
2838/// 'types' section, while assigning the type index to the representing2897/// 'types' section, while assigning the type index to the representing
2839/// section (import, export, function).2898/// section (import, export, function).
2840fn mergeTypes(wasm: *Wasm) !void {2899fn mergeTypes(wasm: *Wasm) !void {
2900 const gpa = wasm.base.comp.gpa;
2841 // A map to track which functions have already had their2901 // A map to track which functions have already had their
2842 // type inserted. If we do this for the same function multiple times,2902 // type inserted. If we do this for the same function multiple times,
2843 // it will be overwritten with the incorrect type.2903 // 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);
2845 try dirty.ensureUnusedCapacity(@as(u32, @intCast(wasm.functions.count())));2905 try dirty.ensureUnusedCapacity(@as(u32, @intCast(wasm.functions.count())));
2846 defer dirty.deinit();2906 defer dirty.deinit();
28472907
...@@ -2873,6 +2933,7 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2873,6 +2933,7 @@ fn mergeTypes(wasm: *Wasm) !void {
2873}2933}
28742934
2875fn setupExports(wasm: *Wasm) !void {2935fn setupExports(wasm: *Wasm) !void {
2936 const gpa = wasm.base.comp.gpa;
2876 if (wasm.base.options.output_mode == .Obj) return;2937 if (wasm.base.options.output_mode == .Obj) return;
2877 log.debug("Building exports from symbols", .{});2938 log.debug("Building exports from symbols", .{});
28782939
...@@ -2903,11 +2964,11 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2903,11 +2964,11 @@ fn setupExports(wasm: *Wasm) !void {
2903 const sym_name = sym_loc.getName(wasm);2964 const sym_name = sym_loc.getName(wasm);
2904 const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: {2965 const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: {
2905 if (sym_loc.file == null) break :blk symbol.name;2966 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);
2907 };2968 };
2908 const exp: types.Export = if (symbol.tag == .data) exp: {2969 const exp: types.Export = if (symbol.tag == .data) exp: {
2909 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));2970 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, .{
2911 .global_type = .{ .valtype = .i32, .mutable = false },2972 .global_type = .{ .valtype = .i32, .mutable = false },
2912 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },2973 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },
2913 });2974 });
...@@ -2926,7 +2987,7 @@ fn setupExports(wasm: *Wasm) !void {...@@ -2926,7 +2987,7 @@ fn setupExports(wasm: *Wasm) !void {
2926 wasm.string_table.get(exp.name),2987 wasm.string_table.get(exp.name),
2927 exp.index,2988 exp.index,
2928 });2989 });
2929 try wasm.exports.append(wasm.base.allocator, exp);2990 try wasm.exports.append(gpa, exp);
2930 }2991 }
29312992
2932 log.debug("Completed building exports. Total count: ({d})", .{wasm.exports.items.len});2993 log.debug("Completed building exports. Total count: ({d})", .{wasm.exports.items.len});
...@@ -2957,8 +3018,6 @@ fn setupStart(wasm: *Wasm) !void {...@@ -2957,8 +3018,6 @@ fn setupStart(wasm: *Wasm) !void {
2957fn setupMemory(wasm: *Wasm) !void {3018fn setupMemory(wasm: *Wasm) !void {
2958 log.debug("Setting up memory layout", .{});3019 log.debug("Setting up memory layout", .{});
2959 const page_size = std.wasm.page_size; // 64kb3020 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;
2962 const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention3021 const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention
2963 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention3022 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
29643023
...@@ -2974,7 +3033,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2974,7 +3033,7 @@ fn setupMemory(wasm: *Wasm) !void {
29743033
2975 if (place_stack_first and !is_obj) {3034 if (place_stack_first and !is_obj) {
2976 memory_ptr = stack_alignment.forward(memory_ptr);3035 memory_ptr = stack_alignment.forward(memory_ptr);
2977 memory_ptr += stack_size;3036 memory_ptr += wasm.base.stack_size;
2978 // We always put the stack pointer global at index 03037 // We always put the stack pointer global at index 0
2979 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));3038 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
2980 }3039 }
...@@ -3021,7 +3080,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -3021,7 +3080,7 @@ fn setupMemory(wasm: *Wasm) !void {
30213080
3022 if (!place_stack_first and !is_obj) {3081 if (!place_stack_first and !is_obj) {
3023 memory_ptr = stack_alignment.forward(memory_ptr);3082 memory_ptr = stack_alignment.forward(memory_ptr);
3024 memory_ptr += stack_size;3083 memory_ptr += wasm.base.stack_size;
3025 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));3084 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
3026 }3085 }
30273086
...@@ -3088,29 +3147,30 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -3088,29 +3147,30 @@ fn setupMemory(wasm: *Wasm) !void {
3088/// index of the segment within the final data section. When the segment does not yet3147/// index of the segment within the final data section. When the segment does not yet
3089/// exist, a new one will be initialized and appended. The new index will be returned in that case.3148/// exist, a new one will be initialized and appended. The new index will be returned in that case.
3090pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {3149pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
3150 const gpa = wasm.base.comp.gpa;
3091 const object: Object = wasm.objects.items[object_index];3151 const object: Object = wasm.objects.items[object_index];
3092 const symbol = object.symtable[symbol_index];3152 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
3095 switch (symbol.tag) {3155 switch (symbol.tag) {
3096 .data => {3156 .data => {
3097 const segment_info = object.segment_info[symbol.index];3157 const segment_info = object.segment_info[symbol.index];
3098 const merge_segment = wasm.base.options.output_mode != .Obj;3158 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));
3100 if (!result.found_existing) {3160 if (!result.found_existing) {
3101 result.value_ptr.* = index;3161 result.value_ptr.* = index;
3102 var flags: u32 = 0;3162 var flags: u32 = 0;
3103 if (wasm.base.options.shared_memory) {3163 if (wasm.base.options.shared_memory) {
3104 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);3164 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
3105 }3165 }
3106 try wasm.segments.append(wasm.base.allocator, .{3166 try wasm.segments.append(gpa, .{
3107 .alignment = .@"1",3167 .alignment = .@"1",
3108 .size = 0,3168 .size = 0,
3109 .offset = 0,3169 .offset = 0,
3110 .flags = flags,3170 .flags = flags,
3111 });3171 });
3112 try wasm.segment_info.putNoClobber(wasm.base.allocator, index, .{3172 try wasm.segment_info.putNoClobber(gpa, index, .{
3113 .name = try wasm.base.allocator.dupe(u8, segment_info.name),3173 .name = try gpa.dupe(u8, segment_info.name),
3114 .alignment = segment_info.alignment,3174 .alignment = segment_info.alignment,
3115 .flags = segment_info.flags,3175 .flags = segment_info.flags,
3116 });3176 });
...@@ -3183,7 +3243,8 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3...@@ -3183,7 +3243,8 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3
31833243
3184/// Appends a new segment with default field values3244/// Appends a new segment with default field values
3185fn appendDummySegment(wasm: *Wasm) !void {3245fn 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, .{
3187 .alignment = .@"1",3248 .alignment = .@"1",
3188 .size = 0,3249 .size = 0,
3189 .offset = 0,3250 .offset = 0,
...@@ -3203,6 +3264,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -3203,6 +3264,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
3203 // and then return said symbol's index. The final table will be populated3264 // and then return said symbol's index. The final table will be populated
3204 // during `flush` when we know all possible error names.3265 // during `flush` when we know all possible error names.
32053266
3267 const gpa = wasm.base.comp.gpa;
3206 const atom_index = try wasm.createAtom();3268 const atom_index = try wasm.createAtom();
3207 const atom = wasm.getAtomPtr(atom_index);3269 const atom = wasm.getAtomPtr(atom_index);
3208 const slice_ty = Type.slice_const_u8_sentinel_0;3270 const slice_ty = Type.slice_const_u8_sentinel_0;
...@@ -3210,7 +3272,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -3210,7 +3272,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
3210 atom.alignment = slice_ty.abiAlignment(mod);3272 atom.alignment = slice_ty.abiAlignment(mod);
3211 const sym_index = atom.sym_index;3273 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");
3214 const symbol = &wasm.symbols.items[sym_index];3276 const symbol = &wasm.symbols.items[sym_index];
3215 symbol.* = .{3277 symbol.* = .{
3216 .name = sym_name,3278 .name = sym_name,
...@@ -3222,7 +3284,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -3222,7 +3284,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
3222 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);3284 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
3223 symbol.mark();3285 symbol.mark();
32243286
3225 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});3287 try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {});
32263288
3227 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});3289 log.debug("Error name table was created with symbol index: ({d})", .{sym_index});
3228 wasm.error_table_symbol = sym_index;3290 wasm.error_table_symbol = sym_index;
...@@ -3234,6 +3296,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {...@@ -3234,6 +3296,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
3234/// This creates a table that consists of pointers and length to each error name.3296/// This creates a table that consists of pointers and length to each error name.
3235/// The table is what is being pointed to within the runtime bodies that are generated.3297/// The table is what is being pointed to within the runtime bodies that are generated.
3236fn populateErrorNameTable(wasm: *Wasm) !void {3298fn populateErrorNameTable(wasm: *Wasm) !void {
3299 const gpa = wasm.base.comp.gpa;
3237 const symbol_index = wasm.error_table_symbol orelse return;3300 const symbol_index = wasm.error_table_symbol orelse return;
3238 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;3301 const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
32393302
...@@ -3243,7 +3306,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3243,7 +3306,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3243 const names_atom_index = try wasm.createAtom();3306 const names_atom_index = try wasm.createAtom();
3244 const names_atom = wasm.getAtomPtr(names_atom_index);3307 const names_atom = wasm.getAtomPtr(names_atom_index);
3245 names_atom.alignment = .@"1";3308 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");
3247 const names_symbol = &wasm.symbols.items[names_atom.sym_index];3310 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
3248 names_symbol.* = .{3311 names_symbol.* = .{
3249 .name = sym_name,3312 .name = sym_name,
...@@ -3269,10 +3332,10 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3269,10 +3332,10 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3269 const slice_ty = Type.slice_const_u8_sentinel_0;3332 const slice_ty = Type.slice_const_u8_sentinel_0;
3270 const offset = @as(u32, @intCast(atom.code.items.len));3333 const offset = @as(u32, @intCast(atom.code.items.len));
3271 // first we create the data for the slice of the name3334 // 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 relocated3335 try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated
3273 try atom.code.writer(wasm.base.allocator).writeInt(u32, len - 1, .little);3336 try atom.code.writer(gpa).writeInt(u32, len - 1, .little);
3274 // create relocation to the error name3337 // create relocation to the error name
3275 try atom.relocs.append(wasm.base.allocator, .{3338 try atom.relocs.append(gpa, .{
3276 .index = names_atom.sym_index,3339 .index = names_atom.sym_index,
3277 .relocation_type = .R_WASM_MEMORY_ADDR_I32,3340 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
3278 .offset = offset,3341 .offset = offset,
...@@ -3282,7 +3345,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3282,7 +3345,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3282 addend += len;3345 addend += len;
32833346
3284 // as we updated the error name table, we now store the actual name within the names atom3347 // 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);
3286 names_atom.code.appendSliceAssumeCapacity(error_name);3349 names_atom.code.appendSliceAssumeCapacity(error_name);
3287 names_atom.code.appendAssumeCapacity(0);3350 names_atom.code.appendAssumeCapacity(0);
32883351
...@@ -3291,8 +3354,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3291,8 +3354,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3291 names_atom.size = addend;3354 names_atom.size = addend;
32923355
3293 const name_loc = names_atom.symbolLoc();3356 const name_loc = names_atom.symbolLoc();
3294 try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});3357 try wasm.resolved_symbols.put(gpa, name_loc, {});
3295 try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index);3358 try wasm.symbol_atom.put(gpa, name_loc, names_atom_index);
32963359
3297 // link the atoms with the rest of the binary so they can be allocated3360 // link the atoms with the rest of the binary so they can be allocated
3298 // and relocations will be performed.3361 // and relocations will be performed.
...@@ -3304,7 +3367,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3304,7 +3367,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3304/// This initializes the index, appends a new segment,3367/// This initializes the index, appends a new segment,
3305/// and finally, creates a managed `Atom`.3368/// and finally, creates a managed `Atom`.
3306pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index {3369pub 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);
3308 index.* = new_index;3372 index.* = new_index;
3309 try wasm.appendDummySegment();3373 try wasm.appendDummySegment();
33103374
...@@ -3312,7 +3376,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !...@@ -3312,7 +3376,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
3312 const atom = wasm.getAtomPtr(atom_index);3376 const atom = wasm.getAtomPtr(atom_index);
3313 wasm.symbols.items[atom.sym_index] = .{3377 wasm.symbols.items[atom.sym_index] = .{
3314 .tag = .section,3378 .tag = .section,
3315 .name = try wasm.string_table.put(wasm.base.allocator, name),3379 .name = try wasm.string_table.put(gpa, name),
3316 .index = 0,3380 .index = 0,
3317 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),3381 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
3318 };3382 };
...@@ -3322,8 +3386,10 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !...@@ -3322,8 +3386,10 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
3322}3386}
33233387
3324fn resetState(wasm: *Wasm) void {3388fn resetState(wasm: *Wasm) void {
3389 const gpa = wasm.base.comp.gpa;
3390
3325 for (wasm.segment_info.values()) |segment_info| {3391 for (wasm.segment_info.values()) |segment_info| {
3326 wasm.base.allocator.free(segment_info.name);3392 gpa.free(segment_info.name);
3327 }3393 }
33283394
3329 var atom_it = wasm.decls.valueIterator();3395 var atom_it = wasm.decls.valueIterator();
...@@ -3358,16 +3424,12 @@ fn resetState(wasm: *Wasm) void {...@@ -3358,16 +3424,12 @@ fn resetState(wasm: *Wasm) void {
3358}3424}
33593425
3360pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {3426pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
3361 if (wasm.base.options.emit == null) {3427 const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld;
3362 if (wasm.llvm_object) |llvm_object| {3428 const use_llvm = wasm.base.comp.config.use_llvm;
3363 return try llvm_object.flushModule(comp, prog_node);
3364 }
3365 return;
3366 }
33673429
3368 if (build_options.have_llvm and wasm.base.options.use_lld) {3430 if (use_lld) {
3369 return wasm.linkWithLLD(comp, prog_node);3431 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) {
3371 return wasm.linkWithZld(comp, prog_node);3433 return wasm.linkWithZld(comp, prog_node);
3372 } else {3434 } else {
3373 return wasm.flushModule(comp, prog_node);3435 return wasm.flushModule(comp, prog_node);
...@@ -3379,21 +3441,22 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3379,21 +3441,22 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3379 const tracy = trace(@src());3441 const tracy = trace(@src());
3380 defer tracy.end();3442 defer tracy.end();
33813443
3382 const gpa = wasm.base.allocator;3444 const gpa = wasm.base.comp.gpa;
3383 const options = wasm.base.options;
33843445
3385 // Used for all temporary memory allocated during flushin3446 // Used for all temporary memory allocated during flushin
3386 var arena_instance = std.heap.ArenaAllocator.init(gpa);3447 var arena_instance = std.heap.ArenaAllocator.init(gpa);
3387 defer arena_instance.deinit();3448 defer arena_instance.deinit();
3388 const arena = arena_instance.allocator();3449 const arena = arena_instance.allocator();
33893450
3390 const directory = options.emit.?.directory; // Just an alias to make it shorter to type.3451 const directory = wasm.base.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});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
3393 // If there is no Zig code to compile, then we should skip flushing the output file because it3456 // If there is no Zig code to compile, then we should skip flushing the output file because it
3394 // will not be part of the linker line anyway.3457 // will not be part of the linker line anyway.
3395 const module_obj_path: ?[]const u8 = if (options.module != null) blk: {3458 const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: {
3396 assert(options.use_llvm); // `linkWithZld` should never be called when the Wasm backend is used3459 assert(use_llvm); // `linkWithZld` should never be called when the Wasm backend is used
3397 try wasm.flushModule(comp, prog_node);3460 try wasm.flushModule(comp, prog_node);
33983461
3399 if (fs.path.dirname(full_out_path)) |dirname| {3462 if (fs.path.dirname(full_out_path)) |dirname| {
...@@ -3416,12 +3479,14 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3416,12 +3479,14 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3416 const id_symlink_basename = "zld.id";3479 const id_symlink_basename = "zld.id";
34173480
3418 var man: Cache.Manifest = undefined;3481 var man: Cache.Manifest = undefined;
3419 defer if (!options.disable_lld_caching) man.deinit();3482 defer if (!wasm.base.disable_lld_caching) man.deinit();
3420 var digest: [Cache.hex_digest_len]u8 = undefined;3483 var digest: [Cache.hex_digest_len]u8 = undefined;
34213484
3485 const objects = wasm.base.comp.objects;
3486
3422 // NOTE: The following section must be maintained to be equal3487 // NOTE: The following section must be maintained to be equal
3423 // as the section defined in `linkWithLLD`3488 // as the section defined in `linkWithLLD`
3424 if (!options.disable_lld_caching) {3489 if (!wasm.base.disable_lld_caching) {
3425 man = comp.cache_parent.obtain();3490 man = comp.cache_parent.obtain();
34263491
3427 // We are about to obtain this lock, so here we give other processes a chance first.3492 // 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...@@ -3429,7 +3494,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34293494
3430 comptime assert(Compilation.link_hash_implementation_version == 10);3495 comptime assert(Compilation.link_hash_implementation_version == 10);
34313496
3432 for (options.objects) |obj| {3497 for (objects) |obj| {
3433 _ = try man.addFile(obj.path, null);3498 _ = try man.addFile(obj.path, null);
3434 man.hash.add(obj.must_link);3499 man.hash.add(obj.must_link);
3435 }3500 }
...@@ -3438,19 +3503,19 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3438,19 +3503,19 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3438 }3503 }
3439 try man.addOptionalFile(module_obj_path);3504 try man.addOptionalFile(module_obj_path);
3440 try man.addOptionalFile(compiler_rt_path);3505 try man.addOptionalFile(compiler_rt_path);
3441 man.hash.addOptionalBytes(options.entry);3506 man.hash.addOptionalBytes(wasm.base.comp.config.entry);
3442 man.hash.addOptional(options.stack_size_override);3507 man.hash.add(wasm.base.stack_size);
3443 man.hash.add(wasm.base.options.build_id);3508 man.hash.add(wasm.base.build_id);
3444 man.hash.add(options.import_memory);3509 man.hash.add(wasm.base.comp.config.import_memory);
3445 man.hash.add(options.import_table);3510 man.hash.add(wasm.base.comp.config.shared_memory);
3446 man.hash.add(options.export_table);3511 man.hash.add(wasm.import_table);
3447 man.hash.addOptional(options.initial_memory);3512 man.hash.add(wasm.export_table);
3448 man.hash.addOptional(options.max_memory);3513 man.hash.addOptional(wasm.initial_memory);
3449 man.hash.add(options.shared_memory);3514 man.hash.addOptional(wasm.max_memory);
3450 man.hash.addOptional(options.global_base);3515 man.hash.addOptional(wasm.global_base);
3451 man.hash.add(options.export_symbol_names.len);3516 man.hash.add(wasm.export_symbol_names.len);
3452 // strip does not need to go into the linker hash because it is part of the hash namespace3517 // 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| {
3454 man.hash.addBytes(symbol_name);3519 man.hash.addBytes(symbol_name);
3455 }3520 }
34563521
...@@ -3485,30 +3550,36 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3485,30 +3550,36 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34853550
3486 // Positional arguments to the linker such as object files and static archives.3551 // Positional arguments to the linker such as object files and static archives.
3487 var positionals = std.ArrayList([]const u8).init(arena);3552 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
3490 // When the target os is WASI, we allow linking with WASI-LIBC3562 // When the target os is WASI, we allow linking with WASI-LIBC
3491 if (options.target.os.tag == .wasi) {3563 if (target.os.tag == .wasi) {
3492 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or3564 const is_exe_or_dyn_lib = output_mode == .Exe or
3493 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);3565 (output_mode == .Lib and link_mode == .Dynamic);
3494 if (is_exe_or_dyn_lib) {3566 if (is_exe_or_dyn_lib) {
3495 const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs;3567 for (wasm.wasi_emulated_libs) |crt_file| {
3496 for (wasi_emulated_libs) |crt_file| {
3497 try positionals.append(try comp.get_libc_crt_file(3568 try positionals.append(try comp.get_libc_crt_file(
3498 arena,3569 arena,
3499 wasi_libc.emulatedLibCRFileLibName(crt_file),3570 wasi_libc.emulatedLibCRFileLibName(crt_file),
3500 ));3571 ));
3501 }3572 }
35023573
3503 if (wasm.base.options.link_libc) {3574 if (link_libc) {
3504 try positionals.append(try comp.get_libc_crt_file(3575 try positionals.append(try comp.get_libc_crt_file(
3505 arena,3576 arena,
3506 wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model),3577 wasi_libc.execModelCrtFileFullName(wasi_exec_model),
3507 ));3578 ));
3508 try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));3579 try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));
3509 }3580 }
35103581
3511 if (wasm.base.options.link_libcpp) {3582 if (link_libcpp) {
3512 try positionals.append(comp.libcxx_static_lib.?.full_object_path);3583 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
3513 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);3584 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
3514 }3585 }
...@@ -3519,7 +3590,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3519,7 +3590,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3519 try positionals.append(path);3590 try positionals.append(path);
3520 }3591 }
35213592
3522 for (options.objects) |object| {3593 for (objects) |object| {
3523 try positionals.append(object.path);3594 try positionals.append(object.path);
3524 }3595 }
35253596
...@@ -3562,7 +3633,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3562,7 +3633,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3562 try wasm.setupExports();3633 try wasm.setupExports();
3563 try wasm.writeToFile(enabled_features, emit_features_count, arena);3634 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) {
3566 // Update the file with the digest. If it fails we can continue; it only3637 // Update the file with the digest. If it fails we can continue; it only
3567 // means that the next invocation will have an unnecessary cache miss.3638 // means that the next invocation will have an unnecessary cache miss.
3568 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {3639 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...@@ -3594,15 +3665,18 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3594 try wasm.populateErrorNameTable();3665 try wasm.populateErrorNameTable();
35953666
3596 // Used for all temporary memory allocated during flushin3667 // 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);
3598 defer arena_instance.deinit();3670 defer arena_instance.deinit();
3599 const arena = arena_instance.allocator();3671 const arena = arena_instance.allocator();
36003672
3673 const objects = wasm.base.comp.objects;
3674
3601 // Positional arguments to the linker such as object files and static archives.3675 // Positional arguments to the linker such as object files and static archives.
3602 var positionals = std.ArrayList([]const u8).init(arena);3676 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| {
3606 positionals.appendAssumeCapacity(object.path);3680 positionals.appendAssumeCapacity(object.path);
3607 }3681 }
36083682
...@@ -3711,6 +3785,10 @@ fn writeToFile(...@@ -3711,6 +3785,10 @@ fn writeToFile(
3711 feature_count: u32,3785 feature_count: u32,
3712 arena: Allocator,3786 arena: Allocator,
3713) !void {3787) !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
3714 // Size of each section header3792 // Size of each section header
3715 const header_size = 5 + 1;3793 const header_size = 5 + 1;
3716 // The amount of sections that will be written3794 // The amount of sections that will be written
...@@ -3719,9 +3797,9 @@ fn writeToFile(...@@ -3719,9 +3797,9 @@ fn writeToFile(
3719 var code_section_index: ?u32 = null;3797 var code_section_index: ?u32 = null;
3720 // Index of the data section. Used to tell relocation table where the section lives.3798 // Index of the data section. Used to tell relocation table where the section lives.
3721 var data_section_index: ?u32 = null;3799 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);
3725 defer binary_bytes.deinit();3803 defer binary_bytes.deinit();
3726 const binary_writer = binary_bytes.writer();3804 const binary_writer = binary_bytes.writer();
37273805
...@@ -3774,8 +3852,8 @@ fn writeToFile(...@@ -3774,8 +3852,8 @@ fn writeToFile(
3774 if (import_memory) {3852 if (import_memory) {
3775 const mem_name = if (is_obj) "__linear_memory" else "memory";3853 const mem_name = if (is_obj) "__linear_memory" else "memory";
3776 const mem_imp: types.Import = .{3854 const mem_imp: types.Import = .{
3777 .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name),3855 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
3778 .name = try wasm.string_table.put(wasm.base.allocator, mem_name),3856 .name = try wasm.string_table.put(gpa, mem_name),
3779 .kind = .{ .memory = wasm.memories.limits },3857 .kind = .{ .memory = wasm.memories.limits },
3780 };3858 };
3781 try wasm.emitImport(binary_writer, mem_imp);3859 try wasm.emitImport(binary_writer, mem_imp);
...@@ -3955,7 +4033,7 @@ fn writeToFile(...@@ -3955,7 +4033,7 @@ fn writeToFile(
3955 var atom_index = wasm.atoms.get(code_index).?;4033 var atom_index = wasm.atoms.get(code_index).?;
39564034
3957 // The code section must be sorted in line with the function order.4035 // 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());
3959 defer sorted_atoms.deinit();4037 defer sorted_atoms.deinit();
39604038
3961 while (true) {4039 while (true) {
...@@ -3966,7 +4044,7 @@ fn writeToFile(...@@ -3966,7 +4044,7 @@ fn writeToFile(
3966 sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions4044 sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions
3967 atom_index = atom.prev orelse break;4045 atom_index = atom.prev orelse break;
3968 }4046 }
3969 std.debug.assert(wasm.functions.count() == sorted_atoms.items.len);4047 assert(wasm.functions.count() == sorted_atoms.items.len);
39704048
3971 const atom_sort_fn = struct {4049 const atom_sort_fn = struct {
3972 fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool {4050 fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool {
...@@ -4086,7 +4164,7 @@ fn writeToFile(...@@ -4086,7 +4164,7 @@ fn writeToFile(
4086 if (!wasm.base.options.strip) {4164 if (!wasm.base.options.strip) {
4087 // The build id must be computed on the main sections only,4165 // The build id must be computed on the main sections only,
4088 // so we have to do it now, before the debug sections.4166 // so we have to do it now, before the debug sections.
4089 switch (wasm.base.options.build_id) {4167 switch (wasm.base.build_id) {
4090 .none => {},4168 .none => {},
4091 .fast => {4169 .fast => {
4092 var id: [16]u8 = undefined;4170 var id: [16]u8 = undefined;
...@@ -4121,7 +4199,7 @@ fn writeToFile(...@@ -4121,7 +4199,7 @@ fn writeToFile(
4121 // try dwarf.writeDbgLineHeader();4199 // try dwarf.writeDbgLineHeader();
4122 // }4200 // }
41234201
4124 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);4202 var debug_bytes = std.ArrayList(u8).init(gpa);
4125 defer debug_bytes.deinit();4203 defer debug_bytes.deinit();
41264204
4127 const DebugSection = struct {4205 const DebugSection = struct {
...@@ -4362,8 +4440,10 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem...@@ -4362,8 +4440,10 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
4362}4440}
43634441
4364fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {4442fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {
4443 const gpa = wasm.base.comp.gpa;
4444
4365 // We must emit subsection size, so first write to a temporary list4445 // 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);
4367 defer section_list.deinit();4447 defer section_list.deinit();
4368 const sub_writer = section_list.writer();4448 const sub_writer = section_list.writer();
43694449
...@@ -4445,12 +4525,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4445,12 +4525,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4445 const tracy = trace(@src());4525 const tracy = trace(@src());
4446 defer tracy.end();4526 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);
4449 defer arena_allocator.deinit();4530 defer arena_allocator.deinit();
4450 const arena = arena_allocator.allocator();4531 const arena = arena_allocator.allocator();
44514532
4452 const directory = wasm.base.options.emit.?.directory; // Just an alias to make it shorter to type.4533 const directory = wasm.base.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});4534 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path});
44544535
4455 // If there is no Zig code to compile, then we should skip flushing the output file because it4536 // If there is no Zig code to compile, then we should skip flushing the output file because it
4456 // will not be part of the linker line anyway.4537 // will not be part of the linker line anyway.
...@@ -4481,11 +4562,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4481,11 +4562,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4481 const id_symlink_basename = "lld.id";4562 const id_symlink_basename = "lld.id";
44824563
4483 var man: Cache.Manifest = undefined;4564 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
4486 var digest: [Cache.hex_digest_len]u8 = undefined;4567 var digest: [Cache.hex_digest_len]u8 = undefined;
44874568
4488 if (!wasm.base.options.disable_lld_caching) {4569 if (!wasm.base.disable_lld_caching) {
4489 man = comp.cache_parent.obtain();4570 man = comp.cache_parent.obtain();
44904571
4491 // We are about to obtain this lock, so here we give other processes a chance first.4572 // 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) !...@@ -4502,13 +4583,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4502 }4583 }
4503 try man.addOptionalFile(module_obj_path);4584 try man.addOptionalFile(module_obj_path);
4504 try man.addOptionalFile(compiler_rt_path);4585 try man.addOptionalFile(compiler_rt_path);
4505 man.hash.addOptionalBytes(wasm.base.options.entry);4586 man.hash.addOptionalBytes(wasm.base.comp.config.entry);
4506 man.hash.addOptional(wasm.base.options.stack_size_override);4587 man.hash.add(wasm.base.stack_size);
4507 man.hash.add(wasm.base.options.build_id);4588 man.hash.add(wasm.base.build_id);
4508 man.hash.add(wasm.base.options.import_memory);4589 man.hash.add(wasm.base.options.import_memory);
4509 man.hash.add(wasm.base.options.export_memory);4590 man.hash.add(wasm.base.options.export_memory);
4510 man.hash.add(wasm.base.options.import_table);4591 man.hash.add(wasm.import_table);
4511 man.hash.add(wasm.base.options.export_table);4592 man.hash.add(wasm.export_table);
4512 man.hash.addOptional(wasm.base.options.initial_memory);4593 man.hash.addOptional(wasm.base.options.initial_memory);
4513 man.hash.addOptional(wasm.base.options.max_memory);4594 man.hash.addOptional(wasm.base.options.max_memory);
4514 man.hash.add(wasm.base.options.shared_memory);4595 man.hash.add(wasm.base.options.shared_memory);
...@@ -4573,7 +4654,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4573,7 +4654,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4573 }4654 }
4574 } else {4655 } else {
4575 // Create an LLD command line and invoke it.4656 // 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);
4577 defer argv.deinit();4658 defer argv.deinit();
4578 // We will invoke ourselves as a child process to gain access to LLD.4659 // We will invoke ourselves as a child process to gain access to LLD.
4579 // This is necessary because LLD does not behave properly as a library -4660 // 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) !...@@ -4598,22 +4679,20 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4598 try argv.append("--export-memory");4679 try argv.append("--export-memory");
4599 }4680 }
46004681
4601 if (wasm.base.options.import_table) {4682 if (wasm.import_table) {
4602 assert(!wasm.base.options.export_table);4683 assert(!wasm.export_table);
4603 try argv.append("--import-table");4684 try argv.append("--import-table");
4604 }4685 }
46054686
4606 if (wasm.base.options.export_table) {4687 if (wasm.export_table) {
4607 assert(!wasm.base.options.import_table);4688 assert(!wasm.import_table);
4608 try argv.append("--export-table");4689 try argv.append("--export-table");
4609 }4690 }
46104691
4611 if (wasm.base.options.gc_sections) |gc| {4692 // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly
4612 // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly4693 // specified it as garbage collection is enabled by default.
4613 // specified it as garbage collection is enabled by default.4694 if (!wasm.base.gc_sections) {
4614 if (!gc) {4695 try argv.append("--no-gc-sections");
4615 try argv.append("--no-gc-sections");
4616 }
4617 }4696 }
46184697
4619 if (wasm.base.options.strip) {4698 if (wasm.base.options.strip) {
...@@ -4662,12 +4741,10 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4662,12 +4741,10 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4662 try argv.append("--no-entry");4741 try argv.append("--no-entry");
4663 }4742 }
46644743
4665 // Increase the default stack size to a more reasonable value of 1MB instead of4744 try argv.appendSlice(&.{
4666 // the default of 1 Wasm page being 64KB, unless overridden by the user.4745 "-z",
4667 try argv.append("-z");4746 try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}),
4668 const stack_size = wasm.base.options.stack_size_override orelse std.wasm.page_size * 16;4747 });
4669 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
4670 try argv.append(arg);
46714748
4672 if (wasm.base.options.import_symbols) {4749 if (wasm.base.options.import_symbols) {
4673 try argv.append("--allow-undefined");4750 try argv.append("--allow-undefined");
...@@ -4681,7 +4758,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4681,7 +4758,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4681 }4758 }
46824759
4683 // XXX - TODO: add when wasm-ld supports --build-id.4760 // XXX - TODO: add when wasm-ld supports --build-id.
4684 // if (wasm.base.options.build_id) {4761 // if (wasm.base.build_id) {
4685 // try argv.append("--build-id=tree");4762 // try argv.append("--build-id=tree");
4686 // }4763 // }
46874764
...@@ -4695,8 +4772,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4695,8 +4772,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4695 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or4772 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or
4696 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);4773 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);
4697 if (is_exe_or_dyn_lib) {4774 if (is_exe_or_dyn_lib) {
4698 const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs;4775 for (wasm.wasi_emulated_libs) |crt_file| {
4699 for (wasi_emulated_libs) |crt_file| {
4700 try argv.append(try comp.get_libc_crt_file(4776 try argv.append(try comp.get_libc_crt_file(
4701 arena,4777 arena,
4702 wasi_libc.emulatedLibCRFileLibName(crt_file),4778 wasi_libc.emulatedLibCRFileLibName(crt_file),
...@@ -4753,7 +4829,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4753,7 +4829,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4753 try argv.append(p);4829 try argv.append(p);
4754 }4830 }
47554831
4756 if (wasm.base.options.verbose_link) {4832 if (wasm.base.comp.verbose_link) {
4757 // Skip over our own name so that the LLD linker name is the first argv item.4833 // Skip over our own name so that the LLD linker name is the first argv item.
4758 Compilation.dump_argv(argv.items[1..]);4834 Compilation.dump_argv(argv.items[1..]);
4759 }4835 }
...@@ -4838,7 +4914,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -4838,7 +4914,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
4838 }4914 }
4839 }4915 }
48404916
4841 if (!wasm.base.options.disable_lld_caching) {4917 if (!wasm.base.disable_lld_caching) {
4842 // Update the file with the digest. If it fails we can continue; it only4918 // Update the file with the digest. If it fails we can continue; it only
4843 // means that the next invocation will have an unnecessary cache miss.4919 // means that the next invocation will have an unnecessary cache miss.
4844 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {4920 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 {...@@ -5113,14 +5189,15 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
5113 if (wasm.getTypeIndex(func_type)) |index| {5189 if (wasm.getTypeIndex(func_type)) |index| {
5114 return index;5190 return index;
5115 }5191 }
5192 const gpa = wasm.base.comp.gpa;
51165193
5117 // functype does not exist.5194 // functype does not exist.
5118 const index = @as(u32, @intCast(wasm.func_types.items.len));5195 const index: u32 = @intCast(wasm.func_types.items.len);
5119 const params = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.params);5196 const params = try gpa.dupe(std.wasm.Valtype, func_type.params);
5120 errdefer wasm.base.allocator.free(params);5197 errdefer gpa.free(params);
5121 const returns = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.returns);5198 const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns);
5122 errdefer wasm.base.allocator.free(returns);5199 errdefer gpa.free(returns);
5123 try wasm.func_types.append(wasm.base.allocator, .{5200 try wasm.func_types.append(gpa, .{
5124 .params = params,5201 .params = params,
5125 .returns = returns,5202 .returns = returns,
5126 });5203 });
...@@ -5131,9 +5208,10 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {...@@ -5131,9 +5208,10 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
5131/// Asserts declaration has an associated `Atom`.5208/// Asserts declaration has an associated `Atom`.
5132/// Returns the index into the list of types.5209/// Returns the index into the list of types.
5133pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {5210pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 {
5211 const gpa = wasm.base.comp.gpa;
5134 const atom_index = wasm.decls.get(decl_index).?;5212 const atom_index = wasm.decls.get(decl_index).?;
5135 const index = try wasm.putOrGetFuncType(func_type);5213 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);
5137 return index;5215 return index;
5138}5216}
51395217
...@@ -5142,8 +5220,7 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s...@@ -5142,8 +5220,7 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
5142fn markReferences(wasm: *Wasm) !void {5220fn markReferences(wasm: *Wasm) !void {
5143 const tracy = trace(@src());5221 const tracy = trace(@src());
5144 defer tracy.end();5222 defer tracy.end();
5145 const do_garbage_collect = wasm.base.options.gc_sections orelse5223 const do_garbage_collect = wasm.base.gc_sections;
5146 (wasm.base.options.output_mode != .Obj);
51475224
5148 for (wasm.resolved_symbols.keys()) |sym_loc| {5225 for (wasm.resolved_symbols.keys()) |sym_loc| {
5149 const sym = sym_loc.getSymbol(wasm);5226 const sym = sym_loc.getSymbol(wasm);
src/main.zig+21-23
...@@ -842,7 +842,7 @@ fn buildOutputType(...@@ -842,7 +842,7 @@ fn buildOutputType(
842 var linker_print_gc_sections: bool = false;842 var linker_print_gc_sections: bool = false;
843 var linker_print_icf_sections: bool = false;843 var linker_print_icf_sections: bool = false;
844 var linker_print_map: bool = false;844 var linker_print_map: bool = false;
845 var linker_opt_bisect_limit: i32 = -1;845 var llvm_opt_bisect_limit: c_int = -1;
846 var linker_z_nocopyreloc = false;846 var linker_z_nocopyreloc = false;
847 var linker_z_nodelete = false;847 var linker_z_nodelete = false;
848 var linker_z_notext = false;848 var linker_z_notext = false;
...@@ -859,7 +859,7 @@ fn buildOutputType(...@@ -859,7 +859,7 @@ fn buildOutputType(
859 var linker_module_definition_file: ?[]const u8 = null;859 var linker_module_definition_file: ?[]const u8 = null;
860 var test_no_exec = false;860 var test_no_exec = false;
861 var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{};861 var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{};
862 var stack_size_override: ?u64 = null;862 var stack_size: ?u64 = null;
863 var image_base_override: ?u64 = null;863 var image_base_override: ?u64 = null;
864 var link_eh_frame_hdr = false;864 var link_eh_frame_hdr = false;
865 var link_emit_relocs = false;865 var link_emit_relocs = false;
...@@ -892,7 +892,7 @@ fn buildOutputType(...@@ -892,7 +892,7 @@ fn buildOutputType(
892 var contains_res_file: bool = false;892 var contains_res_file: bool = false;
893 var reference_trace: ?u32 = null;893 var reference_trace: ?u32 = null;
894 var pdb_out_path: ?[]const u8 = null;894 var pdb_out_path: ?[]const u8 = null;
895 var dwarf_format: ?std.dwarf.Format = null;895 var debug_format: ?link.File.DebugFormat = null;
896 var error_limit: ?Module.ErrorInt = null;896 var error_limit: ?Module.ErrorInt = null;
897 var want_structured_cfg: ?bool = null;897 var want_structured_cfg: ?bool = null;
898 // These are before resolving sysroot.898 // These are before resolving sysroot.
...@@ -1129,10 +1129,7 @@ fn buildOutputType(...@@ -1129,10 +1129,7 @@ fn buildOutputType(
1129 } else if (mem.eql(u8, arg, "--force_undefined")) {1129 } else if (mem.eql(u8, arg, "--force_undefined")) {
1130 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});1130 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
1131 } else if (mem.eql(u8, arg, "--stack")) {1131 } else if (mem.eql(u8, arg, "--stack")) {
1132 const next_arg = args_iter.nextOrFatal();1132 stack_size = parseStackSize(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 };
1136 } else if (mem.eql(u8, arg, "--image-base")) {1133 } else if (mem.eql(u8, arg, "--image-base")) {
1137 const next_arg = args_iter.nextOrFatal();1134 const next_arg = args_iter.nextOrFatal();
1138 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {1135 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
...@@ -1487,9 +1484,9 @@ fn buildOutputType(...@@ -1487,9 +1484,9 @@ fn buildOutputType(
1487 } else if (mem.eql(u8, arg, "-fno-strip")) {1484 } else if (mem.eql(u8, arg, "-fno-strip")) {
1488 mod_opts.strip = false;1485 mod_opts.strip = false;
1489 } else if (mem.eql(u8, arg, "-gdwarf32")) {1486 } else if (mem.eql(u8, arg, "-gdwarf32")) {
1490 dwarf_format = .@"32";1487 debug_format = .{ .dwarf = .@"32" };
1491 } else if (mem.eql(u8, arg, "-gdwarf64")) {1488 } else if (mem.eql(u8, arg, "-gdwarf64")) {
1492 dwarf_format = .@"64";1489 debug_format = .{ .dwarf = .@"64" };
1493 } else if (mem.eql(u8, arg, "-fformatted-panics")) {1490 } else if (mem.eql(u8, arg, "-fformatted-panics")) {
1494 formatted_panics = true;1491 formatted_panics = true;
1495 } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {1492 } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {
...@@ -1511,7 +1508,9 @@ fn buildOutputType(...@@ -1511,7 +1508,9 @@ fn buildOutputType(
1511 } else if (mem.eql(u8, arg, "-fno-builtin")) {1508 } else if (mem.eql(u8, arg, "-fno-builtin")) {
1512 no_builtin = true;1509 no_builtin = true;
1513 } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) {1510 } 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) });
1515 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {1514 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
1516 link_eh_frame_hdr = true;1515 link_eh_frame_hdr = true;
1517 } else if (mem.eql(u8, arg, "--dynamicbase")) {1516 } else if (mem.eql(u8, arg, "--dynamicbase")) {
...@@ -1994,11 +1993,11 @@ fn buildOutputType(...@@ -1994,11 +1993,11 @@ fn buildOutputType(
1994 },1993 },
1995 .gdwarf32 => {1994 .gdwarf32 => {
1996 mod_opts.strip = false;1995 mod_opts.strip = false;
1997 dwarf_format = .@"32";1996 debug_format = .{ .dwarf = .@"32" };
1998 },1997 },
1999 .gdwarf64 => {1998 .gdwarf64 => {
2000 mod_opts.strip = false;1999 mod_opts.strip = false;
2001 dwarf_format = .@"64";2000 debug_format = .{ .dwarf = .@"64" };
2002 },2001 },
2003 .sanitize => {2002 .sanitize => {
2004 if (mem.eql(u8, it.only_arg, "undefined")) {2003 if (mem.eql(u8, it.only_arg, "undefined")) {
...@@ -2257,10 +2256,7 @@ fn buildOutputType(...@@ -2257,10 +2256,7 @@ fn buildOutputType(
2257 } else if (mem.eql(u8, z_arg, "norelro")) {2256 } else if (mem.eql(u8, z_arg, "norelro")) {
2258 linker_z_relro = false;2257 linker_z_relro = false;
2259 } else if (mem.startsWith(u8, z_arg, "stack-size=")) {2258 } else if (mem.startsWith(u8, z_arg, "stack-size=")) {
2260 const next_arg = z_arg["stack-size=".len..];2259 stack_size = parseStackSize(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 };
2264 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {2260 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
2265 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);2261 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
2266 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {2262 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
...@@ -2285,10 +2281,7 @@ fn buildOutputType(...@@ -2285,10 +2281,7 @@ fn buildOutputType(
2285 } else if (mem.eql(u8, arg, "-u")) {2281 } else if (mem.eql(u8, arg, "-u")) {
2286 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});2282 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});
2287 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {2283 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {
2288 const stack_size = linker_args_it.nextOrFatal();2284 stack_size = parseStackSize(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 };
2292 } else if (mem.eql(u8, arg, "--image-base")) {2285 } else if (mem.eql(u8, arg, "--image-base")) {
2293 const image_base = linker_args_it.nextOrFatal();2286 const image_base = linker_args_it.nextOrFatal();
2294 image_base_override = std.fmt.parseUnsigned(u64, image_base, 0) catch |err| {2287 image_base_override = std.fmt.parseUnsigned(u64, image_base, 0) catch |err| {
...@@ -3407,7 +3400,7 @@ fn buildOutputType(...@@ -3407,7 +3400,7 @@ fn buildOutputType(
3407 .linker_print_gc_sections = linker_print_gc_sections,3400 .linker_print_gc_sections = linker_print_gc_sections,
3408 .linker_print_icf_sections = linker_print_icf_sections,3401 .linker_print_icf_sections = linker_print_icf_sections,
3409 .linker_print_map = linker_print_map,3402 .linker_print_map = linker_print_map,
3410 .linker_opt_bisect_limit = linker_opt_bisect_limit,3403 .llvm_opt_bisect_limit = llvm_opt_bisect_limit,
3411 .linker_global_base = linker_global_base,3404 .linker_global_base = linker_global_base,
3412 .linker_export_symbol_names = linker_export_symbol_names.items,3405 .linker_export_symbol_names = linker_export_symbol_names.items,
3413 .linker_z_nocopyreloc = linker_z_nocopyreloc,3406 .linker_z_nocopyreloc = linker_z_nocopyreloc,
...@@ -3430,7 +3423,7 @@ fn buildOutputType(...@@ -3430,7 +3423,7 @@ fn buildOutputType(
3430 .link_eh_frame_hdr = link_eh_frame_hdr,3423 .link_eh_frame_hdr = link_eh_frame_hdr,
3431 .link_emit_relocs = link_emit_relocs,3424 .link_emit_relocs = link_emit_relocs,
3432 .force_undefined_symbols = force_undefined_symbols,3425 .force_undefined_symbols = force_undefined_symbols,
3433 .stack_size_override = stack_size_override,3426 .stack_size = stack_size,
3434 .image_base_override = image_base_override,3427 .image_base_override = image_base_override,
3435 .formatted_panics = formatted_panics,3428 .formatted_panics = formatted_panics,
3436 .function_sections = function_sections,3429 .function_sections = function_sections,
...@@ -3459,7 +3452,7 @@ fn buildOutputType(...@@ -3459,7 +3452,7 @@ fn buildOutputType(
3459 .test_runner_path = test_runner_path,3452 .test_runner_path = test_runner_path,
3460 .disable_lld_caching = !output_to_cache,3453 .disable_lld_caching = !output_to_cache,
3461 .subsystem = subsystem,3454 .subsystem = subsystem,
3462 .dwarf_format = dwarf_format,3455 .debug_format = debug_format,
3463 .debug_compile_errors = debug_compile_errors,3456 .debug_compile_errors = debug_compile_errors,
3464 .enable_link_snapshots = enable_link_snapshots,3457 .enable_link_snapshots = enable_link_snapshots,
3465 .install_name = install_name,3458 .install_name = install_name,
...@@ -7688,3 +7681,8 @@ fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target {...@@ -7688,3 +7681,8 @@ fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target {
7688 return std.zig.system.resolveTargetQuery(target_query) catch |err|7681 return std.zig.system.resolveTargetQuery(target_query) catch |err|
7689 fatal("unable to resolve target: {s}", .{@errorName(err)});7682 fatal("unable to resolve target: {s}", .{@errorName(err)});
7690}7683}
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...@@ -226,7 +226,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
226 .is_native_abi = false,226 .is_native_abi = false,
227 .self_exe_path = comp.self_exe_path,227 .self_exe_path = comp.self_exe_path,
228 .verbose_cc = comp.verbose_cc,228 .verbose_cc = comp.verbose_cc,
229 .verbose_link = comp.bin_file.options.verbose_link,229 .verbose_link = comp.verbose_link,
230 .verbose_air = comp.verbose_air,230 .verbose_air = comp.verbose_air,
231 .verbose_llvm_ir = comp.verbose_llvm_ir,231 .verbose_llvm_ir = comp.verbose_llvm_ir,
232 .verbose_cimport = comp.verbose_cimport,232 .verbose_cimport = comp.verbose_cimport,
src/target.zig+8
...@@ -323,6 +323,14 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool {...@@ -323,6 +323,14 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool {
323 };323 };
324}324}
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
326/// The set of targets that our own self-hosted backends have robust support for.334/// The set of targets that our own self-hosted backends have robust support for.
327/// Used to select between LLVM backend and self-hosted backend when compiling in335/// Used to select between LLVM backend and self-hosted backend when compiling in
328/// debug mode. A given target should only return true here if it is passing greater336/// debug mode. A given target should only return true here if it is passing greater