authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-05-21 08:27:15+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-26 06:42:14+01:00
logbdc2b2846d3f8f3cd81b50cddb56a3a6f3f29485
tree2fbeca7f7c3c855f683b0e1dcc5981ed97314a59
parent2f9cae345a309bfc28b0cc09bc57247fe0f07a9a
signaturelock-open Commit is signed but in an unrecognized format.

MappedFile: implement `realign`

Note from mlugg: this commit is a stripped-down version of Casey's implementation of `realign` from his WIP COFF linker branch. I've read through the code, and while it's a bit inefficient in some cases, it should work fine (and indeed does seem okay on this branch). I expect that Casey will end up replacing this with his full implementation when he opens a PR with his work.

2 files changed, 91 insertions(+), 7 deletions(-)

src/link/Elf2.zig+1-1
......@@ -2947,7 +2947,7 @@ fn uavMapIndex(
29472947 } else {
29482948 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
29492949 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
2950 node.realign(&elf.mf, resolved_align.toStdMem());
2950 try node.realign(&elf.mf, gpa, resolved_align.toStdMem());
29512951 }
29522952 }
29532953 return umi;
src/link/MappedFile.zig+90-6
......@@ -305,12 +305,20 @@ pub const Node = extern struct {
305305 }
306306 }
307307
308 pub fn realign(ni: Node.Index, mf: *MappedFile, new_alignment: std.mem.Alignment) void {
309 ni.get(mf).flags.alignment = new_alignment;
310
311 const old_offset, const old_size = ni.location(mf).resolve(mf);
312 if (!new_alignment.check(@intCast(old_offset)) or !new_alignment.check(@intCast(old_size))) {
313 @panic("TODO MappedFile.realign");
308 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.
309 ///
310 /// Asserts that `ni` is not `Node.Index.root`.
311 pub fn realign(
312 ni: Node.Index,
313 mf: *MappedFile,
314 gpa: std.mem.Allocator,
315 new_alignment: std.mem.Alignment,
316 ) !void {
317 try mf.realignNode(gpa, ni, new_alignment);
318 var writers_it = mf.writers.first;
319 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
320 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
321 w.interface.buffer = w.ni.slice(mf);
314322 }
315323 }
316324
......@@ -852,6 +860,82 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
852860 }
853861}
854862
863fn realignNode(
864 mf: *MappedFile,
865 gpa: std.mem.Allocator,
866 ni: Node.Index,
867 new_alignment: std.mem.Alignment,
868) !void {
869 assert(ni != Node.Index.root); // currently unsupported
870
871 const node = ni.get(mf);
872 const old_offset, const size = node.location().resolve(mf);
873
874 assert(new_alignment.compare(.gt, node.flags.alignment));
875
876 defer if (std.debug.runtime_safety) mf.verify();
877
878 node.flags.alignment = new_alignment;
879
880 const new_size = node.flags.alignment.forward(@intCast(size));
881 if (new_alignment.check(@intCast(old_offset))) {
882 if (new_size > size) try mf.resizeNode(gpa, ni, new_size);
883 return;
884 }
885
886 _, const parent_size = node.parent.location(mf).resolve(mf);
887 const trailing_end = trailing_end: switch (node.next) {
888 .none => parent_size,
889 else => |next_ni| {
890 const next_offset, _ = next_ni.location(mf).resolve(mf);
891 break :trailing_end next_offset;
892 },
893 };
894
895 const forward_offset = new_alignment.forward(@intCast(old_offset));
896 if (forward_offset + new_size <= trailing_end) {
897 // Shift into the free space if possible
898 try mf.ensureCapacityForSetLocation(gpa);
899 if (node.flags.has_content) {
900 const old_file_offset = ni.fileLocation(mf, false).offset;
901 const new_file_offset = (old_file_offset - old_offset) + forward_offset;
902 if (new_file_offset < old_file_offset + size) {
903 @memmove(
904 mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)],
905 mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)],
906 );
907 } else try mf.moveRange(old_file_offset, new_file_offset, size);
908 @memset(mf.memory_map.memory[@intCast(new_file_offset + size)..][0..@intCast(new_size - size)], 0);
909 }
910
911 ni.setLocationAssumeCapacity(mf, forward_offset, new_size);
912 } else {
913 const temp_size = node.flags.alignment.forward(@intCast(new_size + 1));
914 try mf.resizeNode(gpa, ni, temp_size);
915 const new_offset, _ = ni.location(mf).resolve(mf);
916
917 try mf.ensureCapacityForSetLocation(gpa);
918
919 // Non-fixed nodes may now be aligned if the resize moved them
920 const new_forward_offset = new_alignment.forward(@intCast(new_offset));
921 const final_offset = if (new_forward_offset != new_offset) final_offset: {
922 if (node.flags.has_content) {
923 const old_file_offset = ni.fileLocation(mf, false).offset;
924 const new_file_offset = (old_file_offset - new_offset) + new_forward_offset;
925 @memmove(
926 mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)],
927 mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)],
928 );
929 @memset(mf.memory_map.memory[@intCast(old_file_offset)..@intCast(new_file_offset)], 0);
930 }
931
932 break :final_offset new_forward_offset;
933 } else new_offset;
934
935 ni.setLocationAssumeCapacity(mf, final_offset, new_size);
936 }
937}
938
855939fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void {
856940 // make a copy of this node at the new location
857941 try mf.copyRange(old_file_offset, new_file_offset, size);