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(
596596 "-target", try target.query.zigTriple(b.allocator),
597597 "-mcpu", try target.query.serializeCpuAlloc(b.allocator),
598598 });
599
600 if (target.query.dynamic_linker.get()) |dynamic_linker| {
601 try zig_args.append("--dynamic-linker");
602 try zig_args.append(dynamic_linker);
599 if (target.query.dynamic_linker) |dynamic_linker| {
600 if (dynamic_linker.get()) |dynamic_linker_path| {
601 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 }
603606 }
604607 }
605608 }
lib/std/Io/File.zig+4-9
......@@ -434,8 +434,7 @@ pub const Reader = struct {
434434 return err;
435435 };
436436 }
437 r.interface.seek = 0;
438 r.interface.end = 0;
437 r.interface.tossBuffered();
439438 },
440439 .failure => return r.seek_err.?,
441440 }
......@@ -467,15 +466,11 @@ pub const Reader = struct {
467466 }
468467
469468 fn setLogicalPos(r: *Reader, offset: u64) void {
470 const logical_pos = logicalPos(r);
469 const logical_pos = r.logicalPos();
471470 if (offset < logical_pos or offset >= r.pos) {
472 r.interface.seek = 0;
473 r.interface.end = 0;
471 r.interface.tossBuffered();
474472 r.pos = offset;
475 } else {
476 const logical_delta: usize = @intCast(offset - logical_pos);
477 r.interface.seek += logical_delta;
478 }
473 } else r.interface.toss(@intCast(offset - logical_pos));
479474 }
480475
481476 /// 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,
4646abi: ?Target.Abi = null,
4747
4848/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
49/// based on the `os_tag`.
50dynamic_linker: Target.DynamicLinker = .none,
49/// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
50/// linker is used regardless of `os_tag`.
51dynamic_linker: ?Target.DynamicLinker = null,
5152
5253/// `null` means default for the cpu/arch/os combo.
5354ofmt: ?Target.ObjectFormat = null,
......@@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {
213214 const diags = args.diagnostics orelse &dummy_diags;
214215
215216 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,
217218 };
218219
219220 var it = mem.splitScalar(u8, args.arch_os_abi, '-');
......@@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {
381382
382383pub fn isNativeOs(self: Query) bool {
383384 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;
385386}
386387
387388pub fn isNativeAbi(self: Query) bool {
......@@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {
599600 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
600601 if (a.android_api_level != b.android_api_level) return false;
601602 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;
603604 if (a.ofmt != b.ofmt) return false;
604605
605606 return true;
......@@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {
611612 return SemanticVersion.order(a.?, b.?) == .eq;
612613}
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
614621test parse {
615622 const io = std.testing.io;
616623
lib/std/c.zig+2-1
......@@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {
70137013 LAZY: bool = false,
70147014 NOW: bool = false,
70157015 NOLOAD: bool = false,
7016 _3: u5 = 0,
7016 DEEPBIND: bool = false,
7017 _4: u4 = 0,
70177018 GLOBAL: bool = false,
70187019 _9: u3 = 0,
70197020 NODELETE: bool = false,
lib/std/elf.zig+46
......@@ -943,11 +943,30 @@ pub const Elf32 = struct {
943943 unused: u5 = 0,
944944 };
945945 };
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 };
946963 comptime {
947964 assert(@sizeOf(Elf32.Ehdr) == 52);
948965 assert(@sizeOf(Elf32.Phdr) == 32);
949966 assert(@sizeOf(Elf32.Shdr) == 40);
950967 assert(@sizeOf(Elf32.Sym) == 16);
968 assert(@sizeOf(Elf32.Rel) == 8);
969 assert(@sizeOf(Elf32.Rela) == 12);
951970 }
952971};
953972pub const Elf64 = struct {
......@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {
10081027 pub const Info = Elf32.Sym.Info;
10091028 pub const Other = Elf32.Sym.Other;
10101029 };
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 };
10111047 comptime {
10121048 assert(@sizeOf(Elf64.Ehdr) == 64);
10131049 assert(@sizeOf(Elf64.Phdr) == 56);
10141050 assert(@sizeOf(Elf64.Shdr) == 64);
10151051 assert(@sizeOf(Elf64.Sym) == 24);
1052 assert(@sizeOf(Elf64.Rel) == 16);
1053 assert(@sizeOf(Elf64.Rela) == 24);
10161054 }
10171055};
10181056pub const ElfN = switch (@sizeOf(usize)) {
......@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {
14281466 _,
14291467
14301468 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 }
14311477};
14321478
14331479/// 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 {
562562 // Apply the initial relocations as early as possible in the startup process. We cannot
563563 // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
564564 // so this must be fully inlined.
565 if (builtin.position_independent_executable) {
565 if (builtin.link_mode == .static and builtin.position_independent_executable) {
566566 @call(.always_inline, std.pie.relocate, .{phdrs});
567567 }
568568
lib/std/zig/system.zig+4-7
......@@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(
585585 .os = os,
586586 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
587587 .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,
589589 };
590590 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
593593 var got_dyn_section: bool = false;
594594 {
......@@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
938938 const is_linux = builtin.target.os.tag == .linux;
939939 const is_illumos = builtin.target.os.tag == .illumos;
940940 const is_darwin = builtin.target.os.tag.isDarwin();
941 const have_all_info = query.dynamic_linker.get() != null and
941 const have_all_info = query.dynamic_linker != null and
942942 query.abi != null and (!is_linux or query.abi.?.isGnu());
943943 const os_is_non_native = query.os_tag != null;
944944 // The illumos environment is always the same.
......@@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
11261126 .os = os,
11271127 .abi = abi,
11281128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
1129 .dynamic_linker = if (query.dynamic_linker.get() == null)
1130 Target.DynamicLinker.standard(cpu, os, abi)
1131 else
1132 query.dynamic_linker,
1129 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
11331130 };
11341131}
11351132
src/Compilation.zig+4-29
......@@ -258,8 +258,6 @@ test_filters: []const []const u8,
258258
259259link_task_wait_group: WaitGroup = .{},
260260link_prog_node: std.Progress.Node = .none,
261link_const_prog_node: std.Progress.Node = .none,
262link_synth_prog_node: std.Progress.Node = .none,
263261
264262llvm_opt_bisect_limit: c_int,
265263
......@@ -1991,7 +1989,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19911989 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;
19921990 },
19931991 }
1994 if (options.config.use_new_linker) break :s .zcu;
19951992 }
19961993 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
19971994 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
30663063 // we also want it around during `flush`.
30673064 if (comp.bin_file) |lf| {
30683065 comp.link_prog_node = main_progress_node.start("Linking", 0);
3069 if (lf.cast(.elf2)) |elf| {
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 }
3066 lf.startProgress(comp.link_prog_node);
30803067 }
3081 defer {
3068 defer if (comp.bin_file) |lf| {
3069 lf.endProgress();
30823070 comp.link_prog_node.end();
30833071 comp.link_prog_node = .none;
3084 comp.link_const_prog_node.end();
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 }
3072 };
30983073
30993074 try comp.performAllTheWork(main_progress_node);
31003075
src/Compilation/Config.zig+24-7
......@@ -123,6 +123,7 @@ pub const ResolveError = error{
123123 WasiExecModelRequiresWasi,
124124 SharedMemoryIsWasmOnly,
125125 ObjectFilesCannotShareMemory,
126 ObjectFilesCannotSpecifyDynamicLinker,
126127 SharedMemoryRequiresAtomicsAndBulkMemory,
127128 ThreadsRequireSharedMemory,
128129 EmittingLlvmModuleRequiresLlvmBackend,
......@@ -131,6 +132,7 @@ pub const ResolveError = error{
131132 EmittingBinaryRequiresLlvmLibrary,
132133 LldIncompatibleObjectFormat,
133134 LldCannotIncrementallyLink,
135 LldCannotSpecifyDynamicLinkerForSharedLibraries,
134136 LtoRequiresLld,
135137 SanitizeThreadRequiresLibCpp,
136138 LibCRequiresLibUnwind,
......@@ -142,6 +144,7 @@ pub const ResolveError = error{
142144 TargetCannotStaticLinkExecutables,
143145 LibCRequiresDynamicLinking,
144146 SharedLibrariesRequireDynamicLinking,
147 DynamicLinkingWithLldRequiresSharedLibraries,
145148 ExportMemoryAndDynamicIncompatible,
146149 DynamicLibraryPrecludesPie,
147150 TargetRequiresPie,
......@@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {
274277 if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
275278 break :b .dynamic;
276279 }
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
285281 if (options.link_mode) |link_mode| break :b link_mode;
286282
283 if (options.any_dyn_libs) break :b .dynamic;
284
287285 if (explicitly_exe_or_dyn_lib and link_libc) {
288286 // When using the native glibc/musl ABI, dynamic linking is usually what people want.
289287 if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
......@@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {
425423 break :b use_llvm;
426424 };
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
428445 const use_new_linker = b: {
429446 if (use_lld) {
430447 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 {
182182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
183183 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
184184 .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 },
185189 .type = .FUNC,
186190 })) else if (emit.bin_file.cast(.macho)) |macho_file|
187191 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
......@@ -217,9 +221,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217221 }, emit.lower.target), reloc_info),
218222 .mov => try emit.encodeInst(try .new(.none, .mov, &.{
219223 lowered_inst.ops[0],
220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{
221 .base = .{ .reg = .ds },
222 }) },
224 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
223225 }, emit.lower.target), reloc_info),
224226 else => unreachable,
225227 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {
......@@ -322,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {
322324 }, emit.lower.target), &.{.{
323325 .op_index = 0,
324326 .target = .{
325 .index = if (emit.bin_file.cast(.elf)) |elf_file|
326 try elf_file.getGlobalSymbol("__tls_get_addr", null)
327 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
327 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
328 "__tls_get_addr",
329 if (comp.config.link_libc) "c" else null,
330 ) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
328331 .name = "__tls_get_addr",
332 .lib_name = if (comp.config.link_libc) "c" else null,
329333 .type = .FUNC,
330334 })) else unreachable,
331335 .is_extern = true,
......@@ -720,7 +724,7 @@ pub fn emitMir(emit: *Emit) Error!void {
720724
721725 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
722726 .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"),
724728 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
725729 }, zo);
726730 for (emit.lower.mir.table) |entry| {
......@@ -738,7 +742,7 @@ pub fn emitMir(emit: *Emit) Error!void {
738742 table_reloc.source_offset,
739743 @enumFromInt(emit.atom_index),
740744 @as(i64, table_offset) + table_reloc.target_offset,
741 .{ .X86_64 = .@"32" },
745 .{ .X86_64 = .@"32S" },
742746 );
743747 for (emit.lower.mir.table) |entry| {
744748 try elf.addReloc(
......@@ -824,7 +828,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
824828 const zo = elf_file.zigObjectPtr().?;
825829 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
826830 const r_type: std.elf.R_X86_64 = if (!emit.pic)
827 .@"32"
831 .@"32S"
828832 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)
829833 .GOTPCREL
830834 else
......@@ -855,7 +859,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
855859 end_offset - 4,
856860 @enumFromInt(reloc.target.index),
857861 reloc.off,
858 .{ .X86_64 = .@"32" },
862 .{ .X86_64 = .@"32S" },
859863 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
860864 @enumFromInt(emit.atom_index),
861865 end_offset - 4,
src/link.zig+26-22
......@@ -571,6 +571,26 @@ pub const File = struct {
571571 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
572572 }
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
574594 pub fn makeWritable(base: *File) !void {
575595 dev.check(.make_writable);
576596 const comp = base.comp;
......@@ -620,10 +640,10 @@ pub const File = struct {
620640 &coff.mf
621641 else
622642 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, .{
624644 .mode = .read_write,
625 }));
626 base.file = mf.file;
645 });
646 base.file = .adaptFromNewApi(mf.file);
627647 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
628648 },
629649 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
......@@ -648,6 +668,7 @@ pub const File = struct {
648668 pub fn makeExecutable(base: *File) !void {
649669 dev.check(.make_executable);
650670 const comp = base.comp;
671 const io = comp.io;
651672 switch (comp.config.output_mode) {
652673 .Obj => return,
653674 .Lib => switch (comp.config.link_mode) {
......@@ -698,8 +719,8 @@ pub const File = struct {
698719 unreachable;
699720 mf.unmap();
700721 assert(mf.file.handle == f.handle);
722 mf.file.close(io);
701723 mf.file = undefined;
702 f.close();
703724 base.file = null;
704725 },
705726 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
......@@ -1120,7 +1141,7 @@ pub const File = struct {
11201141 pub fn loadInput(base: *File, input: Input) anyerror!void {
11211142 if (base.tag == .lld) return;
11221143 switch (base.tag) {
1123 inline .elf, .wasm => |tag| {
1144 inline .elf, .elf2, .wasm => |tag| {
11241145 dev.check(tag.devFeature());
11251146 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
11261147 },
......@@ -1281,9 +1302,6 @@ pub const PrelinkTask = union(enum) {
12811302 /// Tells the linker to load a shared library, possibly one that is a
12821303 /// GNU ld script.
12831304 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,
12871305};
12881306pub const ZcuTask = union(enum) {
12891307 /// Write the constant value for a Decl to the output file.
......@@ -1461,20 +1479,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
14611479 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
14621480 };
14631481 },
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 },
14781482 }
14791483}
14801484pub 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 {
2626 src_loc: Zcu.LazySrcLoc,
2727}),
2828relocs: std.ArrayList(Reloc),
29const_prog_node: std.Progress.Node,
30synth_prog_node: std.Progress.Node,
2931
3032pub const default_file_alignment: u16 = 0x200;
3133pub const default_size_of_stack_reserve: u32 = 0x1000000;
......@@ -630,11 +632,11 @@ fn create(
630632 };
631633
632634 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, .{
634636 .read = true,
635637 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
636638 });
637 errdefer file.close();
639 errdefer file.close(comp.io);
638640 coff.* = .{
639641 .base = .{
640642 .tag = .coff2,
......@@ -642,7 +644,7 @@ fn create(
642644 .comp = comp,
643645 .emit = path,
644646
645 .file = file,
647 .file = .adaptFromNewApi(file),
646648 .gc_sections = false,
647649 .print_gc_sections = false,
648650 .build_id = .none,
......@@ -671,6 +673,8 @@ fn create(
671673 }),
672674 .pending_uavs = .empty,
673675 .relocs = .empty,
676 .const_prog_node = .none,
677 .synth_prog_node = .none,
674678 };
675679 errdefer coff.deinit();
676680
......@@ -973,6 +977,26 @@ fn initHeaders(
973977 assert(coff.nodes.len == expected_nodes_len);
974978}
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
9761000fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
9771001 return coff.nodes.get(@intFromEnum(ni));
9781002}
......@@ -1172,7 +1196,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo
11721196 });
11731197 if (!sym_gop.found_existing) {
11741198 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
1175 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
1199 coff.synth_prog_node.increaseEstimatedTotalItems(1);
11761200 }
11771201 return sym_gop.value_ptr.*;
11781202}
......@@ -1250,7 +1274,7 @@ pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {
12501274 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
12511275 if (!sym_gop.found_existing) {
12521276 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();
1253 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
1277 coff.synth_prog_node.increaseEstimatedTotalItems(1);
12541278 }
12551279 return sym_gop.value_ptr.*;
12561280}
......@@ -1585,7 +1609,7 @@ pub fn lowerUav(
15851609 .alignment = uav_align,
15861610 .src_loc = src_loc,
15871611 };
1588 coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);
1612 coff.const_prog_node.increaseEstimatedTotalItems(1);
15891613 }
15901614 }
15911615 return .{ .sym_index = @intFromEnum(si) };
......@@ -1726,17 +1750,16 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
17261750 const comp = coff.base.comp;
17271751 task: {
17281752 while (coff.pending_uavs.pop()) |pending_uav| {
1729 const sub_prog_node =
1730 coff.idleProgNode(tid, comp.link_const_prog_node, .{ .uav = pending_uav.key });
1753 const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key });
17311754 defer sub_prog_node.end();
17321755 coff.flushUav(
1733 .{ .zcu = coff.base.comp.zcu.?, .tid = tid },
1756 .{ .zcu = comp.zcu.?, .tid = tid },
17341757 pending_uav.key,
17351758 pending_uav.value.alignment,
17361759 pending_uav.value.src_loc,
17371760 ) catch |err| switch (err) {
17381761 error.OutOfMemory => return error.OutOfMemory,
1739 else => |e| return coff.base.comp.link_diags.fail(
1762 else => |e| return comp.link_diags.fail(
17401763 "linker failed to lower constant: {t}",
17411764 .{e},
17421765 ),
......@@ -1744,17 +1767,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
17441767 break :task;
17451768 }
17461769 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 };
17481771 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);
17491772 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(
17511774 gmi.globalName(coff).name.toSlice(coff),
17521775 0,
17531776 );
17541777 defer sub_prog_node.end();
17551778 coff.flushGlobal(pt, gmi) catch |err| switch (err) {
17561779 error.OutOfMemory => return error.OutOfMemory,
1757 else => |e| return coff.base.comp.link_diags.fail(
1780 else => |e| return comp.link_diags.fail(
17581781 "linker failed to lower constant: {t}",
17591782 .{e},
17601783 ),
......@@ -1763,7 +1786,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
17631786 }
17641787 var lazy_it = coff.lazy.iterator();
17651788 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 };
17671790 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
17681791 lazy.value.pending_index += 1;
17691792 const kind = switch (lmr.kind) {
......@@ -1771,7 +1794,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
17711794 .const_data => "data",
17721795 };
17731796 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(
17751798 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
17761799 kind,
17771800 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),
......@@ -1781,7 +1804,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
17811804 defer sub_prog_node.end();
17821805 coff.flushLazy(pt, lmr) catch |err| switch (err) {
17831806 error.OutOfMemory => return error.OutOfMemory,
1784 else => |e| return coff.base.comp.link_diags.fail(
1807 else => |e| return comp.link_diags.fail(
17851808 "linker failed to lower lazy {s}: {t}",
17861809 .{ kind, e },
17871810 ),
......@@ -1802,6 +1825,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
18021825 }
18031826 }
18041827 if (coff.pending_uavs.count() > 0) return true;
1828 if (coff.globals.count() > coff.global_pending_index) return true;
18051829 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
18061830 if (coff.mf.updates.items.len > 0) return true;
18071831 return false;
src/link/Elf.zig+11-7
......@@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {
18821882 const comp = self.base.comp;
18831883 const target = self.getTarget();
18841884 const ptr_size = self.ptrWidthBytes();
1885 const shared_objects = self.shared_objects.values();
18861885
18871886 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
18881887 .Exe => true,
18891888 .Lib => comp.config.link_mode == .dynamic,
18901889 .Obj => false,
18911890 };
1892 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
1893
1894 const needs_interp = have_dynamic_linker and
1895 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
1891 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib;
18961892
18971893 const needs_eh_frame = blk: {
18981894 if (self.zigObjectPtr()) |zo|
......@@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {
20042000 });
20052001 }
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) {
20082012 self.section_indexes.interp = try self.addSection(.{
20092013 .name = try self.insertShString(".interp"),
20102014 .type = elf.SHT_PROGBITS,
......@@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {
20132017 });
20142018 }
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()) {
20172021 if (self.section_indexes.dynstrtab == null) {
20182022 self.section_indexes.dynstrtab = try self.addSection(.{
20192023 .name = try self.insertShString(".dynstr"),
src/link/Elf/Archive.zig+1-3
......@@ -34,8 +34,6 @@ pub fn parse(
3434 defer strtab.deinit(gpa);
3535
3636 while (pos < size) {
37 pos = mem.alignForward(usize, pos, 2);
38
3937 var hdr: elf.ar_hdr = undefined;
4038 {
4139 const n = try handle.preadAll(mem.asBytes(&hdr), pos);
......@@ -50,7 +48,7 @@ pub fn parse(
5048 }
5149
5250 const obj_size = try hdr.size();
53 defer pos += obj_size;
51 defer pos = std.mem.alignForward(usize, pos + obj_size, 2);
5452
5553 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
5654 if (hdr.isStrtab()) {
src/link/Elf2.zig+1138-249
......@@ -1,11 +1,27 @@
11base: link.File,
2options: link.File.OpenOptions,
23mf: MappedFile,
3known: Node.Known,
4ni: Node.Known,
45nodes: std.MultiArrayList(Node),
56phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,
68symtab: std.ArrayList(Symbol),
79shstrtab: StringTable,
810strtab: 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,
925globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
1026navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
1127uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
......@@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
2036relocs: std.ArrayList(Reloc),
2137/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
2238entry_hack: Symbol.Index,
39const_prog_node: std.Progress.Node,
40synth_prog_node: std.Progress.Node,
41input_prog_node: std.Progress.Node,
2342
2443pub const Node = union(enum) {
2544 file,
......@@ -27,11 +46,52 @@ pub const Node = union(enum) {
2746 shdr,
2847 segment: u32,
2948 section: Symbol.Index,
49 input_section: InputSectionIndex,
3050 nav: NavMapIndex,
3151 uav: UavMapIndex,
3252 lazy_code: LazyMapRef.Index(.code),
3353 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
3595 pub const NavMapIndex = enum(u32) {
3696 _,
3797
......@@ -88,13 +148,13 @@ pub const Node = union(enum) {
88148 };
89149
90150 pub const Known = struct {
91 pub const rodata: MappedFile.Node.Index = @enumFromInt(1);
92 pub const ehdr: MappedFile.Node.Index = @enumFromInt(2);
93 pub const phdr: MappedFile.Node.Index = @enumFromInt(3);
94 pub const shdr: MappedFile.Node.Index = @enumFromInt(4);
95 pub const text: MappedFile.Node.Index = @enumFromInt(5);
96 pub const data: MappedFile.Node.Index = @enumFromInt(6);
97
151 comptime file: MappedFile.Node.Index = .root,
152 comptime ehdr: MappedFile.Node.Index = @enumFromInt(1),
153 comptime shdr: MappedFile.Node.Index = @enumFromInt(2),
154 comptime rodata: MappedFile.Node.Index = @enumFromInt(3),
155 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
156 comptime text: MappedFile.Node.Index = @enumFromInt(5),
157 comptime data: MappedFile.Node.Index = @enumFromInt(6),
98158 tls: MappedFile.Node.Index,
99159 };
100160
......@@ -176,7 +236,6 @@ pub const Symbol = struct {
176236 rodata,
177237 text,
178238 data,
179 tdata,
180239 _,
181240
182241 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
......@@ -189,44 +248,65 @@ pub const Symbol = struct {
189248 return ni;
190249 }
191250
251 pub fn next(si: Symbol.Index) Symbol.Index {
252 return @enumFromInt(@intFromEnum(si) + 1);
253 }
254
192255 pub const InitOptions = struct {
193256 name: []const u8 = "",
194 size: std.elf.Word = 0,
257 lib_name: ?[]const u8 = null,
258 value: u64 = 0,
259 size: u64 = 0,
195260 type: std.elf.STT,
196261 bind: std.elf.STB = .LOCAL,
197262 visibility: std.elf.STV = .DEFAULT,
198263 shndx: std.elf.Section = std.elf.SHN_UNDEF,
199264 };
200265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
201 const name_entry = try elf.string(.strtab, opts.name);
202 try Symbol.Index.symtab.node(elf).resize(
203 &elf.mf,
204 elf.base.comp.gpa,
205 @as(usize, switch (elf.identClass()) {
206 .NONE, _ => unreachable,
207 .@"32" => @sizeOf(std.elf.Elf32.Sym),
208 .@"64" => @sizeOf(std.elf.Elf64.Sym),
209 }) * elf.symtab.items.len,
210 );
266 const gpa = elf.base.comp.gpa;
267 const target_endian = elf.targetEndian();
268 const sym_size: usize = switch (elf.identClass()) {
269 .NONE, _ => unreachable,
270 inline else => |class| @sizeOf(class.ElfN().Sym),
271 };
272 const name_strtab_entry = try elf.string(.strtab, opts.name);
273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
211274 switch (elf.symPtr(si)) {
212 inline else => |sym| sym.* = .{
213 .name = name_entry,
214 .value = 0,
215 .size = opts.size,
216 .info = .{
217 .type = opts.type,
218 .bind = opts.bind,
219 },
220 .other = .{
221 .visibility = opts.visibility,
222 },
223 .shndx = opts.shndx,
275 inline else => |sym, class| {
276 sym.* = .{
277 .name = name_strtab_entry,
278 .value = @intCast(opts.value),
279 .size = @intCast(opts.size),
280 .info = .{ .type = opts.type, .bind = opts.bind },
281 .other = .{ .visibility = opts.visibility },
282 .shndx = opts.shndx,
283 };
284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
285 },
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);
224305 },
225306 }
226307 }
227308
228 pub fn flushMoved(si: Symbol.Index, elf: *Elf) void {
229 const value = elf.computeNodeVAddr(si.node(elf));
309 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
230310 switch (elf.symPtr(si)) {
231311 inline else => |sym, class| {
232312 elf.targetStore(&sym.value, @intCast(value));
......@@ -241,9 +321,12 @@ pub const Symbol = struct {
241321 }
242322
243323 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
244 for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| {
245 if (reloc.loc != si) break;
246 reloc.apply(elf);
324 switch (si.get(elf).loc_relocs) {
325 .none => {},
326 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
327 if (reloc.loc != si) break;
328 reloc.apply(elf);
329 },
247330 }
248331 }
249332
......@@ -267,6 +350,19 @@ pub const Symbol = struct {
267350 }
268351 };
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
270366 comptime {
271367 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
272368 }
......@@ -287,6 +383,22 @@ pub const Reloc = extern struct {
287383 AARCH64: std.elf.R_AARCH64,
288384 RISCV: std.elf.R_RISCV,
289385 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 }
290402 };
291403
292404 pub const Index = enum(u32) {
......@@ -329,7 +441,7 @@ pub const Reloc = extern struct {
329441 target_value,
330442 target_endian,
331443 ),
332 .PC32 => std.mem.writeInt(
444 .PC32, .PLT32 => std.mem.writeInt(
333445 i32,
334446 loc_slice[0..4],
335447 @intCast(@as(i64, @bitCast(target_value -% loc_value))),
......@@ -341,9 +453,15 @@ pub const Reloc = extern struct {
341453 @intCast(target_value),
342454 target_endian,
343455 ),
456 .@"32S" => std.mem.writeInt(
457 i32,
458 loc_slice[0..4],
459 @intCast(@as(i64, @bitCast(target_value))),
460 target_endian,
461 ),
344462 .TPOFF32 => {
345463 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];
347465 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
348466 std.mem.writeInt(
349467 i32,
......@@ -352,6 +470,18 @@ pub const Reloc = extern struct {
352470 target_endian,
353471 );
354472 },
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 ),
355485 },
356486 }
357487 },
......@@ -401,7 +531,6 @@ fn create(
401531 path: std.Build.Cache.Path,
402532 options: link.File.OpenOptions,
403533) !*Elf {
404 _ = options;
405534 const target = &comp.root_mod.resolved_target.result;
406535 assert(target.ofmt == .elf);
407536 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {
......@@ -434,20 +563,24 @@ fn create(
434563 .Obj => .REL,
435564 };
436565 const machine = target.toElfMachine();
437 const maybe_interp = switch (comp.config.output_mode) {
438 .Exe, .Lib => switch (comp.config.link_mode) {
439 .static => null,
440 .dynamic => target.dynamic_linker.get(),
566 const maybe_interp = switch (comp.config.link_mode) {
567 .static => null,
568 .dynamic => switch (comp.config.output_mode) {
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,
441575 },
442 .Obj => null,
443576 };
444577
445578 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, .{
447580 .read = true,
448581 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
449582 });
450 errdefer file.close();
583 errdefer file.close(comp.io);
451584 elf.* = .{
452585 .base = .{
453586 .tag = .elf2,
......@@ -455,19 +588,26 @@ fn create(
455588 .comp = comp,
456589 .emit = path,
457590
458 .file = file,
591 .file = .adaptFromNewApi(file),
459592 .gc_sections = false,
460593 .print_gc_sections = false,
461594 .build_id = .none,
462595 .allow_shlib_undefined = false,
463596 .stack_size = 0,
464597 },
598 .options = options,
465599 .mf = try .init(file, comp.gpa),
466 .known = .{
600 .ni = .{
467601 .tls = .none,
468602 },
469603 .nodes = .empty,
470604 .phdrs = .empty,
605 .si = .{
606 .dynsym = .null,
607 .dynstr = .null,
608 .dynamic = .null,
609 .tdata = .null,
610 },
471611 .symtab = .empty,
472612 .shstrtab = .{
473613 .map = .empty,
......@@ -477,6 +617,15 @@ fn create(
477617 .map = .empty,
478618 .size = 1,
479619 },
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,
480629 .globals = .empty,
481630 .navs = .empty,
482631 .uavs = .empty,
......@@ -487,6 +636,9 @@ fn create(
487636 .pending_uavs = .empty,
488637 .relocs = .empty,
489638 .entry_hack = .null,
639 .const_prog_node = .none,
640 .synth_prog_node = .none,
641 .input_prog_node = .none,
490642 };
491643 errdefer elf.deinit();
492644
......@@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void {
502654 elf.symtab.deinit(gpa);
503655 elf.shstrtab.map.deinit(gpa);
504656 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);
505663 elf.globals.deinit(gpa);
506664 elf.navs.deinit(gpa);
507665 elf.uavs.deinit(gpa);
......@@ -522,6 +680,13 @@ fn initHeaders(
522680) !void {
523681 const comp = elf.base.comp;
524682 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 };
525690 const addr_align: std.mem.Alignment = switch (class) {
526691 .NONE, _ => unreachable,
527692 .@"32" => .@"4",
......@@ -541,42 +706,32 @@ fn initHeaders(
541706 phnum += 1;
542707 const data_phndx = phnum;
543708 phnum += 1;
709 const dynamic_phndx = if (have_dynamic_section) phndx: {
710 defer phnum += 1;
711 break :phndx phnum;
712 } else undefined;
544713 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
545714 defer phnum += 1;
546715 break :phndx phnum;
547716 } 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);
550719 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
551720 try elf.phdrs.resize(gpa, phnum);
552721 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
563723 switch (class) {
564724 .NONE, _ => unreachable,
565725 inline else => |ct_class| {
566 const ElfN = switch (ct_class) {
567 .NONE, _ => comptime unreachable,
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, .{
726 const ElfN = ct_class.ElfN();
727 assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{
573728 .size = @sizeOf(ElfN.Ehdr),
574729 .alignment = addr_align,
575730 .fixed = true,
576731 }));
577732 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)));
580735 const EI = std.elf.EI;
581736 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
582737 ehdr.ident[EI.CLASS] = @intFromEnum(class);
......@@ -602,37 +757,47 @@ fn initHeaders(
602757 },
603758 }
604759
605 assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
606 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
760 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
761 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
607762 .alignment = addr_align,
608763 .moved = true,
609764 .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,
610771 .bubbles_moved = false,
611772 }));
612 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
613 elf.phdrs.items[phdr_phndx] = Node.Known.phdr;
773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
614775
615 assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
616 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
776 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
617778 .alignment = addr_align,
779 .moved = true,
780 .resized = true,
781 .bubbles_moved = false,
618782 }));
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, .{
622787 .alignment = elf.mf.flags.block_size,
623788 .moved = true,
624789 .bubbles_moved = false,
625790 }));
626791 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, .{
630795 .alignment = elf.mf.flags.block_size,
631796 .moved = true,
632797 .bubbles_moved = false,
633798 }));
634799 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
637802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
638803 else => 0,
......@@ -648,14 +813,10 @@ fn initHeaders(
648813 switch (class) {
649814 .NONE, _ => unreachable,
650815 inline else => |ct_class| {
651 const ElfN = switch (ct_class) {
652 .NONE, _ => comptime unreachable,
653 .@"32" => std.elf.Elf32,
654 .@"64" => std.elf.Elf64,
655 };
816 const ElfN = ct_class.ElfN();
656817 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)));
659820 const ph_phdr = &phdr[phdr_phndx];
660821 ph_phdr.* = .{
661822 .type = std.elf.PT_PHDR,
......@@ -665,7 +826,7 @@ fn initHeaders(
665826 .filesz = 0,
666827 .memsz = 0,
667828 .flags = .{ .R = true },
668 .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()),
829 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
669830 };
670831 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
671832
......@@ -684,7 +845,7 @@ fn initHeaders(
684845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
685846 }
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);
688849 const ph_rodata = &phdr[rodata_phndx];
689850 ph_rodata.* = .{
690851 .type = std.elf.PT_NULL,
......@@ -694,12 +855,12 @@ fn initHeaders(
694855 .filesz = @intCast(rodata_size),
695856 .memsz = @intCast(rodata_size),
696857 .flags = .{ .R = true },
697 .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()),
858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
698859 };
699860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
700861 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);
703864 const ph_text = &phdr[text_phndx];
704865 ph_text.* = .{
705866 .type = std.elf.PT_NULL,
......@@ -709,12 +870,12 @@ fn initHeaders(
709870 .filesz = @intCast(text_size),
710871 .memsz = @intCast(text_size),
711872 .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()),
713874 };
714875 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
715876 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);
718879 const ph_data = &phdr[data_phndx];
719880 ph_data.* = .{
720881 .type = std.elf.PT_NULL,
......@@ -724,11 +885,26 @@ fn initHeaders(
724885 .filesz = @intCast(data_size),
725886 .memsz = @intCast(data_size),
726887 .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()),
728889 };
729890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
730891 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
732908 if (comp.config.any_non_single_threaded) {
733909 const ph_tls = &phdr[tls_phndx];
734910 ph_tls.* = .{
......@@ -744,7 +920,7 @@ fn initHeaders(
744920 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
745921 }
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)));
748924 sh_null.* = .{
749925 .name = try elf.string(.shstrtab, ""),
750926 .type = std.elf.SHT_NULL,
......@@ -766,114 +942,187 @@ fn initHeaders(
766942 .target_relocs = .none,
767943 .unused = 0,
768944 };
769 assert(try elf.addSection(Node.Known.rodata, .{
945 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
770946 .type = std.elf.SHT_SYMTAB,
947 .size = @sizeOf(ElfN.Sym) * 1,
771948 .addralign = addr_align,
772949 .entsize = @sizeOf(ElfN.Sym),
773 }) == .symtab);
774
775 const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf)));
776 symtab.* = .{
950 }));
951 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
952 symtab_null.* = .{
777953 .name = try elf.string(.strtab, ""),
778954 .value = 0,
779955 .size = 0,
780 .info = .{
781 .type = .NOTYPE,
782 .bind = .LOCAL,
783 },
784 .other = .{
785 .visibility = .DEFAULT,
786 },
956 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
957 .other = .{ .visibility = .DEFAULT },
787958 .shndx = std.elf.SHN_UNDEF,
788959 };
960 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
789961
790962 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
791963 ehdr.shstrndx = ehdr.shnum;
792964 },
793965 }
794 assert(try elf.addSection(Node.Known.rodata, .{
966 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
795967 .type = std.elf.SHT_STRTAB,
796968 .addralign = elf.mf.flags.block_size,
797969 .entsize = 1,
798 }) == .shstrtab);
799 assert(try elf.addSection(Node.Known.rodata, .{
970 }));
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",
800977 .type = std.elf.SHT_STRTAB,
978 .size = 1,
801979 .addralign = elf.mf.flags.block_size,
802980 .entsize = 1,
803 }) == .strtab);
804 try elf.renameSection(.symtab, ".symtab");
805 try elf.renameSection(.shstrtab, ".shstrtab");
806 try elf.renameSection(.strtab, ".strtab");
981 }));
807982 try elf.linkSections(.symtab, .strtab);
808 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
809 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
983 elf.si.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, .{
812986 .name = ".rodata",
813987 .flags = .{ .ALLOC = true },
814988 .addralign = elf.mf.flags.block_size,
815 }) == .rodata);
816 assert(try elf.addSection(Node.Known.text, .{
989 }));
990 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
817991 .name = ".text",
818992 .flags = .{ .ALLOC = true, .EXECINSTR = true },
819993 .addralign = elf.mf.flags.block_size,
820 }) == .text);
821 assert(try elf.addSection(Node.Known.data, .{
994 }));
995 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
822996 .name = ".data",
823997 .flags = .{ .WRITE = true, .ALLOC = true },
824998 .addralign = elf.mf.flags.block_size,
825 }) == .data);
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 }
999 }));
8411000 if (maybe_interp) |interp| {
842 try elf.nodes.ensureUnusedCapacity(gpa, 1);
843 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
8441002 .size = interp.len + 1,
8451003 .moved = true,
8461004 .resized = true,
1005 .bubbles_moved = false,
8471006 });
8481007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
8491008 elf.phdrs.items[interp_phndx] = interp_ni;
8501009
8511010 const sec_interp_si = try elf.addSection(interp_ni, .{
8521011 .name = ".interp",
853 .size = @intCast(interp.len + 1),
8541012 .flags = .{ .ALLOC = true },
1013 .size = @intCast(interp.len + 1),
8551014 });
8561015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
8571016 @memcpy(sec_interp[0..interp.len], interp);
8581017 sec_interp[interp.len] = 0;
8591018 }
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 }
8601081 assert(elf.nodes.len == expected_nodes_len);
8611082}
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
8631110fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
8641111 return elf.nodes.get(@intFromEnum(ni));
8651112}
8661113fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
8671114 const parent_vaddr = parent_vaddr: {
8681115 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {
869 .file, .ehdr, .shdr => unreachable,
1116 .file => return 0,
1117 .ehdr, .shdr => unreachable,
8701118 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
8711119 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
8721120 },
8731121 .section => |si| si,
1122 .input_section => unreachable,
8741123 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
8751124 };
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)) {
8771126 inline else => |sym| elf.targetLoad(&sym.value),
8781127 };
8791128 };
......@@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) {
9281177 @"64": *std.elf.Elf64.Ehdr,
9291178};
9301179pub fn ehdrPtr(elf: *Elf) EhdrPtr {
931 const slice = Node.Known.ehdr.slice(&elf.mf);
1180 const slice = elf.ni.ehdr.slice(&elf.mf);
9321181 return switch (elf.identClass()) {
9331182 .NONE, _ => unreachable,
9341183 inline else => |class| @unionInit(
......@@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
9531202 @"64": []std.elf.Elf64.Phdr,
9541203};
9551204pub fn phdrSlice(elf: *Elf) PhdrSlice {
956 const slice = Node.Known.phdr.slice(&elf.mf);
1205 const slice = elf.ni.phdr.slice(&elf.mf);
9571206 return switch (elf.identClass()) {
9581207 .NONE, _ => unreachable,
9591208 inline else => |class| @unionInit(
......@@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) {
9701219 @"64": []std.elf.Elf64.Shdr,
9711220};
9721221pub fn shdrSlice(elf: *Elf) ShdrSlice {
973 const slice = Node.Known.shdr.slice(&elf.mf);
1222 const slice = elf.ni.shdr.slice(&elf.mf);
9741223 return switch (elf.identClass()) {
9751224 .NONE, _ => unreachable,
9761225 inline else => |class| @unionInit(
......@@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) {
9871236 @"64": []std.elf.Elf64.Sym,
9881237};
9891238pub 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);
9911240 return switch (elf.identClass()) {
9921241 .NONE, _ => unreachable,
9931242 inline else => |class| @unionInit(
......@@ -1009,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
10091258 };
10101259}
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
10121273fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
10131274 defer elf.symtab.addOneAssumeCapacity().* = .{
10141275 .ni = .none,
......@@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I
10271288
10281289pub fn globalSymbol(elf: *Elf, opts: struct {
10291290 name: []const u8,
1291 lib_name: ?[]const u8 = null,
10301292 type: std.elf.STT,
10311293 bind: std.elf.STB = .GLOBAL,
10321294 visibility: std.elf.STV = .DEFAULT,
......@@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct {
10361298 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
10371299 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
10381300 .name = opts.name,
1301 .lib_name = opts.lib_name,
10391302 .type = opts.type,
10401303 .bind = opts.bind,
10411304 .visibility = opts.visibility,
......@@ -1072,30 +1335,33 @@ fn navType(
10721335 },
10731336 };
10741337}
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}
10751349fn navSection(
10761350 elf: *Elf,
10771351 ip: *const InternPool,
10781352 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
10791353) Symbol.Index {
1080 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| {
1081 if (std.mem.eql(u8, @"linksection", ".rodata") or
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 }
1354 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1355 if (elf.namedSection(@"linksection")) |si| return si;
10901356 return switch (navType(
10911357 ip,
10921358 .{ .fully_resolved = nav_fr },
10931359 elf.base.comp.config.any_non_single_threaded,
10941360 )) {
10951361 else => unreachable,
1096 .FUNC => .text,
1097 .OBJECT => .data,
1098 .TLS => .tdata,
1362 .FUNC => elf.si.text,
1363 .OBJECT => elf.si.data,
1364 .TLS => elf.si.tdata,
10991365 };
11001366}
11011367fn 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.
11151381 const nav = ip.getNav(nav_index);
11161382 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
11171383 .name = @"extern".name.toSlice(ip),
1384 .lib_name = @"extern".lib_name.toSlice(ip),
11181385 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
11191386 .bind = switch (@"extern".linkage) {
11201387 .internal => .LOCAL,
......@@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
11561423 .const_data => .OBJECT,
11571424 },
11581425 });
1159 elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
1426 elf.synth_prog_node.increaseEstimatedTotalItems(1);
11601427 }
11611428 return lazy_gop.value_ptr.*;
11621429}
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
11641943pub fn getNavVAddr(
11651944 elf: *Elf,
11661945 pt: Zcu.PerThread,
......@@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
11841963 reloc_info.offset,
11851964 target_si,
11861965 reloc_info.addend,
1187 switch (elf.ehdrField(.machine)) {
1188 else => unreachable,
1189 .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
1190 .NONE, _ => unreachable,
1191 .@"32" => .@"32",
1192 .@"64" => .@"64",
1193 } },
1194 },
1966 .absAddr(elf),
11951967 );
11961968 return switch (elf.symPtr(target_si)) {
11971969 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
12011973fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12021974 name: []const u8 = "",
12031975 type: std.elf.Word = std.elf.SHT_NULL,
1204 size: std.elf.Word = 0,
12051976 flags: std.elf.SHF = .{},
1977 size: std.elf.Word = 0,
12061978 addralign: std.mem.Alignment = .@"1",
12071979 entsize: std.elf.Word = 0,
12081980}) !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 }
12091986 const gpa = elf.base.comp.gpa;
12101987 try elf.nodes.ensureUnusedCapacity(gpa, 1);
12111988 try elf.symtab.ensureUnusedCapacity(gpa, 1);
......@@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12191996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
12201997 },
12211998 };
1222 try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size);
1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
12232000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
12242001 .alignment = opts.addralign,
12252002 .size = opts.size,
1226 .moved = true,
2003 .resized = opts.size > 0,
12272004 });
12282005 const si = elf.addSymbolAssumeCapacity();
12292006 elf.nodes.appendAssumeCapacity(.{ .section = si });
12302007 si.get(elf).ni = ni;
2008 const addr = elf.computeNodeVAddr(ni);
2009 const offset = ni.fileLocation(&elf.mf, false).offset;
12312010 try si.init(elf, .{
1232 .name = opts.name,
2011 .value = addr,
12332012 .size = opts.size,
12342013 .type = .SECTION,
12352014 .shndx = shndx,
......@@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12412020 .name = shstrtab_entry,
12422021 .type = opts.type,
12432022 .flags = .{ .shf = opts.flags },
1244 .addr = 0,
1245 .offset = 0,
2023 .addr = @intCast(addr),
2024 .offset = @intCast(offset),
12462025 .size = opts.size,
12472026 .link = 0,
12482027 .info = 0,
......@@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12562035}
12572036
12582037fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1259 const strtab_entry = try elf.string(.strtab, name);
12602038 const shstrtab_entry = try elf.string(.shstrtab, name);
12612039 switch (elf.shdrSlice()) {
1262 inline else => |shdr, class| {
1263 const sym = @field(elf.symPtr(si), @tagName(class));
1264 elf.targetStore(&sym.name, strtab_entry);
1265 const sh = &shdr[elf.targetLoad(&sym.shndx)];
1266 elf.targetStore(&sh.name, shstrtab_entry);
1267 },
2040 inline else => |shdr, class| elf.targetStore(
2041 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2042 shstrtab_entry,
2043 ),
12682044 }
12692045}
12702046
......@@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
12772053}
12782054
12792055fn 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()) {
12812057 inline else => |shndx, class| elf.targetLoad(
12822058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
12832059 ),
......@@ -1285,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
12852061 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
12862062}
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 {
12892065 if (key.len == 0) return 0;
12902066 return @field(elf, @tagName(section)).get(
12912067 elf.base.comp.gpa,
12922068 &elf.mf,
1293 @field(Symbol.Index, @tagName(section)).node(elf),
2069 @field(elf.si, @tagName(section)).node(elf),
12942070 key,
12952071 );
12962072}
......@@ -1303,10 +2079,20 @@ pub fn addReloc(
13032079 addend: i64,
13042080 @"type": Reloc.Type,
13052081) !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 {
13072093 const target = target_si.get(elf);
13082094 const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len);
1309 (try elf.relocs.addOne(gpa)).* = .{
2095 elf.relocs.addOneAssumeCapacity().* = .{
13102096 .type = @"type",
13112097 .prev = .none,
13122098 .next = target.target_relocs,
......@@ -1323,11 +2109,6 @@ pub fn addReloc(
13232109 target.target_relocs = ri;
13242110}
13252111
1326pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void {
1327 _ = elf;
1328 _ = prog_node;
1329}
1330
13312112pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
13322113 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
13332114 error.OutOfMemory,
......@@ -1430,7 +2211,7 @@ pub fn lowerUav(
14302211 .alignment = uav_align,
14312212 .src_loc = src_loc,
14322213 };
1433 elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);
2214 elf.const_prog_node.increaseEstimatedTotalItems(1);
14342215 }
14352216 }
14362217 return .{ .sym_index = @intFromEnum(si) };
......@@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
15342315 }) catch |err| switch (err) {
15352316 error.OutOfMemory => return error.OutOfMemory,
15362317 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}),
15382319 };
15392320}
15402321
......@@ -1553,20 +2334,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15532334 const comp = elf.base.comp;
15542335 task: {
15552336 while (elf.pending_uavs.pop()) |pending_uav| {
1556 const sub_prog_node = elf.idleProgNode(
1557 tid,
1558 comp.link_const_prog_node,
1559 .{ .uav = pending_uav.key },
1560 );
2337 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });
15612338 defer sub_prog_node.end();
15622339 elf.flushUav(
1563 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
2340 .{ .zcu = comp.zcu.?, .tid = tid },
15642341 pending_uav.key,
15652342 pending_uav.value.alignment,
15662343 pending_uav.value.src_loc,
15672344 ) catch |err| switch (err) {
15682345 error.OutOfMemory => return error.OutOfMemory,
1569 else => |e| return elf.base.comp.link_diags.fail(
2346 else => |e| return comp.link_diags.fail(
15702347 "linker failed to lower constant: {t}",
15712348 .{e},
15722349 ),
......@@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15752352 }
15762353 var lazy_it = elf.lazy.iterator();
15772354 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 };
15792356 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
15802357 lazy.value.pending_index += 1;
15812358 const kind = switch (lmr.kind) {
......@@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15832360 .const_data => "data",
15842361 };
15852362 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(
15872364 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
15882365 kind,
15892366 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
......@@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15932370 defer sub_prog_node.end();
15942371 elf.flushLazy(pt, lmr) catch |err| switch (err) {
15952372 error.OutOfMemory => return error.OutOfMemory,
1596 else => |e| return elf.base.comp.link_diags.fail(
2373 else => |e| return comp.link_diags.fail(
15972374 "linker failed to lower lazy {s}: {t}",
15982375 .{ kind, e },
15992376 ),
16002377 };
16012378 break :task;
16022379 };
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 }
16032403 while (elf.mf.updates.pop()) |ni| {
16042404 const clean_moved = ni.cleanMoved(&elf.mf);
16052405 const clean_resized = ni.cleanResized(&elf.mf);
......@@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
16142414 }
16152415 if (elf.pending_uavs.count() > 0) return true;
16162416 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;
16172418 if (elf.mf.updates.items.len > 0) return true;
16182419 return false;
16192420}
......@@ -1628,6 +2429,14 @@ fn idleProgNode(
16282429 return prog_node.start(name: switch (node) {
16292430 else => |tag| @tagName(tag),
16302431 .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 },
16312440 .nav => |nmi| {
16322441 const ip = &elf.base.comp.zcu.?.intern_pool;
16332442 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);
......@@ -1655,7 +2464,7 @@ fn flushUav(
16552464 switch (sym.ni) {
16562465 .none => {
16572466 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), .{
16592468 .alignment = uav_align.toStdMem(),
16602469 .moved = true,
16612470 });
......@@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
17492558 si.applyLocationRelocs(elf);
17502559}
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 {
17532580 switch (elf.getNode(ni)) {
1754 .file => unreachable,
2581 else => unreachable,
17552582 .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0),
17562583 .shdr => switch (elf.ehdrPtr()) {
17572584 inline else => |ehdr| elf.targetStore(
......@@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
17592586 @intCast(ni.fileLocation(&elf.mf, false).offset),
17602587 ),
17612588 },
1762 .segment => |phndx| switch (elf.phdrSlice()) {
1763 inline else => |phdr, class| {
1764 const ph = &phdr[phndx];
1765 elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));
1766 switch (elf.targetLoad(&ph.type)) {
1767 else => unreachable,
1768 std.elf.PT_NULL, std.elf.PT_LOAD => return,
1769 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
1770 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
1771 std.elf.PT_TLS => {},
1772 }
1773 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
1774 ph.paddr = ph.vaddr;
1775 },
2589 .segment => |phndx| {
2590 switch (elf.phdrSlice()) {
2591 inline else => |phdr| elf.targetStore(
2592 &phdr[phndx].offset,
2593 @intCast(ni.fileLocation(&elf.mf, false).offset),
2594 ),
2595 }
2596 var child_it = ni.children(&elf.mf);
2597 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
17762598 },
17772599 .section => |si| switch (elf.shdrSlice()) {
1778 inline else => |shdr, class| {
1779 const sym = @field(elf.symPtr(si), @tagName(class));
1780 const sh = &shdr[elf.targetLoad(&sym.shndx)];
1781 elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset));
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 },
2600 inline else => |shdr, class| elf.targetStore(
2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
2602 @intCast(ni.fileLocation(&elf.mf, false).offset),
2603 ),
17882604 },
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 ),
17902667 }
17912668 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
17922669}
......@@ -1852,14 +2729,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
18522729 else => unreachable,
18532730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
18542731 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(
18562733 &sh.info,
18572734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
18582735 ),
1859 std.elf.SHT_STRTAB => {},
2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
18602737 }
18612738 },
18622739 },
2740 .input_section => {},
18632741 .nav, .uav, .lazy_code, .lazy_const_data => {},
18642742 }
18652743}
......@@ -1983,6 +2861,14 @@ pub fn printNode(
19832861 switch (node) {
19842862 else => {},
19852863 .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 },
19862872 .nav => |nmi| {
19872873 const zcu = elf.base.comp.zcu.?;
19882874 const ip = &zcu.intern_pool;
......@@ -2027,25 +2913,28 @@ pub fn printNode(
20272913 leaf = false;
20282914 try elf.printNode(tid, w, child_ni, indent + 1);
20292915 }
2030 if (leaf) {
2031 const file_loc = ni.fileLocation(&elf.mf, false);
2032 if (file_loc.size == 0) return;
2033 var address = file_loc.offset;
2034 const line_len = 0x10;
2035 var line_it = std.mem.window(
2036 u8,
2037 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2038 line_len,
2039 line_len,
2040 );
2041 while (line_it.next()) |line_bytes| : (address += line_len) {
2042 try w.splatByteAll(' ', indent + 1);
2043 try w.print("{x:0>8} ", .{address});
2044 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
2045 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
2046 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
2047 try w.writeByte('\n');
2048 }
2916 if (!leaf) return;
2917 const file_loc = ni.fileLocation(&elf.mf, false);
2918 var address = file_loc.offset;
2919 if (file_loc.size == 0) {
2920 try w.splatByteAll(' ', indent + 1);
2921 try w.print("{x:0>8}\n", .{address});
2922 return;
2923 }
2924 const line_len = 0x10;
2925 var line_it = std.mem.window(
2926 u8,
2927 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2928 line_len,
2929 line_len,
2930 );
2931 while (line_it.next()) |line_bytes| : (address += line_len) {
2932 try w.splatByteAll(' ', indent + 1);
2933 try w.print("{x:0>8} ", .{address});
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');
20492938 }
20502939}
20512940
src/link/Lld.zig+4-5
......@@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
808808 const link_mode = comp.config.link_mode;
809809 const is_dyn_lib = link_mode == .dynamic and is_lib;
810810 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;
812811 const target = &comp.root_mod.resolved_target.result;
813812 const compiler_rt_path: ?Cache.Path = blk: {
814813 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
......@@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
10701069 }
10711070 }
10721071
1073 if (have_dynamic_linker and
1074 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker))
1075 {
1072 if (output_mode == .Exe and link_mode == .dynamic) {
10761073 if (target.dynamic_linker.get()) |dynamic_linker| {
1077 try argv.append("-dynamic-linker");
1074 try argv.append("--dynamic-linker");
10781075 try argv.append(dynamic_linker);
1076 } else {
1077 try argv.append("--no-dynamic-linker");
10791078 }
10801079 }
10811080
src/link/MappedFile.zig+26-15
......@@ -1,4 +1,4 @@
1file: std.fs.File,
1file: std.Io.File,
22flags: packed struct {
33 block_size: std.mem.Alignment,
44 copy_file_range_unsupported: bool,
......@@ -24,7 +24,7 @@ pub const Error = std.posix.MMapError || std.posix.MRemapError || std.fs.File.Se
2424 NoSpaceLeft,
2525};
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 {
2828 var mf: MappedFile = .{
2929 .file = file,
3030 .flags = undefined,
......@@ -144,6 +144,15 @@ pub const Node = extern struct {
144144 }
145145 };
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
147156 pub const Index = enum(u32) {
148157 none,
149158 _,
......@@ -275,7 +284,7 @@ pub const Node = extern struct {
275284 ni: Node.Index,
276285 mf: *const MappedFile,
277286 set_has_content: bool,
278 ) struct { offset: u64, size: u64 } {
287 ) FileLocation {
279288 var offset, const size = ni.location(mf).resolve(mf);
280289 var parent_ni = ni;
281290 while (true) {
......@@ -386,7 +395,7 @@ pub const Node = extern struct {
386395
387396 fn sendFile(
388397 interface: *std.Io.Writer,
389 file_reader: *std.fs.File.Reader,
398 file_reader: *std.Io.File.Reader,
390399 limit: std.Io.Limit,
391400 ) std.Io.Writer.FileError!usize {
392401 if (limit == .nothing) return 0;
......@@ -397,14 +406,14 @@ pub const Node = extern struct {
397406 switch (file_reader.mode) {
398407 .positional => {
399408 const fr_buf = file_reader.interface.buffered();
400 const buf_copy_size = interface.write(fr_buf) catch unreachable;
401 file_reader.interface.toss(buf_copy_size);
402 if (buf_copy_size < fr_buf.len) return buf_copy_size;
403 assert(file_reader.logicalPos() == file_reader.pos);
404
409 if (fr_buf.len > 0) {
410 const n = interface.write(fr_buf) catch unreachable;
411 file_reader.interface.toss(n);
412 return n;
413 }
405414 const w: *Writer = @fieldParentPtr("interface", interface);
406 const copy_size: usize = @intCast(w.mf.copyFileRange(
407 .adaptFromNewApi(file_reader.file),
415 const n: usize = @intCast(w.mf.copyFileRange(
416 file_reader.file,
408417 file_reader.pos,
409418 w.ni.fileLocation(w.mf, true).offset + interface.end,
410419 limit.minInt(interface.unusedCapacityLen()),
......@@ -412,8 +421,10 @@ pub const Node = extern struct {
412421 w.err = err;
413422 return error.WriteFailed;
414423 });
415 interface.end += copy_size;
416 return copy_size;
424 if (n == 0) return error.Unimplemented;
425 file_reader.pos += n;
426 interface.end += n;
427 return n;
417428 },
418429 .streaming,
419430 .streaming_reading,
......@@ -614,7 +625,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
614625 // Resize the entire file
615626 if (ni == Node.Index.root) {
616627 try mf.ensureCapacityForSetLocation(gpa);
617 try mf.file.setEndPos(new_size);
628 try std.fs.File.adaptFromNewApi(mf.file).setEndPos(new_size);
618629 try mf.ensureTotalCapacity(@intCast(new_size));
619630 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
620631 return;
......@@ -894,7 +905,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
894905
895906fn copyFileRange(
896907 mf: *MappedFile,
897 old_file: std.fs.File,
908 old_file: std.Io.File,
898909 old_file_offset: u64,
899910 new_file_offset: u64,
900911 size: u64,
src/main.zig+23-7
......@@ -558,6 +558,7 @@ const usage_build_generic =
558558 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
559559 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
560560 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
561 \\ --no-dynamic-linker Do not set any dynamic interpreter path
561562 \\ --sysroot [path] Set the system root directory (usually /)
562563 \\ --version [ver] Dynamic library semver
563564 \\ -fentry Enable entry point with default symbol name
......@@ -1301,6 +1302,8 @@ fn buildOutputType(
13011302 mod_opts.optimize_mode = parseOptimizeMode(rest);
13021303 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
13031304 create_module.dynamic_linker = args_iter.nextOrFatal();
1305 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
1306 create_module.dynamic_linker = "";
13041307 } else if (mem.eql(u8, arg, "--sysroot")) {
13051308 const next_arg = args_iter.nextOrFatal();
13061309 create_module.sysroot = next_arg;
......@@ -2418,6 +2421,11 @@ fn buildOutputType(
24182421 mem.eql(u8, arg, "-dynamic-linker"))
24192422 {
24202423 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 = "";
24212429 } else if (mem.eql(u8, arg, "-E") or
24222430 mem.eql(u8, arg, "--export-dynamic") or
24232431 mem.eql(u8, arg, "-export-dynamic"))
......@@ -3191,13 +3199,14 @@ fn buildOutputType(
31913199 const resolved_soname: ?[]const u8 = switch (soname) {
31923200 .yes => |explicit| explicit,
31933201 .no => null,
3194 .yes_default_value => switch (target.ofmt) {
3195 .elf => if (have_version)
3202 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
3203 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
3204 if (have_version)
31963205 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
31973206 else
3198 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),
3199 else => null,
3200 },
3207 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name})
3208 else
3209 null,
32013210 };
32023211
32033212 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
......@@ -3646,7 +3655,11 @@ fn buildOutputType(
36463655 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
36473656 }
36483657 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 }
36503663 }
36513664 try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
36523665 }
......@@ -3793,7 +3806,7 @@ fn createModule(
37933806 .result = target,
37943807 .is_native_os = target_query.isNativeOs(),
37953808 .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,
37973810 };
37983811 };
37993812
......@@ -3965,6 +3978,7 @@ fn createModule(
39653978 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
39663979 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
39673980 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
3981 error.ObjectFilesCannotSpecifyDynamicLinker => fatal("object files cannot specify --dynamic-linker", .{}),
39683982 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
39693983 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
39703984 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
......@@ -3973,6 +3987,7 @@ fn createModule(
39733987 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
39743988 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
39753989 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", .{}),
39763991 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
39773992 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
39783993 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
......@@ -3984,6 +3999,7 @@ fn createModule(
39843999 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
39854000 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
39864001 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
4002 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
39874003 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
39884004 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
39894005 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),