zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit bdc2b2846d3f8f3cd81b50cddb56a3a6f3f29485 (tree)
parent 2f9cae345a309bfc28b0cc09bc57247fe0f07a9a
Author: Casey Banner <kcbanner@gmail.com>
Date:   Thu, 21 May 2026 08:27:15 +0100

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.

Diffstat:
Msrc/link/Elf2.zig | 2+-
Msrc/link/MappedFile.zig | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig @@ -2947,7 +2947,7 @@ fn uavMapIndex( } else { const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { - node.realign(&elf.mf, resolved_align.toStdMem()); + try node.realign(&elf.mf, gpa, resolved_align.toStdMem()); } } return umi; diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig @@ -305,12 +305,20 @@ pub const Node = extern struct { } } - pub fn realign(ni: Node.Index, mf: *MappedFile, new_alignment: std.mem.Alignment) void { - ni.get(mf).flags.alignment = new_alignment; - - const old_offset, const old_size = ni.location(mf).resolve(mf); - if (!new_alignment.check(@intCast(old_offset)) or !new_alignment.check(@intCast(old_size))) { - @panic("TODO MappedFile.realign"); + /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. + /// + /// Asserts that `ni` is not `Node.Index.root`. + pub fn realign( + ni: Node.Index, + mf: *MappedFile, + gpa: std.mem.Allocator, + new_alignment: std.mem.Alignment, + ) !void { + try mf.realignNode(gpa, ni, new_alignment); + var writers_it = mf.writers.first; + while (writers_it) |writer_node| : (writers_it = writer_node.next) { + const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); + w.interface.buffer = w.ni.slice(mf); } } @@ -852,6 +860,82 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested } } +fn realignNode( + mf: *MappedFile, + gpa: std.mem.Allocator, + ni: Node.Index, + new_alignment: std.mem.Alignment, +) !void { + assert(ni != Node.Index.root); // currently unsupported + + const node = ni.get(mf); + const old_offset, const size = node.location().resolve(mf); + + assert(new_alignment.compare(.gt, node.flags.alignment)); + + defer if (std.debug.runtime_safety) mf.verify(); + + node.flags.alignment = new_alignment; + + const new_size = node.flags.alignment.forward(@intCast(size)); + if (new_alignment.check(@intCast(old_offset))) { + if (new_size > size) try mf.resizeNode(gpa, ni, new_size); + return; + } + + _, const parent_size = node.parent.location(mf).resolve(mf); + const trailing_end = trailing_end: switch (node.next) { + .none => parent_size, + else => |next_ni| { + const next_offset, _ = next_ni.location(mf).resolve(mf); + break :trailing_end next_offset; + }, + }; + + const forward_offset = new_alignment.forward(@intCast(old_offset)); + if (forward_offset + new_size <= trailing_end) { + // Shift into the free space if possible + try mf.ensureCapacityForSetLocation(gpa); + if (node.flags.has_content) { + const old_file_offset = ni.fileLocation(mf, false).offset; + const new_file_offset = (old_file_offset - old_offset) + forward_offset; + if (new_file_offset < old_file_offset + size) { + @memmove( + mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], + mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], + ); + } else try mf.moveRange(old_file_offset, new_file_offset, size); + @memset(mf.memory_map.memory[@intCast(new_file_offset + size)..][0..@intCast(new_size - size)], 0); + } + + ni.setLocationAssumeCapacity(mf, forward_offset, new_size); + } else { + const temp_size = node.flags.alignment.forward(@intCast(new_size + 1)); + try mf.resizeNode(gpa, ni, temp_size); + const new_offset, _ = ni.location(mf).resolve(mf); + + try mf.ensureCapacityForSetLocation(gpa); + + // Non-fixed nodes may now be aligned if the resize moved them + const new_forward_offset = new_alignment.forward(@intCast(new_offset)); + const final_offset = if (new_forward_offset != new_offset) final_offset: { + if (node.flags.has_content) { + const old_file_offset = ni.fileLocation(mf, false).offset; + const new_file_offset = (old_file_offset - new_offset) + new_forward_offset; + @memmove( + mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], + mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], + ); + @memset(mf.memory_map.memory[@intCast(old_file_offset)..@intCast(new_file_offset)], 0); + } + + break :final_offset new_forward_offset; + } else new_offset; + + ni.setLocationAssumeCapacity(mf, final_offset, new_size); + } +} + fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { // make a copy of this node at the new location try mf.copyRange(old_file_offset, new_file_offset, size);