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,...@@ -258,8 +258,6 @@ test_filters: []const []const u8,
258258
259link_task_wait_group: WaitGroup = .{},259link_task_wait_group: WaitGroup = .{},
260link_prog_node: std.Progress.Node = .none,260link_prog_node: std.Progress.Node = .none,
261link_const_prog_node: std.Progress.Node = .none,
262link_synth_prog_node: std.Progress.Node = .none,
263261
264llvm_opt_bisect_limit: c_int,262llvm_opt_bisect_limit: c_int,
265263
...@@ -3066,35 +3064,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3066,35 +3064,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3066 // we also want it around during `flush`.3064 // we also want it around during `flush`.
3067 if (comp.bin_file) |lf| {3065 if (comp.bin_file) |lf| {
3068 comp.link_prog_node = main_progress_node.start("Linking", 0);3066 comp.link_prog_node = main_progress_node.start("Linking", 0);
3069 if (lf.cast(.elf2)) |elf| {3067 lf.startProgress(comp.link_prog_node);
3070 comp.link_prog_node.increaseEstimatedTotalItems(3);
3071 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3072 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
3073 elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);
3074 } else if (lf.cast(.coff2)) |coff| {
3075 comp.link_prog_node.increaseEstimatedTotalItems(3);
3076 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3077 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
3078 coff.mf.update_prog_node = comp.link_prog_node.start("Relocations", coff.mf.updates.items.len);
3079 }
3080 }3068 }
3081 defer {3069 defer if (comp.bin_file) |lf| {
3070 lf.endProgress();
3082 comp.link_prog_node.end();3071 comp.link_prog_node.end();
3083 comp.link_prog_node = .none;3072 comp.link_prog_node = .none;
3084 comp.link_const_prog_node.end();3073 };
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 }
30983074
3099 try comp.performAllTheWork(main_progress_node);3075 try comp.performAllTheWork(main_progress_node);
31003076
src/link.zig+26-22
...@@ -571,6 +571,26 @@ pub const File = struct {...@@ -571,6 +571,26 @@ pub const File = struct {
571 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;571 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
572 }572 }
573573
574 pub fn startProgress(base: *File, prog_node: std.Progress.Node) void {
575 switch (base.tag) {
576 else => {},
577 inline .elf2, .coff2 => |tag| {
578 dev.check(tag.devFeature());
579 return @as(*tag.Type(), @fieldParentPtr("base", base)).startProgress(prog_node);
580 },
581 }
582 }
583
584 pub fn endProgress(base: *File) void {
585 switch (base.tag) {
586 else => {},
587 inline .elf2, .coff2 => |tag| {
588 dev.check(tag.devFeature());
589 return @as(*tag.Type(), @fieldParentPtr("base", base)).endProgress();
590 },
591 }
592 }
593
574 pub fn makeWritable(base: *File) !void {594 pub fn makeWritable(base: *File) !void {
575 dev.check(.make_writable);595 dev.check(.make_writable);
576 const comp = base.comp;596 const comp = base.comp;
...@@ -620,10 +640,10 @@ pub const File = struct {...@@ -620,10 +640,10 @@ pub const File = struct {
620 &coff.mf640 &coff.mf
621 else641 else
622 unreachable;642 unreachable;
623 mf.file = .adaptFromNewApi(try Io.Dir.openFile(base.emit.root_dir.handle.adaptToNewApi(), io, base.emit.sub_path, .{643 mf.file = try base.emit.root_dir.handle.adaptToNewApi().openFile(io, base.emit.sub_path, .{
624 .mode = .read_write,644 .mode = .read_write,
625 }));645 });
626 base.file = mf.file;646 base.file = .adaptFromNewApi(mf.file);
627 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));647 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
628 },648 },
629 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),649 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
...@@ -648,6 +668,7 @@ pub const File = struct {...@@ -648,6 +668,7 @@ pub const File = struct {
648 pub fn makeExecutable(base: *File) !void {668 pub fn makeExecutable(base: *File) !void {
649 dev.check(.make_executable);669 dev.check(.make_executable);
650 const comp = base.comp;670 const comp = base.comp;
671 const io = comp.io;
651 switch (comp.config.output_mode) {672 switch (comp.config.output_mode) {
652 .Obj => return,673 .Obj => return,
653 .Lib => switch (comp.config.link_mode) {674 .Lib => switch (comp.config.link_mode) {
...@@ -698,8 +719,8 @@ pub const File = struct {...@@ -698,8 +719,8 @@ pub const File = struct {
698 unreachable;719 unreachable;
699 mf.unmap();720 mf.unmap();
700 assert(mf.file.handle == f.handle);721 assert(mf.file.handle == f.handle);
722 mf.file.close(io);
701 mf.file = undefined;723 mf.file = undefined;
702 f.close();
703 base.file = null;724 base.file = null;
704 },725 },
705 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),726 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
...@@ -1120,7 +1141,7 @@ pub const File = struct {...@@ -1120,7 +1141,7 @@ pub const File = struct {
1120 pub fn loadInput(base: *File, input: Input) anyerror!void {1141 pub fn loadInput(base: *File, input: Input) anyerror!void {
1121 if (base.tag == .lld) return;1142 if (base.tag == .lld) return;
1122 switch (base.tag) {1143 switch (base.tag) {
1123 inline .elf, .wasm => |tag| {1144 inline .elf, .elf2, .wasm => |tag| {
1124 dev.check(tag.devFeature());1145 dev.check(tag.devFeature());
1125 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);1146 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1126 },1147 },
...@@ -1281,9 +1302,6 @@ pub const PrelinkTask = union(enum) {...@@ -1281,9 +1302,6 @@ pub const PrelinkTask = union(enum) {
1281 /// Tells the linker to load a shared library, possibly one that is a1302 /// Tells the linker to load a shared library, possibly one that is a
1282 /// GNU ld script.1303 /// GNU ld script.
1283 load_dso: Path,1304 load_dso: Path,
1284 /// Tells the linker to load an input which could be an object file,
1285 /// archive, or shared library.
1286 load_input: Input,
1287};1305};
1288pub const ZcuTask = union(enum) {1306pub const ZcuTask = union(enum) {
1289 /// Write the constant value for a Decl to the output file.1307 /// Write the constant value for a Decl to the output file.
...@@ -1461,20 +1479,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1461,20 +1479,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1461 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),1479 else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
1462 };1480 };
1463 },1481 },
1464 .load_input => |input| {
1465 const prog_node = comp.link_prog_node.start("Parse Input", 0);
1466 defer prog_node.end();
1467 base.loadInput(input) catch |err| switch (err) {
1468 error.LinkFailure => return, // error reported via link_diags
1469 else => |e| {
1470 if (input.path()) |path| {
1471 diags.addParseError(path, "failed to parse linker input: {s}", .{@errorName(e)});
1472 } else {
1473 diags.addError("failed to {s}: {s}", .{ input.taskName(), @errorName(e) });
1474 }
1475 },
1476 };
1477 },
1478 }1482 }
1479}1483}
1480pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {1484pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
src/link/Coff.zig+40-16
...@@ -26,6 +26,8 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -26,6 +26,8 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
26 src_loc: Zcu.LazySrcLoc,26 src_loc: Zcu.LazySrcLoc,
27}),27}),
28relocs: std.ArrayList(Reloc),28relocs: std.ArrayList(Reloc),
29const_prog_node: std.Progress.Node,
30synth_prog_node: std.Progress.Node,
2931
30pub const default_file_alignment: u16 = 0x200;32pub const default_file_alignment: u16 = 0x200;
31pub const default_size_of_stack_reserve: u32 = 0x1000000;33pub const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -630,11 +632,11 @@ fn create(...@@ -630,11 +632,11 @@ fn create(
630 };632 };
631633
632 const coff = try arena.create(Coff);634 const coff = try arena.create(Coff);
633 const file = try path.root_dir.handle.createFile(path.sub_path, .{635 const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{
634 .read = true,636 .read = true,
635 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),637 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
636 });638 });
637 errdefer file.close();639 errdefer file.close(comp.io);
638 coff.* = .{640 coff.* = .{
639 .base = .{641 .base = .{
640 .tag = .coff2,642 .tag = .coff2,
...@@ -642,7 +644,7 @@ fn create(...@@ -642,7 +644,7 @@ fn create(
642 .comp = comp,644 .comp = comp,
643 .emit = path,645 .emit = path,
644646
645 .file = file,647 .file = .adaptFromNewApi(file),
646 .gc_sections = false,648 .gc_sections = false,
647 .print_gc_sections = false,649 .print_gc_sections = false,
648 .build_id = .none,650 .build_id = .none,
...@@ -671,6 +673,8 @@ fn create(...@@ -671,6 +673,8 @@ fn create(
671 }),673 }),
672 .pending_uavs = .empty,674 .pending_uavs = .empty,
673 .relocs = .empty,675 .relocs = .empty,
676 .const_prog_node = .none,
677 .synth_prog_node = .none,
674 };678 };
675 errdefer coff.deinit();679 errdefer coff.deinit();
676680
...@@ -973,6 +977,26 @@ fn initHeaders(...@@ -973,6 +977,26 @@ fn initHeaders(
973 assert(coff.nodes.len == expected_nodes_len);977 assert(coff.nodes.len == expected_nodes_len);
974}978}
975979
980pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void {
981 prog_node.increaseEstimatedTotalItems(3);
982 coff.const_prog_node = prog_node.start("Constants", coff.pending_uavs.count());
983 coff.synth_prog_node = prog_node.start("Synthetics", count: {
984 var count = coff.globals.count() - coff.global_pending_index;
985 for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
986 break :count count;
987 });
988 coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len);
989}
990
991pub fn endProgress(coff: *Coff) void {
992 coff.mf.update_prog_node.end();
993 coff.mf.update_prog_node = .none;
994 coff.synth_prog_node.end();
995 coff.synth_prog_node = .none;
996 coff.const_prog_node.end();
997 coff.const_prog_node = .none;
998}
999
976fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {1000fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
977 return coff.nodes.get(@intFromEnum(ni));1001 return coff.nodes.get(@intFromEnum(ni));
978}1002}
...@@ -1172,7 +1196,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo...@@ -1172,7 +1196,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo
1172 });1196 });
1173 if (!sym_gop.found_existing) {1197 if (!sym_gop.found_existing) {
1174 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();1198 sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity();
1175 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1199 coff.synth_prog_node.increaseEstimatedTotalItems(1);
1176 }1200 }
1177 return sym_gop.value_ptr.*;1201 return sym_gop.value_ptr.*;
1178}1202}
...@@ -1250,7 +1274,7 @@ pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {...@@ -1250,7 +1274,7 @@ pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index {
1250 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);1274 const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1251 if (!sym_gop.found_existing) {1275 if (!sym_gop.found_existing) {
1252 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();1276 sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity();
1253 coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1277 coff.synth_prog_node.increaseEstimatedTotalItems(1);
1254 }1278 }
1255 return sym_gop.value_ptr.*;1279 return sym_gop.value_ptr.*;
1256}1280}
...@@ -1585,7 +1609,7 @@ pub fn lowerUav(...@@ -1585,7 +1609,7 @@ pub fn lowerUav(
1585 .alignment = uav_align,1609 .alignment = uav_align,
1586 .src_loc = src_loc,1610 .src_loc = src_loc,
1587 };1611 };
1588 coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);1612 coff.const_prog_node.increaseEstimatedTotalItems(1);
1589 }1613 }
1590 }1614 }
1591 return .{ .sym_index = @intFromEnum(si) };1615 return .{ .sym_index = @intFromEnum(si) };
...@@ -1726,17 +1750,16 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1726,17 +1750,16 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1726 const comp = coff.base.comp;1750 const comp = coff.base.comp;
1727 task: {1751 task: {
1728 while (coff.pending_uavs.pop()) |pending_uav| {1752 while (coff.pending_uavs.pop()) |pending_uav| {
1729 const sub_prog_node =1753 const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key });
1730 coff.idleProgNode(tid, comp.link_const_prog_node, .{ .uav = pending_uav.key });
1731 defer sub_prog_node.end();1754 defer sub_prog_node.end();
1732 coff.flushUav(1755 coff.flushUav(
1733 .{ .zcu = coff.base.comp.zcu.?, .tid = tid },1756 .{ .zcu = comp.zcu.?, .tid = tid },
1734 pending_uav.key,1757 pending_uav.key,
1735 pending_uav.value.alignment,1758 pending_uav.value.alignment,
1736 pending_uav.value.src_loc,1759 pending_uav.value.src_loc,
1737 ) catch |err| switch (err) {1760 ) catch |err| switch (err) {
1738 error.OutOfMemory => return error.OutOfMemory,1761 error.OutOfMemory => return error.OutOfMemory,
1739 else => |e| return coff.base.comp.link_diags.fail(1762 else => |e| return comp.link_diags.fail(
1740 "linker failed to lower constant: {t}",1763 "linker failed to lower constant: {t}",
1741 .{e},1764 .{e},
1742 ),1765 ),
...@@ -1744,17 +1767,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1744,17 +1767,17 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1744 break :task;1767 break :task;
1745 }1768 }
1746 if (coff.global_pending_index < coff.globals.count()) {1769 if (coff.global_pending_index < coff.globals.count()) {
1747 const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid };1770 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
1748 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);1771 const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index);
1749 coff.global_pending_index += 1;1772 coff.global_pending_index += 1;
1750 const sub_prog_node = comp.link_synth_prog_node.start(1773 const sub_prog_node = coff.synth_prog_node.start(
1751 gmi.globalName(coff).name.toSlice(coff),1774 gmi.globalName(coff).name.toSlice(coff),
1752 0,1775 0,
1753 );1776 );
1754 defer sub_prog_node.end();1777 defer sub_prog_node.end();
1755 coff.flushGlobal(pt, gmi) catch |err| switch (err) {1778 coff.flushGlobal(pt, gmi) catch |err| switch (err) {
1756 error.OutOfMemory => return error.OutOfMemory,1779 error.OutOfMemory => return error.OutOfMemory,
1757 else => |e| return coff.base.comp.link_diags.fail(1780 else => |e| return comp.link_diags.fail(
1758 "linker failed to lower constant: {t}",1781 "linker failed to lower constant: {t}",
1759 .{e},1782 .{e},
1760 ),1783 ),
...@@ -1763,7 +1786,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1763,7 +1786,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1763 }1786 }
1764 var lazy_it = coff.lazy.iterator();1787 var lazy_it = coff.lazy.iterator();
1765 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {1788 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
1766 const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid };1789 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid };
1767 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };1790 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
1768 lazy.value.pending_index += 1;1791 lazy.value.pending_index += 1;
1769 const kind = switch (lmr.kind) {1792 const kind = switch (lmr.kind) {
...@@ -1771,7 +1794,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1771,7 +1794,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1771 .const_data => "data",1794 .const_data => "data",
1772 };1795 };
1773 var name: [std.Progress.Node.max_name_len]u8 = undefined;1796 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1774 const sub_prog_node = comp.link_synth_prog_node.start(1797 const sub_prog_node = coff.synth_prog_node.start(
1775 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{1798 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1776 kind,1799 kind,
1777 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),1800 Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt),
...@@ -1781,7 +1804,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1781,7 +1804,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1781 defer sub_prog_node.end();1804 defer sub_prog_node.end();
1782 coff.flushLazy(pt, lmr) catch |err| switch (err) {1805 coff.flushLazy(pt, lmr) catch |err| switch (err) {
1783 error.OutOfMemory => return error.OutOfMemory,1806 error.OutOfMemory => return error.OutOfMemory,
1784 else => |e| return coff.base.comp.link_diags.fail(1807 else => |e| return comp.link_diags.fail(
1785 "linker failed to lower lazy {s}: {t}",1808 "linker failed to lower lazy {s}: {t}",
1786 .{ kind, e },1809 .{ kind, e },
1787 ),1810 ),
...@@ -1802,6 +1825,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1802,6 +1825,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1802 }1825 }
1803 }1826 }
1804 if (coff.pending_uavs.count() > 0) return true;1827 if (coff.pending_uavs.count() > 0) return true;
1828 if (coff.globals.count() > coff.global_pending_index) return true;
1805 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;1829 for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
1806 if (coff.mf.updates.items.len > 0) return true;1830 if (coff.mf.updates.items.len > 0) return true;
1807 return false;1831 return false;
src/link/Elf2.zig+447-73
...@@ -6,6 +6,18 @@ phdrs: std.ArrayList(MappedFile.Node.Index),...@@ -6,6 +6,18 @@ phdrs: std.ArrayList(MappedFile.Node.Index),
6symtab: std.ArrayList(Symbol),6symtab: std.ArrayList(Symbol),
7shstrtab: StringTable,7shstrtab: StringTable,
8strtab: StringTable,8strtab: 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,
9globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),21globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
10navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),22navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
11uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),23uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
...@@ -20,6 +32,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -20,6 +32,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
20relocs: std.ArrayList(Reloc),32relocs: std.ArrayList(Reloc),
21/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.33/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
22entry_hack: Symbol.Index,34entry_hack: Symbol.Index,
35const_prog_node: std.Progress.Node,
36synth_prog_node: std.Progress.Node,
37input_prog_node: std.Progress.Node,
2338
24pub const Node = union(enum) {39pub const Node = union(enum) {
25 file,40 file,
...@@ -27,11 +42,53 @@ pub const Node = union(enum) {...@@ -27,11 +42,53 @@ pub const Node = union(enum) {
27 shdr,42 shdr,
28 segment: u32,43 segment: u32,
29 section: Symbol.Index,44 section: Symbol.Index,
45 input_section: InputSectionIndex,
30 nav: NavMapIndex,46 nav: NavMapIndex,
31 uav: UavMapIndex,47 uav: UavMapIndex,
32 lazy_code: LazyMapRef.Index(.code),48 lazy_code: LazyMapRef.Index(.code),
33 lazy_const_data: LazyMapRef.Index(.const_data),49 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
35 pub const NavMapIndex = enum(u32) {92 pub const NavMapIndex = enum(u32) {
36 _,93 _,
3794
...@@ -189,9 +246,14 @@ pub const Symbol = struct {...@@ -189,9 +246,14 @@ pub const Symbol = struct {
189 return ni;246 return ni;
190 }247 }
191248
249 pub fn next(si: Symbol.Index) Symbol.Index {
250 return @enumFromInt(@intFromEnum(si) + 1);
251 }
252
192 pub const InitOptions = struct {253 pub const InitOptions = struct {
193 name: []const u8 = "",254 name: []const u8 = "",
194 size: std.elf.Word = 0,255 value: u64 = 0,
256 size: u64 = 0,
195 type: std.elf.STT,257 type: std.elf.STT,
196 bind: std.elf.STB = .LOCAL,258 bind: std.elf.STB = .LOCAL,
197 visibility: std.elf.STV = .DEFAULT,259 visibility: std.elf.STV = .DEFAULT,
...@@ -211,8 +273,8 @@ pub const Symbol = struct {...@@ -211,8 +273,8 @@ pub const Symbol = struct {
211 switch (elf.symPtr(si)) {273 switch (elf.symPtr(si)) {
212 inline else => |sym| sym.* = .{274 inline else => |sym| sym.* = .{
213 .name = name_entry,275 .name = name_entry,
214 .value = 0,276 .value = @intCast(opts.value),
215 .size = opts.size,277 .size = @intCast(opts.size),
216 .info = .{278 .info = .{
217 .type = opts.type,279 .type = opts.type,
218 .bind = opts.bind,280 .bind = opts.bind,
...@@ -225,8 +287,7 @@ pub const Symbol = struct {...@@ -225,8 +287,7 @@ pub const Symbol = struct {
225 }287 }
226 }288 }
227289
228 pub fn flushMoved(si: Symbol.Index, elf: *Elf) void {290 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
229 const value = elf.computeNodeVAddr(si.node(elf));
230 switch (elf.symPtr(si)) {291 switch (elf.symPtr(si)) {
231 inline else => |sym, class| {292 inline else => |sym, class| {
232 elf.targetStore(&sym.value, @intCast(value));293 elf.targetStore(&sym.value, @intCast(value));
...@@ -443,11 +504,11 @@ fn create(...@@ -443,11 +504,11 @@ fn create(
443 };504 };
444505
445 const elf = try arena.create(Elf);506 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, .{
447 .read = true,508 .read = true,
448 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),509 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
449 });510 });
450 errdefer file.close();511 errdefer file.close(comp.io);
451 elf.* = .{512 elf.* = .{
452 .base = .{513 .base = .{
453 .tag = .elf2,514 .tag = .elf2,
...@@ -455,7 +516,7 @@ fn create(...@@ -455,7 +516,7 @@ fn create(
455 .comp = comp,516 .comp = comp,
456 .emit = path,517 .emit = path,
457518
458 .file = file,519 .file = .adaptFromNewApi(file),
459 .gc_sections = false,520 .gc_sections = false,
460 .print_gc_sections = false,521 .print_gc_sections = false,
461 .build_id = .none,522 .build_id = .none,
...@@ -477,6 +538,9 @@ fn create(...@@ -477,6 +538,9 @@ fn create(
477 .map = .empty,538 .map = .empty,
478 .size = 1,539 .size = 1,
479 },540 },
541 .inputs = .empty,
542 .input_sections = .empty,
543 .input_section_pending_index = 0,
480 .globals = .empty,544 .globals = .empty,
481 .navs = .empty,545 .navs = .empty,
482 .uavs = .empty,546 .uavs = .empty,
...@@ -487,6 +551,9 @@ fn create(...@@ -487,6 +551,9 @@ fn create(
487 .pending_uavs = .empty,551 .pending_uavs = .empty,
488 .relocs = .empty,552 .relocs = .empty,
489 .entry_hack = .null,553 .entry_hack = .null,
554 .const_prog_node = .none,
555 .synth_prog_node = .none,
556 .input_prog_node = .none,
490 };557 };
491 errdefer elf.deinit();558 errdefer elf.deinit();
492559
...@@ -502,6 +569,8 @@ pub fn deinit(elf: *Elf) void {...@@ -502,6 +569,8 @@ pub fn deinit(elf: *Elf) void {
502 elf.symtab.deinit(gpa);569 elf.symtab.deinit(gpa);
503 elf.shstrtab.map.deinit(gpa);570 elf.shstrtab.map.deinit(gpa);
504 elf.strtab.map.deinit(gpa);571 elf.strtab.map.deinit(gpa);
572 elf.inputs.deinit(gpa);
573 elf.input_sections.deinit(gpa);
505 elf.globals.deinit(gpa);574 elf.globals.deinit(gpa);
506 elf.navs.deinit(gpa);575 elf.navs.deinit(gpa);
507 elf.uavs.deinit(gpa);576 elf.uavs.deinit(gpa);
...@@ -796,16 +865,18 @@ fn initHeaders(...@@ -796,16 +865,18 @@ fn initHeaders(
796 .addralign = elf.mf.flags.block_size,865 .addralign = elf.mf.flags.block_size,
797 .entsize = 1,866 .entsize = 1,
798 }) == .shstrtab);867 }) == .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
799 assert(try elf.addSection(Node.Known.rodata, .{872 assert(try elf.addSection(Node.Known.rodata, .{
873 .name = ".strtab",
800 .type = std.elf.SHT_STRTAB,874 .type = std.elf.SHT_STRTAB,
801 .addralign = elf.mf.flags.block_size,875 .addralign = elf.mf.flags.block_size,
876 .size = 1,
802 .entsize = 1,877 .entsize = 1,
803 }) == .strtab);878 }) == .strtab);
804 try elf.renameSection(.symtab, ".symtab");
805 try elf.renameSection(.shstrtab, ".shstrtab");
806 try elf.renameSection(.strtab, ".strtab");
807 try elf.linkSections(.symtab, .strtab);879 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;880 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
810881
811 assert(try elf.addSection(Node.Known.rodata, .{882 assert(try elf.addSection(Node.Known.rodata, .{
...@@ -860,6 +931,32 @@ fn initHeaders(...@@ -860,6 +931,32 @@ fn initHeaders(
860 assert(elf.nodes.len == expected_nodes_len);931 assert(elf.nodes.len == expected_nodes_len);
861}932}
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
863fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {960fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
864 return elf.nodes.get(@intFromEnum(ni));961 return elf.nodes.get(@intFromEnum(ni));
865}962}
...@@ -871,6 +968,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -871,6 +968,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
871 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),968 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
872 },969 },
873 .section => |si| si,970 .section => |si| si,
971 .input_section => unreachable,
874 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),972 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
875 };973 };
876 break :parent_vaddr switch (elf.symPtr(parent_si)) {974 break :parent_vaddr switch (elf.symPtr(parent_si)) {
...@@ -1072,21 +1170,24 @@ fn navType(...@@ -1072,21 +1170,24 @@ fn navType(
1072 },1170 },
1073 };1171 };
1074}1172}
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}
1075fn navSection(1184fn navSection(
1076 elf: *Elf,1185 elf: *Elf,
1077 ip: *const InternPool,1186 ip: *const InternPool,
1078 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),1187 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
1079) Symbol.Index {1188) Symbol.Index {
1080 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| {1189 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
1081 if (std.mem.eql(u8, @"linksection", ".rodata") or1190 if (namedSection(@"linksection")) |si| return si;
1082 std.mem.startsWith(u8, @"linksection", ".rodata.")) return .rodata;
1083 if (std.mem.eql(u8, @"linksection", ".text") or
1084 std.mem.startsWith(u8, @"linksection", ".text.")) return .text;
1085 if (std.mem.eql(u8, @"linksection", ".data") or
1086 std.mem.startsWith(u8, @"linksection", ".data.")) return .data;
1087 if (std.mem.eql(u8, @"linksection", ".tdata") or
1088 std.mem.startsWith(u8, @"linksection", ".tdata.")) return .tdata;
1089 }
1090 return switch (navType(1191 return switch (navType(
1091 ip,1192 ip,
1092 .{ .fully_resolved = nav_fr },1193 .{ .fully_resolved = nav_fr },
...@@ -1156,11 +1257,236 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {...@@ -1156,11 +1257,236 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
1156 .const_data => .OBJECT,1257 .const_data => .OBJECT,
1157 },1258 },
1158 });1259 });
1159 elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);1260 elf.synth_prog_node.increaseEstimatedTotalItems(1);
1160 }1261 }
1161 return lazy_gop.value_ptr.*;1262 return lazy_gop.value_ptr.*;
1162}1263}
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
1164pub fn getNavVAddr(1490pub fn getNavVAddr(
1165 elf: *Elf,1491 elf: *Elf,
1166 pt: Zcu.PerThread,1492 pt: Zcu.PerThread,
...@@ -1228,12 +1554,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1228,12 +1554,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1228 const si = elf.addSymbolAssumeCapacity();1554 const si = elf.addSymbolAssumeCapacity();
1229 elf.nodes.appendAssumeCapacity(.{ .section = si });1555 elf.nodes.appendAssumeCapacity(.{ .section = si });
1230 si.get(elf).ni = ni;1556 si.get(elf).ni = ni;
1231 try si.init(elf, .{1557 try si.init(elf, .{ .size = opts.size, .type = .SECTION, .shndx = shndx });
1232 .name = opts.name,
1233 .size = opts.size,
1234 .type = .SECTION,
1235 .shndx = shndx,
1236 });
1237 switch (elf.shdrSlice()) {1558 switch (elf.shdrSlice()) {
1238 inline else => |shdr| {1559 inline else => |shdr| {
1239 const sh = &shdr[shndx];1560 const sh = &shdr[shndx];
...@@ -1256,15 +1577,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1256,15 +1577,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1256}1577}
12571578
1258fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {1579fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1259 const strtab_entry = try elf.string(.strtab, name);
1260 const shstrtab_entry = try elf.string(.shstrtab, name);1580 const shstrtab_entry = try elf.string(.shstrtab, name);
1261 switch (elf.shdrSlice()) {1581 switch (elf.shdrSlice()) {
1262 inline else => |shdr, class| {1582 inline else => |shdr, class| elf.targetStore(
1263 const sym = @field(elf.symPtr(si), @tagName(class));1583 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
1264 elf.targetStore(&sym.name, strtab_entry);1584 shstrtab_entry,
1265 const sh = &shdr[elf.targetLoad(&sym.shndx)];1585 ),
1266 elf.targetStore(&sh.name, shstrtab_entry);
1267 },
1268 }1586 }
1269}1587}
12701588
...@@ -1323,11 +1641,6 @@ pub fn addReloc(...@@ -1323,11 +1641,6 @@ pub fn addReloc(
1323 target.target_relocs = ri;1641 target.target_relocs = ri;
1324}1642}
13251643
1326pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void {
1327 _ = elf;
1328 _ = prog_node;
1329}
1330
1331pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {1644pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
1332 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {1645 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
1333 error.OutOfMemory,1646 error.OutOfMemory,
...@@ -1430,7 +1743,7 @@ pub fn lowerUav(...@@ -1430,7 +1743,7 @@ pub fn lowerUav(
1430 .alignment = uav_align,1743 .alignment = uav_align,
1431 .src_loc = src_loc,1744 .src_loc = src_loc,
1432 };1745 };
1433 elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);1746 elf.const_prog_node.increaseEstimatedTotalItems(1);
1434 }1747 }
1435 }1748 }
1436 return .{ .sym_index = @intFromEnum(si) };1749 return .{ .sym_index = @intFromEnum(si) };
...@@ -1534,7 +1847,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {...@@ -1534,7 +1847,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
1534 }) catch |err| switch (err) {1847 }) catch |err| switch (err) {
1535 error.OutOfMemory => return error.OutOfMemory,1848 error.OutOfMemory => return error.OutOfMemory,
1536 error.CodegenFail => return error.LinkFailure,1849 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}),
1538 };1851 };
1539}1852}
15401853
...@@ -1553,20 +1866,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1553,20 +1866,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1553 const comp = elf.base.comp;1866 const comp = elf.base.comp;
1554 task: {1867 task: {
1555 while (elf.pending_uavs.pop()) |pending_uav| {1868 while (elf.pending_uavs.pop()) |pending_uav| {
1556 const sub_prog_node = elf.idleProgNode(1869 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });
1557 tid,
1558 comp.link_const_prog_node,
1559 .{ .uav = pending_uav.key },
1560 );
1561 defer sub_prog_node.end();1870 defer sub_prog_node.end();
1562 elf.flushUav(1871 elf.flushUav(
1563 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },1872 .{ .zcu = comp.zcu.?, .tid = tid },
1564 pending_uav.key,1873 pending_uav.key,
1565 pending_uav.value.alignment,1874 pending_uav.value.alignment,
1566 pending_uav.value.src_loc,1875 pending_uav.value.src_loc,
1567 ) catch |err| switch (err) {1876 ) catch |err| switch (err) {
1568 error.OutOfMemory => return error.OutOfMemory,1877 error.OutOfMemory => return error.OutOfMemory,
1569 else => |e| return elf.base.comp.link_diags.fail(1878 else => |e| return comp.link_diags.fail(
1570 "linker failed to lower constant: {t}",1879 "linker failed to lower constant: {t}",
1571 .{e},1880 .{e},
1572 ),1881 ),
...@@ -1575,7 +1884,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1575,7 +1884,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1575 }1884 }
1576 var lazy_it = elf.lazy.iterator();1885 var lazy_it = elf.lazy.iterator();
1577 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {1886 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 };
1579 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };1888 const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
1580 lazy.value.pending_index += 1;1889 lazy.value.pending_index += 1;
1581 const kind = switch (lmr.kind) {1890 const kind = switch (lmr.kind) {
...@@ -1583,7 +1892,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1583,7 +1892,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1583 .const_data => "data",1892 .const_data => "data",
1584 };1893 };
1585 var name: [std.Progress.Node.max_name_len]u8 = undefined;1894 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(
1587 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{1896 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1588 kind,1897 kind,
1589 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),1898 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
...@@ -1593,13 +1902,27 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1593,13 +1902,27 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1593 defer sub_prog_node.end();1902 defer sub_prog_node.end();
1594 elf.flushLazy(pt, lmr) catch |err| switch (err) {1903 elf.flushLazy(pt, lmr) catch |err| switch (err) {
1595 error.OutOfMemory => return error.OutOfMemory,1904 error.OutOfMemory => return error.OutOfMemory,
1596 else => |e| return elf.base.comp.link_diags.fail(1905 else => |e| return comp.link_diags.fail(
1597 "linker failed to lower lazy {s}: {t}",1906 "linker failed to lower lazy {s}: {t}",
1598 .{ kind, e },1907 .{ kind, e },
1599 ),1908 ),
1600 };1909 };
1601 break :task;1910 break :task;
1602 };1911 };
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 }
1603 while (elf.mf.updates.pop()) |ni| {1926 while (elf.mf.updates.pop()) |ni| {
1604 const clean_moved = ni.cleanMoved(&elf.mf);1927 const clean_moved = ni.cleanMoved(&elf.mf);
1605 const clean_resized = ni.cleanResized(&elf.mf);1928 const clean_resized = ni.cleanResized(&elf.mf);
...@@ -1614,6 +1937,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1614,6 +1937,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1614 }1937 }
1615 if (elf.pending_uavs.count() > 0) return true;1938 if (elf.pending_uavs.count() > 0) return true;
1616 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;1939 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;
1617 if (elf.mf.updates.items.len > 0) return true;1941 if (elf.mf.updates.items.len > 0) return true;
1618 return false;1942 return false;
1619}1943}
...@@ -1628,6 +1952,10 @@ fn idleProgNode(...@@ -1628,6 +1952,10 @@ fn idleProgNode(
1628 return prog_node.start(name: switch (node) {1952 return prog_node.start(name: switch (node) {
1629 else => |tag| @tagName(tag),1953 else => |tag| @tagName(tag),
1630 .section => |si| elf.sectionName(si),1954 .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,
1631 .nav => |nmi| {1959 .nav => |nmi| {
1632 const ip = &elf.base.comp.zcu.?.intern_pool;1960 const ip = &elf.base.comp.zcu.?.intern_pool;
1633 break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);1961 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 {...@@ -1749,6 +2077,23 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
1749 si.applyLocationRelocs(elf);2077 si.applyLocationRelocs(elf);
1750}2078}
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
1752fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {2097fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1753 switch (elf.getNode(ni)) {2098 switch (elf.getNode(ni)) {
1754 .file => unreachable,2099 .file => unreachable,
...@@ -1786,7 +2131,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1786,7 +2131,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1786 }2131 }
1787 },2132 },
1788 },2133 },
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 ),
1790 }2156 }
1791 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);2157 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
1792}2158}
...@@ -1860,6 +2226,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1860,6 +2226,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
1860 }2226 }
1861 },2227 },
1862 },2228 },
2229 .input_section => {},
1863 .nav, .uav, .lazy_code, .lazy_const_data => {},2230 .nav, .uav, .lazy_code, .lazy_const_data => {},
1864 }2231 }
1865}2232}
...@@ -1983,6 +2350,10 @@ pub fn printNode(...@@ -1983,6 +2350,10 @@ pub fn printNode(
1983 switch (node) {2350 switch (node) {
1984 else => {},2351 else => {},
1985 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),2352 .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 }),
1986 .nav => |nmi| {2357 .nav => |nmi| {
1987 const zcu = elf.base.comp.zcu.?;2358 const zcu = elf.base.comp.zcu.?;
1988 const ip = &zcu.intern_pool;2359 const ip = &zcu.intern_pool;
...@@ -2027,25 +2398,28 @@ pub fn printNode(...@@ -2027,25 +2398,28 @@ pub fn printNode(
2027 leaf = false;2398 leaf = false;
2028 try elf.printNode(tid, w, child_ni, indent + 1);2399 try elf.printNode(tid, w, child_ni, indent + 1);
2029 }2400 }
2030 if (leaf) {2401 if (!leaf) return;
2031 const file_loc = ni.fileLocation(&elf.mf, false);2402 const file_loc = ni.fileLocation(&elf.mf, false);
2032 if (file_loc.size == 0) return;2403 var address = file_loc.offset;
2033 var address = file_loc.offset;2404 if (file_loc.size == 0) {
2034 const line_len = 0x10;2405 try w.splatByteAll(' ', indent + 1);
2035 var line_it = std.mem.window(2406 try w.print("{x:0>8}\n", .{address});
2036 u8,2407 return;
2037 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],2408 }
2038 line_len,2409 const line_len = 0x10;
2039 line_len,2410 var line_it = std.mem.window(
2040 );2411 u8,
2041 while (line_it.next()) |line_bytes| : (address += line_len) {2412 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2042 try w.splatByteAll(' ', indent + 1);2413 line_len,
2043 try w.print("{x:0>8} ", .{address});2414 line_len,
2044 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});2415 );
2045 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);2416 while (line_it.next()) |line_bytes| : (address += line_len) {
2046 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');2417 try w.splatByteAll(' ', indent + 1);
2047 try w.writeByte('\n');2418 try w.print("{x:0>8} ", .{address});
2048 }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');
2049 }2423 }
2050}2424}
20512425
src/link/MappedFile.zig+17-13
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1file: std.fs.File,1file: std.Io.File,
2flags: packed struct {2flags: packed struct {
3 block_size: std.mem.Alignment,3 block_size: std.mem.Alignment,
4 copy_file_range_unsupported: bool,4 copy_file_range_unsupported: bool,
...@@ -24,7 +24,7 @@ pub const Error = std.posix.MMapError || std.posix.MRemapError || std.fs.File.Se...@@ -24,7 +24,7 @@ pub const Error = std.posix.MMapError || std.posix.MRemapError || std.fs.File.Se
24 NoSpaceLeft,24 NoSpaceLeft,
25};25};
2626
27pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {27pub fn init(file: std.Io.File, gpa: std.mem.Allocator) !MappedFile {
28 var mf: MappedFile = .{28 var mf: MappedFile = .{
29 .file = file,29 .file = file,
30 .flags = undefined,30 .flags = undefined,
...@@ -386,7 +386,7 @@ pub const Node = extern struct {...@@ -386,7 +386,7 @@ pub const Node = extern struct {
386386
387 fn sendFile(387 fn sendFile(
388 interface: *std.Io.Writer,388 interface: *std.Io.Writer,
389 file_reader: *std.fs.File.Reader,389 file_reader: *std.Io.File.Reader,
390 limit: std.Io.Limit,390 limit: std.Io.Limit,
391 ) std.Io.Writer.FileError!usize {391 ) std.Io.Writer.FileError!usize {
392 if (limit == .nothing) return 0;392 if (limit == .nothing) return 0;
...@@ -397,14 +397,16 @@ pub const Node = extern struct {...@@ -397,14 +397,16 @@ pub const Node = extern struct {
397 switch (file_reader.mode) {397 switch (file_reader.mode) {
398 .positional => {398 .positional => {
399 const fr_buf = file_reader.interface.buffered();399 const fr_buf = file_reader.interface.buffered();
400 const buf_copy_size = interface.write(fr_buf) catch unreachable;400 if (fr_buf.len > 0) {
401 file_reader.interface.toss(buf_copy_size);401 const n = interface.write(fr_buf) catch unreachable;
402 if (buf_copy_size < fr_buf.len) return buf_copy_size;402 file_reader.interface.toss(n);
403 assert(file_reader.logicalPos() == file_reader.pos);403 return n;
404 }
404405
406 assert(file_reader.logicalPos() == file_reader.pos);
405 const w: *Writer = @fieldParentPtr("interface", interface);407 const w: *Writer = @fieldParentPtr("interface", interface);
406 const copy_size: usize = @intCast(w.mf.copyFileRange(408 const n: usize = @intCast(w.mf.copyFileRange(
407 .adaptFromNewApi(file_reader.file),409 file_reader.file,
408 file_reader.pos,410 file_reader.pos,
409 w.ni.fileLocation(w.mf, true).offset + interface.end,411 w.ni.fileLocation(w.mf, true).offset + interface.end,
410 limit.minInt(interface.unusedCapacityLen()),412 limit.minInt(interface.unusedCapacityLen()),
...@@ -412,8 +414,10 @@ pub const Node = extern struct {...@@ -412,8 +414,10 @@ pub const Node = extern struct {
412 w.err = err;414 w.err = err;
413 return error.WriteFailed;415 return error.WriteFailed;
414 });416 });
415 interface.end += copy_size;417 if (n == 0) return error.Unimplemented;
416 return copy_size;418 file_reader.pos += n;
419 interface.end += n;
420 return n;
417 },421 },
418 .streaming,422 .streaming,
419 .streaming_reading,423 .streaming_reading,
...@@ -614,7 +618,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -614,7 +618,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
614 // Resize the entire file618 // Resize the entire file
615 if (ni == Node.Index.root) {619 if (ni == Node.Index.root) {
616 try mf.ensureCapacityForSetLocation(gpa);620 try mf.ensureCapacityForSetLocation(gpa);
617 try mf.file.setEndPos(new_size);621 try std.fs.File.adaptFromNewApi(mf.file).setEndPos(new_size);
618 try mf.ensureTotalCapacity(@intCast(new_size));622 try mf.ensureTotalCapacity(@intCast(new_size));
619 ni.setLocationAssumeCapacity(mf, old_offset, new_size);623 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
620 return;624 return;
...@@ -894,7 +898,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:...@@ -894,7 +898,7 @@ fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
894898
895fn copyFileRange(899fn copyFileRange(
896 mf: *MappedFile,900 mf: *MappedFile,
897 old_file: std.fs.File,901 old_file: std.Io.File,
898 old_file_offset: u64,902 old_file_offset: u64,
899 new_file_offset: u64,903 new_file_offset: u64,
900 size: u64,904 size: u64,