authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:05:49-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:05:49-04:00
log6f0476e41d2f9b040a9883b288171c6a50c29ed5
treee8baa001358a74fbb559bd44e91e84db52d01e26
parenta072d821be9e4bae68c7c14e9438f3750d2c0c89

Elf2: start implementing input object loading


5 files changed, 534 insertions(+), 152 deletions(-)

src/Compilation.zig+4-28
......@@ -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
......@@ -3066,35 +3064,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
30663064 // we also want it around during `flush`.
30673065 if (comp.bin_file) |lf| {
30683066 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 }
3067 lf.startProgress(comp.link_prog_node);
30803068 }
3081 defer {
3069 defer if (comp.bin_file) |lf| {
3070 lf.endProgress();
30823071 comp.link_prog_node.end();
30833072 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 }
3073 };
30983074
30993075 try comp.performAllTheWork(main_progress_node);
31003076
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/Elf2.zig+447-73
......@@ -6,6 +6,18 @@ phdrs: std.ArrayList(MappedFile.Node.Index),
66symtab: std.ArrayList(Symbol),
77shstrtab: StringTable,
88strtab: StringTable,
9inputs: std.ArrayList(struct {
10 path: std.Build.Cache.Path,
11 si: Symbol.Index,
12}),
13input_sections: std.ArrayList(struct {
14 ii: Node.InputIndex,
15 ni: MappedFile.Node.Index,
16 addr: u64,
17 offset: u64,
18 size: u64,
19}),
20input_section_pending_index: u32,
921globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
1022navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
1123uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
......@@ -20,6 +32,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
2032relocs: std.ArrayList(Reloc),
2133/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
2234entry_hack: Symbol.Index,
35const_prog_node: std.Progress.Node,
36synth_prog_node: std.Progress.Node,
37input_prog_node: std.Progress.Node,
2338
2439pub const Node = union(enum) {
2540 file,
......@@ -27,11 +42,53 @@ pub const Node = union(enum) {
2742 shdr,
2843 segment: u32,
2944 section: Symbol.Index,
45 input_section: InputSectionIndex,
3046 nav: NavMapIndex,
3147 uav: UavMapIndex,
3248 lazy_code: LazyMapRef.Index(.code),
3349 lazy_const_data: LazyMapRef.Index(.const_data),
3450
51 pub const InputIndex = enum(u32) {
52 _,
53
54 pub fn path(ii: InputIndex, elf: *const Elf) std.Build.Cache.Path {
55 return elf.inputs.items[@intFromEnum(ii)].path;
56 }
57
58 pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
59 return elf.inputs.items[@intFromEnum(ii)].si;
60 }
61
62 pub fn nextSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
63 const next_ii = @intFromEnum(ii) + 1;
64 return if (next_ii < elf.inputs.items.len)
65 @as(InputIndex, @enumFromInt(next_ii)).symbol(elf)
66 else
67 @enumFromInt(elf.symtab.items.len);
68 }
69 };
70
71 pub const InputSectionIndex = enum(u32) {
72 _,
73
74 pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex {
75 return elf.input_sections.items[@intFromEnum(isi)].ii;
76 }
77
78 pub fn node(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.Index {
79 return elf.input_sections.items[@intFromEnum(isi)].ni;
80 }
81
82 pub fn addr(isi: InputSectionIndex, elf: *Elf) *u64 {
83 return &elf.input_sections.items[@intFromEnum(isi)].addr;
84 }
85
86 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) struct { u64, u64 } {
87 const input_section = &elf.input_sections.items[@intFromEnum(isi)];
88 return .{ input_section.offset, input_section.size };
89 }
90 };
91
3592 pub const NavMapIndex = enum(u32) {
3693 _,
3794
......@@ -189,9 +246,14 @@ pub const Symbol = struct {
189246 return ni;
190247 }
191248
249 pub fn next(si: Symbol.Index) Symbol.Index {
250 return @enumFromInt(@intFromEnum(si) + 1);
251 }
252
192253 pub const InitOptions = struct {
193254 name: []const u8 = "",
194 size: std.elf.Word = 0,
255 value: u64 = 0,
256 size: u64 = 0,
195257 type: std.elf.STT,
196258 bind: std.elf.STB = .LOCAL,
197259 visibility: std.elf.STV = .DEFAULT,
......@@ -211,8 +273,8 @@ pub const Symbol = struct {
211273 switch (elf.symPtr(si)) {
212274 inline else => |sym| sym.* = .{
213275 .name = name_entry,
214 .value = 0,
215 .size = opts.size,
276 .value = @intCast(opts.value),
277 .size = @intCast(opts.size),
216278 .info = .{
217279 .type = opts.type,
218280 .bind = opts.bind,
......@@ -225,8 +287,7 @@ pub const Symbol = struct {
225287 }
226288 }
227289
228 pub fn flushMoved(si: Symbol.Index, elf: *Elf) void {
229 const value = elf.computeNodeVAddr(si.node(elf));
290 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
230291 switch (elf.symPtr(si)) {
231292 inline else => |sym, class| {
232293 elf.targetStore(&sym.value, @intCast(value));
......@@ -443,11 +504,11 @@ fn create(
443504 };
444505
445506 const elf = try arena.create(Elf);
446 const file = try path.root_dir.handle.createFile(path.sub_path, .{
507 const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{
447508 .read = true,
448509 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
449510 });
450 errdefer file.close();
511 errdefer file.close(comp.io);
451512 elf.* = .{
452513 .base = .{
453514 .tag = .elf2,
......@@ -455,7 +516,7 @@ fn create(
455516 .comp = comp,
456517 .emit = path,
457518
458 .file = file,
519 .file = .adaptFromNewApi(file),
459520 .gc_sections = false,
460521 .print_gc_sections = false,
461522 .build_id = .none,
......@@ -477,6 +538,9 @@ fn create(
477538 .map = .empty,
478539 .size = 1,
479540 },
541 .inputs = .empty,
542 .input_sections = .empty,
543 .input_section_pending_index = 0,
480544 .globals = .empty,
481545 .navs = .empty,
482546 .uavs = .empty,
......@@ -487,6 +551,9 @@ fn create(
487551 .pending_uavs = .empty,
488552 .relocs = .empty,
489553 .entry_hack = .null,
554 .const_prog_node = .none,
555 .synth_prog_node = .none,
556 .input_prog_node = .none,
490557 };
491558 errdefer elf.deinit();
492559
......@@ -502,6 +569,8 @@ pub fn deinit(elf: *Elf) void {
502569 elf.symtab.deinit(gpa);
503570 elf.shstrtab.map.deinit(gpa);
504571 elf.strtab.map.deinit(gpa);
572 elf.inputs.deinit(gpa);
573 elf.input_sections.deinit(gpa);
505574 elf.globals.deinit(gpa);
506575 elf.navs.deinit(gpa);
507576 elf.uavs.deinit(gpa);
......@@ -796,16 +865,18 @@ fn initHeaders(
796865 .addralign = elf.mf.flags.block_size,
797866 .entsize = 1,
798867 }) == .shstrtab);
868 try elf.renameSection(.symtab, ".symtab");
869 try elf.renameSection(.shstrtab, ".shstrtab");
870 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
871
799872 assert(try elf.addSection(Node.Known.rodata, .{
873 .name = ".strtab",
800874 .type = std.elf.SHT_STRTAB,
801875 .addralign = elf.mf.flags.block_size,
876 .size = 1,
802877 .entsize = 1,
803878 }) == .strtab);
804 try elf.renameSection(.symtab, ".symtab");
805 try elf.renameSection(.shstrtab, ".shstrtab");
806 try elf.renameSection(.strtab, ".strtab");
807879 try elf.linkSections(.symtab, .strtab);
808 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
809880 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
810881
811882 assert(try elf.addSection(Node.Known.rodata, .{
......@@ -860,6 +931,32 @@ fn initHeaders(
860931 assert(elf.nodes.len == expected_nodes_len);
861932}
862933
934pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
935 prog_node.increaseEstimatedTotalItems(4);
936 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count());
937 elf.synth_prog_node = prog_node.start("Synthetics", count: {
938 var count: usize = 0;
939 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
940 break :count count;
941 });
942 elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len);
943 elf.input_prog_node = prog_node.start(
944 "Inputs",
945 elf.input_sections.items.len - elf.input_section_pending_index,
946 );
947}
948
949pub fn endProgress(elf: *Elf) void {
950 elf.input_prog_node.end();
951 elf.input_prog_node = .none;
952 elf.mf.update_prog_node.end();
953 elf.mf.update_prog_node = .none;
954 elf.synth_prog_node.end();
955 elf.synth_prog_node = .none;
956 elf.const_prog_node.end();
957 elf.const_prog_node = .none;
958}
959
863960fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
864961 return elf.nodes.get(@intFromEnum(ni));
865962}
......@@ -871,6 +968,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
871968 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
872969 },
873970 .section => |si| si,
971 .input_section => unreachable,
874972 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
875973 };
876974 break :parent_vaddr switch (elf.symPtr(parent_si)) {
......@@ -1072,21 +1170,24 @@ fn navType(
10721170 },
10731171 };
10741172}
1173fn namedSection(name: []const u8) ?Symbol.Index {
1174 if (std.mem.eql(u8, name, ".rodata") or
1175 std.mem.startsWith(u8, name, ".rodata.")) return .rodata;
1176 if (std.mem.eql(u8, name, ".text") or
1177 std.mem.startsWith(u8, name, ".text.")) return .text;
1178 if (std.mem.eql(u8, name, ".data") or
1179 std.mem.startsWith(u8, name, ".data.")) return .data;
1180 if (std.mem.eql(u8, name, ".tdata") or
1181 std.mem.startsWith(u8, name, ".tdata.")) return .tdata;
1182 return null;
1183}
10751184fn navSection(
10761185 elf: *Elf,
10771186 ip: *const InternPool,
10781187 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
10791188) 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 }
1189 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1190 if (namedSection(@"linksection")) |si| return si;
10901191 return switch (navType(
10911192 ip,
10921193 .{ .fully_resolved = nav_fr },
......@@ -1156,11 +1257,236 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
11561257 .const_data => .OBJECT,
11571258 },
11581259 });
1159 elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
1260 elf.synth_prog_node.increaseEstimatedTotalItems(1);
11601261 }
11611262 return lazy_gop.value_ptr.*;
11621263}
11631264
1265pub fn loadInput(elf: *Elf, input: link.Input) !void {
1266 const comp = elf.base.comp;
1267 const gpa = comp.gpa;
1268 const diags = &comp.link_diags;
1269 switch (input) {
1270 .object => |object| {
1271 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
1272 log.debug("loadInput(.{{ .object = {f} }}) = {d}", .{ object.path, ii });
1273 {
1274 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1275 try elf.inputs.ensureUnusedCapacity(gpa, 1);
1276 const si = try elf.initSymbolAssumeCapacity(.{
1277 .name = std.fs.path.stem(object.path.sub_path),
1278 .type = .FILE,
1279 .shndx = std.elf.SHN_ABS,
1280 });
1281 elf.inputs.addOneAssumeCapacity().* = .{
1282 .path = object.path,
1283 .si = si,
1284 };
1285 }
1286 var buf: [4096]u8 = undefined;
1287 var fr = object.file.reader(comp.io, &buf);
1288 const r = &fr.interface;
1289 const ident = try r.peek(std.elf.EI.NIDENT);
1290 if (!std.mem.eql(u8, elf.mf.contents[0..std.elf.EI.NIDENT], ident))
1291 return diags.failParse(object.path, "wrong ident", .{});
1292 const target_endian = elf.targetEndian();
1293 switch (elf.identClass()) {
1294 .NONE, _ => unreachable,
1295 inline else => |class| {
1296 const ehdr = try r.peekStruct(
1297 @typeInfo(@FieldType(EhdrPtr, @tagName(class))).pointer.child,
1298 target_endian,
1299 );
1300 if (ehdr.type != .REL)
1301 return diags.failParse(object.path, "unsupported object type", .{});
1302 if (ehdr.machine != elf.ehdrField(.machine))
1303 return diags.failParse(object.path, "wrong machine", .{});
1304 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
1305 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
1306 return diags.failParse(object.path, "missing section names", .{});
1307 const Shdr = @typeInfo(@FieldType(ShdrSlice, @tagName(class))).pointer.child;
1308 if (ehdr.shentsize < @sizeOf(Shdr))
1309 return diags.failParse(object.path, "unsupported shentsize", .{});
1310 const shstrtab = shstrtab: {
1311 try fr.seekTo(ehdr.shoff + ehdr.shentsize * ehdr.shstrndx);
1312 const shdr = try r.peekStruct(Shdr, target_endian);
1313 if (shdr.type != std.elf.SHT_STRTAB)
1314 return diags.failParse(object.path, "invalid shstrtab type", .{});
1315 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
1316 errdefer gpa.free(shstrtab);
1317 try fr.seekTo(shdr.offset);
1318 try r.readSliceAll(shstrtab);
1319 break :shstrtab shstrtab;
1320 };
1321 defer gpa.free(shstrtab);
1322 const Sym = @typeInfo(@FieldType(SymPtr, @tagName(class))).pointer.child;
1323 try fr.seekTo(ehdr.shoff + ehdr.shentsize);
1324 var symtab_shdr: Shdr = .{
1325 .name = 0,
1326 .type = 0,
1327 .flags = .{ .shf = .{} },
1328 .addr = 0,
1329 .offset = 0,
1330 .size = 0,
1331 .link = 0,
1332 .info = 0,
1333 .addralign = 0,
1334 .entsize = 0,
1335 };
1336 const sections = try gpa.alloc(struct {
1337 shndx: u32,
1338 ni: MappedFile.Node.Index,
1339 }, ehdr.shnum);
1340 defer gpa.free(sections);
1341 @memset(sections, .{ .shndx = std.elf.SHN_UNDEF, .ni = .none });
1342 for (sections[1..ehdr.shnum]) |*section| {
1343 const shdr = try r.peekStruct(Shdr, target_endian);
1344 try r.discardAll(ehdr.shentsize);
1345 switch (shdr.type) {
1346 else => continue,
1347 std.elf.SHT_PROGBITS => {},
1348 std.elf.SHT_SYMTAB => {
1349 if (symtab_shdr.entsize > 0)
1350 return diags.failParse(object.path, "too many symtabs", .{});
1351 if (shdr.entsize < @sizeOf(Sym))
1352 return diags.failParse(object.path, "unsupported entsize", .{});
1353 symtab_shdr = shdr;
1354 continue;
1355 },
1356 std.elf.SHT_NOBITS => {},
1357 }
1358 if (shdr.name >= shstrtab.len) continue;
1359 const name = std.mem.sliceTo(shstrtab[shdr.name..], 0);
1360 const si = namedSection(name) orelse continue;
1361 section.shndx = elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx);
1362 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1363 try elf.input_sections.ensureUnusedCapacity(gpa, 1);
1364 section.ni = try elf.mf.addLastChildNode(gpa, si.node(elf), .{
1365 .size = shdr.size,
1366 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
1367 usize,
1368 @intCast(@max(shdr.addralign, 1)),
1369 )),
1370 .moved = true,
1371 });
1372 elf.nodes.appendAssumeCapacity(.{
1373 .input_section = @enumFromInt(elf.input_sections.items.len),
1374 });
1375 elf.input_sections.addOneAssumeCapacity().* = .{
1376 .ii = ii,
1377 .ni = section.ni,
1378 .addr = shdr.addr,
1379 .offset = shdr.offset,
1380 .size = shdr.size,
1381 };
1382 elf.synth_prog_node.increaseEstimatedTotalItems(1);
1383 }
1384 if (symtab_shdr.info <= 1) return;
1385 const strtab = strtab: {
1386 try fr.seekTo(ehdr.shoff + ehdr.shentsize * symtab_shdr.link);
1387 const shdr = try r.peekStruct(Shdr, target_endian);
1388 if (shdr.type != std.elf.SHT_STRTAB)
1389 return diags.failParse(object.path, "invalid strtab type", .{});
1390 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
1391 errdefer gpa.free(strtab);
1392 try fr.seekTo(shdr.offset);
1393 try r.readSliceAll(strtab);
1394 break :strtab strtab;
1395 };
1396 defer gpa.free(strtab);
1397 try elf.symtab.ensureUnusedCapacity(gpa, symtab_shdr.info);
1398 try elf.globals.ensureUnusedCapacity(gpa, symtab_shdr.info);
1399 try fr.seekTo(symtab_shdr.offset + symtab_shdr.entsize);
1400 for (1..try std.math.divExact(
1401 usize,
1402 @intCast(symtab_shdr.size),
1403 @intCast(symtab_shdr.entsize),
1404 )) |_| {
1405 const input_sym = try r.peekStruct(Sym, target_endian);
1406 try r.discardAll64(symtab_shdr.entsize);
1407 switch (input_sym.info.type) {
1408 else => continue,
1409 .OBJECT, .FUNC => {},
1410 }
1411 if (input_sym.name >= strtab.len or input_sym.shndx >= sections.len) continue;
1412 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
1413 const si = try elf.initSymbolAssumeCapacity(.{
1414 .name = name,
1415 .value = input_sym.value,
1416 .size = input_sym.size,
1417 .type = input_sym.info.type,
1418 .bind = input_sym.info.bind,
1419 .visibility = input_sym.other.visibility,
1420 .shndx = @intCast(sections[input_sym.shndx].shndx),
1421 });
1422 {
1423 const sym = si.get(elf);
1424 sym.ni = sections[input_sym.shndx].ni;
1425 assert(sym.loc_relocs == .none);
1426 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1427 }
1428 switch (input_sym.info.bind) {
1429 else => {},
1430 .GLOBAL => {
1431 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
1432 &@field(elf.symPtr(si), @tagName(class)).name,
1433 ));
1434 if (gop.found_existing) switch (elf.targetLoad(
1435 switch (elf.symPtr(gop.value_ptr.*)) {
1436 inline else => |sym| &sym.info,
1437 },
1438 ).bind) {
1439 else => unreachable,
1440 .GLOBAL => return diags.failParse(
1441 object.path,
1442 "multiple definitions of '{s}'",
1443 .{name},
1444 ),
1445 .WEAK => {},
1446 };
1447 gop.value_ptr.* = si;
1448 },
1449 .WEAK => {
1450 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
1451 &@field(elf.symPtr(si), @tagName(class)).name,
1452 ));
1453 if (!gop.found_existing) gop.value_ptr.* = si;
1454 },
1455 }
1456 }
1457 },
1458 }
1459 },
1460 else => {},
1461 }
1462}
1463
1464pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
1465 _ = prog_node;
1466 elf.prelinkInner() catch |err| switch (err) {
1467 error.OutOfMemory => return error.OutOfMemory,
1468 else => |e| return elf.base.comp.link_diags.fail("prelink failed: {t}", .{e}),
1469 };
1470}
1471fn prelinkInner(elf: *Elf) !void {
1472 const gpa = elf.base.comp.gpa;
1473 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1474 try elf.inputs.ensureUnusedCapacity(gpa, 1);
1475 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
1476 std.fs.path.stem(elf.base.emit.sub_path),
1477 });
1478 defer gpa.free(zcu_name);
1479 const si = try elf.initSymbolAssumeCapacity(.{
1480 .name = zcu_name,
1481 .type = .FILE,
1482 .shndx = std.elf.SHN_ABS,
1483 });
1484 elf.inputs.addOneAssumeCapacity().* = .{
1485 .path = elf.base.emit,
1486 .si = si,
1487 };
1488}
1489
11641490pub fn getNavVAddr(
11651491 elf: *Elf,
11661492 pt: Zcu.PerThread,
......@@ -1228,12 +1554,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12281554 const si = elf.addSymbolAssumeCapacity();
12291555 elf.nodes.appendAssumeCapacity(.{ .section = si });
12301556 si.get(elf).ni = ni;
1231 try si.init(elf, .{
1232 .name = opts.name,
1233 .size = opts.size,
1234 .type = .SECTION,
1235 .shndx = shndx,
1236 });
1557 try si.init(elf, .{ .size = opts.size, .type = .SECTION, .shndx = shndx });
12371558 switch (elf.shdrSlice()) {
12381559 inline else => |shdr| {
12391560 const sh = &shdr[shndx];
......@@ -1256,15 +1577,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
12561577}
12571578
12581579fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1259 const strtab_entry = try elf.string(.strtab, name);
12601580 const shstrtab_entry = try elf.string(.shstrtab, name);
12611581 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 },
1582 inline else => |shdr, class| elf.targetStore(
1583 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
1584 shstrtab_entry,
1585 ),
12681586 }
12691587}
12701588
......@@ -1323,11 +1641,6 @@ pub fn addReloc(
13231641 target.target_relocs = ri;
13241642}
13251643
1326pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void {
1327 _ = elf;
1328 _ = prog_node;
1329}
1330
13311644pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
13321645 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
13331646 error.OutOfMemory,
......@@ -1430,7 +1743,7 @@ pub fn lowerUav(
14301743 .alignment = uav_align,
14311744 .src_loc = src_loc,
14321745 };
1433 elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);
1746 elf.const_prog_node.increaseEstimatedTotalItems(1);
14341747 }
14351748 }
14361749 return .{ .sym_index = @intFromEnum(si) };
......@@ -1534,7 +1847,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
15341847 }) catch |err| switch (err) {
15351848 error.OutOfMemory => return error.OutOfMemory,
15361849 error.CodegenFail => return error.LinkFailure,
1537 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}),
1850 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed: {t}", .{e}),
15381851 };
15391852}
15401853
......@@ -1553,20 +1866,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15531866 const comp = elf.base.comp;
15541867 task: {
15551868 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 );
1869 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });
15611870 defer sub_prog_node.end();
15621871 elf.flushUav(
1563 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
1872 .{ .zcu = comp.zcu.?, .tid = tid },
15641873 pending_uav.key,
15651874 pending_uav.value.alignment,
15661875 pending_uav.value.src_loc,
15671876 ) catch |err| switch (err) {
15681877 error.OutOfMemory => return error.OutOfMemory,
1569 else => |e| return elf.base.comp.link_diags.fail(
1878 else => |e| return comp.link_diags.fail(
15701879 "linker failed to lower constant: {t}",
15711880 .{e},
15721881 ),
......@@ -1575,7 +1884,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15751884 }
15761885 var lazy_it = elf.lazy.iterator();
15771886 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 };
1887 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
15791888 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
15801889 lazy.value.pending_index += 1;
15811890 const kind = switch (lmr.kind) {
......@@ -1583,7 +1892,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15831892 .const_data => "data",
15841893 };
15851894 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1586 const sub_prog_node = comp.link_synth_prog_node.start(
1895 const sub_prog_node = elf.synth_prog_node.start(
15871896 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
15881897 kind,
15891898 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
......@@ -1593,13 +1902,27 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
15931902 defer sub_prog_node.end();
15941903 elf.flushLazy(pt, lmr) catch |err| switch (err) {
15951904 error.OutOfMemory => return error.OutOfMemory,
1596 else => |e| return elf.base.comp.link_diags.fail(
1905 else => |e| return comp.link_diags.fail(
15971906 "linker failed to lower lazy {s}: {t}",
15981907 .{ kind, e },
15991908 ),
16001909 };
16011910 break :task;
16021911 };
1912 if (elf.input_section_pending_index < elf.input_sections.items.len) {
1913 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);
1914 elf.input_section_pending_index += 1;
1915 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));
1916 defer sub_prog_node.end();
1917 elf.flushInputSection(isi) catch |err| switch (err) {
1918 else => |e| return comp.link_diags.fail("linker failed to read input section '{s}' from \"{f}\": {t}", .{
1919 elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section),
1920 isi.input(elf).path(elf).fmtEscapeString(),
1921 e,
1922 }),
1923 };
1924 break :task;
1925 }
16031926 while (elf.mf.updates.pop()) |ni| {
16041927 const clean_moved = ni.cleanMoved(&elf.mf);
16051928 const clean_resized = ni.cleanResized(&elf.mf);
......@@ -1614,6 +1937,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
16141937 }
16151938 if (elf.pending_uavs.count() > 0) return true;
16161939 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
1940 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
16171941 if (elf.mf.updates.items.len > 0) return true;
16181942 return false;
16191943}
......@@ -1628,6 +1952,10 @@ fn idleProgNode(
16281952 return prog_node.start(name: switch (node) {
16291953 else => |tag| @tagName(tag),
16301954 .section => |si| elf.sectionName(si),
1955 .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{
1956 isi.input(elf).path(elf),
1957 elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section),
1958 }) catch &name,
16311959 .nav => |nmi| {
16321960 const ip = &elf.base.comp.zcu.?.intern_pool;
16331961 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);
......@@ -1749,6 +2077,23 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
17492077 si.applyLocationRelocs(elf);
17502078}
17512079
2080fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
2081 const offset, const size = isi.fileLocation(elf);
2082 if (size == 0) return;
2083 const comp = elf.base.comp;
2084 const gpa = comp.gpa;
2085 const io = comp.io;
2086 const path = isi.input(elf).path(elf);
2087 const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{});
2088 defer file.close(io);
2089 var fr = file.reader(io, &.{});
2090 try fr.seekTo(offset);
2091 var nw: MappedFile.Node.Writer = undefined;
2092 isi.node(elf).writer(&elf.mf, gpa, &nw);
2093 defer nw.deinit();
2094 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(size))) != size) return error.EndOfStream;
2095}
2096
17522097fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
17532098 switch (elf.getNode(ni)) {
17542099 .file => unreachable,
......@@ -1786,7 +2131,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
17862131 }
17872132 },
17882133 },
1789 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(elf),
2134 .input_section => |isi| {
2135 const addr = isi.addr(elf);
2136 const old_addr = addr.*;
2137 const new_addr = elf.computeNodeVAddr(ni);
2138 addr.* = new_addr;
2139 const ii = isi.input(elf);
2140 var si = ii.symbol(elf);
2141 const end_si = ii.nextSymbol(elf);
2142 while (cond: {
2143 si = si.next();
2144 break :cond si != end_si;
2145 }) {
2146 if (si.get(elf).ni != ni) continue;
2147 si.flushMoved(elf, switch (elf.symPtr(si)) {
2148 inline else => |sym| elf.targetLoad(&sym.value),
2149 } - old_addr + new_addr);
2150 }
2151 },
2152 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
2153 elf,
2154 elf.computeNodeVAddr(ni),
2155 ),
17902156 }
17912157 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
17922158}
......@@ -1860,6 +2226,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
18602226 }
18612227 },
18622228 },
2229 .input_section => {},
18632230 .nav, .uav, .lazy_code, .lazy_const_data => {},
18642231 }
18652232}
......@@ -1983,6 +2350,10 @@ pub fn printNode(
19832350 switch (node) {
19842351 else => {},
19852352 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
2353 .input_section => |isi| try w.print("({f}, {s})", .{
2354 isi.input(elf).path(elf),
2355 elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section),
2356 }),
19862357 .nav => |nmi| {
19872358 const zcu = elf.base.comp.zcu.?;
19882359 const ip = &zcu.intern_pool;
......@@ -2027,25 +2398,28 @@ pub fn printNode(
20272398 leaf = false;
20282399 try elf.printNode(tid, w, child_ni, indent + 1);
20292400 }
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 }
2401 if (!leaf) return;
2402 const file_loc = ni.fileLocation(&elf.mf, false);
2403 var address = file_loc.offset;
2404 if (file_loc.size == 0) {
2405 try w.splatByteAll(' ', indent + 1);
2406 try w.print("{x:0>8}\n", .{address});
2407 return;
2408 }
2409 const line_len = 0x10;
2410 var line_it = std.mem.window(
2411 u8,
2412 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2413 line_len,
2414 line_len,
2415 );
2416 while (line_it.next()) |line_bytes| : (address += line_len) {
2417 try w.splatByteAll(' ', indent + 1);
2418 try w.print("{x:0>8} ", .{address});
2419 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
2420 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
2421 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
2422 try w.writeByte('\n');
20492423 }
20502424}
20512425
src/link/MappedFile.zig+17-13
......@@ -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,
......@@ -386,7 +386,7 @@ pub const Node = extern struct {
386386
387387 fn sendFile(
388388 interface: *std.Io.Writer,
389 file_reader: *std.fs.File.Reader,
389 file_reader: *std.Io.File.Reader,
390390 limit: std.Io.Limit,
391391 ) std.Io.Writer.FileError!usize {
392392 if (limit == .nothing) return 0;
......@@ -397,14 +397,16 @@ pub const Node = extern struct {
397397 switch (file_reader.mode) {
398398 .positional => {
399399 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);
400 if (fr_buf.len > 0) {
401 const n = interface.write(fr_buf) catch unreachable;
402 file_reader.interface.toss(n);
403 return n;
404 }
404405
406 assert(file_reader.logicalPos() == file_reader.pos);
405407 const w: *Writer = @fieldParentPtr("interface", interface);
406 const copy_size: usize = @intCast(w.mf.copyFileRange(
407 .adaptFromNewApi(file_reader.file),
408 const n: usize = @intCast(w.mf.copyFileRange(
409 file_reader.file,
408410 file_reader.pos,
409411 w.ni.fileLocation(w.mf, true).offset + interface.end,
410412 limit.minInt(interface.unusedCapacityLen()),
......@@ -412,8 +414,10 @@ pub const Node = extern struct {
412414 w.err = err;
413415 return error.WriteFailed;
414416 });
415 interface.end += copy_size;
416 return copy_size;
417 if (n == 0) return error.Unimplemented;
418 file_reader.pos += n;
419 interface.end += n;
420 return n;
417421 },
418422 .streaming,
419423 .streaming_reading,
......@@ -614,7 +618,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
614618 // Resize the entire file
615619 if (ni == Node.Index.root) {
616620 try mf.ensureCapacityForSetLocation(gpa);
617 try mf.file.setEndPos(new_size);
621 try std.fs.File.adaptFromNewApi(mf.file).setEndPos(new_size);
618622 try mf.ensureTotalCapacity(@intCast(new_size));
619623 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
620624 return;
......@@ -894,7 +898,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
894898
895899fn copyFileRange(
896900 mf: *MappedFile,
897 old_file: std.fs.File,
901 old_file: std.Io.File,
898902 old_file_offset: u64,
899903 new_file_offset: u64,
900904 size: u64,