authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-30 12:09:13-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-10-30 12:09:13-04:00
log5b060ef9d4acab0a92891e83d354f1c8e8e658e5
tree719022194a5bca2d7c2392ca1a3fb3de9ff926bb
parent4174ab9c2c98d798452dd745d5d5dc657d601591
parent0834e696f75d8477e5bc7a2dc49e7d10800039bc
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25558 from jacobly0/elfv2-load-obj

Elf2: start implementing input object loading

18 files changed, 1387 insertions(+), 397 deletions(-)

lib/std/Build/Module.zig+7-4
...@@ -596,10 +596,13 @@ pub fn appendZigProcessFlags(...@@ -596,10 +596,13 @@ pub fn appendZigProcessFlags(
596 "-target", try target.query.zigTriple(b.allocator),596 "-target", try target.query.zigTriple(b.allocator),
597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),
598 });598 });
599599 if (target.query.dynamic_linker) |dynamic_linker| {
600 if (target.query.dynamic_linker.get()) |dynamic_linker| {600 if (dynamic_linker.get()) |dynamic_linker_path| {
601 try zig_args.append("--dynamic-linker");601 try zig_args.append("--dynamic-linker");
602 try zig_args.append(dynamic_linker);602 try zig_args.append(dynamic_linker_path);
603 } else {
604 try zig_args.append("--no-dynamic-linker");
605 }
603 }606 }
604 }607 }
605 }608 }
lib/std/Io/File.zig+4-9
...@@ -434,8 +434,7 @@ pub const Reader = struct {...@@ -434,8 +434,7 @@ pub const Reader = struct {
434 return err;434 return err;
435 };435 };
436 }436 }
437 r.interface.seek = 0;437 r.interface.tossBuffered();
438 r.interface.end = 0;
439 },438 },
440 .failure => return r.seek_err.?,439 .failure => return r.seek_err.?,
441 }440 }
...@@ -467,15 +466,11 @@ pub const Reader = struct {...@@ -467,15 +466,11 @@ pub const Reader = struct {
467 }466 }
468467
469 fn setLogicalPos(r: *Reader, offset: u64) void {468 fn setLogicalPos(r: *Reader, offset: u64) void {
470 const logical_pos = logicalPos(r);469 const logical_pos = r.logicalPos();
471 if (offset < logical_pos or offset >= r.pos) {470 if (offset < logical_pos or offset >= r.pos) {
472 r.interface.seek = 0;471 r.interface.tossBuffered();
473 r.interface.end = 0;
474 r.pos = offset;472 r.pos = offset;
475 } else {473 } else r.interface.toss(@intCast(offset - logical_pos));
476 const logical_delta: usize = @intCast(offset - logical_pos);
477 r.interface.seek += logical_delta;
478 }
479 }474 }
480475
481 /// Number of slices to store on the stack, when trying to send as many byte476 /// Number of slices to store on the stack, when trying to send as many byte
lib/std/Target/Query.zig+12-5
...@@ -46,8 +46,9 @@ android_api_level: ?u32 = null,...@@ -46,8 +46,9 @@ android_api_level: ?u32 = null,
46abi: ?Target.Abi = null,46abi: ?Target.Abi = null,
4747
48/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path48/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
49/// based on the `os_tag`.49/// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
50dynamic_linker: Target.DynamicLinker = .none,50/// linker is used regardless of `os_tag`.
51dynamic_linker: ?Target.DynamicLinker = null,
5152
52/// `null` means default for the cpu/arch/os combo.53/// `null` means default for the cpu/arch/os combo.
53ofmt: ?Target.ObjectFormat = null,54ofmt: ?Target.ObjectFormat = null,
...@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {...@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {
213 const diags = args.diagnostics orelse &dummy_diags;214 const diags = args.diagnostics orelse &dummy_diags;
214215
215 var result: Query = .{216 var result: Query = .{
216 .dynamic_linker = Target.DynamicLinker.init(args.dynamic_linker),217 .dynamic_linker = if (args.dynamic_linker) |dynamic_linker| .init(dynamic_linker) else null,
217 };218 };
218219
219 var it = mem.splitScalar(u8, args.arch_os_abi, '-');220 var it = mem.splitScalar(u8, args.arch_os_abi, '-');
...@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {...@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {
381382
382pub fn isNativeOs(self: Query) bool {383pub fn isNativeOs(self: Query) bool {
383 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and384 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
384 self.dynamic_linker.get() == null and self.glibc_version == null and self.android_api_level == null;385 self.dynamic_linker == null and self.glibc_version == null and self.android_api_level == null;
385}386}
386387
387pub fn isNativeAbi(self: Query) bool {388pub fn isNativeAbi(self: Query) bool {
...@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {...@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {
599 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;600 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
600 if (a.android_api_level != b.android_api_level) return false;601 if (a.android_api_level != b.android_api_level) return false;
601 if (a.abi != b.abi) return false;602 if (a.abi != b.abi) return false;
602 if (!a.dynamic_linker.eql(b.dynamic_linker)) return false;603 if (!dynamicLinkerEqualOpt(a.dynamic_linker, b.dynamic_linker)) return false;
603 if (a.ofmt != b.ofmt) return false;604 if (a.ofmt != b.ofmt) return false;
604605
605 return true;606 return true;
...@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {...@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {
611 return SemanticVersion.order(a.?, b.?) == .eq;612 return SemanticVersion.order(a.?, b.?) == .eq;
612}613}
613614
615fn dynamicLinkerEqualOpt(a: ?Target.DynamicLinker, b: ?Target.DynamicLinker) bool {
616 if (a == null and b == null) return true;
617 if (a == null or b == null) return false;
618 return a.?.eql(b.?);
619}
620
614test parse {621test parse {
615 const io = std.testing.io;622 const io = std.testing.io;
616623
lib/std/c.zig+2-1
...@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {...@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {
7013 LAZY: bool = false,7013 LAZY: bool = false,
7014 NOW: bool = false,7014 NOW: bool = false,
7015 NOLOAD: bool = false,7015 NOLOAD: bool = false,
7016 _3: u5 = 0,7016 DEEPBIND: bool = false,
7017 _4: u4 = 0,
7017 GLOBAL: bool = false,7018 GLOBAL: bool = false,
7018 _9: u3 = 0,7019 _9: u3 = 0,
7019 NODELETE: bool = false,7020 NODELETE: bool = false,
lib/std/elf.zig+46
...@@ -943,11 +943,30 @@ pub const Elf32 = struct {...@@ -943,11 +943,30 @@ pub const Elf32 = struct {
943 unused: u5 = 0,943 unused: u5 = 0,
944 };944 };
945 };945 };
946 pub const Rel = extern struct {
947 offset: Elf32.Addr,
948 info: Info,
949 addend: u0 = 0,
950
951 pub const Info = packed struct(u32) {
952 type: u8,
953 sym: u24,
954 };
955 };
956 pub const Rela = extern struct {
957 offset: Elf32.Addr,
958 info: Info,
959 addend: i32,
960
961 pub const Info = Elf32.Rel.Info;
962 };
946 comptime {963 comptime {
947 assert(@sizeOf(Elf32.Ehdr) == 52);964 assert(@sizeOf(Elf32.Ehdr) == 52);
948 assert(@sizeOf(Elf32.Phdr) == 32);965 assert(@sizeOf(Elf32.Phdr) == 32);
949 assert(@sizeOf(Elf32.Shdr) == 40);966 assert(@sizeOf(Elf32.Shdr) == 40);
950 assert(@sizeOf(Elf32.Sym) == 16);967 assert(@sizeOf(Elf32.Sym) == 16);
968 assert(@sizeOf(Elf32.Rel) == 8);
969 assert(@sizeOf(Elf32.Rela) == 12);
951 }970 }
952};971};
953pub const Elf64 = struct {972pub const Elf64 = struct {
...@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {...@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {
1008 pub const Info = Elf32.Sym.Info;1027 pub const Info = Elf32.Sym.Info;
1009 pub const Other = Elf32.Sym.Other;1028 pub const Other = Elf32.Sym.Other;
1010 };1029 };
1030 pub const Rel = extern struct {
1031 offset: Elf64.Addr,
1032 info: Info,
1033 addend: u0 = 0,
1034
1035 pub const Info = packed struct(u64) {
1036 type: u32,
1037 sym: u32,
1038 };
1039 };
1040 pub const Rela = extern struct {
1041 offset: Elf64.Addr,
1042 info: Info,
1043 addend: i64,
1044
1045 pub const Info = Elf64.Rel.Info;
1046 };
1011 comptime {1047 comptime {
1012 assert(@sizeOf(Elf64.Ehdr) == 64);1048 assert(@sizeOf(Elf64.Ehdr) == 64);
1013 assert(@sizeOf(Elf64.Phdr) == 56);1049 assert(@sizeOf(Elf64.Phdr) == 56);
1014 assert(@sizeOf(Elf64.Shdr) == 64);1050 assert(@sizeOf(Elf64.Shdr) == 64);
1015 assert(@sizeOf(Elf64.Sym) == 24);1051 assert(@sizeOf(Elf64.Sym) == 24);
1052 assert(@sizeOf(Elf64.Rel) == 16);
1053 assert(@sizeOf(Elf64.Rela) == 24);
1016 }1054 }
1017};1055};
1018pub const ElfN = switch (@sizeOf(usize)) {1056pub const ElfN = switch (@sizeOf(usize)) {
...@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {...@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {
1428 _,1466 _,
14291467
1430 pub const NUM = @typeInfo(CLASS).@"enum".fields.len;1468 pub const NUM = @typeInfo(CLASS).@"enum".fields.len;
1469
1470 pub fn ElfN(comptime class: CLASS) type {
1471 return switch (class) {
1472 .NONE, _ => comptime unreachable,
1473 .@"32" => Elf32,
1474 .@"64" => Elf64,
1475 };
1476 }
1431};1477};
14321478
1433/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)`1479/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)`
lib/std/start.zig+1-1
...@@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
562 // Apply the initial relocations as early as possible in the startup process. We cannot562 // Apply the initial relocations as early as possible in the startup process. We cannot
563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
564 // so this must be fully inlined.564 // so this must be fully inlined.
565 if (builtin.position_independent_executable) {565 if (builtin.link_mode == .static and builtin.position_independent_executable) {
566 @call(.always_inline, std.pie.relocate, .{phdrs});566 @call(.always_inline, std.pie.relocate, .{phdrs});
567 }567 }
568568
lib/std/zig/system.zig+4-7
...@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(...@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(
585 .os = os,585 .os = os,
586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
587 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),587 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
588 .dynamic_linker = query.dynamic_linker,588 .dynamic_linker = query.dynamic_linker orelse .none,
589 };589 };
590 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC590 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
591 const look_for_ld = query.dynamic_linker.get() == null;591 const look_for_ld = query.dynamic_linker == null;
592592
593 var got_dyn_section: bool = false;593 var got_dyn_section: bool = false;
594 {594 {
...@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ...@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
938 const is_linux = builtin.target.os.tag == .linux;938 const is_linux = builtin.target.os.tag == .linux;
939 const is_illumos = builtin.target.os.tag == .illumos;939 const is_illumos = builtin.target.os.tag == .illumos;
940 const is_darwin = builtin.target.os.tag.isDarwin();940 const is_darwin = builtin.target.os.tag.isDarwin();
941 const have_all_info = query.dynamic_linker.get() != null and941 const have_all_info = query.dynamic_linker != null and
942 query.abi != null and (!is_linux or query.abi.?.isGnu());942 query.abi != null and (!is_linux or query.abi.?.isGnu());
943 const os_is_non_native = query.os_tag != null;943 const os_is_non_native = query.os_tag != null;
944 // The illumos environment is always the same.944 // The illumos environment is always the same.
...@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer...@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
1126 .os = os,1126 .os = os,
1127 .abi = abi,1127 .abi = abi,
1128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),1128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
1129 .dynamic_linker = if (query.dynamic_linker.get() == null)1129 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
1130 Target.DynamicLinker.standard(cpu, os, abi)
1131 else
1132 query.dynamic_linker,
1133 };1130 };
1134}1131}
11351132
src/Compilation.zig+4-29
...@@ -258,8 +258,6 @@ test_filters: []const []const u8,...@@ -258,8 +258,6 @@ test_filters: []const []const u8,
258258
259link_task_wait_group: WaitGroup = .{},259link_task_wait_group: WaitGroup = .{},
260link_prog_node: std.Progress.Node = .none,260link_prog_node: std.Progress.Node = .none,
261link_const_prog_node: std.Progress.Node = .none,
262link_synth_prog_node: std.Progress.Node = .none,
263261
264llvm_opt_bisect_limit: c_int,262llvm_opt_bisect_limit: c_int,
265263
...@@ -1991,7 +1989,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1991,7 +1989,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1991 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;1989 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;
1992 },1990 },
1993 }1991 }
1994 if (options.config.use_new_linker) break :s .zcu;
1995 }1992 }
1996 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm1993 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
1997 if (is_exe_or_dyn_lib) break :s .lib;1994 if (is_exe_or_dyn_lib) break :s .lib;
...@@ -3066,35 +3063,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3066,35 +3063,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3066 // we also want it around during `flush`.3063 // we also want it around during `flush`.
3067 if (comp.bin_file) |lf| {3064 if (comp.bin_file) |lf| {
3068 comp.link_prog_node = main_progress_node.start("Linking", 0);3065 comp.link_prog_node = main_progress_node.start("Linking", 0);
3069 if (lf.cast(.elf2)) |elf| {3066 lf.startProgress(comp.link_prog_node);
3070 comp.link_prog_node.increaseEstimatedTotalItems(3);
3071 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3072 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
3073 elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);
3074 } else if (lf.cast(.coff2)) |coff| {
3075 comp.link_prog_node.increaseEstimatedTotalItems(3);
3076 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3077 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
3078 coff.mf.update_prog_node = comp.link_prog_node.start("Relocations", coff.mf.updates.items.len);
3079 }
3080 }3067 }
3081 defer {3068 defer if (comp.bin_file) |lf| {
3069 lf.endProgress();
3082 comp.link_prog_node.end();3070 comp.link_prog_node.end();
3083 comp.link_prog_node = .none;3071 comp.link_prog_node = .none;
3084 comp.link_const_prog_node.end();3072 };
3085 comp.link_const_prog_node = .none;
3086 comp.link_synth_prog_node.end();
3087 comp.link_synth_prog_node = .none;
3088 if (comp.bin_file) |lf| {
3089 if (lf.cast(.elf2)) |elf| {
3090 elf.mf.update_prog_node.end();
3091 elf.mf.update_prog_node = .none;
3092 } else if (lf.cast(.coff2)) |coff| {
3093 coff.mf.update_prog_node.end();
3094 coff.mf.update_prog_node = .none;
3095 }
3096 }
3097 }
30983073
3099 try comp.performAllTheWork(main_progress_node);3074 try comp.performAllTheWork(main_progress_node);
31003075
src/Compilation/Config.zig+24-7
...@@ -123,6 +123,7 @@ pub const ResolveError = error{...@@ -123,6 +123,7 @@ pub const ResolveError = error{
123 WasiExecModelRequiresWasi,123 WasiExecModelRequiresWasi,
124 SharedMemoryIsWasmOnly,124 SharedMemoryIsWasmOnly,
125 ObjectFilesCannotShareMemory,125 ObjectFilesCannotShareMemory,
126 ObjectFilesCannotSpecifyDynamicLinker,
126 SharedMemoryRequiresAtomicsAndBulkMemory,127 SharedMemoryRequiresAtomicsAndBulkMemory,
127 ThreadsRequireSharedMemory,128 ThreadsRequireSharedMemory,
128 EmittingLlvmModuleRequiresLlvmBackend,129 EmittingLlvmModuleRequiresLlvmBackend,
...@@ -131,6 +132,7 @@ pub const ResolveError = error{...@@ -131,6 +132,7 @@ pub const ResolveError = error{
131 EmittingBinaryRequiresLlvmLibrary,132 EmittingBinaryRequiresLlvmLibrary,
132 LldIncompatibleObjectFormat,133 LldIncompatibleObjectFormat,
133 LldCannotIncrementallyLink,134 LldCannotIncrementallyLink,
135 LldCannotSpecifyDynamicLinkerForSharedLibraries,
134 LtoRequiresLld,136 LtoRequiresLld,
135 SanitizeThreadRequiresLibCpp,137 SanitizeThreadRequiresLibCpp,
136 LibCRequiresLibUnwind,138 LibCRequiresLibUnwind,
...@@ -142,6 +144,7 @@ pub const ResolveError = error{...@@ -142,6 +144,7 @@ pub const ResolveError = error{
142 TargetCannotStaticLinkExecutables,144 TargetCannotStaticLinkExecutables,
143 LibCRequiresDynamicLinking,145 LibCRequiresDynamicLinking,
144 SharedLibrariesRequireDynamicLinking,146 SharedLibrariesRequireDynamicLinking,
147 DynamicLinkingWithLldRequiresSharedLibraries,
145 ExportMemoryAndDynamicIncompatible,148 ExportMemoryAndDynamicIncompatible,
146 DynamicLibraryPrecludesPie,149 DynamicLibraryPrecludesPie,
147 TargetRequiresPie,150 TargetRequiresPie,
...@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {
274 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;277 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
275 break :b .dynamic;278 break :b .dynamic;
276 }279 }
277 // When creating a executable that links to system libraries, we
278 // require dynamic linking, but we must not link static libraries
279 // or object files dynamically!
280 if (options.any_dyn_libs and options.output_mode == .Exe) {
281 if (options.link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
282 break :b .dynamic;
283 }
284280
285 if (options.link_mode) |link_mode| break :b link_mode;281 if (options.link_mode) |link_mode| break :b link_mode;
286282
283 if (options.any_dyn_libs) break :b .dynamic;
284
287 if (explicitly_exe_or_dyn_lib and link_libc) {285 if (explicitly_exe_or_dyn_lib and link_libc) {
288 // When using the native glibc/musl ABI, dynamic linking is usually what people want.286 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
289 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {287 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
...@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {
425 break :b use_llvm;423 break :b use_llvm;
426 };424 };
427425
426 switch (options.output_mode) {
427 .Exe => if (options.any_dyn_libs) {
428 // When creating a executable that links to system libraries, we
429 // require dynamic linking, but we must not link static libraries
430 // or object files dynamically!
431 if (link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
432 } else if (use_lld and !link_libc and !link_libcpp and !link_libunwind) {
433 // Lld does not support creating dynamic executables when not
434 // linking to any shared libraries.
435 if (link_mode == .dynamic) return error.DynamicLinkingWithLldRequiresSharedLibraries;
436 },
437 .Lib => if (use_lld and options.resolved_target.is_explicit_dynamic_linker) {
438 return error.LldCannotSpecifyDynamicLinkerForSharedLibraries;
439 },
440 .Obj => if (options.resolved_target.is_explicit_dynamic_linker) {
441 return error.ObjectFilesCannotSpecifyDynamicLinker;
442 },
443 }
444
428 const use_new_linker = b: {445 const use_new_linker = b: {
429 if (use_lld) {446 if (use_lld) {
430 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;447 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;
src/codegen/x86_64/Emit.zig+14-10
...@@ -182,6 +182,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -182,6 +182,10 @@ pub fn emitMir(emit: *Emit) Error!void {
182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
184 .name = extern_func.toSlice(&emit.lower.mir).?,184 .name = extern_func.toSlice(&emit.lower.mir).?,
185 .lib_name = switch (comp.compiler_rt_strat) {
186 .none, .lib, .obj, .zcu => null,
187 .dyn_lib => "compiler_rt",
188 },
185 .type = .FUNC,189 .type = .FUNC,
186 })) else if (emit.bin_file.cast(.macho)) |macho_file|190 })) else if (emit.bin_file.cast(.macho)) |macho_file|
187 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)191 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
...@@ -217,9 +221,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -217,9 +221,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217 }, emit.lower.target), reloc_info),221 }, emit.lower.target), reloc_info),
218 .mov => try emit.encodeInst(try .new(.none, .mov, &.{222 .mov => try emit.encodeInst(try .new(.none, .mov, &.{
219 lowered_inst.ops[0],223 lowered_inst.ops[0],
220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{224 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
221 .base = .{ .reg = .ds },
222 }) },
223 }, emit.lower.target), reloc_info),225 }, emit.lower.target), reloc_info),
224 else => unreachable,226 else => unreachable,
225 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {227 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {
...@@ -322,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -322,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {
322 }, emit.lower.target), &.{.{324 }, emit.lower.target), &.{.{
323 .op_index = 0,325 .op_index = 0,
324 .target = .{326 .target = .{
325 .index = if (emit.bin_file.cast(.elf)) |elf_file|327 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
326 try elf_file.getGlobalSymbol("__tls_get_addr", null)328 "__tls_get_addr",
327 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{329 if (comp.config.link_libc) "c" else null,
330 ) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
328 .name = "__tls_get_addr",331 .name = "__tls_get_addr",
332 .lib_name = if (comp.config.link_libc) "c" else null,
329 .type = .FUNC,333 .type = .FUNC,
330 })) else unreachable,334 })) else unreachable,
331 .is_extern = true,335 .is_extern = true,
...@@ -720,7 +724,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -720,7 +724,7 @@ pub fn emitMir(emit: *Emit) Error!void {
720724
721 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{725 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
722 .r_offset = table_reloc.source_offset,726 .r_offset = table_reloc.source_offset,
723 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),727 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32S"),
724 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,728 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
725 }, zo);729 }, zo);
726 for (emit.lower.mir.table) |entry| {730 for (emit.lower.mir.table) |entry| {
...@@ -738,7 +742,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -738,7 +742,7 @@ pub fn emitMir(emit: *Emit) Error!void {
738 table_reloc.source_offset,742 table_reloc.source_offset,
739 @enumFromInt(emit.atom_index),743 @enumFromInt(emit.atom_index),
740 @as(i64, table_offset) + table_reloc.target_offset,744 @as(i64, table_offset) + table_reloc.target_offset,
741 .{ .X86_64 = .@"32" },745 .{ .X86_64 = .@"32S" },
742 );746 );
743 for (emit.lower.mir.table) |entry| {747 for (emit.lower.mir.table) |entry| {
744 try elf.addReloc(748 try elf.addReloc(
...@@ -824,7 +828,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -824,7 +828,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
824 const zo = elf_file.zigObjectPtr().?;828 const zo = elf_file.zigObjectPtr().?;
825 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;829 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
826 const r_type: std.elf.R_X86_64 = if (!emit.pic)830 const r_type: std.elf.R_X86_64 = if (!emit.pic)
827 .@"32"831 .@"32S"
828 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)832 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)
829 .GOTPCREL833 .GOTPCREL
830 else834 else
...@@ -855,7 +859,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -855,7 +859,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
855 end_offset - 4,859 end_offset - 4,
856 @enumFromInt(reloc.target.index),860 @enumFromInt(reloc.target.index),
857 reloc.off,861 reloc.off,
858 .{ .X86_64 = .@"32" },862 .{ .X86_64 = .@"32S" },
859 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(863 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
860 @enumFromInt(emit.atom_index),864 @enumFromInt(emit.atom_index),
861 end_offset - 4,865 end_offset - 4,
src/link.zig+26-22
...@@ -571,6 +571,26 @@ pub const File = struct {...@@ -571,6 +571,26 @@ pub const File = struct {
571 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;571 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
572 }572 }
573573
574 pub fn startProgress(base: *File, prog_node: std.Progress.Node) void {
575 switch (base.tag) {
576 else => {},
577 inline .elf2, .coff2 => |tag| {
578 dev.check(tag.devFeature());
579 return @as(*tag.Type(), @fieldParentPtr("base", base)).startProgress(prog_node);
580 },
581 }
582 }
583
584 pub fn endProgress(base: *File) void {
585 switch (base.tag) {
586 else => {},
587 inline .elf2, .coff2 => |tag| {
588 dev.check(tag.devFeature());
589 return @as(*tag.Type(), @fieldParentPtr("base", base)).endProgress();
590 },
591 }
592 }
593
574 pub fn makeWritable(base: *File) !void {594 pub fn makeWritable(base: *File) !void {
575 dev.check(.make_writable);595 dev.check(.make_writable);
576 const comp = base.comp;596 const comp = base.comp;
...@@ -620,10 +640,10 @@ pub const File = struct {...@@ -620,10 +640,10 @@ pub const File = struct {
620 &coff.mf640 &coff.mf
621 else641 else
622 unreachable;642 unreachable;
623 mf.file = .adaptFromNewApi(try Io.Dir.openFile(base.emit.root_dir.handle.adaptToNewApi(), io, base.emit.sub_path, .{643 mf.file = try base.emit.root_dir.handle.adaptToNewApi().openFile(io, base.emit.sub_path, .{
624 .mode = .read_write,644 .mode = .read_write,
625 }));645 });
626 base.file = mf.file;646 base.file = .adaptFromNewApi(mf.file);
627 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));647 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
628 },648 },
629 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),649 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
...@@ -648,6 +668,7 @@ pub const File = struct {...@@ -648,6 +668,7 @@ pub const File = struct {
648 pub fn makeExecutable(base: *File) !void {668 pub fn makeExecutable(base: *File) !void {
649 dev.check(.make_executable);669 dev.check(.make_executable);
650 const comp = base.comp;670 const comp = base.comp;
671 const io = comp.io;
651 switch (comp.config.output_mode) {672 switch (comp.config.output_mode) {
652 .Obj => return,673 .Obj => return,
653 .Lib => switch (comp.config.link_mode) {674 .Lib => switch (comp.config.link_mode) {
...@@ -698,8 +719,8 @@ pub const File = struct {...@@ -698,8 +719,8 @@ pub const File = struct {
698 unreachable;719 unreachable;
699 mf.unmap();720 mf.unmap();
700 assert(mf.file.handle == f.handle);721 assert(mf.file.handle == f.handle);
722 mf.file.close(io);
701 mf.file = undefined;723 mf.file = undefined;
702 f.close();
703 base.file = null;724 base.file = null;
704 },725 },
705 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),726 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
...@@ -1120,7 +1141,7 @@ pub const File = struct {...@@ -1120,7 +1141,7 @@ pub const File = struct {
1120 pub fn loadInput(base: *File, input: Input) anyerror!void {1141 pub fn loadInput(base: *File, input: Input) anyerror!void {
1121 if (base.tag == .lld) return;1142 if (base.tag == .lld) return;
1122 switch (base.tag) {1143 switch (base.tag) {
1123 inline .elf, .wasm => |tag| {1144 inline .elf, .elf2, .wasm => |tag| {
1124 dev.check(tag.devFeature());1145 dev.check(tag.devFeature());
1125 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);1146 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1126 },1147 },
...@@ -1281,9 +1302,6 @@ pub const PrelinkTask = union(enum) {...@@ -1281,9 +1302,6 @@ pub const PrelinkTask = union(enum) {
1281 /// Tells the linker to load a shared library, possibly one that is a1302 /// Tells the linker to load a shared library, possibly one that is a
1282 /// GNU ld script.1303 /// GNU ld script.
1283 load_dso: Path,1304 load_dso: Path,
1284 /// Tells the linker to load an input which could be an object file,
1285 /// archive, or shared library.
1286 load_input: Input,
1287};1305};
1288pub const ZcuTask = union(enum) {1306pub const ZcuTask = union(enum) {
1289 /// Write the constant value for a Decl to the output file.1307 /// Write the constant value for a Decl to the output file.
...@@ -1461,20 +1479,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1461,20 +1479,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1461 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),1479 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
1462 };1480 };
1463 },1481 },
1464 .load_input => |input| {
1465 const prog_node = comp.link_prog_node.start("Parse Input", 0);
1466 defer prog_node.end();
1467 base.loadInput(input) catch |err| switch (err) {
1468 error.LinkFailure => return, // error reported via link_diags
1469 else => |e| {
1470 if (input.path()) |path| {
1471 diags.addParseError(path, "failed to parse linker input: {s}", .{@errorName(e)});
1472 } else {
1473 diags.addError("failed to {s}: {s}", .{ input.taskName(), @errorName(e) });
1474 }
1475 },
1476 };
1477 },
1478 }1482 }
1479}1483}
1480pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {1484pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
src/link/Coff.zig+40-16
...@@ -26,6 +26,8 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -26,6 +26,8 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
26 src_loc: Zcu.LazySrcLoc,26 src_loc: Zcu.LazySrcLoc,
27}),27}),
28relocs: std.ArrayList(Reloc),28relocs: std.ArrayList(Reloc),
29const_prog_node: std.Progress.Node,
30synth_prog_node: std.Progress.Node,
2931
30pub const default_file_alignment: u16 = 0x200;32pub const default_file_alignment: u16 = 0x200;
31pub const default_size_of_stack_reserve: u32 = 0x1000000;33pub const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -630,11 +632,11 @@ fn create(...@@ -630,11 +632,11 @@ fn create(
630 };632 };
631633
632 const coff = try arena.create(Coff);634 const coff = try arena.create(Coff);
633 const file = try path.root_dir.handle.createFile(path.sub_path, .{635 const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{
634 .read = true,636 .read = true,
635 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),637 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
636 });638 });
637 errdefer file.close();639 errdefer file.close(comp.io);
638 coff.* = .{640 coff.* = .{
639 .base = .{641 .base = .{
640 .tag = .coff2,642 .tag = .coff2,
...@@ -642,7 +644,7 @@ fn create(...@@ -642,7 +644,7 @@ fn create(
642 .comp = comp,644 .comp = comp,
643 .emit = path,645 .emit = path,
644646
645 .file = file,647 .file = .adaptFromNewApi(file),
646 .gc_sections = false,648 .gc_sections = false,
647 .print_gc_sections = false,649 .print_gc_sections = false,
648 .build_id = .none,650 .build_id = .none,
...@@ -671,6 +673,8 @@ fn create(...@@ -671,6 +673,8 @@ fn create(
671 }),673 }),
672 .pending_uavs = .empty,674 .pending_uavs = .empty,
673 .relocs = .empty,675 .relocs = .empty,
676 .const_prog_node = .none,
677 .synth_prog_node = .none,
674 };678 };
675 errdefer coff.deinit();679 errdefer coff.deinit();
676680
...@@ -973,6 +977,26 @@ fn initHeaders(...@@ -973,6 +977,26 @@ fn initHeaders(
973 assert(coff.nodes.len == expected_nodes_len);977 assert(coff.nodes.len == expected_nodes_len);
974}978}
975979
980pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {
981 prog_node.increaseEstimatedTotalItems(3);
982 coff.const_prog_node = prog_node.start("Constants", coff.pending_uavs.count());
983 coff.synth_prog_node = prog_node.start("Synthetics", count: {
984 var count = coff.globals.count() - coff.global_pending_index;
985 for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
986 break :count count;
987 });
988 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);
989}
990
991pub fn endProgress(coff: *Coff) void {
992 coff.mf.update_prog_node.end();
993 coff.mf.update_prog_node = .none;
994 coff.synth_prog_node.end();
995 coff.synth_prog_node = .none;
996 coff.const_prog_node.end();
997 coff.const_prog_node = .none;
998}
999
976fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {1000fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
977 return coff.nodes.get(@intFromEnum(ni));1001 return coff.nodes.get(@intFromEnum(ni));
978}1002}
...@@ -1172,7 +1196,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo...@@ -1172,7 +1196,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo
1172 });1196 });
1173 if (!sym_gop.found_existing) {1197 if (!sym_gop.found_existing) {
1174 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();1198 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
1175 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1199 coff.synth_prog_node.increaseEstimatedTotalItems(1);
1176 }1200 }
1177 return sym_gop.value_ptr.*;1201 return sym_gop.value_ptr.*;
1178}1202}
...@@ -1250,7 +1274,7 @@ pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {...@@ -1250,7 +1274,7 @@ pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {
1250 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);1274 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1251 if (!sym_gop.found_existing) {1275 if (!sym_gop.found_existing) {
1252 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();1276 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();
1253 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1277 coff.synth_prog_node.increaseEstimatedTotalItems(1);
1254 }1278 }
1255 return sym_gop.value_ptr.*;1279 return sym_gop.value_ptr.*;
1256}1280}
...@@ -1585,7 +1609,7 @@ pub fn lowerUav(...@@ -1585,7 +1609,7 @@ pub fn lowerUav(
1585 .alignment = uav_align,1609 .alignment = uav_align,
1586 .src_loc = src_loc,1610 .src_loc = src_loc,
1587 };1611 };
1588 coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);1612 coff.const_prog_node.increaseEstimatedTotalItems(1);
1589 }1613 }
1590 }1614 }
1591 return .{ .sym_index = @intFromEnum(si) };1615 return .{ .sym_index = @intFromEnum(si) };
...@@ -1726,17 +1750,16 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1726,17 +1750,16 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1726 const comp = coff.base.comp;1750 const comp = coff.base.comp;
1727 task: {1751 task: {
1728 while (coff.pending_uavs.pop()) |pending_uav| {1752 while (coff.pending_uavs.pop()) |pending_uav| {
1729 const sub_prog_node =1753 const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key });
1730 coff.idleProgNode(tid, comp.link_const_prog_node, .{ .uav = pending_uav.key });
1731 defer sub_prog_node.end();1754 defer sub_prog_node.end();
1732 coff.flushUav(1755 coff.flushUav(
1733 .{ .zcu = coff.base.comp.zcu.?, .tid = tid },1756 .{ .zcu = comp.zcu.?, .tid = tid },
1734 pending_uav.key,1757 pending_uav.key,
1735 pending_uav.value.alignment,1758 pending_uav.value.alignment,
1736 pending_uav.value.src_loc,1759 pending_uav.value.src_loc,
1737 ) catch |err| switch (err) {1760 ) catch |err| switch (err) {
1738 error.OutOfMemory => return error.OutOfMemory,1761 error.OutOfMemory => return error.OutOfMemory,
1739 else => |e| return coff.base.comp.link_diags.fail(1762 else => |e| return comp.link_diags.fail(
1740 "linker failed to lower constant: {t}",1763 "linker failed to lower constant: {t}",
1741 .{e},1764 .{e},
1742 ),1765 ),
...@@ -1744,17 +1767,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1744,17 +1767,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1744 break :task;1767 break :task;
1745 }1768 }
1746 if (coff.global_pending_index < coff.globals.count()) {1769 if (coff.global_pending_index < coff.globals.count()) {
1747 const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid };1770 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
1748 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);1771 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);
1749 coff.global_pending_index += 1;1772 coff.global_pending_index += 1;
1750 const sub_prog_node = comp.link_synth_prog_node.start(1773 const sub_prog_node = coff.synth_prog_node.start(
1751 gmi.globalName(coff).name.toSlice(coff),1774 gmi.globalName(coff).name.toSlice(coff),
1752 0,1775 0,
1753 );1776 );
1754 defer sub_prog_node.end();1777 defer sub_prog_node.end();
1755 coff.flushGlobal(pt, gmi) catch |err| switch (err) {1778 coff.flushGlobal(pt, gmi) catch |err| switch (err) {
1756 error.OutOfMemory => return error.OutOfMemory,1779 error.OutOfMemory => return error.OutOfMemory,
1757 else => |e| return coff.base.comp.link_diags.fail(1780 else => |e| return comp.link_diags.fail(
1758 "linker failed to lower constant: {t}",1781 "linker failed to lower constant: {t}",
1759 .{e},1782 .{e},
1760 ),1783 ),
...@@ -1763,7 +1786,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1763,7 +1786,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1763 }1786 }
1764 var lazy_it = coff.lazy.iterator();1787 var lazy_it = coff.lazy.iterator();
1765 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {1788 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
1766 const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid };1789 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
1767 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };1790 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
1768 lazy.value.pending_index += 1;1791 lazy.value.pending_index += 1;
1769 const kind = switch (lmr.kind) {1792 const kind = switch (lmr.kind) {
...@@ -1771,7 +1794,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1771,7 +1794,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1771 .const_data => "data",1794 .const_data => "data",
1772 };1795 };
1773 var name: [std.Progress.Node.max_name_len]u8 = undefined;1796 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1774 const sub_prog_node = comp.link_synth_prog_node.start(1797 const sub_prog_node = coff.synth_prog_node.start(
1775 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{1798 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1776 kind,1799 kind,
1777 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),1800 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),
...@@ -1781,7 +1804,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1781,7 +1804,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1781 defer sub_prog_node.end();1804 defer sub_prog_node.end();
1782 coff.flushLazy(pt, lmr) catch |err| switch (err) {1805 coff.flushLazy(pt, lmr) catch |err| switch (err) {
1783 error.OutOfMemory => return error.OutOfMemory,1806 error.OutOfMemory => return error.OutOfMemory,
1784 else => |e| return coff.base.comp.link_diags.fail(1807 else => |e| return comp.link_diags.fail(
1785 "linker failed to lower lazy {s}: {t}",1808 "linker failed to lower lazy {s}: {t}",
1786 .{ kind, e },1809 .{ kind, e },
1787 ),1810 ),
...@@ -1802,6 +1825,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1802,6 +1825,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1802 }1825 }
1803 }1826 }
1804 if (coff.pending_uavs.count() > 0) return true;1827 if (coff.pending_uavs.count() > 0) return true;
1828 if (coff.globals.count() > coff.global_pending_index) return true;
1805 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;1829 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
1806 if (coff.mf.updates.items.len > 0) return true;1830 if (coff.mf.updates.items.len > 0) return true;
1807 return false;1831 return false;
src/link/Elf.zig+11-7
...@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {
1882 const comp = self.base.comp;1882 const comp = self.base.comp;
1883 const target = self.getTarget();1883 const target = self.getTarget();
1884 const ptr_size = self.ptrWidthBytes();1884 const ptr_size = self.ptrWidthBytes();
1885 const shared_objects = self.shared_objects.values();
18861885
1887 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {1886 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
1888 .Exe => true,1887 .Exe => true,
1889 .Lib => comp.config.link_mode == .dynamic,1888 .Lib => comp.config.link_mode == .dynamic,
1890 .Obj => false,1889 .Obj => false,
1891 };1890 };
1892 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);1891 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib;
1893
1894 const needs_interp = have_dynamic_linker and
1895 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
18961892
1897 const needs_eh_frame = blk: {1893 const needs_eh_frame = blk: {
1898 if (self.zigObjectPtr()) |zo|1894 if (self.zigObjectPtr()) |zo|
...@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {
2004 });2000 });
2005 }2001 }
20062002
2007 if (needs_interp and self.section_indexes.interp == null) {2003 if (needs_interp: {
2004 if (comp.config.link_mode == .static) break :needs_interp false;
2005 if (target.dynamic_linker.get() == null) break :needs_interp false;
2006 break :needs_interp switch (comp.config.output_mode) {
2007 .Exe => true,
2008 .Lib => comp.root_mod.resolved_target.is_explicit_dynamic_linker,
2009 .Obj => false,
2010 };
2011 } and self.section_indexes.interp == null) {
2008 self.section_indexes.interp = try self.addSection(.{2012 self.section_indexes.interp = try self.addSection(.{
2009 .name = try self.insertShString(".interp"),2013 .name = try self.insertShString(".interp"),
2010 .type = elf.SHT_PROGBITS,2014 .type = elf.SHT_PROGBITS,
...@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {
2013 });2017 });
2014 }2018 }
20152019
2016 if (self.isEffectivelyDynLib() or shared_objects.len > 0 or comp.config.pie) {2020 if (have_dynamic_linker or comp.config.pie or self.isEffectivelyDynLib()) {
2017 if (self.section_indexes.dynstrtab == null) {2021 if (self.section_indexes.dynstrtab == null) {
2018 self.section_indexes.dynstrtab = try self.addSection(.{2022 self.section_indexes.dynstrtab = try self.addSection(.{
2019 .name = try self.insertShString(".dynstr"),2023 .name = try self.insertShString(".dynstr"),
src/link/Elf/Archive.zig+1-3
...@@ -34,8 +34,6 @@ pub fn parse(...@@ -34,8 +34,6 @@ pub fn parse(
34 defer strtab.deinit(gpa);34 defer strtab.deinit(gpa);
3535
36 while (pos < size) {36 while (pos < size) {
37 pos = mem.alignForward(usize, pos, 2);
38
39 var hdr: elf.ar_hdr = undefined;37 var hdr: elf.ar_hdr = undefined;
40 {38 {
41 const n = try handle.preadAll(mem.asBytes(&hdr), pos);39 const n = try handle.preadAll(mem.asBytes(&hdr), pos);
...@@ -50,7 +48,7 @@ pub fn parse(...@@ -50,7 +48,7 @@ pub fn parse(
50 }48 }
5149
52 const obj_size = try hdr.size();50 const obj_size = try hdr.size();
53 defer pos += obj_size;51 defer pos = std.mem.alignForward(usize, pos + obj_size, 2);
5452
55 if (hdr.isSymtab() or hdr.isSymtab64()) continue;53 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
56 if (hdr.isStrtab()) {54 if (hdr.isStrtab()) {
src/link/Elf2.zig+1138-249
...@@ -1,11 +1,27 @@...@@ -1,11 +1,27 @@
1base: link.File,1base: link.File,
2options: link.File.OpenOptions,
2mf: MappedFile,3mf: MappedFile,
3known: Node.Known,4ni: Node.Known,
4nodes: std.MultiArrayList(Node),5nodes: std.MultiArrayList(Node),
5phdrs: std.ArrayList(MappedFile.Node.Index),6phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,
6symtab: std.ArrayList(Symbol),8symtab: std.ArrayList(Symbol),
7shstrtab: StringTable,9shstrtab: StringTable,
8strtab: StringTable,10strtab: StringTable,
11dynsym: std.ArrayList(Symbol.Index),
12dynstr: StringTable,
13needed: std.AutoArrayHashMapUnmanaged(u32, void),
14inputs: std.ArrayList(struct {
15 path: std.Build.Cache.Path,
16 member: ?[]const u8,
17 si: Symbol.Index,
18}),
19input_sections: std.ArrayList(struct {
20 ii: Node.InputIndex,
21 file_location: MappedFile.Node.FileLocation,
22 si: Symbol.Index,
23}),
24input_section_pending_index: u32,
9globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),25globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
10navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),26navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
11uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),27uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
...@@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
20relocs: std.ArrayList(Reloc),36relocs: std.ArrayList(Reloc),
21/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.37/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
22entry_hack: Symbol.Index,38entry_hack: Symbol.Index,
39const_prog_node: std.Progress.Node,
40synth_prog_node: std.Progress.Node,
41input_prog_node: std.Progress.Node,
2342
24pub const Node = union(enum) {43pub const Node = union(enum) {
25 file,44 file,
...@@ -27,11 +46,52 @@ pub const Node = union(enum) {...@@ -27,11 +46,52 @@ pub const Node = union(enum) {
27 shdr,46 shdr,
28 segment: u32,47 segment: u32,
29 section: Symbol.Index,48 section: Symbol.Index,
49 input_section: InputSectionIndex,
30 nav: NavMapIndex,50 nav: NavMapIndex,
31 uav: UavMapIndex,51 uav: UavMapIndex,
32 lazy_code: LazyMapRef.Index(.code),52 lazy_code: LazyMapRef.Index(.code),
33 lazy_const_data: LazyMapRef.Index(.const_data),53 lazy_const_data: LazyMapRef.Index(.const_data),
3454
55 pub const InputIndex = enum(u32) {
56 _,
57
58 pub fn path(ii: InputIndex, elf: *const Elf) std.Build.Cache.Path {
59 return elf.inputs.items[@intFromEnum(ii)].path;
60 }
61
62 pub fn member(ii: InputIndex, elf: *const Elf) ?[]const u8 {
63 return elf.inputs.items[@intFromEnum(ii)].member;
64 }
65
66 pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
67 return elf.inputs.items[@intFromEnum(ii)].si;
68 }
69
70 pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
71 const next_ii = @intFromEnum(ii) + 1;
72 return if (next_ii < elf.inputs.items.len)
73 @as(InputIndex, @enumFromInt(next_ii)).symbol(elf)
74 else
75 @enumFromInt(elf.symtab.items.len);
76 }
77 };
78
79 pub const InputSectionIndex = enum(u32) {
80 _,
81
82 pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex {
83 return elf.input_sections.items[@intFromEnum(isi)].ii;
84 }
85
86 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation {
87 return elf.input_sections.items[@intFromEnum(isi)].file_location;
88 }
89
90 pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index {
91 return elf.input_sections.items[@intFromEnum(isi)].si;
92 }
93 };
94
35 pub const NavMapIndex = enum(u32) {95 pub const NavMapIndex = enum(u32) {
36 _,96 _,
3797
...@@ -88,13 +148,13 @@ pub const Node = union(enum) {...@@ -88,13 +148,13 @@ pub const Node = union(enum) {
88 };148 };
89149
90 pub const Known = struct {150 pub const Known = struct {
91 pub const rodata: MappedFile.Node.Index = @enumFromInt(1);151 comptime file: MappedFile.Node.Index = .root,
92 pub const ehdr: MappedFile.Node.Index = @enumFromInt(2);152 comptime ehdr: MappedFile.Node.Index = @enumFromInt(1),
93 pub const phdr: MappedFile.Node.Index = @enumFromInt(3);153 comptime shdr: MappedFile.Node.Index = @enumFromInt(2),
94 pub const shdr: MappedFile.Node.Index = @enumFromInt(4);154 comptime rodata: MappedFile.Node.Index = @enumFromInt(3),
95 pub const text: MappedFile.Node.Index = @enumFromInt(5);155 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
96 pub const data: MappedFile.Node.Index = @enumFromInt(6);156 comptime text: MappedFile.Node.Index = @enumFromInt(5),
97157 comptime data: MappedFile.Node.Index = @enumFromInt(6),
98 tls: MappedFile.Node.Index,158 tls: MappedFile.Node.Index,
99 };159 };
100160
...@@ -176,7 +236,6 @@ pub const Symbol = struct {...@@ -176,7 +236,6 @@ pub const Symbol = struct {
176 rodata,236 rodata,
177 text,237 text,
178 data,238 data,
179 tdata,
180 _,239 _,
181240
182 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {241 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
...@@ -189,44 +248,65 @@ pub const Symbol = struct {...@@ -189,44 +248,65 @@ pub const Symbol = struct {
189 return ni;248 return ni;
190 }249 }
191250
251 pub fn next(si: Symbol.Index) Symbol.Index {
252 return @enumFromInt(@intFromEnum(si) + 1);
253 }
254
192 pub const InitOptions = struct {255 pub const InitOptions = struct {
193 name: []const u8 = "",256 name: []const u8 = "",
194 size: std.elf.Word = 0,257 lib_name: ?[]const u8 = null,
258 value: u64 = 0,
259 size: u64 = 0,
195 type: std.elf.STT,260 type: std.elf.STT,
196 bind: std.elf.STB = .LOCAL,261 bind: std.elf.STB = .LOCAL,
197 visibility: std.elf.STV = .DEFAULT,262 visibility: std.elf.STV = .DEFAULT,
198 shndx: std.elf.Section = std.elf.SHN_UNDEF,263 shndx: std.elf.Section = std.elf.SHN_UNDEF,
199 };264 };
200 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
201 const name_entry = try elf.string(.strtab, opts.name);266 const gpa = elf.base.comp.gpa;
202 try Symbol.Index.symtab.node(elf).resize(267 const target_endian = elf.targetEndian();
203 &elf.mf,268 const sym_size: usize = switch (elf.identClass()) {
204 elf.base.comp.gpa,269 .NONE, _ => unreachable,
205 @as(usize, switch (elf.identClass()) {270 inline else => |class| @sizeOf(class.ElfN().Sym),
206 .NONE, _ => unreachable,271 };
207 .@"32" => @sizeOf(std.elf.Elf32.Sym),272 const name_strtab_entry = try elf.string(.strtab, opts.name);
208 .@"64" => @sizeOf(std.elf.Elf64.Sym),273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
209 }) * elf.symtab.items.len,
210 );
211 switch (elf.symPtr(si)) {274 switch (elf.symPtr(si)) {
212 inline else => |sym| sym.* = .{275 inline else => |sym, class| {
213 .name = name_entry,276 sym.* = .{
214 .value = 0,277 .name = name_strtab_entry,
215 .size = opts.size,278 .value = @intCast(opts.value),
216 .info = .{279 .size = @intCast(opts.size),
217 .type = opts.type,280 .info = .{ .type = opts.type, .bind = opts.bind },
218 .bind = opts.bind,281 .other = .{ .visibility = opts.visibility },
219 },282 .shndx = opts.shndx,
220 .other = .{283 };
221 .visibility = opts.visibility,284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
222 },285 },
223 .shndx = opts.shndx,286 }
287 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
288 const dsi = elf.dynsym.items.len;
289 try elf.dynsym.append(gpa, si);
290 const dynsym_ni = elf.si.dynsym.node(elf);
291 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
292 try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len);
293 switch (elf.dynsymSlice()) {
294 inline else => |dynsym, class| {
295 const dsym = &dynsym[dsi];
296 dsym.* = .{
297 .name = name_dynstr_entry,
298 .value = @intCast(opts.value),
299 .size = @intCast(opts.size),
300 .info = .{ .type = opts.type, .bind = opts.bind },
301 .other = .{ .visibility = opts.visibility },
302 .shndx = opts.shndx,
303 };
304 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);
224 },305 },
225 }306 }
226 }307 }
227308
228 pub fn flushMoved(si: Symbol.Index, elf: *Elf) void {309 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
229 const value = elf.computeNodeVAddr(si.node(elf));
230 switch (elf.symPtr(si)) {310 switch (elf.symPtr(si)) {
231 inline else => |sym, class| {311 inline else => |sym, class| {
232 elf.targetStore(&sym.value, @intCast(value));312 elf.targetStore(&sym.value, @intCast(value));
...@@ -241,9 +321,12 @@ pub const Symbol = struct {...@@ -241,9 +321,12 @@ pub const Symbol = struct {
241 }321 }
242322
243 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {323 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
244 for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| {324 switch (si.get(elf).loc_relocs) {
245 if (reloc.loc != si) break;325 .none => {},
246 reloc.apply(elf);326 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
327 if (reloc.loc != si) break;
328 reloc.apply(elf);
329 },
247 }330 }
248 }331 }
249332
...@@ -267,6 +350,19 @@ pub const Symbol = struct {...@@ -267,6 +350,19 @@ pub const Symbol = struct {
267 }350 }
268 };351 };
269352
353 pub const Known = struct {
354 comptime symtab: Symbol.Index = .symtab,
355 comptime shstrtab: Symbol.Index = .shstrtab,
356 comptime strtab: Symbol.Index = .strtab,
357 comptime rodata: Symbol.Index = .rodata,
358 comptime text: Symbol.Index = .text,
359 comptime data: Symbol.Index = .data,
360 dynsym: Symbol.Index,
361 dynstr: Symbol.Index,
362 dynamic: Symbol.Index,
363 tdata: Symbol.Index,
364 };
365
270 comptime {366 comptime {
271 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);367 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
272 }368 }
...@@ -287,6 +383,22 @@ pub const Reloc = extern struct {...@@ -287,6 +383,22 @@ pub const Reloc = extern struct {
287 AARCH64: std.elf.R_AARCH64,383 AARCH64: std.elf.R_AARCH64,
288 RISCV: std.elf.R_RISCV,384 RISCV: std.elf.R_RISCV,
289 PPC64: std.elf.R_PPC64,385 PPC64: std.elf.R_PPC64,
386
387 pub fn absAddr(elf: *Elf) Reloc.Type {
388 return switch (elf.ehdrField(.machine)) {
389 else => unreachable,
390 .AARCH64 => .{ .AARCH64 = .ABS64 },
391 .PPC64 => .{ .PPC64 = .ADDR64 },
392 .RISCV => .{ .RISCV = .@"64" },
393 .X86_64 => .{ .X86_64 = .@"64" },
394 };
395 }
396 pub fn sizeAddr(elf: *Elf) Reloc.Type {
397 return switch (elf.ehdrField(.machine)) {
398 else => unreachable,
399 .X86_64 => .{ .X86_64 = .SIZE64 },
400 };
401 }
290 };402 };
291403
292 pub const Index = enum(u32) {404 pub const Index = enum(u32) {
...@@ -329,7 +441,7 @@ pub const Reloc = extern struct {...@@ -329,7 +441,7 @@ pub const Reloc = extern struct {
329 target_value,441 target_value,
330 target_endian,442 target_endian,
331 ),443 ),
332 .PC32 => std.mem.writeInt(444 .PC32, .PLT32 => std.mem.writeInt(
333 i32,445 i32,
334 loc_slice[0..4],446 loc_slice[0..4],
335 @intCast(@as(i64, @bitCast(target_value -% loc_value))),447 @intCast(@as(i64, @bitCast(target_value -% loc_value))),
...@@ -341,9 +453,15 @@ pub const Reloc = extern struct {...@@ -341,9 +453,15 @@ pub const Reloc = extern struct {
341 @intCast(target_value),453 @intCast(target_value),
342 target_endian,454 target_endian,
343 ),455 ),
456 .@"32S" => std.mem.writeInt(
457 i32,
458 loc_slice[0..4],
459 @intCast(@as(i64, @bitCast(target_value))),
460 target_endian,
461 ),
344 .TPOFF32 => {462 .TPOFF32 => {
345 const phdr = @field(elf.phdrSlice(), @tagName(class));463 const phdr = @field(elf.phdrSlice(), @tagName(class));
346 const ph = &phdr[elf.getNode(elf.known.tls).segment];464 const ph = &phdr[elf.getNode(elf.ni.tls).segment];
347 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);465 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
348 std.mem.writeInt(466 std.mem.writeInt(
349 i32,467 i32,
...@@ -352,6 +470,18 @@ pub const Reloc = extern struct {...@@ -352,6 +470,18 @@ pub const Reloc = extern struct {
352 target_endian,470 target_endian,
353 );471 );
354 },472 },
473 .SIZE32 => std.mem.writeInt(
474 u32,
475 loc_slice[0..4],
476 @intCast(elf.targetLoad(&target_sym.size)),
477 target_endian,
478 ),
479 .SIZE64 => std.mem.writeInt(
480 u64,
481 loc_slice[0..8],
482 @intCast(elf.targetLoad(&target_sym.size)),
483 target_endian,
484 ),
355 },485 },
356 }486 }
357 },487 },
...@@ -401,7 +531,6 @@ fn create(...@@ -401,7 +531,6 @@ fn create(
401 path: std.Build.Cache.Path,531 path: std.Build.Cache.Path,
402 options: link.File.OpenOptions,532 options: link.File.OpenOptions,
403) !*Elf {533) !*Elf {
404 _ = options;
405 const target = &comp.root_mod.resolved_target.result;534 const target = &comp.root_mod.resolved_target.result;
406 assert(target.ofmt == .elf);535 assert(target.ofmt == .elf);
407 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {536 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {
...@@ -434,20 +563,24 @@ fn create(...@@ -434,20 +563,24 @@ fn create(
434 .Obj => .REL,563 .Obj => .REL,
435 };564 };
436 const machine = target.toElfMachine();565 const machine = target.toElfMachine();
437 const maybe_interp = switch (comp.config.output_mode) {566 const maybe_interp = switch (comp.config.link_mode) {
438 .Exe, .Lib => switch (comp.config.link_mode) {567 .static => null,
439 .static => null,568 .dynamic => switch (comp.config.output_mode) {
440 .dynamic => target.dynamic_linker.get(),569 .Exe => target.dynamic_linker.get(),
570 .Lib => if (comp.root_mod.resolved_target.is_explicit_dynamic_linker)
571 target.dynamic_linker.get()
572 else
573 null,
574 .Obj => null,
441 },575 },
442 .Obj => null,
443 };576 };
444577
445 const elf = try arena.create(Elf);578 const elf = try arena.create(Elf);
446 const file = try path.root_dir.handle.createFile(path.sub_path, .{579 const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{
447 .read = true,580 .read = true,
448 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),581 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
449 });582 });
450 errdefer file.close();583 errdefer file.close(comp.io);
451 elf.* = .{584 elf.* = .{
452 .base = .{585 .base = .{
453 .tag = .elf2,586 .tag = .elf2,
...@@ -455,19 +588,26 @@ fn create(...@@ -455,19 +588,26 @@ fn create(
455 .comp = comp,588 .comp = comp,
456 .emit = path,589 .emit = path,
457590
458 .file = file,591 .file = .adaptFromNewApi(file),
459 .gc_sections = false,592 .gc_sections = false,
460 .print_gc_sections = false,593 .print_gc_sections = false,
461 .build_id = .none,594 .build_id = .none,
462 .allow_shlib_undefined = false,595 .allow_shlib_undefined = false,
463 .stack_size = 0,596 .stack_size = 0,
464 },597 },
598 .options = options,
465 .mf = try .init(file, comp.gpa),599 .mf = try .init(file, comp.gpa),
466 .known = .{600 .ni = .{
467 .tls = .none,601 .tls = .none,
468 },602 },
469 .nodes = .empty,603 .nodes = .empty,
470 .phdrs = .empty,604 .phdrs = .empty,
605 .si = .{
606 .dynsym = .null,
607 .dynstr = .null,
608 .dynamic = .null,
609 .tdata = .null,
610 },
471 .symtab = .empty,611 .symtab = .empty,
472 .shstrtab = .{612 .shstrtab = .{
473 .map = .empty,613 .map = .empty,
...@@ -477,6 +617,15 @@ fn create(...@@ -477,6 +617,15 @@ fn create(
477 .map = .empty,617 .map = .empty,
478 .size = 1,618 .size = 1,
479 },619 },
620 .dynsym = .empty,
621 .dynstr = .{
622 .map = .empty,
623 .size = 1,
624 },
625 .needed = .empty,
626 .inputs = .empty,
627 .input_sections = .empty,
628 .input_section_pending_index = 0,
480 .globals = .empty,629 .globals = .empty,
481 .navs = .empty,630 .navs = .empty,
482 .uavs = .empty,631 .uavs = .empty,
...@@ -487,6 +636,9 @@ fn create(...@@ -487,6 +636,9 @@ fn create(
487 .pending_uavs = .empty,636 .pending_uavs = .empty,
488 .relocs = .empty,637 .relocs = .empty,
489 .entry_hack = .null,638 .entry_hack = .null,
639 .const_prog_node = .none,
640 .synth_prog_node = .none,
641 .input_prog_node = .none,
490 };642 };
491 errdefer elf.deinit();643 errdefer elf.deinit();
492644
...@@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void {...@@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void {
502 elf.symtab.deinit(gpa);654 elf.symtab.deinit(gpa);
503 elf.shstrtab.map.deinit(gpa);655 elf.shstrtab.map.deinit(gpa);
504 elf.strtab.map.deinit(gpa);656 elf.strtab.map.deinit(gpa);
657 elf.dynsym.deinit(gpa);
658 elf.dynstr.map.deinit(gpa);
659 elf.needed.deinit(gpa);
660 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
661 elf.inputs.deinit(gpa);
662 elf.input_sections.deinit(gpa);
505 elf.globals.deinit(gpa);663 elf.globals.deinit(gpa);
506 elf.navs.deinit(gpa);664 elf.navs.deinit(gpa);
507 elf.uavs.deinit(gpa);665 elf.uavs.deinit(gpa);
...@@ -522,6 +680,13 @@ fn initHeaders(...@@ -522,6 +680,13 @@ fn initHeaders(
522) !void {680) !void {
523 const comp = elf.base.comp;681 const comp = elf.base.comp;
524 const gpa = comp.gpa;682 const gpa = comp.gpa;
683 const have_dynamic_section = switch (@"type") {
684 .NONE => unreachable,
685 .REL => false,
686 .EXEC => comp.config.link_mode == .dynamic,
687 .DYN => true,
688 .CORE, _ => unreachable,
689 };
525 const addr_align: std.mem.Alignment = switch (class) {690 const addr_align: std.mem.Alignment = switch (class) {
526 .NONE, _ => unreachable,691 .NONE, _ => unreachable,
527 .@"32" => .@"4",692 .@"32" => .@"4",
...@@ -541,42 +706,32 @@ fn initHeaders(...@@ -541,42 +706,32 @@ fn initHeaders(
541 phnum += 1;706 phnum += 1;
542 const data_phndx = phnum;707 const data_phndx = phnum;
543 phnum += 1;708 phnum += 1;
709 const dynamic_phndx = if (have_dynamic_section) phndx: {
710 defer phnum += 1;
711 break :phndx phnum;
712 } else undefined;
544 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {713 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
545 defer phnum += 1;714 defer phnum += 1;
546 break :phndx phnum;715 break :phndx phnum;
547 } else undefined;716 } else undefined;
548717
549 const expected_nodes_len = 5 + phnum * 2;718 const expected_nodes_len = 5 + phnum * 2 + @as(usize, 2) * @intFromBool(have_dynamic_section);
550 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);719 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
551 try elf.phdrs.resize(gpa, phnum);720 try elf.phdrs.resize(gpa, phnum);
552 elf.nodes.appendAssumeCapacity(.file);721 elf.nodes.appendAssumeCapacity(.file);
553722
554 assert(Node.Known.rodata == try elf.mf.addOnlyChildNode(gpa, .root, .{
555 .alignment = elf.mf.flags.block_size,
556 .fixed = true,
557 .moved = true,
558 .bubbles_moved = false,
559 }));
560 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
561 elf.phdrs.items[rodata_phndx] = Node.Known.rodata;
562
563 switch (class) {723 switch (class) {
564 .NONE, _ => unreachable,724 .NONE, _ => unreachable,
565 inline else => |ct_class| {725 inline else => |ct_class| {
566 const ElfN = switch (ct_class) {726 const ElfN = ct_class.ElfN();
567 .NONE, _ => comptime unreachable,727 assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{
568 .@"32" => std.elf.Elf32,
569 .@"64" => std.elf.Elf64,
570 };
571
572 assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{
573 .size = @sizeOf(ElfN.Ehdr),728 .size = @sizeOf(ElfN.Ehdr),
574 .alignment = addr_align,729 .alignment = addr_align,
575 .fixed = true,730 .fixed = true,
576 }));731 }));
577 elf.nodes.appendAssumeCapacity(.ehdr);732 elf.nodes.appendAssumeCapacity(.ehdr);
578733
579 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(Node.Known.ehdr.slice(&elf.mf)));734 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
580 const EI = std.elf.EI;735 const EI = std.elf.EI;
581 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);736 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
582 ehdr.ident[EI.CLASS] = @intFromEnum(class);737 ehdr.ident[EI.CLASS] = @intFromEnum(class);
...@@ -602,37 +757,47 @@ fn initHeaders(...@@ -602,37 +757,47 @@ fn initHeaders(
602 },757 },
603 }758 }
604759
605 assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{760 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
606 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),761 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
607 .alignment = addr_align,762 .alignment = addr_align,
608 .moved = true,763 .moved = true,
609 .resized = true,764 .resized = true,
765 }));
766 elf.nodes.appendAssumeCapacity(.shdr);
767
768 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
769 .alignment = elf.mf.flags.block_size,
770 .moved = true,
610 .bubbles_moved = false,771 .bubbles_moved = false,
611 }));772 }));
612 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
613 elf.phdrs.items[phdr_phndx] = Node.Known.phdr;774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
614775
615 assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{776 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
616 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
617 .alignment = addr_align,778 .alignment = addr_align,
779 .moved = true,
780 .resized = true,
781 .bubbles_moved = false,
618 }));782 }));
619 elf.nodes.appendAssumeCapacity(.shdr);783 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
784 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
620785
621 assert(Node.Known.text == try elf.mf.addLastChildNode(gpa, .root, .{786 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
622 .alignment = elf.mf.flags.block_size,787 .alignment = elf.mf.flags.block_size,
623 .moved = true,788 .moved = true,
624 .bubbles_moved = false,789 .bubbles_moved = false,
625 }));790 }));
626 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });791 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
627 elf.phdrs.items[text_phndx] = Node.Known.text;792 elf.phdrs.items[text_phndx] = elf.ni.text;
628793
629 assert(Node.Known.data == try elf.mf.addLastChildNode(gpa, .root, .{794 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
630 .alignment = elf.mf.flags.block_size,795 .alignment = elf.mf.flags.block_size,
631 .moved = true,796 .moved = true,
632 .bubbles_moved = false,797 .bubbles_moved = false,
633 }));798 }));
634 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });799 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
635 elf.phdrs.items[data_phndx] = Node.Known.data;800 elf.phdrs.items[data_phndx] = elf.ni.data;
636801
637 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
638 else => 0,803 else => 0,
...@@ -648,14 +813,10 @@ fn initHeaders(...@@ -648,14 +813,10 @@ fn initHeaders(
648 switch (class) {813 switch (class) {
649 .NONE, _ => unreachable,814 .NONE, _ => unreachable,
650 inline else => |ct_class| {815 inline else => |ct_class| {
651 const ElfN = switch (ct_class) {816 const ElfN = ct_class.ElfN();
652 .NONE, _ => comptime unreachable,
653 .@"32" => std.elf.Elf32,
654 .@"64" => std.elf.Elf64,
655 };
656 const target_endian = elf.targetEndian();817 const target_endian = elf.targetEndian();
657818
658 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf)));819 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
659 const ph_phdr = &phdr[phdr_phndx];820 const ph_phdr = &phdr[phdr_phndx];
660 ph_phdr.* = .{821 ph_phdr.* = .{
661 .type = std.elf.PT_PHDR,822 .type = std.elf.PT_PHDR,
...@@ -665,7 +826,7 @@ fn initHeaders(...@@ -665,7 +826,7 @@ fn initHeaders(
665 .filesz = 0,826 .filesz = 0,
666 .memsz = 0,827 .memsz = 0,
667 .flags = .{ .R = true },828 .flags = .{ .R = true },
668 .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()),829 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
669 };830 };
670 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);831 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
671832
...@@ -684,7 +845,7 @@ fn initHeaders(...@@ -684,7 +845,7 @@ fn initHeaders(
684 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
685 }846 }
686847
687 _, const rodata_size = Node.Known.rodata.location(&elf.mf).resolve(&elf.mf);848 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
688 const ph_rodata = &phdr[rodata_phndx];849 const ph_rodata = &phdr[rodata_phndx];
689 ph_rodata.* = .{850 ph_rodata.* = .{
690 .type = std.elf.PT_NULL,851 .type = std.elf.PT_NULL,
...@@ -694,12 +855,12 @@ fn initHeaders(...@@ -694,12 +855,12 @@ fn initHeaders(
694 .filesz = @intCast(rodata_size),855 .filesz = @intCast(rodata_size),
695 .memsz = @intCast(rodata_size),856 .memsz = @intCast(rodata_size),
696 .flags = .{ .R = true },857 .flags = .{ .R = true },
697 .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()),858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
698 };859 };
699 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
700 ph_vaddr += @intCast(rodata_size);861 ph_vaddr += @intCast(rodata_size);
701862
702 _, const text_size = Node.Known.text.location(&elf.mf).resolve(&elf.mf);863 _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
703 const ph_text = &phdr[text_phndx];864 const ph_text = &phdr[text_phndx];
704 ph_text.* = .{865 ph_text.* = .{
705 .type = std.elf.PT_NULL,866 .type = std.elf.PT_NULL,
...@@ -709,12 +870,12 @@ fn initHeaders(...@@ -709,12 +870,12 @@ fn initHeaders(
709 .filesz = @intCast(text_size),870 .filesz = @intCast(text_size),
710 .memsz = @intCast(text_size),871 .memsz = @intCast(text_size),
711 .flags = .{ .R = true, .X = true },872 .flags = .{ .R = true, .X = true },
712 .@"align" = @intCast(Node.Known.text.alignment(&elf.mf).toByteUnits()),873 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
713 };874 };
714 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);875 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
715 ph_vaddr += @intCast(text_size);876 ph_vaddr += @intCast(text_size);
716877
717 _, const data_size = Node.Known.data.location(&elf.mf).resolve(&elf.mf);878 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
718 const ph_data = &phdr[data_phndx];879 const ph_data = &phdr[data_phndx];
719 ph_data.* = .{880 ph_data.* = .{
720 .type = std.elf.PT_NULL,881 .type = std.elf.PT_NULL,
...@@ -724,11 +885,26 @@ fn initHeaders(...@@ -724,11 +885,26 @@ fn initHeaders(
724 .filesz = @intCast(data_size),885 .filesz = @intCast(data_size),
725 .memsz = @intCast(data_size),886 .memsz = @intCast(data_size),
726 .flags = .{ .R = true, .W = true },887 .flags = .{ .R = true, .W = true },
727 .@"align" = @intCast(Node.Known.data.alignment(&elf.mf).toByteUnits()),888 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
728 };889 };
729 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
730 ph_vaddr += @intCast(data_size);891 ph_vaddr += @intCast(data_size);
731892
893 if (have_dynamic_section) {
894 const ph_dynamic = &phdr[dynamic_phndx];
895 ph_dynamic.* = .{
896 .type = std.elf.PT_DYNAMIC,
897 .offset = 0,
898 .vaddr = 0,
899 .paddr = 0,
900 .filesz = 0,
901 .memsz = 0,
902 .flags = .{ .R = true, .W = true },
903 .@"align" = @intCast(addr_align.toByteUnits()),
904 };
905 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
906 }
907
732 if (comp.config.any_non_single_threaded) {908 if (comp.config.any_non_single_threaded) {
733 const ph_tls = &phdr[tls_phndx];909 const ph_tls = &phdr[tls_phndx];
734 ph_tls.* = .{910 ph_tls.* = .{
...@@ -744,7 +920,7 @@ fn initHeaders(...@@ -744,7 +920,7 @@ fn initHeaders(
744 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);920 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
745 }921 }
746922
747 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(Node.Known.shdr.slice(&elf.mf)));923 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
748 sh_null.* = .{924 sh_null.* = .{
749 .name = try elf.string(.shstrtab, ""),925 .name = try elf.string(.shstrtab, ""),
750 .type = std.elf.SHT_NULL,926 .type = std.elf.SHT_NULL,
...@@ -766,114 +942,187 @@ fn initHeaders(...@@ -766,114 +942,187 @@ fn initHeaders(
766 .target_relocs = .none,942 .target_relocs = .none,
767 .unused = 0,943 .unused = 0,
768 };944 };
769 assert(try elf.addSection(Node.Known.rodata, .{945 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
770 .type = std.elf.SHT_SYMTAB,946 .type = std.elf.SHT_SYMTAB,
947 .size = @sizeOf(ElfN.Sym) * 1,
771 .addralign = addr_align,948 .addralign = addr_align,
772 .entsize = @sizeOf(ElfN.Sym),949 .entsize = @sizeOf(ElfN.Sym),
773 }) == .symtab);950 }));
774951 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
775 const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf)));952 symtab_null.* = .{
776 symtab.* = .{
777 .name = try elf.string(.strtab, ""),953 .name = try elf.string(.strtab, ""),
778 .value = 0,954 .value = 0,
779 .size = 0,955 .size = 0,
780 .info = .{956 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
781 .type = .NOTYPE,957 .other = .{ .visibility = .DEFAULT },
782 .bind = .LOCAL,
783 },
784 .other = .{
785 .visibility = .DEFAULT,
786 },
787 .shndx = std.elf.SHN_UNDEF,958 .shndx = std.elf.SHN_UNDEF,
788 };959 };
960 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
789961
790 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));962 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
791 ehdr.shstrndx = ehdr.shnum;963 ehdr.shstrndx = ehdr.shnum;
792 },964 },
793 }965 }
794 assert(try elf.addSection(Node.Known.rodata, .{966 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
795 .type = std.elf.SHT_STRTAB,967 .type = std.elf.SHT_STRTAB,
796 .addralign = elf.mf.flags.block_size,968 .addralign = elf.mf.flags.block_size,
797 .entsize = 1,969 .entsize = 1,
798 }) == .shstrtab);970 }));
799 assert(try elf.addSection(Node.Known.rodata, .{971 try elf.renameSection(.symtab, ".symtab");
972 try elf.renameSection(.shstrtab, ".shstrtab");
973 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
974
975 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
976 .name = ".strtab",
800 .type = std.elf.SHT_STRTAB,977 .type = std.elf.SHT_STRTAB,
978 .size = 1,
801 .addralign = elf.mf.flags.block_size,979 .addralign = elf.mf.flags.block_size,
802 .entsize = 1,980 .entsize = 1,
803 }) == .strtab);981 }));
804 try elf.renameSection(.symtab, ".symtab");
805 try elf.renameSection(.shstrtab, ".shstrtab");
806 try elf.renameSection(.strtab, ".strtab");
807 try elf.linkSections(.symtab, .strtab);982 try elf.linkSections(.symtab, .strtab);
808 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;983 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
809 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
810984
811 assert(try elf.addSection(Node.Known.rodata, .{985 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
812 .name = ".rodata",986 .name = ".rodata",
813 .flags = .{ .ALLOC = true },987 .flags = .{ .ALLOC = true },
814 .addralign = elf.mf.flags.block_size,988 .addralign = elf.mf.flags.block_size,
815 }) == .rodata);989 }));
816 assert(try elf.addSection(Node.Known.text, .{990 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
817 .name = ".text",991 .name = ".text",
818 .flags = .{ .ALLOC = true, .EXECINSTR = true },992 .flags = .{ .ALLOC = true, .EXECINSTR = true },
819 .addralign = elf.mf.flags.block_size,993 .addralign = elf.mf.flags.block_size,
820 }) == .text);994 }));
821 assert(try elf.addSection(Node.Known.data, .{995 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
822 .name = ".data",996 .name = ".data",
823 .flags = .{ .WRITE = true, .ALLOC = true },997 .flags = .{ .WRITE = true, .ALLOC = true },
824 .addralign = elf.mf.flags.block_size,998 .addralign = elf.mf.flags.block_size,
825 }) == .data);999 }));
826 if (comp.config.any_non_single_threaded) {
827 try elf.nodes.ensureUnusedCapacity(gpa, 1);
828 elf.known.tls = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
829 .alignment = elf.mf.flags.block_size,
830 .moved = true,
831 });
832 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
833 elf.phdrs.items[tls_phndx] = elf.known.tls;
834
835 assert(try elf.addSection(elf.known.tls, .{
836 .name = ".tdata",
837 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
838 .addralign = elf.mf.flags.block_size,
839 }) == .tdata);
840 }
841 if (maybe_interp) |interp| {1000 if (maybe_interp) |interp| {
842 try elf.nodes.ensureUnusedCapacity(gpa, 1);1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
843 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
844 .size = interp.len + 1,1002 .size = interp.len + 1,
845 .moved = true,1003 .moved = true,
846 .resized = true,1004 .resized = true,
1005 .bubbles_moved = false,
847 });1006 });
848 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });1007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
849 elf.phdrs.items[interp_phndx] = interp_ni;1008 elf.phdrs.items[interp_phndx] = interp_ni;
8501009
851 const sec_interp_si = try elf.addSection(interp_ni, .{1010 const sec_interp_si = try elf.addSection(interp_ni, .{
852 .name = ".interp",1011 .name = ".interp",
853 .size = @intCast(interp.len + 1),
854 .flags = .{ .ALLOC = true },1012 .flags = .{ .ALLOC = true },
1013 .size = @intCast(interp.len + 1),
855 });1014 });
856 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);1015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
857 @memcpy(sec_interp[0..interp.len], interp);1016 @memcpy(sec_interp[0..interp.len], interp);
858 sec_interp[interp.len] = 0;1017 sec_interp[interp.len] = 0;
859 }1018 }
1019 if (have_dynamic_section) {
1020 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1021 .moved = true,
1022 .bubbles_moved = false,
1023 });
1024 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1025 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
1026
1027 switch (class) {
1028 .NONE, _ => unreachable,
1029 inline else => |ct_class| {
1030 const ElfN = ct_class.ElfN();
1031 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1032 .name = ".dynsym",
1033 .type = std.elf.SHT_DYNSYM,
1034 .size = @sizeOf(ElfN.Sym) * 1,
1035 .addralign = addr_align,
1036 .entsize = @sizeOf(ElfN.Sym),
1037 });
1038 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1039 dynsym_null.* = .{
1040 .name = try elf.string(.dynstr, ""),
1041 .value = 0,
1042 .size = 0,
1043 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1044 .other = .{ .visibility = .DEFAULT },
1045 .shndx = std.elf.SHN_UNDEF,
1046 };
1047 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null);
1048 },
1049 }
1050 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1051 .name = ".dynstr",
1052 .type = std.elf.SHT_STRTAB,
1053 .size = 1,
1054 .addralign = elf.mf.flags.block_size,
1055 .entsize = 1,
1056 });
1057 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1058 .name = ".dynamic",
1059 .type = std.elf.SHT_DYNAMIC,
1060 .flags = .{ .ALLOC = true, .WRITE = true },
1061 .addralign = addr_align,
1062 });
1063 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1064 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1065 }
1066 if (comp.config.any_non_single_threaded) {
1067 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1068 .alignment = elf.mf.flags.block_size,
1069 .moved = true,
1070 .bubbles_moved = false,
1071 });
1072 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
1073 elf.phdrs.items[tls_phndx] = elf.ni.tls;
1074
1075 elf.si.tdata = try elf.addSection(elf.ni.tls, .{
1076 .name = ".tdata",
1077 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1078 .addralign = elf.mf.flags.block_size,
1079 });
1080 }
860 assert(elf.nodes.len == expected_nodes_len);1081 assert(elf.nodes.len == expected_nodes_len);
861}1082}
8621083
1084pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
1085 prog_node.increaseEstimatedTotalItems(4);
1086 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count());
1087 elf.synth_prog_node = prog_node.start("Synthetics", count: {
1088 var count: usize = 0;
1089 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
1090 break :count count;
1091 });
1092 elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len);
1093 elf.input_prog_node = prog_node.start(
1094 "Inputs",
1095 elf.input_sections.items.len - elf.input_section_pending_index,
1096 );
1097}
1098
1099pub fn endProgress(elf: *Elf) void {
1100 elf.input_prog_node.end();
1101 elf.input_prog_node = .none;
1102 elf.mf.update_prog_node.end();
1103 elf.mf.update_prog_node = .none;
1104 elf.synth_prog_node.end();
1105 elf.synth_prog_node = .none;
1106 elf.const_prog_node.end();
1107 elf.const_prog_node = .none;
1108}
1109
863fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {1110fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
864 return elf.nodes.get(@intFromEnum(ni));1111 return elf.nodes.get(@intFromEnum(ni));
865}1112}
866fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {1113fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
867 const parent_vaddr = parent_vaddr: {1114 const parent_vaddr = parent_vaddr: {
868 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {1115 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {
869 .file, .ehdr, .shdr => unreachable,1116 .file => return 0,
1117 .ehdr, .shdr => unreachable,
870 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {1118 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
871 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),1119 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
872 },1120 },
873 .section => |si| si,1121 .section => |si| si,
1122 .input_section => unreachable,
874 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),1123 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
875 };1124 };
876 break :parent_vaddr switch (elf.symPtr(parent_si)) {1125 break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) {
877 inline else => |sym| elf.targetLoad(&sym.value),1126 inline else => |sym| elf.targetLoad(&sym.value),
878 };1127 };
879 };1128 };
...@@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {...@@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {
928 @"64": *std.elf.Elf64.Ehdr,1177 @"64": *std.elf.Elf64.Ehdr,
929};1178};
930pub fn ehdrPtr(elf: *Elf) EhdrPtr {1179pub fn ehdrPtr(elf: *Elf) EhdrPtr {
931 const slice = Node.Known.ehdr.slice(&elf.mf);1180 const slice = elf.ni.ehdr.slice(&elf.mf);
932 return switch (elf.identClass()) {1181 return switch (elf.identClass()) {
933 .NONE, _ => unreachable,1182 .NONE, _ => unreachable,
934 inline else => |class| @unionInit(1183 inline else => |class| @unionInit(
...@@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {...@@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
953 @"64": []std.elf.Elf64.Phdr,1202 @"64": []std.elf.Elf64.Phdr,
954};1203};
955pub fn phdrSlice(elf: *Elf) PhdrSlice {1204pub fn phdrSlice(elf: *Elf) PhdrSlice {
956 const slice = Node.Known.phdr.slice(&elf.mf);1205 const slice = elf.ni.phdr.slice(&elf.mf);
957 return switch (elf.identClass()) {1206 return switch (elf.identClass()) {
958 .NONE, _ => unreachable,1207 .NONE, _ => unreachable,
959 inline else => |class| @unionInit(1208 inline else => |class| @unionInit(
...@@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {...@@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {
970 @"64": []std.elf.Elf64.Shdr,1219 @"64": []std.elf.Elf64.Shdr,
971};1220};
972pub fn shdrSlice(elf: *Elf) ShdrSlice {1221pub fn shdrSlice(elf: *Elf) ShdrSlice {
973 const slice = Node.Known.shdr.slice(&elf.mf);1222 const slice = elf.ni.shdr.slice(&elf.mf);
974 return switch (elf.identClass()) {1223 return switch (elf.identClass()) {
975 .NONE, _ => unreachable,1224 .NONE, _ => unreachable,
976 inline else => |class| @unionInit(1225 inline else => |class| @unionInit(
...@@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {...@@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {
987 @"64": []std.elf.Elf64.Sym,1236 @"64": []std.elf.Elf64.Sym,
988};1237};
989pub fn symtabSlice(elf: *Elf) SymtabSlice {1238pub fn symtabSlice(elf: *Elf) SymtabSlice {
990 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);1239 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
991 return switch (elf.identClass()) {1240 return switch (elf.identClass()) {
992 .NONE, _ => unreachable,1241 .NONE, _ => unreachable,
993 inline else => |class| @unionInit(1242 inline else => |class| @unionInit(
...@@ -1009,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {...@@ -1009,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1009 };1258 };
1010}1259}
10111260
1261pub fn dynsymSlice(elf: *Elf) SymtabSlice {
1262 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);
1263 return switch (elf.identClass()) {
1264 .NONE, _ => unreachable,
1265 inline else => |class| @unionInit(
1266 SymtabSlice,
1267 @tagName(class),
1268 @ptrCast(@alignCast(slice)),
1269 ),
1270 };
1271}
1272
1012fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {1273fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
1013 defer elf.symtab.addOneAssumeCapacity().* = .{1274 defer elf.symtab.addOneAssumeCapacity().* = .{
1014 .ni = .none,1275 .ni = .none,
...@@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I...@@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I
10271288
1028pub fn globalSymbol(elf: *Elf, opts: struct {1289pub fn globalSymbol(elf: *Elf, opts: struct {
1029 name: []const u8,1290 name: []const u8,
1291 lib_name: ?[]const u8 = null,
1030 type: std.elf.STT,1292 type: std.elf.STT,
1031 bind: std.elf.STB = .GLOBAL,1293 bind: std.elf.STB = .GLOBAL,
1032 visibility: std.elf.STV = .DEFAULT,1294 visibility: std.elf.STV = .DEFAULT,
...@@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {...@@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {
1036 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));1298 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
1037 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{1299 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1038 .name = opts.name,1300 .name = opts.name,
1301 .lib_name = opts.lib_name,
1039 .type = opts.type,1302 .type = opts.type,
1040 .bind = opts.bind,1303 .bind = opts.bind,
1041 .visibility = opts.visibility,1304 .visibility = opts.visibility,
...@@ -1072,30 +1335,33 @@ fn navType(...@@ -1072,30 +1335,33 @@ fn navType(
1072 },1335 },
1073 };1336 };
1074}1337}
1338fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
1339 if (std.mem.eql(u8, name, ".rodata") or
1340 std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata;
1341 if (std.mem.eql(u8, name, ".text") or
1342 std.mem.startsWith(u8, name, ".text.")) return elf.si.text;
1343 if (std.mem.eql(u8, name, ".data") or
1344 std.mem.startsWith(u8, name, ".data.")) return elf.si.data;
1345 if (std.mem.eql(u8, name, ".tdata") or
1346 std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata;
1347 return null;
1348}
1075fn navSection(1349fn navSection(
1076 elf: *Elf,1350 elf: *Elf,
1077 ip: *const InternPool,1351 ip: *const InternPool,
1078 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),1352 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
1079) Symbol.Index {1353) Symbol.Index {
1080 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| {1354 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1081 if (std.mem.eql(u8, @"linksection", ".rodata") or1355 if (elf.namedSection(@"linksection")) |si| return si;
1082 std.mem.startsWith(u8, @"linksection", ".rodata.")) return .rodata;
1083 if (std.mem.eql(u8, @"linksection", ".text") or
1084 std.mem.startsWith(u8, @"linksection", ".text.")) return .text;
1085 if (std.mem.eql(u8, @"linksection", ".data") or
1086 std.mem.startsWith(u8, @"linksection", ".data.")) return .data;
1087 if (std.mem.eql(u8, @"linksection", ".tdata") or
1088 std.mem.startsWith(u8, @"linksection", ".tdata.")) return .tdata;
1089 }
1090 return switch (navType(1356 return switch (navType(
1091 ip,1357 ip,
1092 .{ .fully_resolved = nav_fr },1358 .{ .fully_resolved = nav_fr },
1093 elf.base.comp.config.any_non_single_threaded,1359 elf.base.comp.config.any_non_single_threaded,
1094 )) {1360 )) {
1095 else => unreachable,1361 else => unreachable,
1096 .FUNC => .text,1362 .FUNC => elf.si.text,
1097 .OBJECT => .data,1363 .OBJECT => elf.si.data,
1098 .TLS => .tdata,1364 .TLS => elf.si.tdata,
1099 };1365 };
1100}1366}
1101fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {1367fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
...@@ -1115,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol....@@ -1115,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
1115 const nav = ip.getNav(nav_index);1381 const nav = ip.getNav(nav_index);
1116 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{1382 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1117 .name = @"extern".name.toSlice(ip),1383 .name = @"extern".name.toSlice(ip),
1384 .lib_name = @"extern".lib_name.toSlice(ip),
1118 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),1385 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
1119 .bind = switch (@"extern".linkage) {1386 .bind = switch (@"extern".linkage) {
1120 .internal => .LOCAL,1387 .internal => .LOCAL,
...@@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {...@@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
1156 .const_data => .OBJECT,1423 .const_data => .OBJECT,
1157 },1424 },
1158 });1425 });
1159 elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1426 elf.synth_prog_node.increaseEstimatedTotalItems(1);
1160 }1427 }
1161 return lazy_gop.value_ptr.*;1428 return lazy_gop.value_ptr.*;
1162}1429}
11631430
1431pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1432 std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void {
1433 const io = elf.base.comp.io;
1434 var buf: [4096]u8 = undefined;
1435 switch (input) {
1436 .object => |object| {
1437 var fr = object.file.reader(io, &buf);
1438 elf.loadObject(object.path, null, &fr, .{
1439 .offset = fr.logicalPos(),
1440 .size = try fr.getSize(),
1441 }) catch |err| switch (err) {
1442 error.ReadFailed => return fr.err.?,
1443 else => |e| return e,
1444 };
1445 },
1446 .archive => |archive| {
1447 var fr = archive.file.reader(io, &buf);
1448 elf.loadArchive(archive.path, &fr) catch |err| switch (err) {
1449 error.ReadFailed => return fr.err.?,
1450 else => |e| return e,
1451 };
1452 },
1453 .res => unreachable,
1454 .dso => |dso| {
1455 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);
1456 var fr = dso.file.reader(io, &buf);
1457 elf.loadDso(dso.path, &fr) catch |err| switch (err) {
1458 error.ReadFailed => return fr.err.?,
1459 else => |e| return e,
1460 };
1461 },
1462 .dso_exact => |dso_exact| try elf.loadDsoExact(dso_exact.name),
1463 }
1464}
1465fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
1466 const comp = elf.base.comp;
1467 const gpa = comp.gpa;
1468 const diags = &comp.link_diags;
1469 const r = &fr.interface;
1470
1471 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
1472 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))
1473 return diags.failParse(path, "bad magic", .{});
1474 var strtab: std.Io.Writer.Allocating = .init(gpa);
1475 defer strtab.deinit();
1476 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
1477 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
1478 return diags.failParse(path, "bad file magic", .{});
1479 const offset = fr.logicalPos();
1480 const size = header.size() catch
1481 return diags.failParse(path, "bad member size", .{});
1482 if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) {
1483 strtab.clearRetainingCapacity();
1484 try strtab.ensureTotalCapacityPrecise(size);
1485 r.streamExact(&strtab.writer, size) catch |err| switch (err) {
1486 error.WriteFailed => return error.OutOfMemory,
1487 else => |e| return e,
1488 };
1489 continue;
1490 }
1491 load_object: {
1492 const member = header.name() orelse member: {
1493 const strtab_offset = header.nameOffset() catch |err| switch (err) {
1494 error.Overflow => break :member error.Overflow,
1495 error.InvalidCharacter => break :load_object,
1496 } orelse break :load_object;
1497 const strtab_written = strtab.written();
1498 if (strtab_offset > strtab_written.len) break :member error.Overflow;
1499 const member = std.mem.sliceTo(strtab_written[strtab_offset..], '\n');
1500 break :member if (std.mem.endsWith(u8, member, "/"))
1501 member[0 .. member.len - "/".len]
1502 else
1503 member;
1504 } catch |err| switch (err) {
1505 error.Overflow => return diags.failParse(path, "bad member name offset", .{}),
1506 };
1507 if (!std.mem.endsWith(u8, member, ".o")) break :load_object;
1508 try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size });
1509 }
1510 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));
1511 } else |err| switch (err) {
1512 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
1513 else => |e| return e,
1514 }
1515}
1516fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) {
1517 return .{ .data = member };
1518}
1519fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
1520 try w.print("({f})", .{std.zig.fmtString(member orelse return)});
1521}
1522fn loadObject(
1523 elf: *Elf,
1524 path: std.Build.Cache.Path,
1525 member: ?[]const u8,
1526 fr: *std.Io.File.Reader,
1527 fl: MappedFile.Node.FileLocation,
1528) !void {
1529 const comp = elf.base.comp;
1530 const gpa = comp.gpa;
1531 const diags = &comp.link_diags;
1532 const r = &fr.interface;
1533
1534 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
1535 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
1536 const ident = try r.peek(std.elf.EI.NIDENT);
1537 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))
1538 return diags.failParse(path, "bad ident", .{});
1539 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1540 try elf.inputs.ensureUnusedCapacity(gpa, 1);
1541 elf.inputs.addOneAssumeCapacity().* = .{
1542 .path = path,
1543 .member = if (member) |m| try gpa.dupe(u8, m) else null,
1544 .si = try elf.initSymbolAssumeCapacity(.{
1545 .name = std.fs.path.stem(member orelse path.sub_path),
1546 .type = .FILE,
1547 .shndx = std.elf.SHN_ABS,
1548 }),
1549 };
1550 const target_endian = elf.targetEndian();
1551 switch (elf.identClass()) {
1552 .NONE, _ => unreachable,
1553 inline else => |class| {
1554 const ElfN = class.ElfN();
1555 const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian);
1556 if (ehdr.type != .REL) return diags.failParse(path, "unsupported object type", .{});
1557 if (ehdr.machine != elf.ehdrField(.machine))
1558 return diags.failParse(path, "bad machine", .{});
1559 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
1560 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)
1561 return diags.failParse(path, "bad section header location", .{});
1562 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
1563 return diags.failParse(path, "unsupported shentsize", .{});
1564 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
1565 defer gpa.free(sections);
1566 try fr.seekTo(fl.offset + ehdr.shoff);
1567 for (sections) |*section| {
1568 section.* = .{
1569 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
1570 .si = .null,
1571 };
1572 try r.discardAll(ehdr.shentsize);
1573 switch (section.shdr.type) {
1574 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
1575 else => if (section.shdr.offset + section.shdr.size > fl.size)
1576 return diags.failParse(path, "bad section location", .{}),
1577 }
1578 }
1579 const shstrtab = shstrtab: {
1580 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
1581 return diags.failParse(path, "missing section names", .{});
1582 const shdr = &sections[ehdr.shstrndx].shdr;
1583 if (shdr.type != std.elf.SHT_STRTAB)
1584 return diags.failParse(path, "invalid shstrtab type", .{});
1585 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
1586 errdefer gpa.free(shstrtab);
1587 try fr.seekTo(fl.offset + shdr.offset);
1588 try r.readSliceAll(shstrtab);
1589 break :shstrtab shstrtab;
1590 };
1591 defer gpa.free(shstrtab);
1592 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
1593 try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
1594 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
1595 for (sections[1..]) |*section| switch (section.shdr.type) {
1596 else => {},
1597 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {
1598 if (section.shdr.name >= shstrtab.len) continue;
1599 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
1600 const parent_si = elf.namedSection(name) orelse continue;
1601 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{
1602 .size = section.shdr.size,
1603 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
1604 usize,
1605 @intCast(@max(section.shdr.addralign, 1)),
1606 )),
1607 .moved = true,
1608 });
1609 elf.nodes.appendAssumeCapacity(.{
1610 .input_section = @enumFromInt(elf.input_sections.items.len),
1611 });
1612 section.si = try elf.initSymbolAssumeCapacity(.{
1613 .type = .SECTION,
1614 .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx),
1615 });
1616 section.si.get(elf).ni = ni;
1617 elf.input_sections.addOneAssumeCapacity().* = .{
1618 .ii = ii,
1619 .si = section.si,
1620 .file_location = .{
1621 .offset = fl.offset + section.shdr.offset,
1622 .size = section.shdr.size,
1623 },
1624 };
1625 elf.synth_prog_node.increaseEstimatedTotalItems(1);
1626 },
1627 };
1628 var symmap: std.ArrayList(Symbol.Index) = .empty;
1629 defer symmap.deinit(gpa);
1630 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
1631 else => {},
1632 std.elf.SHT_SYMTAB => {
1633 if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))
1634 return diags.failParse(path, "unsupported symtab entsize", .{});
1635 const strtab = strtab: {
1636 if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)
1637 return diags.failParse(path, "missing symbol names", .{});
1638 const shdr = &sections[symtab.shdr.link].shdr;
1639 if (shdr.type != std.elf.SHT_STRTAB)
1640 return diags.failParse(path, "invalid strtab type", .{});
1641 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
1642 errdefer gpa.free(strtab);
1643 try fr.seekTo(fl.offset + shdr.offset);
1644 try r.readSliceAll(strtab);
1645 break :strtab strtab;
1646 };
1647 defer gpa.free(strtab);
1648 const symnum = std.math.divExact(
1649 u32,
1650 @intCast(symtab.shdr.size),
1651 @intCast(symtab.shdr.entsize),
1652 ) catch return diags.failParse(
1653 path,
1654 "symtab section size (0x{x}) is not a multiple of entsize (0x{x})",
1655 .{ symtab.shdr.size, symtab.shdr.entsize },
1656 );
1657 symmap.clearRetainingCapacity();
1658 try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue);
1659 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
1660 try elf.globals.ensureUnusedCapacity(gpa, symnum);
1661 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
1662 for (symmap.items) |*si| {
1663 si.* = .null;
1664 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
1665 try r.discardAll64(symtab.shdr.entsize);
1666 if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or
1667 input_sym.shndx >= ehdr.shnum) continue;
1668 switch (input_sym.info.type) {
1669 else => continue,
1670 .SECTION => {
1671 const section = &sections[input_sym.shndx];
1672 if (input_sym.value == section.shdr.addr) si.* = section.si;
1673 continue;
1674 },
1675 .OBJECT, .FUNC => {},
1676 }
1677 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
1678 const parent_si = sections[input_sym.shndx].si;
1679 si.* = try elf.initSymbolAssumeCapacity(.{
1680 .name = name,
1681 .value = input_sym.value,
1682 .size = input_sym.size,
1683 .type = input_sym.info.type,
1684 .bind = input_sym.info.bind,
1685 .visibility = input_sym.other.visibility,
1686 .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) {
1687 inline else => |parent_sym| &parent_sym.shndx,
1688 }),
1689 });
1690 si.get(elf).ni = parent_si.get(elf).ni;
1691 switch (input_sym.info.bind) {
1692 else => {},
1693 .GLOBAL => {
1694 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
1695 &@field(elf.symPtr(si.*), @tagName(class)).name,
1696 ));
1697 if (gop.found_existing) switch (elf.targetLoad(
1698 switch (elf.symPtr(gop.value_ptr.*)) {
1699 inline else => |sym| &sym.info,
1700 },
1701 ).bind) {
1702 else => unreachable,
1703 .GLOBAL => return diags.failParse(
1704 path,
1705 "multiple definitions of '{s}'",
1706 .{name},
1707 ),
1708 .WEAK => {},
1709 };
1710 gop.value_ptr.* = si.*;
1711 },
1712 .WEAK => {
1713 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
1714 &@field(elf.symPtr(si.*), @tagName(class)).name,
1715 ));
1716 if (!gop.found_existing) gop.value_ptr.* = si.*;
1717 },
1718 }
1719 }
1720 for (sections[1..]) |*rels| switch (rels.shdr.type) {
1721 else => {},
1722 inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| {
1723 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
1724 rels.shdr.info >= ehdr.shnum) continue;
1725 const Rel = switch (sht) {
1726 else => comptime unreachable,
1727 std.elf.SHT_REL => ElfN.Rel,
1728 std.elf.SHT_RELA => ElfN.Rela,
1729 };
1730 if (rels.shdr.entsize < @sizeOf(Rel))
1731 return diags.failParse(path, "unsupported rel entsize", .{});
1732 const loc_sec = &sections[rels.shdr.info];
1733 if (loc_sec.si == .null) continue;
1734 const relnum = std.math.divExact(
1735 u32,
1736 @intCast(rels.shdr.size),
1737 @intCast(rels.shdr.entsize),
1738 ) catch return diags.failParse(
1739 path,
1740 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
1741 .{ rels.shdr.size, rels.shdr.entsize },
1742 );
1743 try elf.relocs.ensureUnusedCapacity(gpa, relnum);
1744 try fr.seekTo(fl.offset + rels.shdr.offset);
1745 for (0..relnum) |_| {
1746 const rel = try r.peekStruct(Rel, target_endian);
1747 try r.discardAll64(rels.shdr.entsize);
1748 if (rel.info.sym >= symnum) continue;
1749 const target_si = symmap.items[rel.info.sym - 1];
1750 if (target_si == .null) continue;
1751 elf.addRelocAssumeCapacity(
1752 loc_sec.si,
1753 rel.offset - loc_sec.shdr.addr,
1754 target_si,
1755 rel.addend,
1756 switch (elf.ehdrField(.machine)) {
1757 else => unreachable,
1758 inline .AARCH64,
1759 .PPC64,
1760 .RISCV,
1761 .X86_64,
1762 => |machine| @unionInit(
1763 Reloc.Type,
1764 @tagName(machine),
1765 @enumFromInt(rel.info.type),
1766 ),
1767 },
1768 );
1769 }
1770 },
1771 };
1772 },
1773 };
1774 },
1775 }
1776}
1777fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
1778 const comp = elf.base.comp;
1779 const diags = &comp.link_diags;
1780 const r = &fr.interface;
1781
1782 log.debug("loadDso({f})", .{path.fmtEscapeString()});
1783 const ident = try r.peek(std.elf.EI.NIDENT);
1784 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))
1785 return diags.failParse(path, "bad ident", .{});
1786 const target_endian = elf.targetEndian();
1787 switch (elf.identClass()) {
1788 .NONE, _ => unreachable,
1789 inline else => |class| {
1790 const ElfN = class.ElfN();
1791 const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian);
1792 if (ehdr.type != .DYN) return diags.failParse(path, "unsupported dso type", .{});
1793 if (ehdr.machine != elf.ehdrField(.machine))
1794 return diags.failParse(path, "bad machine", .{});
1795 if (ehdr.phoff == 0 or ehdr.phnum <= 1)
1796 return diags.failParse(path, "no program headers", .{});
1797 try fr.seekTo(ehdr.phoff);
1798 const dynamic_ph = for (0..ehdr.phnum) |_| {
1799 const ph = try r.peekStruct(ElfN.Phdr, target_endian);
1800 try r.discardAll(ehdr.phentsize);
1801 switch (ph.type) {
1802 else => {},
1803 std.elf.PT_DYNAMIC => break ph,
1804 }
1805 } else return diags.failParse(path, "no dynamic segment", .{});
1806 const dynnum = std.math.divExact(
1807 u32,
1808 @intCast(dynamic_ph.filesz),
1809 @sizeOf(ElfN.Addr) * 2,
1810 ) catch return diags.failParse(
1811 path,
1812 "dynamic segment filesz (0x{x}) is not a multiple of entsize (0x{x})",
1813 .{ dynamic_ph.filesz, @sizeOf(ElfN.Addr) * 2 },
1814 );
1815 var strtab: ?ElfN.Addr = null;
1816 var strsz: ?ElfN.Addr = null;
1817 var soname: ?ElfN.Addr = null;
1818 try fr.seekTo(dynamic_ph.offset);
1819 for (0..dynnum) |_| {
1820 const key = try r.takeInt(ElfN.Addr, target_endian);
1821 const value = try r.takeInt(ElfN.Addr, target_endian);
1822 switch (key) {
1823 else => {},
1824 std.elf.DT_STRTAB => strtab = value,
1825 std.elf.DT_STRSZ => strsz = value,
1826 std.elf.DT_SONAME => soname = value,
1827 }
1828 }
1829 if (strtab == null or soname == null)
1830 return elf.loadDsoExact(std.fs.path.basename(path.sub_path));
1831 if (strsz) |size| if (soname.? >= size)
1832 return diags.failParse(path, "bad soname string", .{});
1833 try fr.seekTo(ehdr.phoff);
1834 const ph = for (0..ehdr.phnum) |_| {
1835 const ph = try r.peekStruct(ElfN.Phdr, target_endian);
1836 try r.discardAll(ehdr.phentsize);
1837 switch (ph.type) {
1838 else => {},
1839 std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and
1840 strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,
1841 }
1842 } else return diags.failParse(path, "strtab not part of a loaded segment", .{});
1843 try fr.seekTo(strtab.? + soname.? - ph.vaddr + ph.offset);
1844 return elf.loadDsoExact(r.peekSentinel(0) catch |err| switch (err) {
1845 error.StreamTooLong => return diags.failParse(path, "soname too lang", .{}),
1846 else => |e| return e,
1847 });
1848 },
1849 }
1850}
1851fn loadDsoExact(elf: *Elf, name: []const u8) !void {
1852 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
1853 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
1854}
1855
1856pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
1857 _ = prog_node;
1858 elf.prelinkInner() catch |err| switch (err) {
1859 error.OutOfMemory => return error.OutOfMemory,
1860 else => |e| return elf.base.comp.link_diags.fail("prelink failed: {t}", .{e}),
1861 };
1862}
1863fn prelinkInner(elf: *Elf) !void {
1864 const gpa = elf.base.comp.gpa;
1865 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1866 try elf.inputs.ensureUnusedCapacity(gpa, 1);
1867 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
1868 std.fs.path.stem(elf.base.emit.sub_path),
1869 });
1870 defer gpa.free(zcu_name);
1871 const si = try elf.initSymbolAssumeCapacity(.{
1872 .name = zcu_name,
1873 .type = .FILE,
1874 .shndx = std.elf.SHN_ABS,
1875 });
1876 elf.inputs.addOneAssumeCapacity().* = .{
1877 .path = elf.base.emit,
1878 .member = null,
1879 .si = si,
1880 };
1881
1882 if (elf.si.dynamic != .null) switch (elf.identClass()) {
1883 .NONE, _ => unreachable,
1884 inline else => |ct_class| {
1885 const ElfN = ct_class.ElfN();
1886 const needed_len = elf.needed.count();
1887 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + 5;
1888 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
1889 const dynamic_ni = elf.si.dynamic.node(elf);
1890 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
1891 const sec_dynamic = dynamic_ni.slice(&elf.mf);
1892 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));
1893 var dynamic_index: usize = 0;
1894 for (
1895 dynamic_entries[dynamic_index..][0..needed_len],
1896 elf.needed.keys(),
1897 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed };
1898 dynamic_index += needed_len;
1899 if (elf.options.soname) |soname| {
1900 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
1901 dynamic_index += 1;
1902 }
1903 dynamic_entries[dynamic_index..][0..5].* = .{
1904 .{ std.elf.DT_SYMTAB, 0 },
1905 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
1906 .{ std.elf.DT_STRTAB, 0 },
1907 .{ std.elf.DT_STRSZ, 0 },
1908 .{ std.elf.DT_NULL, 0 },
1909 };
1910 dynamic_index += 5;
1911 assert(dynamic_index == dynamic_len);
1912 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
1913 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
1914
1915 const dynamic_sym = elf.si.dynamic.get(elf);
1916 assert(dynamic_sym.loc_relocs == .none);
1917 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1918 try elf.addReloc(
1919 elf.si.dynamic,
1920 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
1921 elf.si.dynsym,
1922 0,
1923 .absAddr(elf),
1924 );
1925 try elf.addReloc(
1926 elf.si.dynamic,
1927 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
1928 elf.si.dynstr,
1929 0,
1930 .absAddr(elf),
1931 );
1932 try elf.addReloc(
1933 elf.si.dynamic,
1934 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 2) + 1),
1935 elf.si.dynstr,
1936 0,
1937 .sizeAddr(elf),
1938 );
1939 },
1940 };
1941}
1942
1164pub fn getNavVAddr(1943pub fn getNavVAddr(
1165 elf: *Elf,1944 elf: *Elf,
1166 pt: Zcu.PerThread,1945 pt: Zcu.PerThread,
...@@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In...@@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
1184 reloc_info.offset,1963 reloc_info.offset,
1185 target_si,1964 target_si,
1186 reloc_info.addend,1965 reloc_info.addend,
1187 switch (elf.ehdrField(.machine)) {1966 .absAddr(elf),
1188 else => unreachable,
1189 .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
1190 .NONE, _ => unreachable,
1191 .@"32" => .@"32",
1192 .@"64" => .@"64",
1193 } },
1194 },
1195 );1967 );
1196 return switch (elf.symPtr(target_si)) {1968 return switch (elf.symPtr(target_si)) {
1197 inline else => |sym| elf.targetLoad(&sym.value),1969 inline else => |sym| elf.targetLoad(&sym.value),
...@@ -1201,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In...@@ -1201,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
1201fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {1973fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1202 name: []const u8 = "",1974 name: []const u8 = "",
1203 type: std.elf.Word = std.elf.SHT_NULL,1975 type: std.elf.Word = std.elf.SHT_NULL,
1204 size: std.elf.Word = 0,
1205 flags: std.elf.SHF = .{},1976 flags: std.elf.SHF = .{},
1977 size: std.elf.Word = 0,
1206 addralign: std.mem.Alignment = .@"1",1978 addralign: std.mem.Alignment = .@"1",
1207 entsize: std.elf.Word = 0,1979 entsize: std.elf.Word = 0,
1208}) !Symbol.Index {1980}) !Symbol.Index {
1981 switch (opts.type) {
1982 std.elf.SHT_NULL => assert(opts.size == 0),
1983 std.elf.SHT_PROGBITS => assert(opts.size > 0),
1984 else => {},
1985 }
1209 const gpa = elf.base.comp.gpa;1986 const gpa = elf.base.comp.gpa;
1210 try elf.nodes.ensureUnusedCapacity(gpa, 1);1987 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1211 try elf.symtab.ensureUnusedCapacity(gpa, 1);1988 try elf.symtab.ensureUnusedCapacity(gpa, 1);
...@@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1219 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };1996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
1220 },1997 },
1221 };1998 };
1222 try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size);1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
1223 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{2000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
1224 .alignment = opts.addralign,2001 .alignment = opts.addralign,
1225 .size = opts.size,2002 .size = opts.size,
1226 .moved = true,2003 .resized = opts.size > 0,
1227 });2004 });
1228 const si = elf.addSymbolAssumeCapacity();2005 const si = elf.addSymbolAssumeCapacity();
1229 elf.nodes.appendAssumeCapacity(.{ .section = si });2006 elf.nodes.appendAssumeCapacity(.{ .section = si });
1230 si.get(elf).ni = ni;2007 si.get(elf).ni = ni;
2008 const addr = elf.computeNodeVAddr(ni);
2009 const offset = ni.fileLocation(&elf.mf, false).offset;
1231 try si.init(elf, .{2010 try si.init(elf, .{
1232 .name = opts.name,2011 .value = addr,
1233 .size = opts.size,2012 .size = opts.size,
1234 .type = .SECTION,2013 .type = .SECTION,
1235 .shndx = shndx,2014 .shndx = shndx,
...@@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1241 .name = shstrtab_entry,2020 .name = shstrtab_entry,
1242 .type = opts.type,2021 .type = opts.type,
1243 .flags = .{ .shf = opts.flags },2022 .flags = .{ .shf = opts.flags },
1244 .addr = 0,2023 .addr = @intCast(addr),
1245 .offset = 0,2024 .offset = @intCast(offset),
1246 .size = opts.size,2025 .size = opts.size,
1247 .link = 0,2026 .link = 0,
1248 .info = 0,2027 .info = 0,
...@@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1256}2035}
12572036
1258fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {2037fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1259 const strtab_entry = try elf.string(.strtab, name);
1260 const shstrtab_entry = try elf.string(.shstrtab, name);2038 const shstrtab_entry = try elf.string(.shstrtab, name);
1261 switch (elf.shdrSlice()) {2039 switch (elf.shdrSlice()) {
1262 inline else => |shdr, class| {2040 inline else => |shdr, class| elf.targetStore(
1263 const sym = @field(elf.symPtr(si), @tagName(class));2041 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
1264 elf.targetStore(&sym.name, strtab_entry);2042 shstrtab_entry,
1265 const sh = &shdr[elf.targetLoad(&sym.shndx)];2043 ),
1266 elf.targetStore(&sh.name, shstrtab_entry);
1267 },
1268 }2044 }
1269}2045}
12702046
...@@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {...@@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1277}2053}
12782054
1279fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {2055fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1280 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {2056 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {
1281 inline else => |shndx, class| elf.targetLoad(2057 inline else => |shndx, class| elf.targetLoad(
1282 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,2058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
1283 ),2059 ),
...@@ -1285,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {...@@ -1285,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1285 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];2061 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
1286}2062}
12872063
1288fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 {2064fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
1289 if (key.len == 0) return 0;2065 if (key.len == 0) return 0;
1290 return @field(elf, @tagName(section)).get(2066 return @field(elf, @tagName(section)).get(
1291 elf.base.comp.gpa,2067 elf.base.comp.gpa,
1292 &elf.mf,2068 &elf.mf,
1293 @field(Symbol.Index, @tagName(section)).node(elf),2069 @field(elf.si, @tagName(section)).node(elf),
1294 key,2070 key,
1295 );2071 );
1296}2072}
...@@ -1303,10 +2079,20 @@ pub fn addReloc(...@@ -1303,10 +2079,20 @@ pub fn addReloc(
1303 addend: i64,2079 addend: i64,
1304 @"type": Reloc.Type,2080 @"type": Reloc.Type,
1305) !void {2081) !void {
1306 const gpa = elf.base.comp.gpa;2082 try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1);
2083 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2084}
2085pub fn addRelocAssumeCapacity(
2086 elf: *Elf,
2087 loc_si: Symbol.Index,
2088 offset: u64,
2089 target_si: Symbol.Index,
2090 addend: i64,
2091 @"type": Reloc.Type,
2092) void {
1307 const target = target_si.get(elf);2093 const target = target_si.get(elf);
1308 const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len);2094 const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len);
1309 (try elf.relocs.addOne(gpa)).* = .{2095 elf.relocs.addOneAssumeCapacity().* = .{
1310 .type = @"type",2096 .type = @"type",
1311 .prev = .none,2097 .prev = .none,
1312 .next = target.target_relocs,2098 .next = target.target_relocs,
...@@ -1323,11 +2109,6 @@ pub fn addReloc(...@@ -1323,11 +2109,6 @@ pub fn addReloc(
1323 target.target_relocs = ri;2109 target.target_relocs = ri;
1324}2110}
13252111
1326pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void {
1327 _ = elf;
1328 _ = prog_node;
1329}
1330
1331pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {2112pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
1332 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {2113 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
1333 error.OutOfMemory,2114 error.OutOfMemory,
...@@ -1430,7 +2211,7 @@ pub fn lowerUav(...@@ -1430,7 +2211,7 @@ pub fn lowerUav(
1430 .alignment = uav_align,2211 .alignment = uav_align,
1431 .src_loc = src_loc,2212 .src_loc = src_loc,
1432 };2213 };
1433 elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);2214 elf.const_prog_node.increaseEstimatedTotalItems(1);
1434 }2215 }
1435 }2216 }
1436 return .{ .sym_index = @intFromEnum(si) };2217 return .{ .sym_index = @intFromEnum(si) };
...@@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {...@@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
1534 }) catch |err| switch (err) {2315 }) catch |err| switch (err) {
1535 error.OutOfMemory => return error.OutOfMemory,2316 error.OutOfMemory => return error.OutOfMemory,
1536 error.CodegenFail => return error.LinkFailure,2317 error.CodegenFail => return error.LinkFailure,
1537 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}),2318 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed: {t}", .{e}),
1538 };2319 };
1539}2320}
15402321
...@@ -1553,20 +2334,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1553,20 +2334,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1553 const comp = elf.base.comp;2334 const comp = elf.base.comp;
1554 task: {2335 task: {
1555 while (elf.pending_uavs.pop()) |pending_uav| {2336 while (elf.pending_uavs.pop()) |pending_uav| {
1556 const sub_prog_node = elf.idleProgNode(2337 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });
1557 tid,
1558 comp.link_const_prog_node,
1559 .{ .uav = pending_uav.key },
1560 );
1561 defer sub_prog_node.end();2338 defer sub_prog_node.end();
1562 elf.flushUav(2339 elf.flushUav(
1563 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },2340 .{ .zcu = comp.zcu.?, .tid = tid },
1564 pending_uav.key,2341 pending_uav.key,
1565 pending_uav.value.alignment,2342 pending_uav.value.alignment,
1566 pending_uav.value.src_loc,2343 pending_uav.value.src_loc,
1567 ) catch |err| switch (err) {2344 ) catch |err| switch (err) {
1568 error.OutOfMemory => return error.OutOfMemory,2345 error.OutOfMemory => return error.OutOfMemory,
1569 else => |e| return elf.base.comp.link_diags.fail(2346 else => |e| return comp.link_diags.fail(
1570 "linker failed to lower constant: {t}",2347 "linker failed to lower constant: {t}",
1571 .{e},2348 .{e},
1572 ),2349 ),
...@@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1575 }2352 }
1576 var lazy_it = elf.lazy.iterator();2353 var lazy_it = elf.lazy.iterator();
1577 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {2354 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
1578 const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid };2355 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
1579 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };2356 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
1580 lazy.value.pending_index += 1;2357 lazy.value.pending_index += 1;
1581 const kind = switch (lmr.kind) {2358 const kind = switch (lmr.kind) {
...@@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1583 .const_data => "data",2360 .const_data => "data",
1584 };2361 };
1585 var name: [std.Progress.Node.max_name_len]u8 = undefined;2362 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1586 const sub_prog_node = comp.link_synth_prog_node.start(2363 const sub_prog_node = elf.synth_prog_node.start(
1587 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{2364 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1588 kind,2365 kind,
1589 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),2366 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
...@@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1593 defer sub_prog_node.end();2370 defer sub_prog_node.end();
1594 elf.flushLazy(pt, lmr) catch |err| switch (err) {2371 elf.flushLazy(pt, lmr) catch |err| switch (err) {
1595 error.OutOfMemory => return error.OutOfMemory,2372 error.OutOfMemory => return error.OutOfMemory,
1596 else => |e| return elf.base.comp.link_diags.fail(2373 else => |e| return comp.link_diags.fail(
1597 "linker failed to lower lazy {s}: {t}",2374 "linker failed to lower lazy {s}: {t}",
1598 .{ kind, e },2375 .{ kind, e },
1599 ),2376 ),
1600 };2377 };
1601 break :task;2378 break :task;
1602 };2379 };
2380 if (elf.input_section_pending_index < elf.input_sections.items.len) {
2381 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);
2382 elf.input_section_pending_index += 1;
2383 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf)));
2384 defer sub_prog_node.end();
2385 elf.flushInputSection(isi) catch |err| switch (err) {
2386 else => |e| {
2387 const ii = isi.input(elf);
2388 return comp.link_diags.fail(
2389 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
2390 .{
2391 elf.sectionName(
2392 elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section,
2393 ),
2394 ii.path(elf).fmtEscapeString(),
2395 fmtMemberString(ii.member(elf)),
2396 e,
2397 },
2398 );
2399 },
2400 };
2401 break :task;
2402 }
1603 while (elf.mf.updates.pop()) |ni| {2403 while (elf.mf.updates.pop()) |ni| {
1604 const clean_moved = ni.cleanMoved(&elf.mf);2404 const clean_moved = ni.cleanMoved(&elf.mf);
1605 const clean_resized = ni.cleanResized(&elf.mf);2405 const clean_resized = ni.cleanResized(&elf.mf);
...@@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1614 }2414 }
1615 if (elf.pending_uavs.count() > 0) return true;2415 if (elf.pending_uavs.count() > 0) return true;
1616 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;2416 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
2417 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
1617 if (elf.mf.updates.items.len > 0) return true;2418 if (elf.mf.updates.items.len > 0) return true;
1618 return false;2419 return false;
1619}2420}
...@@ -1628,6 +2429,14 @@ fn idleProgNode(...@@ -1628,6 +2429,14 @@ fn idleProgNode(
1628 return prog_node.start(name: switch (node) {2429 return prog_node.start(name: switch (node) {
1629 else => |tag| @tagName(tag),2430 else => |tag| @tagName(tag),
1630 .section => |si| elf.sectionName(si),2431 .section => |si| elf.sectionName(si),
2432 .input_section => |isi| {
2433 const ii = isi.input(elf);
2434 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
2435 ii.path(elf).fmtEscapeString(),
2436 fmtMemberString(ii.member(elf)),
2437 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),
2438 }) catch &name;
2439 },
1631 .nav => |nmi| {2440 .nav => |nmi| {
1632 const ip = &elf.base.comp.zcu.?.intern_pool;2441 const ip = &elf.base.comp.zcu.?.intern_pool;
1633 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);2442 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);
...@@ -1655,7 +2464,7 @@ fn flushUav(...@@ -1655,7 +2464,7 @@ fn flushUav(
1655 switch (sym.ni) {2464 switch (sym.ni) {
1656 .none => {2465 .none => {
1657 try elf.nodes.ensureUnusedCapacity(gpa, 1);2466 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1658 const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{2467 const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{
1659 .alignment = uav_align.toStdMem(),2468 .alignment = uav_align.toStdMem(),
1660 .moved = true,2469 .moved = true,
1661 });2470 });
...@@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
1749 si.applyLocationRelocs(elf);2558 si.applyLocationRelocs(elf);
1750}2559}
17512560
1752fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {2561fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
2562 const file_loc = isi.fileLocation(elf);
2563 if (file_loc.size == 0) return;
2564 const comp = elf.base.comp;
2565 const gpa = comp.gpa;
2566 const ii = isi.input(elf);
2567 const path = ii.path(elf);
2568 const file = try path.root_dir.handle.adaptToNewApi().openFile(comp.io, path.sub_path, .{});
2569 defer file.close(comp.io);
2570 var fr = file.reader(comp.io, &.{});
2571 try fr.seekTo(file_loc.offset);
2572 var nw: MappedFile.Node.Writer = undefined;
2573 isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw);
2574 defer nw.deinit();
2575 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
2576 return error.EndOfStream;
2577}
2578
2579fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
1753 switch (elf.getNode(ni)) {2580 switch (elf.getNode(ni)) {
1754 .file => unreachable,2581 else => unreachable,
1755 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),2582 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),
1756 .shdr => switch (elf.ehdrPtr()) {2583 .shdr => switch (elf.ehdrPtr()) {
1757 inline else => |ehdr| elf.targetStore(2584 inline else => |ehdr| elf.targetStore(
...@@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1759 @intCast(ni.fileLocation(&elf.mf, false).offset),2586 @intCast(ni.fileLocation(&elf.mf, false).offset),
1760 ),2587 ),
1761 },2588 },
1762 .segment => |phndx| switch (elf.phdrSlice()) {2589 .segment => |phndx| {
1763 inline else => |phdr, class| {2590 switch (elf.phdrSlice()) {
1764 const ph = &phdr[phndx];2591 inline else => |phdr| elf.targetStore(
1765 elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));2592 &phdr[phndx].offset,
1766 switch (elf.targetLoad(&ph.type)) {2593 @intCast(ni.fileLocation(&elf.mf, false).offset),
1767 else => unreachable,2594 ),
1768 std.elf.PT_NULL, std.elf.PT_LOAD => return,2595 }
1769 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},2596 var child_it = ni.children(&elf.mf);
1770 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,2597 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
1771 std.elf.PT_TLS => {},
1772 }
1773 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
1774 ph.paddr = ph.vaddr;
1775 },
1776 },2598 },
1777 .section => |si| switch (elf.shdrSlice()) {2599 .section => |si| switch (elf.shdrSlice()) {
1778 inline else => |shdr, class| {2600 inline else => |shdr, class| elf.targetStore(
1779 const sym = @field(elf.symPtr(si), @tagName(class));2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
1780 const sh = &shdr[elf.targetLoad(&sym.shndx)];2602 @intCast(ni.fileLocation(&elf.mf, false).offset),
1781 elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));2603 ),
1782 const flags = elf.targetLoad(&sh.flags).shf;
1783 if (flags.ALLOC) {
1784 elf.targetStore(&sh.addr, @intCast(elf.computeNodeVAddr(ni)));
1785 if (!flags.TLS) sym.value = sh.addr;
1786 }
1787 },
1788 },2604 },
1789 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(elf),2605 }
2606}
2607
2608fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2609 switch (elf.getNode(ni)) {
2610 .file => unreachable,
2611 .ehdr, .shdr => try elf.flushFileOffset(ni),
2612 .segment => |phndx| {
2613 try elf.flushFileOffset(ni);
2614 switch (elf.phdrSlice()) {
2615 inline else => |phdr, class| {
2616 const ph = &phdr[phndx];
2617 switch (elf.targetLoad(&ph.type)) {
2618 else => unreachable,
2619 std.elf.PT_NULL, std.elf.PT_LOAD => return,
2620 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
2621 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2622 std.elf.PT_TLS => {},
2623 }
2624 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2625 ph.paddr = ph.vaddr;
2626 },
2627 }
2628 },
2629 .section => |si| {
2630 try elf.flushFileOffset(ni);
2631 const addr = elf.computeNodeVAddr(ni);
2632 switch (elf.shdrSlice()) {
2633 inline else => |shdr, class| {
2634 const sym = @field(elf.symPtr(si), @tagName(class));
2635 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2636 const flags = elf.targetLoad(&sh.flags).shf;
2637 if (flags.ALLOC) {
2638 elf.targetStore(&sh.addr, @intCast(addr));
2639 sym.value = sh.addr;
2640 }
2641 },
2642 }
2643 si.flushMoved(elf, addr);
2644 },
2645 .input_section => |isi| {
2646 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
2647 inline else => |sym| elf.targetLoad(&sym.value),
2648 };
2649 const new_addr = elf.computeNodeVAddr(ni);
2650 const ii = isi.input(elf);
2651 var si = ii.symbol(elf);
2652 const end_si = ii.endSymbol(elf);
2653 while (cond: {
2654 si = si.next();
2655 break :cond si != end_si;
2656 }) {
2657 if (si.get(elf).ni != ni) continue;
2658 si.flushMoved(elf, switch (elf.symPtr(si)) {
2659 inline else => |sym| elf.targetLoad(&sym.value),
2660 } - old_addr + new_addr);
2661 }
2662 },
2663 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
2664 elf,
2665 elf.computeNodeVAddr(ni),
2666 ),
1790 }2667 }
1791 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);2668 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
1792}2669}
...@@ -1852,14 +2729,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1852,14 +2729,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
1852 else => unreachable,2729 else => unreachable,
1853 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),2730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
1854 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),2731 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),
1855 std.elf.SHT_SYMTAB => elf.targetStore(2732 std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore(
1856 &sh.info,2733 &sh.info,
1857 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),2734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
1858 ),2735 ),
1859 std.elf.SHT_STRTAB => {},2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
1860 }2737 }
1861 },2738 },
1862 },2739 },
2740 .input_section => {},
1863 .nav, .uav, .lazy_code, .lazy_const_data => {},2741 .nav, .uav, .lazy_code, .lazy_const_data => {},
1864 }2742 }
1865}2743}
...@@ -1983,6 +2861,14 @@ pub fn printNode(...@@ -1983,6 +2861,14 @@ pub fn printNode(
1983 switch (node) {2861 switch (node) {
1984 else => {},2862 else => {},
1985 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),2863 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
2864 .input_section => |isi| {
2865 const ii = isi.input(elf);
2866 try w.print("({f}{f}, {s})", .{
2867 ii.path(elf).fmtEscapeString(),
2868 fmtMemberString(ii.member(elf)),
2869 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),
2870 });
2871 },
1986 .nav => |nmi| {2872 .nav => |nmi| {
1987 const zcu = elf.base.comp.zcu.?;2873 const zcu = elf.base.comp.zcu.?;
1988 const ip = &zcu.intern_pool;2874 const ip = &zcu.intern_pool;
...@@ -2027,25 +2913,28 @@ pub fn printNode(...@@ -2027,25 +2913,28 @@ pub fn printNode(
2027 leaf = false;2913 leaf = false;
2028 try elf.printNode(tid, w, child_ni, indent + 1);2914 try elf.printNode(tid, w, child_ni, indent + 1);
2029 }2915 }
2030 if (leaf) {2916 if (!leaf) return;
2031 const file_loc = ni.fileLocation(&elf.mf, false);2917 const file_loc = ni.fileLocation(&elf.mf, false);
2032 if (file_loc.size == 0) return;2918 var address = file_loc.offset;
2033 var address = file_loc.offset;2919 if (file_loc.size == 0) {
2034 const line_len = 0x10;2920 try w.splatByteAll(' ', indent + 1);
2035 var line_it = std.mem.window(2921 try w.print("{x:0>8}\n", .{address});
2036 u8,2922 return;
2037 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],2923 }
2038 line_len,2924 const line_len = 0x10;
2039 line_len,2925 var line_it = std.mem.window(
2040 );2926 u8,
2041 while (line_it.next()) |line_bytes| : (address += line_len) {2927 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2042 try w.splatByteAll(' ', indent + 1);2928 line_len,
2043 try w.print("{x:0>8} ", .{address});2929 line_len,
2044 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});2930 );
2045 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);2931 while (line_it.next()) |line_bytes| : (address += line_len) {
2046 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');2932 try w.splatByteAll(' ', indent + 1);
2047 try w.writeByte('\n');2933 try w.print("{x:0>8} ", .{address});
2048 }2934 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
2935 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
2936 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
2937 try w.writeByte('\n');
2049 }2938 }
2050}2939}
20512940
src/link/Lld.zig+4-5
...@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
808 const link_mode = comp.config.link_mode;808 const link_mode = comp.config.link_mode;
809 const is_dyn_lib = link_mode == .dynamic and is_lib;809 const is_dyn_lib = link_mode == .dynamic and is_lib;
810 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;810 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
811 const have_dynamic_linker = link_mode == .dynamic and is_exe_or_dyn_lib;
812 const target = &comp.root_mod.resolved_target.result;811 const target = &comp.root_mod.resolved_target.result;
813 const compiler_rt_path: ?Cache.Path = blk: {812 const compiler_rt_path: ?Cache.Path = blk: {
814 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;813 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
...@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1070 }1069 }
1071 }1070 }
10721071
1073 if (have_dynamic_linker and1072 if (output_mode == .Exe and link_mode == .dynamic) {
1074 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker))
1075 {
1076 if (target.dynamic_linker.get()) |dynamic_linker| {1073 if (target.dynamic_linker.get()) |dynamic_linker| {
1077 try argv.append("-dynamic-linker");1074 try argv.append("--dynamic-linker");
1078 try argv.append(dynamic_linker);1075 try argv.append(dynamic_linker);
1076 } else {
1077 try argv.append("--no-dynamic-linker");
1079 }1078 }
1080 }1079 }
10811080
src/link/MappedFile.zig+26-15
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1file: std.fs.File,1file: std.Io.File,
2flags: packed struct {2flags: packed struct {
3 block_size: std.mem.Alignment,3 block_size: std.mem.Alignment,
4 copy_file_range_unsupported: bool,4 copy_file_range_unsupported: bool,
...@@ -24,7 +24,7 @@ pub const Error = std.posix.MMapError || std.posix.MRemapError || std.fs.File.Se...@@ -24,7 +24,7 @@ pub const Error = std.posix.MMapError || std.posix.MRemapError || std.fs.File.Se
24 NoSpaceLeft,24 NoSpaceLeft,
25};25};
2626
27pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {27pub fn init(file: std.Io.File, gpa: std.mem.Allocator) !MappedFile {
28 var mf: MappedFile = .{28 var mf: MappedFile = .{
29 .file = file,29 .file = file,
30 .flags = undefined,30 .flags = undefined,
...@@ -144,6 +144,15 @@ pub const Node = extern struct {...@@ -144,6 +144,15 @@ pub const Node = extern struct {
144 }144 }
145 };145 };
146146
147 pub const FileLocation = struct {
148 offset: u64,
149 size: u64,
150
151 pub fn end(fl: FileLocation) u64 {
152 return fl.offset + fl.size;
153 }
154 };
155
147 pub const Index = enum(u32) {156 pub const Index = enum(u32) {
148 none,157 none,
149 _,158 _,
...@@ -275,7 +284,7 @@ pub const Node = extern struct {...@@ -275,7 +284,7 @@ pub const Node = extern struct {
275 ni: Node.Index,284 ni: Node.Index,
276 mf: *const MappedFile,285 mf: *const MappedFile,
277 set_has_content: bool,286 set_has_content: bool,
278 ) struct { offset: u64, size: u64 } {287 ) FileLocation {
279 var offset, const size = ni.location(mf).resolve(mf);288 var offset, const size = ni.location(mf).resolve(mf);
280 var parent_ni = ni;289 var parent_ni = ni;
281 while (true) {290 while (true) {
...@@ -386,7 +395,7 @@ pub const Node = extern struct {...@@ -386,7 +395,7 @@ pub const Node = extern struct {
386395
387 fn sendFile(396 fn sendFile(
388 interface: *std.Io.Writer,397 interface: *std.Io.Writer,
389 file_reader: *std.fs.File.Reader,398 file_reader: *std.Io.File.Reader,
390 limit: std.Io.Limit,399 limit: std.Io.Limit,
391 ) std.Io.Writer.FileError!usize {400 ) std.Io.Writer.FileError!usize {
392 if (limit == .nothing) return 0;401 if (limit == .nothing) return 0;
...@@ -397,14 +406,14 @@ pub const Node = extern struct {...@@ -397,14 +406,14 @@ pub const Node = extern struct {
397 switch (file_reader.mode) {406 switch (file_reader.mode) {
398 .positional => {407 .positional => {
399 const fr_buf = file_reader.interface.buffered();408 const fr_buf = file_reader.interface.buffered();
400 const buf_copy_size = interface.write(fr_buf) catch unreachable;409 if (fr_buf.len > 0) {
401 file_reader.interface.toss(buf_copy_size);410 const n = interface.write(fr_buf) catch unreachable;
402 if (buf_copy_size < fr_buf.len) return buf_copy_size;411 file_reader.interface.toss(n);
403 assert(file_reader.logicalPos() == file_reader.pos);412 return n;
404413 }
405 const w: *Writer = @fieldParentPtr("interface", interface);414 const w: *Writer = @fieldParentPtr("interface", interface);
406 const copy_size: usize = @intCast(w.mf.copyFileRange(415 const n: usize = @intCast(w.mf.copyFileRange(
407 .adaptFromNewApi(file_reader.file),416 file_reader.file,
408 file_reader.pos,417 file_reader.pos,
409 w.ni.fileLocation(w.mf, true).offset + interface.end,418 w.ni.fileLocation(w.mf, true).offset + interface.end,
410 limit.minInt(interface.unusedCapacityLen()),419 limit.minInt(interface.unusedCapacityLen()),
...@@ -412,8 +421,10 @@ pub const Node = extern struct {...@@ -412,8 +421,10 @@ pub const Node = extern struct {
412 w.err = err;421 w.err = err;
413 return error.WriteFailed;422 return error.WriteFailed;
414 });423 });
415 interface.end += copy_size;424 if (n == 0) return error.Unimplemented;
416 return copy_size;425 file_reader.pos += n;
426 interface.end += n;
427 return n;
417 },428 },
418 .streaming,429 .streaming,
419 .streaming_reading,430 .streaming_reading,
...@@ -614,7 +625,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -614,7 +625,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
614 // Resize the entire file625 // Resize the entire file
615 if (ni == Node.Index.root) {626 if (ni == Node.Index.root) {
616 try mf.ensureCapacityForSetLocation(gpa);627 try mf.ensureCapacityForSetLocation(gpa);
617 try mf.file.setEndPos(new_size);628 try std.fs.File.adaptFromNewApi(mf.file).setEndPos(new_size);
618 try mf.ensureTotalCapacity(@intCast(new_size));629 try mf.ensureTotalCapacity(@intCast(new_size));
619 ni.setLocationAssumeCapacity(mf, old_offset, new_size);630 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
620 return;631 return;
...@@ -894,7 +905,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:...@@ -894,7 +905,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
894905
895fn copyFileRange(906fn copyFileRange(
896 mf: *MappedFile,907 mf: *MappedFile,
897 old_file: std.fs.File,908 old_file: std.Io.File,
898 old_file_offset: u64,909 old_file_offset: u64,
899 new_file_offset: u64,910 new_file_offset: u64,
900 size: u64,911 size: u64,
src/main.zig+23-7
...@@ -558,6 +558,7 @@ const usage_build_generic =...@@ -558,6 +558,7 @@ const usage_build_generic =
558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
561 \\ --no-dynamic-linker Do not set any dynamic interpreter path
561 \\ --sysroot [path] Set the system root directory (usually /)562 \\ --sysroot [path] Set the system root directory (usually /)
562 \\ --version [ver] Dynamic library semver563 \\ --version [ver] Dynamic library semver
563 \\ -fentry Enable entry point with default symbol name564 \\ -fentry Enable entry point with default symbol name
...@@ -1301,6 +1302,8 @@ fn buildOutputType(...@@ -1301,6 +1302,8 @@ fn buildOutputType(
1301 mod_opts.optimize_mode = parseOptimizeMode(rest);1302 mod_opts.optimize_mode = parseOptimizeMode(rest);
1302 } else if (mem.eql(u8, arg, "--dynamic-linker")) {1303 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1303 create_module.dynamic_linker = args_iter.nextOrFatal();1304 create_module.dynamic_linker = args_iter.nextOrFatal();
1305 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
1306 create_module.dynamic_linker = "";
1304 } else if (mem.eql(u8, arg, "--sysroot")) {1307 } else if (mem.eql(u8, arg, "--sysroot")) {
1305 const next_arg = args_iter.nextOrFatal();1308 const next_arg = args_iter.nextOrFatal();
1306 create_module.sysroot = next_arg;1309 create_module.sysroot = next_arg;
...@@ -2418,6 +2421,11 @@ fn buildOutputType(...@@ -2418,6 +2421,11 @@ fn buildOutputType(
2418 mem.eql(u8, arg, "-dynamic-linker"))2421 mem.eql(u8, arg, "-dynamic-linker"))
2419 {2422 {
2420 create_module.dynamic_linker = linker_args_it.nextOrFatal();2423 create_module.dynamic_linker = linker_args_it.nextOrFatal();
2424 } else if (mem.eql(u8, arg, "-I") or
2425 mem.eql(u8, arg, "--no-dynamic-linker") or
2426 mem.eql(u8, arg, "-no-dynamic-linker"))
2427 {
2428 create_module.dynamic_linker = "";
2421 } else if (mem.eql(u8, arg, "-E") or2429 } else if (mem.eql(u8, arg, "-E") or
2422 mem.eql(u8, arg, "--export-dynamic") or2430 mem.eql(u8, arg, "--export-dynamic") or
2423 mem.eql(u8, arg, "-export-dynamic"))2431 mem.eql(u8, arg, "-export-dynamic"))
...@@ -3191,13 +3199,14 @@ fn buildOutputType(...@@ -3191,13 +3199,14 @@ fn buildOutputType(
3191 const resolved_soname: ?[]const u8 = switch (soname) {3199 const resolved_soname: ?[]const u8 = switch (soname) {
3192 .yes => |explicit| explicit,3200 .yes => |explicit| explicit,
3193 .no => null,3201 .no => null,
3194 .yes_default_value => switch (target.ofmt) {3202 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
3195 .elf => if (have_version)3203 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
3204 if (have_version)
3196 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })3205 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
3197 else3206 else
3198 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),3207 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name})
3199 else => null,3208 else
3200 },3209 null,
3201 };3210 };
32023211
3203 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {3212 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
...@@ -3646,7 +3655,11 @@ fn buildOutputType(...@@ -3646,7 +3655,11 @@ fn buildOutputType(
3646 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));3655 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
3647 }3656 }
3648 if (create_module.dynamic_linker) |dl| {3657 if (create_module.dynamic_linker) |dl| {
3649 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });3658 if (dl.len > 0) {
3659 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
3660 } else {
3661 try test_exec_args.append(arena, "--no-dynamic-linker");
3662 }
3650 }3663 }
3651 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file3664 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
3652 }3665 }
...@@ -3793,7 +3806,7 @@ fn createModule(...@@ -3793,7 +3806,7 @@ fn createModule(
3793 .result = target,3806 .result = target,
3794 .is_native_os = target_query.isNativeOs(),3807 .is_native_os = target_query.isNativeOs(),
3795 .is_native_abi = target_query.isNativeAbi(),3808 .is_native_abi = target_query.isNativeAbi(),
3796 .is_explicit_dynamic_linker = !target_query.dynamic_linker.eql(.none),3809 .is_explicit_dynamic_linker = target_query.dynamic_linker != null,
3797 };3810 };
3798 };3811 };
37993812
...@@ -3965,6 +3978,7 @@ fn createModule(...@@ -3965,6 +3978,7 @@ fn createModule(
3965 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),3978 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
3966 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),3979 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
3967 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),3980 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
3981 error.ObjectFilesCannotSpecifyDynamicLinker => fatal("object files cannot specify --dynamic-linker", .{}),
3968 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),3982 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
3969 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),3983 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
3970 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),3984 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
...@@ -3973,6 +3987,7 @@ fn createModule(...@@ -3973,6 +3987,7 @@ fn createModule(
3973 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),3987 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
3974 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),3988 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
3975 error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),3989 error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),
3990 error.LldCannotSpecifyDynamicLinkerForSharedLibraries => fatal("LLD does not support --dynamic-linker on shared libraries", .{}),
3976 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),3991 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
3977 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),3992 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
3978 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),3993 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
...@@ -3984,6 +3999,7 @@ fn createModule(...@@ -3984,6 +3999,7 @@ fn createModule(
3984 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),3999 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
3985 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),4000 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
3986 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),4001 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
4002 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
3987 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),4003 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
3988 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),4004 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
3989 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),4005 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),