authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-17 10:59:01+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-24 20:42:40+01:00
logd9078dae3b6266767d66d5f2100f321b200cbd6b
tree15ff1606b2afe1c2f55ef99eca8539579bc6b9d5
parentff85396f7a85750cb703460b5b57b9860088c5ef
signaturelock-open Commit is signed but in an unrecognized format.

link.MappedFile: new `Alignment` type and non-optional `Node.Index`

There are two refactors here (apologies for putting them in the same commit!). First, I have replaced uses of `std.mem.Alignment` with a new type based on a fixed `u64` address space. While it is technically okay to use `std.mem.Alignment` in `MappedFile` (because memory-mapping limits the file size to the host's address space size), in practice it is somewhat inconvenient. I wanted to use `InternPool.Alignment`, but that type has an annoying problem of its own: for legacy reasons, it is optional (that is, it has a `.none` field), which makes for very ambiguous APIs unless you meticulously assert and comment all uses of the type. I therefore chose to add yet another alignment type to the Zig repository---sorrry! My hope going forward is that at some point, we can rename the existing `InternPool.Alignment` type to `InternPool.Alignment.Optional`, rename this new type to `InternPool.Alignment`, and slowly transition the entire compiler towards correctly distinguishing between "optional" and "non-optional" alignments. Second, I have made `MappedFile.Node.Index` non-optional (i.e. removed its `.none` tag). Notably, the old definition of this type had `.root == .none`, which was pretty awkward (you couldn't represent a node index which could be the root node *and* could be empty) and unsafe (we couldn't get safety checks for trying to use a "null" node index, instead we would just operate on the root node). To fix this, it has been split into `Node.Index` and `Node.Index.Optional`---I'm sure you all know the drill by now, it's just like all of the index types in `InternPool`. Some of the code I've written in this migration is definitely quite ugly, because I did a fairly mechanical replacement (e.g. for the most part I didn't introduce local constants). The code can be neatened up to avoid the mess of `unwrap` calls all over the place! Also, in `link.Coff`, it's possible that I made some fields optional when they shouldn't have been, which would definitely contribute to the `.unwrap().?` mess I wrote in that linker...

4 files changed, 622 insertions(+), 529 deletions(-)

src/InternPool.zig-11
...@@ -5987,17 +5987,6 @@ pub const Alignment = enum(u6) {...@@ -5987,17 +5987,6 @@ pub const Alignment = enum(u6) {
5987 return n + 1;5987 return n + 1;
5988 }5988 }
59895989
5990 pub fn toStdMem(a: Alignment) std.mem.Alignment {
5991 assert(a != .none);
5992 return @fromBackingInt(@intCast(@backingInt(a)));
5993 }
5994
5995 pub fn fromStdMem(a: std.mem.Alignment) Alignment {
5996 const r: Alignment = @fromBackingInt(@intCast(@backingInt(a)));
5997 assert(r != .none);
5998 return r;
5999 }
6000
6001 pub fn toLlvm(a: Alignment) std.zig.llvm.Builder.Alignment {5990 pub fn toLlvm(a: Alignment) std.zig.llvm.Builder.Alignment {
6002 return @fromBackingInt(@intCast(@backingInt(a)));5991 return @fromBackingInt(@intCast(@backingInt(a)));
6003 }5992 }
src/link/Coff.zig+142-144
...@@ -21,6 +21,7 @@ const Zcu = @import("../Zcu.zig");...@@ -21,6 +21,7 @@ const Zcu = @import("../Zcu.zig");
21const ModuleDefinition = @import("../libs/mingw/def.zig").ModuleDefinition;21const ModuleDefinition = @import("../libs/mingw/def.zig").ModuleDefinition;
22const implib = @import("../libs/mingw/implib.zig");22const implib = @import("../libs/mingw/implib.zig");
23const Path = std.Build.Cache.Path;23const Path = std.Build.Cache.Path;
24const Alignment = MappedFile.Alignment;
2425
25base: link.File,26base: link.File,
26options: link.File.OpenOptions,27options: link.File.OpenOptions,
...@@ -602,7 +603,7 @@ pub const Member = struct {...@@ -602,7 +603,7 @@ pub const Member = struct {
602};603};
603604
604pub const LongNamesTable = struct {605pub const LongNamesTable = struct {
605 ni: MappedFile.Node.Index = .none,606 ni: MappedFile.Node.Index.Optional = .none,
606 entries: std.array_hash_map.Auto(void, Entry),607 entries: std.array_hash_map.Auto(void, Entry),
607608
608 pub const Entry = struct {609 pub const Entry = struct {
...@@ -832,7 +833,7 @@ pub const String = enum(u32) {...@@ -832,7 +833,7 @@ pub const String = enum(u32) {
832833
833pub const Section = struct {834pub const Section = struct {
834 si: Symbol.Index,835 si: Symbol.Index,
835 relocation_table_ni: MappedFile.Node.Index,836 relocation_table_ni: MappedFile.Node.Index.Optional,
836837
837 pub const RelocationIndex = enum(u16) {838 pub const RelocationIndex = enum(u16) {
838 none,839 none,
...@@ -855,7 +856,7 @@ pub const Section = struct {...@@ -855,7 +856,7 @@ pub const Section = struct {
855 sn: Symbol.SectionNumber,856 sn: Symbol.SectionNumber,
856 ) ?*align(2) std.coff.Relocation {857 ) ?*align(2) std.coff.Relocation {
857 if (sri == .none) return null;858 if (sri == .none) return null;
858 const table_slice = sn.section(coff).relocation_table_ni.slice(&coff.mf);859 const table_slice = sn.section(coff).relocation_table_ni.unwrap().?.slice(&coff.mf);
859 return @ptrCast(@alignCast(&table_slice[@as(u32, sri.unwrap().?) * std.coff.Relocation.sizeOf()]));860 return @ptrCast(@alignCast(&table_slice[@as(u32, sri.unwrap().?) * std.coff.Relocation.sizeOf()]));
860 }861 }
861 };862 };
...@@ -891,7 +892,7 @@ const SpecialSymbol = enum {...@@ -891,7 +892,7 @@ const SpecialSymbol = enum {
891};892};
892893
893pub const Symbol = struct {894pub const Symbol = struct {
894 ni: MappedFile.Node.Index,895 ni: MappedFile.Node.Index.Optional,
895 rva: u32,896 rva: u32,
896 value: std.meta.BareUnion(Symbol.Value),897 value: std.meta.BareUnion(Symbol.Value),
897 extra: std.meta.BareUnion(Symbol.Extra),898 extra: std.meta.BareUnion(Symbol.Extra),
...@@ -986,7 +987,7 @@ pub const Symbol = struct {...@@ -986,7 +987,7 @@ pub const Symbol = struct {
986 pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 {987 pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 {
987 return switch (sym.flags.value_tag) {988 return switch (sym.flags.value_tag) {
988 .node_offset => offset: {989 .node_offset => offset: {
989 assert(switch (coff.getNode(sym.ni)) {990 assert(switch (coff.getNode(sym.ni.unwrap().?)) {
990 // Separate nodes are not created for these entries per-symbol991 // Separate nodes are not created for these entries per-symbol
991 .input_section, .import_address_table => true,992 .input_section, .import_address_table => true,
992 else => false,993 else => false,
...@@ -1052,9 +1053,7 @@ pub const Symbol = struct {...@@ -1052,9 +1053,7 @@ pub const Symbol = struct {
1052 }1053 }
10531054
1054 pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index {1055 pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index {
1055 const ni = si.get(coff).ni;1056 return si.get(coff).ni.unwrap().?;
1056 assert(ni != .none);
1057 return ni;
1058 }1057 }
10591058
1060 pub fn sti(si: Symbol.Index, coff: *Coff) SymbolTable.Index {1059 pub fn sti(si: Symbol.Index, coff: *Coff) SymbolTable.Index {
...@@ -1075,7 +1074,7 @@ pub const Symbol = struct {...@@ -1075,7 +1074,7 @@ pub const Symbol = struct {
10751074
1076 pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void {1075 pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void {
1077 const sym = si.get(coff);1076 const sym = si.get(coff);
1078 sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff);1077 sym.rva = coff.computeNodeRva(sym.ni.unwrap().?) + sym.nodeOffset(coff);
1079 try si.applyLocationRelocs(coff);1078 try si.applyLocationRelocs(coff);
1080 try si.applyTargetRelocs(coff, .none);1079 try si.applyTargetRelocs(coff, .none);
10811080
...@@ -1199,12 +1198,11 @@ pub const Reloc = extern struct {...@@ -1199,12 +1198,11 @@ pub const Reloc = extern struct {
11991198
1200 pub fn apply(reloc: *Reloc, coff: *Coff) !void {1199 pub fn apply(reloc: *Reloc, coff: *Coff) !void {
1201 const loc_sym = reloc.loc.get(coff);1200 const loc_sym = reloc.loc.get(coff);
1202 switch (loc_sym.ni) {
1203 .none => return,
1204 else => |ni| if (ni.hasMoved(&coff.mf)) return,
1205 }
12061201
1207 const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..];1202 const loc_sym_ni = loc_sym.ni.unwrap() orelse return;
1203 if (loc_sym_ni.hasMoved(&coff.mf)) return;
1204
1205 const loc_slice = loc_sym_ni.slice(&coff.mf)[@intCast(reloc.offset)..];
1208 const target_endian = coff.targetEndian();1206 const target_endian = coff.targetEndian();
1209 const target_machine = coff.targetLoad(&coff.headerPtr().machine);1207 const target_machine = coff.targetLoad(&coff.headerPtr().machine);
12101208
...@@ -1331,9 +1329,12 @@ pub const Reloc = extern struct {...@@ -1331,9 +1329,12 @@ pub const Reloc = extern struct {
1331 }1329 }
13321330
1333 const target_sym = reloc.target.get(coff);1331 const target_sym = reloc.target.get(coff);
1334 const is_abs = switch (target_sym.ni) {1332 const is_abs = if (target_sym.ni.unwrap()) |ni| is_abs: {
1335 .none => if (target_sym.section_number == .ABSOLUTE) true else return,1333 if (ni.hasMoved(&coff.mf)) return;
1336 else => |ni| if (ni.hasMoved(&coff.mf)) return else false,1334 break :is_abs false;
1335 } else is_abs: {
1336 if (target_sym.section_number != .ABSOLUTE) return;
1337 break :is_abs true;
1337 };1338 };
13381339
1339 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));1340 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
...@@ -1573,7 +1574,7 @@ fn create(...@@ -1573,7 +1574,7 @@ fn create(
1573 33...64 => .@"PE32+",1574 33...64 => .@"PE32+",
1574 else => return error.UnsupportedCOFFArchitecture,1575 else => return error.UnsupportedCOFFArchitecture,
1575 };1576 };
1576 const section_align: std.mem.Alignment = switch (machine) {1577 const section_align: Alignment = switch (machine) {
1577 .AMD64, .I386 => @fromBackingInt(@intCast(12)),1578 .AMD64, .I386 => @fromBackingInt(@intCast(12)),
1578 .SH3, .SH3DSP, .SH4, .SH5 => @fromBackingInt(@intCast(12)),1579 .SH3, .SH3DSP, .SH4, .SH5 => @fromBackingInt(@intCast(12)),
1579 .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @fromBackingInt(@intCast(12)),1580 .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @fromBackingInt(@intCast(12)),
...@@ -1617,22 +1618,22 @@ fn create(...@@ -1617,22 +1618,22 @@ fn create(
1617 .entries = .empty,1618 .entries = .empty,
1618 },1619 },
1619 .import_table = .{1620 .import_table = .{
1620 .ni = .none,1621 .ni = undefined,
1621 .entries = .empty,1622 .entries = .empty,
1622 .iat_symbol_indices = .empty,1623 .iat_symbol_indices = .empty,
1623 },1624 },
1624 .export_table = .{1625 .export_table = .{
1625 .ni = .none,1626 .ni = undefined,
1626 .export_directory_table_ni = .none,1627 .export_directory_table_ni = undefined,
1627 .export_address_table_si = .null,1628 .export_address_table_si = .null,
1628 .name_pointer_table_ni = .none,1629 .name_pointer_table_ni = undefined,
1629 .ordinal_table_ni = .none,1630 .ordinal_table_ni = undefined,
1630 .name_table_ni = .none,1631 .name_table_ni = undefined,
1631 .entries = .empty,1632 .entries = .empty,
1632 },1633 },
1633 .symbol_table = .{1634 .symbol_table = .{
1634 .ni = .none,1635 .ni = undefined,
1635 .strings_ni = .none,1636 .strings_ni = undefined,
1636 .strings = .empty,1637 .strings = .empty,
1637 .symbols = .empty,1638 .symbols = .empty,
1638 .pending_symbol_index = 0,1639 .pending_symbol_index = 0,
...@@ -1794,13 +1795,13 @@ fn initHeaders(...@@ -1794,13 +1795,13 @@ fn initHeaders(
1794 minor_subsystem_version: u16,1795 minor_subsystem_version: u16,
1795 magic: std.coff.OptionalHeader.Magic,1796 magic: std.coff.OptionalHeader.Magic,
1796 subsystem: std.coff.Subsystem,1797 subsystem: std.coff.Subsystem,
1797 section_align: std.mem.Alignment,1798 section_align: Alignment,
1798 file_name: []const u8,1799 file_name: []const u8,
1799) !void {1800) !void {
1800 const comp = coff.base.comp;1801 const comp = coff.base.comp;
1801 const gpa = comp.gpa;1802 const gpa = comp.gpa;
1802 const target_endian = coff.targetEndian();1803 const target_endian = coff.targetEndian();
1803 const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment);1804 const file_align: Alignment = comptime .fromByteUnits(default_file_alignment);
1804 const is_image = coff.isImage();1805 const is_image = coff.isImage();
1805 const is_archive = coff.isArchive();1806 const is_archive = coff.isArchive();
1806 const target = &comp.root_mod.resolved_target.result;1807 const target = &comp.root_mod.resolved_target.result;
...@@ -2191,7 +2192,7 @@ fn initHeaders(...@@ -2191,7 +2192,7 @@ fn initHeaders(
2191 coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity();2192 coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity();
21922193
2193 const export_address_table_sym = coff.export_table.export_address_table_si.get(coff);2194 const export_address_table_sym = coff.export_table.export_address_table_si.get(coff);
2194 export_address_table_sym.ni = export_address_table_ni;2195 export_address_table_sym.ni = .wrap(export_address_table_ni);
2195 assert(export_address_table_sym.loc_relocs == .none);2196 assert(export_address_table_sym.loc_relocs == .none);
2196 export_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));2197 export_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
2197 export_address_table_sym.section_number =2198 export_address_table_sym.section_number =
...@@ -2260,7 +2261,7 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2260,7 +2261,7 @@ pub fn initBuiltins(coff: *Coff) !void {
2260 if (coff.isImage()) {2261 if (coff.isImage()) {
2261 const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data });2262 const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data });
2262 const sym = si.get(coff);2263 const sym = si.get(coff);
2263 sym.ni = Node.known.header;2264 sym.ni = .wrap(Node.known.header);
2264 }2265 }
22652266
2266 defer coff.flushSectionMerges() catch unreachable;2267 defer coff.flushSectionMerges() catch unreachable;
...@@ -2302,14 +2303,14 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2302,14 +2303,14 @@ pub fn initBuiltins(coff: *Coff) !void {
2302 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });2303 const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data });
2303 const list_len_sym = list_len_si.get(coff);2304 const list_len_sym = list_len_si.get(coff);
2304 list_len_sym.setExtra(.{ .size = addr_info.size });2305 list_len_sym.setExtra(.{ .size = addr_info.size });
2305 list_len_sym.ni = try coff.mf.addFirstChildNode(gpa, start_sym.ni, .{2306 list_len_sym.ni = .wrap(try coff.mf.addFirstChildNode(gpa, start_sym.ni.unwrap().?, .{
2306 .size = addr_info.size,2307 .size = addr_info.size,
2307 .fixed = true,2308 .fixed = true,
2308 });2309 }));
2309 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });2310 coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si });
2310 list_len_sym.section_number = start_sym.section_number;2311 list_len_sym.section_number = start_sym.section_number;
23112312
2312 const start_slice = list_len_sym.ni.slice(&coff.mf);2313 const start_slice = list_len_sym.ni.unwrap().?.slice(&coff.mf);
2313 switch (addr_info.magic) {2314 switch (addr_info.magic) {
2314 _ => unreachable,2315 _ => unreachable,
2315 inline .PE32, .@"PE32+" => |t| {2316 inline .PE32, .@"PE32+" => |t| {
...@@ -2324,14 +2325,14 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2324,14 +2325,14 @@ pub fn initBuiltins(coff: *Coff) !void {
2324 const list_end_si = coff.addSymbolAssumeCapacity();2325 const list_end_si = coff.addSymbolAssumeCapacity();
2325 const list_end_sym = list_end_si.get(coff);2326 const list_end_sym = list_end_si.get(coff);
2326 list_end_sym.setExtra(.{ .size = addr_info.size });2327 list_end_sym.setExtra(.{ .size = addr_info.size });
2327 list_end_sym.ni = try coff.mf.addFirstChildNode(gpa, end_sym.ni, .{2328 list_end_sym.ni = .wrap(try coff.mf.addFirstChildNode(gpa, end_sym.ni.unwrap().?, .{
2328 .size = addr_info.size,2329 .size = addr_info.size,
2329 .fixed = true,2330 .fixed = true,
2330 });2331 }));
2331 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });2332 coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si });
2332 list_end_sym.section_number = start_sym.section_number;2333 list_end_sym.section_number = start_sym.section_number;
23332334
2334 @memset(list_end_sym.ni.slice(&coff.mf), 0);2335 @memset(list_end_sym.ni.unwrap().?.slice(&coff.mf), 0);
23352336
2336 try list_len_si.flushMoved(coff);2337 try list_len_si.flushMoved(coff);
2337 try list_end_si.flushMoved(coff);2338 try list_end_si.flushMoved(coff);
...@@ -2387,7 +2388,7 @@ fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {...@@ -2387,7 +2388,7 @@ fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
2387}2388}
2388fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {2389fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
2389 const parent_rva = parent_rva: {2390 const parent_rva = parent_rva: {
2390 const parent_si = switch (coff.getNode(ni.parent(&coff.mf))) {2391 const parent_si = switch (coff.getNode(ni.parent(&coff.mf).unwrap().?)) {
2391 .file,2392 .file,
2392 .header,2393 .header,
2393 .signature,2394 .signature,
...@@ -2452,11 +2453,11 @@ fn computeSymbolSectionOffset(...@@ -2452,11 +2453,11 @@ fn computeSymbolSectionOffset(
2452 relative_to: enum { image, pseudo },2453 relative_to: enum { image, pseudo },
2453) u32 {2454) u32 {
2454 var section_offset: u32 = sym.nodeOffset(coff);2455 var section_offset: u32 = sym.nodeOffset(coff);
2455 var parent_ni = sym.ni;2456 var parent_ni = sym.ni.unwrap().?;
2456 while (true) {2457 while (true) {
2457 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);2458 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);
2458 section_offset += @intCast(offset);2459 section_offset += @intCast(offset);
2459 parent_ni = parent_ni.parent(&coff.mf);2460 parent_ni = parent_ni.parent(&coff.mf).unwrap().?;
2460 switch (coff.getNode(parent_ni)) {2461 switch (coff.getNode(parent_ni)) {
2461 else => unreachable,2462 else => unreachable,
2462 .image_section => break,2463 .image_section => break,
...@@ -2475,7 +2476,7 @@ pub inline fn targetEndian(_: *const Coff) std.lang.Endian {...@@ -2475,7 +2476,7 @@ pub inline fn targetEndian(_: *const Coff) std.lang.Endian {
24752476
2476fn targetAddrInfo(coff: *Coff) struct {2477fn targetAddrInfo(coff: *Coff) struct {
2477 size: u8,2478 size: u8,
2478 alignment: std.mem.Alignment,2479 alignment: Alignment,
2479 magic: std.coff.OptionalHeader.Magic,2480 magic: std.coff.OptionalHeader.Magic,
2480} {2481} {
2481 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);2482 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
...@@ -2875,9 +2876,9 @@ fn navSection(...@@ -2875,9 +2876,9 @@ fn navSection(
2875 switch (nav_resolved.@"linksection") {2876 switch (nav_resolved.@"linksection") {
2876 .none => coff.mf.flags.block_size,2877 .none => coff.mf.flags.block_size,
2877 else => switch (nav_resolved.@"align") {2878 else => switch (nav_resolved.@"align") {
2878 .none => Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu),2879 .none => .fromIp(Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu)),
2879 else => |alignment| alignment,2880 else => |a| .fromIp(a),
2880 }.toStdMem(),2881 },
2881 },2882 },
2882 attributes,2883 attributes,
2883 )).symbol(coff);2884 )).symbol(coff);
...@@ -3151,7 +3152,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3151,7 +3152,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3151 else3152 else
3152 .NULL,3153 .NULL,
3153 };3154 };
3154 } else blk: switch (coff.getNode(sym.ni)) {3155 } else blk: switch (coff.getNode(sym.ni.unwrap().?)) {
3155 .image_section => .{3156 .image_section => .{
3156 try coff.getOrPutSymbolName(&sym.section_number.header(coff).name, null),3157 try coff.getOrPutSymbolName(&sym.section_number.header(coff).name, null),
3157 1,3158 1,
...@@ -3192,7 +3193,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3192,7 +3193,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3192 };3193 };
3193 },3194 },
3194 else => {3195 else => {
3195 log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni)), si });3196 log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni.unwrap().?)), si });
3196 unreachable;3197 unreachable;
3197 },3198 },
3198 };3199 };
...@@ -3255,13 +3256,13 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3255,13 +3256,13 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3255 std.mem.byteSwapAllFieldsAligned(std.coff.WeakExternalDefinition, .@"2", aux_ptr);3256 std.mem.byteSwapAllFieldsAligned(std.coff.WeakExternalDefinition, .@"2", aux_ptr);
32563257
3257 break :aux_init;3258 break :aux_init;
3258 } else switch (coff.getNode(sym.ni)) {3259 } else switch (coff.getNode(sym.ni.unwrap().?)) {
3259 .image_section => |sec_si| {3260 .image_section => |sec_si| {
3260 assert(si == sec_si);3261 assert(si == sec_si);
3261 const header = sym.section_number.header(coff);3262 const header = sym.section_number.header(coff);
3262 const aux_ptr = coff.symbolTableSectionAuxEntryPtr(sti.*).?;3263 const aux_ptr = coff.symbolTableSectionAuxEntryPtr(sti.*).?;
3263 aux_ptr.* = .{3264 aux_ptr.* = .{
3264 .length = @intCast(sym.ni.location(&coff.mf).resolve(&coff.mf)[1]),3265 .length = @intCast(sym.ni.unwrap().?.location(&coff.mf).resolve(&coff.mf)[1]),
3265 .number_of_relocations = header.number_of_relocations,3266 .number_of_relocations = header.number_of_relocations,
3266 .number_of_linenumbers = header.number_of_linenumbers,3267 .number_of_linenumbers = header.number_of_linenumbers,
3267 .checksum = 0,3268 .checksum = 0,
...@@ -3288,7 +3289,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {...@@ -3288,7 +3289,7 @@ fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void {
3288 .ABSOLUTE,3289 .ABSOLUTE,
3289 .DEBUG,3290 .DEBUG,
3290 => unreachable,3291 => unreachable,
3291 else => switch (coff.getNode(sym.ni)) {3292 else => switch (coff.getNode(sym.ni.unwrap().?)) {
3292 .image_section => 0,3293 .image_section => 0,
3293 else => coff.computeSymbolSectionOffset(sym, .image),3294 else => coff.computeSymbolSectionOffset(sym, .image),
3294 },3295 },
...@@ -3397,7 +3398,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S...@@ -3397,7 +3398,7 @@ fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !S
33973398
3398 {3399 {
3399 const sym = si.get(coff);3400 const sym = si.get(coff);
3400 sym.ni = ni;3401 sym.ni = .wrap(ni);
3401 sym.rva = rva;3402 sym.rva = rva;
3402 sym.section_number = @fromBackingInt(@intCast(section_table_len));3403 sym.section_number = @fromBackingInt(@intCast(section_table_len));
3403 }3404 }
...@@ -3481,7 +3482,7 @@ const ObjectSectionAttributes = packed struct {...@@ -3481,7 +3482,7 @@ const ObjectSectionAttributes = packed struct {
3481fn pseudoSectionMapIndex(3482fn pseudoSectionMapIndex(
3482 coff: *Coff,3483 coff: *Coff,
3483 name: String,3484 name: String,
3484 alignment: std.mem.Alignment,3485 alignment: Alignment,
3485 attributes: ObjectSectionAttributes,3486 attributes: ObjectSectionAttributes,
3486) !Node.PseudoSectionMapIndex {3487) !Node.PseudoSectionMapIndex {
3487 const gpa = coff.base.comp.gpa;3488 const gpa = coff.base.comp.gpa;
...@@ -3510,7 +3511,7 @@ fn pseudoSectionMapIndex(...@@ -3510,7 +3511,7 @@ fn pseudoSectionMapIndex(
3510 const si = coff.addSymbolAssumeCapacity();3511 const si = coff.addSymbolAssumeCapacity();
3511 pseudo_section_gop.value_ptr.* = si;3512 pseudo_section_gop.value_ptr.* = si;
3512 const sym = si.get(coff);3513 const sym = si.get(coff);
3513 sym.ni = ni;3514 sym.ni = .wrap(ni);
3514 sym.rva = coff.computeNodeRva(ni);3515 sym.rva = coff.computeNodeRva(ni);
3515 sym.section_number = parent.get(coff).section_number;3516 sym.section_number = parent.get(coff).section_number;
3516 assert(sym.loc_relocs == .none);3517 assert(sym.loc_relocs == .none);
...@@ -3543,7 +3544,7 @@ fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 {...@@ -3543,7 +3544,7 @@ fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 {
3543fn objectSectionMapIndex(3544fn objectSectionMapIndex(
3544 coff: *Coff,3545 coff: *Coff,
3545 name: String,3546 name: String,
3546 alignment: std.mem.Alignment,3547 alignment: Alignment,
3547 attributes: ObjectSectionAttributes,3548 attributes: ObjectSectionAttributes,
3548) !Node.ObjectSectionMapIndex {3549) !Node.ObjectSectionMapIndex {
3549 const gpa = coff.base.comp.gpa;3550 const gpa = coff.base.comp.gpa;
...@@ -3565,7 +3566,7 @@ fn objectSectionMapIndex(...@@ -3565,7 +3566,7 @@ fn objectSectionMapIndex(
3565 try coff.nodes.ensureUnusedCapacity(gpa, 1);3566 try coff.nodes.ensureUnusedCapacity(gpa, 1);
3566 try coff.symbols.ensureUnusedCapacity(gpa, 1);3567 try coff.symbols.ensureUnusedCapacity(gpa, 1);
3567 const parent_ni = parent.node(coff);3568 const parent_ni = parent.node(coff);
3568 var prev_ni: MappedFile.Node.Index = .none;3569 var prev_oni: MappedFile.Node.Index.Optional = .none;
3569 var next_it = parent_ni.children(&coff.mf);3570 var next_it = parent_ni.children(&coff.mf);
3570 while (next_it.next()) |next_ni| switch (std.mem.order(3571 while (next_it.next()) |next_ni| switch (std.mem.order(
3571 u8,3572 u8,
...@@ -3574,22 +3575,19 @@ fn objectSectionMapIndex(...@@ -3574,22 +3575,19 @@ fn objectSectionMapIndex(
3574 )) {3575 )) {
3575 .lt => break,3576 .lt => break,
3576 .eq => unreachable,3577 .eq => unreachable,
3577 .gt => prev_ni = next_ni,3578 .gt => prev_oni = .wrap(next_ni),
3578 };
3579 const ni = switch (prev_ni) {
3580 .none => try coff.mf.addFirstChildNode(gpa, parent_ni, .{
3581 .alignment = alignment,
3582 .fixed = true,
3583 }),
3584 else => try coff.mf.addNodeAfter(gpa, prev_ni, .{
3585 .alignment = alignment,
3586 .fixed = true,
3587 }),
3588 };3579 };
3580 const ni = if (prev_oni.unwrap()) |prev_ni| try coff.mf.addNodeAfter(gpa, prev_ni, .{
3581 .alignment = alignment,
3582 .fixed = true,
3583 }) else try coff.mf.addFirstChildNode(gpa, parent_ni, .{
3584 .alignment = alignment,
3585 .fixed = true,
3586 });
3589 const si = coff.addSymbolAssumeCapacity();3587 const si = coff.addSymbolAssumeCapacity();
3590 object_section_gop.value_ptr.* = si;3588 object_section_gop.value_ptr.* = si;
3591 const sym = si.get(coff);3589 const sym = si.get(coff);
3592 sym.ni = ni;3590 sym.ni = .wrap(ni);
3593 sym.rva = coff.computeNodeRva(ni);3591 sym.rva = coff.computeNodeRva(ni);
3594 sym.section_number = parent.get(coff).section_number;3592 sym.section_number = parent.get(coff).section_number;
3595 assert(sym.loc_relocs == .none);3593 assert(sym.loc_relocs == .none);
...@@ -3598,17 +3596,17 @@ fn objectSectionMapIndex(...@@ -3598,17 +3596,17 @@ fn objectSectionMapIndex(
3598 break :sym sym;3596 break :sym sym;
3599 } else object_section_gop.value_ptr.get(coff);3597 } else object_section_gop.value_ptr.get(coff);
36003598
3601 const parent_ni = sym.ni.parent(&coff.mf);3599 const parent_ni = sym.ni.unwrap().?.parent(&coff.mf).unwrap().?;
3602 const parent_alignment = parent_ni.alignment(&coff.mf);3600 const parent_alignment = parent_ni.alignment(&coff.mf);
3603 if (alignment.compare(.gt, parent_alignment)) {3601 if (alignment.compare(.gt, parent_alignment)) {
3604 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });3602 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });
3605 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });3603 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3606 }3604 }
36073605
3608 const old_alignment = sym.ni.alignment(&coff.mf);3606 const old_alignment = sym.ni.unwrap().?.alignment(&coff.mf);
3609 if (alignment.compare(.gt, old_alignment)) {3607 if (alignment.compare(.gt, old_alignment)) {
3610 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });3608 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });
3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });3609 try sym.ni.unwrap().?.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3612 }3610 }
36133611
3614 try coff.verifyParentSectionAttributes(3612 try coff.verifyParentSectionAttributes(
...@@ -3764,8 +3762,10 @@ fn addRelocAssumeCapacity(...@@ -3764,8 +3762,10 @@ fn addRelocAssumeCapacity(
3764 if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr|3762 if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr|
3765 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);3763 coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
37663764
3767 if (section.relocation_table_ni == .none) {3765 if (section.relocation_table_ni.unwrap()) |relocation_table_ni| {
3768 section.relocation_table_ni = try coff.mf.addLastChildNode(3766 try relocation_table_ni.resize(&coff.mf, gpa, new_size);
3767 } else {
3768 section.relocation_table_ni = .wrap(try coff.mf.addLastChildNode(
3769 gpa,3769 gpa,
3770 coff.sectionParent(),3770 coff.sectionParent(),
3771 .{3771 .{
...@@ -3774,10 +3774,8 @@ fn addRelocAssumeCapacity(...@@ -3774,10 +3774,8 @@ fn addRelocAssumeCapacity(
3774 .moved = true,3774 .moved = true,
3775 .resized = true,3775 .resized = true,
3776 },3776 },
3777 );3777 ));
3778 coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });3778 coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });
3779 } else {
3780 try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
3781 }3779 }
37823780
3783 // TODO: These need to allocate from a free list, once deleting relocs from the table is supported3781 // TODO: These need to allocate from a free list, once deleting relocs from the table is supported
...@@ -4581,7 +4579,7 @@ fn loadObject(...@@ -4581,7 +4579,7 @@ fn loadObject(
4581 },4579 },
4582 .SAME_SIZE => {4580 .SAME_SIZE => {
4583 // TODO: Verify that this node isn't resized after creation4581 // TODO: Verify that this node isn't resized after creation
4584 _, const size = si.get(coff).ni.location(&coff.mf).resolve(&coff.mf);4582 _, const size = si.get(coff).ni.unwrap().?.location(&coff.mf).resolve(&coff.mf);
4585 if (size == section.header.size_of_raw_data) {4583 if (size == section.header.size_of_raw_data) {
4586 symbol.si = si;4584 symbol.si = si;
4587 break :comdat .skip;4585 break :comdat .skip;
...@@ -4598,9 +4596,9 @@ fn loadObject(...@@ -4598,9 +4596,9 @@ fn loadObject(
4598 },4596 },
4599 .EXACT_MATCH => {4597 .EXACT_MATCH => {
4600 const sym = si.get(coff);4598 const sym = si.get(coff);
4601 const existing_crc = switch (coff.getNode(sym.ni)) {4599 const existing_crc = switch (coff.getNode(sym.ni.unwrap().?)) {
4602 .input_section => |isi| isi.inputSection(coff).crc,4600 .input_section => |isi| isi.inputSection(coff).crc,
4603 else => Crc32.hash(sym.ni.sliceConst(&coff.mf)),4601 else => Crc32.hash(sym.ni.unwrap().?.sliceConst(&coff.mf)),
4604 };4602 };
46054603
4606 if (existing_crc == section.comdat_crc) {4604 if (existing_crc == section.comdat_crc) {
...@@ -4666,7 +4664,7 @@ fn loadObject(...@@ -4666,7 +4664,7 @@ fn loadObject(
46664664
4667 section.parent_si = (try coff.objectSectionMapIndex(4665 section.parent_si = (try coff.objectSectionMapIndex(
4668 section.name,4666 section.name,
4669 section.header.flags.ALIGN.alignment() orelse .@"1",4667 .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1),
4670 .fromFlags(section.header.flags),4668 .fromFlags(section.header.flags),
4671 )).symbol(coff);4669 )).symbol(coff);
4672 }4670 }
...@@ -4681,7 +4679,7 @@ fn loadObject(...@@ -4681,7 +4679,7 @@ fn loadObject(
46814679
4682 const ni = try coff.mf.addLastChildNode(gpa, section.parent_si.node(coff), .{4680 const ni = try coff.mf.addLastChildNode(gpa, section.parent_si.node(coff), .{
4683 .size = section.header.size_of_raw_data,4681 .size = section.header.size_of_raw_data,
4684 .alignment = section.header.flags.ALIGN.alignment() orelse .@"1",4682 .alignment = .fromByteUnits(section.header.flags.ALIGN.toByteUnits() orelse 1),
4685 .moved = true,4683 .moved = true,
4686 });4684 });
4687 coff.nodes.appendAssumeCapacity(.{ .input_section = @fromBackingInt(@intCast(coff.input_sections.items.len)) });4685 coff.nodes.appendAssumeCapacity(.{ .input_section = @fromBackingInt(@intCast(coff.input_sections.items.len)) });
...@@ -4691,7 +4689,7 @@ fn loadObject(...@@ -4691,7 +4689,7 @@ fn loadObject(
4691 pending_symbols.values()[psi].si = section.si;4689 pending_symbols.values()[psi].si = section.si;
46924690
4693 const sym = section.si.get(coff);4691 const sym = section.si.get(coff);
4694 sym.ni = ni;4692 sym.ni = .wrap(ni);
4695 sym.section_number = section.parent_si.get(coff).section_number;4693 sym.section_number = section.parent_si.get(coff).section_number;
46964694
4697 coff.input_sections.addOneAssumeCapacity().* = .{4695 coff.input_sections.addOneAssumeCapacity().* = .{
...@@ -4852,7 +4850,7 @@ fn loadObject(...@@ -4852,7 +4850,7 @@ fn loadObject(
4852 }4850 }
48534851
4854 if (section.comdat_psi.unwrap() == @as(u32, @intCast(i)))4852 if (section.comdat_psi.unwrap() == @as(u32, @intCast(i)))
4855 coff.getNode(section.si.get(coff).ni).input_section.inputSection(coff).comdat_si = symbol.si;4853 coff.getNode(section.si.get(coff).ni.unwrap().?).input_section.inputSection(coff).comdat_si = symbol.si;
4856 }4854 }
48574855
4858 if (symbol.weak_external_psi.unwrap()) |weak_external_i| {4856 if (symbol.weak_external_psi.unwrap()) |weak_external_i| {
...@@ -4967,14 +4965,14 @@ fn loadObject(...@@ -4967,14 +4965,14 @@ fn loadObject(
4967 const section = &sections[symbol.section_number.toIndex()];4965 const section = &sections[symbol.section_number.toIndex()];
4968 include_section = section.comdat_result == .include;4966 include_section = section.comdat_result == .include;
4969 if (include_section) {4967 if (include_section) {
4970 const isi = coff.getNode(section.si.get(coff).ni).input_section;4968 const isi = coff.getNode(section.si.get(coff).ni.unwrap().?).input_section;
4971 isi.inputSection(coff).first_li = @fromBackingInt(@intCast(coff.input_symbols.items.len));4969 isi.inputSection(coff).first_li = @fromBackingInt(@intCast(coff.input_symbols.items.len));
4972 }4970 }
4973 }4971 }
4974 }4972 }
49754973
4976 if (include_section) {4974 if (include_section) {
4977 assert(coff.getNode(symbol.si.get(coff).ni) == .input_section);4975 assert(coff.getNode(symbol.si.get(coff).ni.unwrap().?) == .input_section);
4978 symbol.si.get(coff).setExtra(.{ .isli = @fromBackingInt(@intCast(coff.input_symbols.items.len)) });4976 symbol.si.get(coff).setExtra(.{ .isli = @fromBackingInt(@intCast(coff.input_symbols.items.len)) });
4979 coff.input_symbols.addOneAssumeCapacity().* = .{4977 coff.input_symbols.addOneAssumeCapacity().* = .{
4980 .si = symbol.si,4978 .si = symbol.si,
...@@ -5002,7 +5000,7 @@ fn failMultipleDefinitions(...@@ -5002,7 +5000,7 @@ fn failMultipleDefinitions(
5002 var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes);5000 var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes);
5003 try err.addMsg("multiple definitions of '{s}'", .{name.toSlice(coff)});5001 try err.addMsg("multiple definitions of '{s}'", .{name.toSlice(coff)});
50045002
5005 switch (coff.getNode(existing_si.get(coff).ni)) {5003 switch (coff.getNode(existing_si.get(coff).ni.unwrap().?)) {
5006 .input_section => |isi| {5004 .input_section => |isi| {
5007 const other_ioi = isi.input(coff);5005 const other_ioi = isi.input(coff);
5008 err.addNote("first seen in input '{f}{f}'", .{5006 err.addNote("first seen in input '{f}{f}'", .{
...@@ -5474,12 +5472,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5474,12 +5472,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5474 try coff.nodes.ensureUnusedCapacity(gpa, 1);5472 try coff.nodes.ensureUnusedCapacity(gpa, 1);
5475 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);5473 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
5476 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{5474 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
5477 .alignment = zcu.navAlignment(nav_index).toStdMem(),5475 .alignment = .fromIp(zcu.navAlignment(nav_index)),
5478 .moved = true,5476 .moved = true,
5479 });5477 });
5480 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });5478 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
5481 const sym = si.get(coff);5479 const sym = si.get(coff);
5482 sym.ni = ni;5480 sym.ni = .wrap(ni);
5483 sym.section_number = sec_si.get(coff).section_number;5481 sym.section_number = sec_si.get(coff).section_number;
5484 },5482 },
5485 else => si.deleteLocationRelocs(coff),5483 else => si.deleteLocationRelocs(coff),
...@@ -5490,7 +5488,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5490,7 +5488,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5490 if (!isImage(coff) and sym.target_relocs != .none)5488 if (!isImage(coff) and sym.target_relocs != .none)
5491 try coff.pendingSymbolTableEntry(si);5489 try coff.pendingSymbolTableEntry(si);
54925490
5493 break :ni sym.ni;5491 break :ni sym.ni.unwrap().?;
5494 };5492 };
54955493
5496 {5494 {
...@@ -5515,7 +5513,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5515,7 +5513,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5515 try ni.resize(&coff.mf, gpa, si.get(coff).extra.size);5513 try ni.resize(&coff.mf, gpa, si.get(coff).extra.size);
5516 var parent_ni = ni;5514 var parent_ni = ni;
5517 while (true) {5515 while (true) {
5518 parent_ni = parent_ni.parent(&coff.mf);5516 parent_ni = parent_ni.parent(&coff.mf).unwrap().?;
5519 switch (coff.getNode(parent_ni)) {5517 switch (coff.getNode(parent_ni)) {
5520 else => unreachable,5518 else => unreachable,
5521 .image_section, .pseudo_section => break,5519 .image_section, .pseudo_section => break,
...@@ -5542,10 +5540,11 @@ pub fn lowerUav(...@@ -5542,10 +5540,11 @@ pub fn lowerUav(
5542 try coff.pending_uavs.ensureUnusedCapacity(gpa, 1);5540 try coff.pending_uavs.ensureUnusedCapacity(gpa, 1);
5543 const umi = try coff.uavMapIndex(uav_val);5541 const umi = try coff.uavMapIndex(uav_val);
5544 const si = umi.symbol(coff);5542 const si = umi.symbol(coff);
5545 if (switch (si.get(coff).ni) {5543 const need_update: bool = update: {
5546 .none => true,5544 const existing_ni = si.get(coff).ni.unwrap() orelse break :update true;
5547 else => |ni| uav_align.toStdMem().order(ni.alignment(&coff.mf)).compare(.gt),5545 break :update Alignment.compare(.fromIp(uav_align), .gt, existing_ni.alignment(&coff.mf));
5548 }) {5546 };
5547 if (need_update) {
5549 const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi);5548 const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi);
5550 if (gop.found_existing) {5549 if (gop.found_existing) {
5551 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);5550 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
...@@ -5603,16 +5602,16 @@ fn updateFuncInner(...@@ -5603,16 +5602,16 @@ fn updateFuncInner(
5603 .debug,5602 .debug,
5604 .safe,5603 .safe,
5605 .fast,5604 .fast,
5606 => target_util.defaultFunctionAlignment(target),5605 => .fromIp(target_util.defaultFunctionAlignment(target)),
5607 .small => target_util.minFunctionAlignment(target),5606 .small => .fromIp(target_util.minFunctionAlignment(target)),
5608 },5607 },
5609 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),5608 else => |a| .fromIp(a.maxStrict(target_util.minFunctionAlignment(target))),
5610 }.toStdMem(),5609 },
5611 .moved = true,5610 .moved = true,
5612 });5611 });
5613 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });5612 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
5614 const sym = si.get(coff);5613 const sym = si.get(coff);
5615 sym.ni = ni;5614 sym.ni = .wrap(ni);
5616 sym.section_number = sec_si.get(coff).section_number;5615 sym.section_number = sec_si.get(coff).section_number;
5617 },5616 },
5618 else => si.deleteLocationRelocs(coff),5617 else => si.deleteLocationRelocs(coff),
...@@ -5622,7 +5621,7 @@ fn updateFuncInner(...@@ -5622,7 +5621,7 @@ fn updateFuncInner(
5622 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));5621 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
5623 if (!isImage(coff) and sym.target_relocs != .none)5622 if (!isImage(coff) and sym.target_relocs != .none)
5624 try coff.pendingSymbolTableEntry(si);5623 try coff.pendingSymbolTableEntry(si);
5625 break :ni sym.ni;5624 break :ni sym.ni.unwrap().?;
5626 };5625 };
56275626
5628 var nw: MappedFile.Node.Writer = undefined;5627 var nw: MappedFile.Node.Writer = undefined;
...@@ -5662,7 +5661,6 @@ fn flushImplib(...@@ -5662,7 +5661,6 @@ fn flushImplib(
5662 implib_file: []const u8,5661 implib_file: []const u8,
5663) !void {5662) !void {
5664 // Emitting implibs is only valid for images5663 // Emitting implibs is only valid for images
5665 assert(coff.export_table.ni != .none);
56665664
5667 const comp = coff.base.comp;5665 const comp = coff.base.comp;
5668 const gpa = comp.gpa;5666 const gpa = comp.gpa;
...@@ -5797,7 +5795,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {...@@ -5797,7 +5795,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
5797 const loc_sym = loc_si.get(coff);5795 const loc_sym = loc_si.get(coff);
57985796
5799 // TODO: Make this a helper for anything that needs to report "referenced by" notes5797 // TODO: Make this a helper for anything that needs to report "referenced by" notes
5800 switch (coff.getNode(loc_sym.ni)) {5798 switch (coff.getNode(loc_sym.ni.unwrap().?)) {
5801 .data_directories => {5799 .data_directories => {
5802 const dir: std.coff.IMAGE.DIRECTORY_ENTRY =5800 const dir: std.coff.IMAGE.DIRECTORY_ENTRY =
5803 @fromBackingInt(@intCast(reloc.offset / @sizeOf(std.coff.ImageDataDirectory)));5801 @fromBackingInt(@intCast(reloc.offset / @sizeOf(std.coff.ImageDataDirectory)));
...@@ -5808,7 +5806,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {...@@ -5808,7 +5806,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
5808 const other_ioi = isi.input(coff);5806 const other_ioi = isi.input(coff);
5809 if (loc_sym.gmi == .none) {5807 if (loc_sym.gmi == .none) {
5810 const section = isi.inputSection(coff);5808 const section = isi.inputSection(coff);
5811 const section_name = coff.getNode(loc_sym.ni.parent(&coff.mf))5809 const section_name = coff.getNode(loc_sym.ni.unwrap().?.parent(&coff.mf).unwrap().?)
5812 .object_section.name(coff).toSlice(coff);5810 .object_section.name(coff).toSlice(coff);
58135811
5814 if (section.comdat_si != .null) {5812 if (section.comdat_si != .null) {
...@@ -6055,8 +6053,8 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -6055,8 +6053,8 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
6055 const sub_prog_node = coff.idleProgNode(6053 const sub_prog_node = coff.idleProgNode(
6056 tid,6054 tid,
6057 coff.symbol_prog_node,6055 coff.symbol_prog_node,
6058 if (sym.ni != .none)6056 if (sym.ni.unwrap()) |sym_ni|
6059 coff.getNode(sym.ni)6057 coff.getNode(sym_ni)
6060 else6058 else
6061 .{ .import_thunk = sym.gmi },6059 .{ .import_thunk = sym.gmi },
6062 );6060 );
...@@ -6173,7 +6171,7 @@ fn idleProgNode(...@@ -6173,7 +6171,7 @@ fn idleProgNode(
6173 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{6171 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
6174 ioi.path(coff).fmtEscapeString(),6172 ioi.path(coff).fmtEscapeString(),
6175 fmtMemberNameString(ioi.memberName(coff)),6173 fmtMemberNameString(ioi.memberName(coff)),
6176 coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),6174 coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf).unwrap().?).object_section.name(coff).toSlice(coff),
6177 }) catch &name;6175 }) catch &name;
6178 },6176 },
6179 .import_thunk => |gmi| gmi.name(coff).toSlice(coff),6177 .import_thunk => |gmi| gmi.name(coff).toSlice(coff),
...@@ -6214,16 +6212,21 @@ fn flushUav(...@@ -6214,16 +6212,21 @@ fn flushUav(
6214 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);6212 if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1);
6215 const sym = si.get(coff);6213 const sym = si.get(coff);
6216 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{6214 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
6217 .alignment = uav_align.toStdMem(),6215 .alignment = .fromIp(uav_align),
6218 .moved = true,6216 .moved = true,
6219 });6217 });
6220 coff.nodes.appendAssumeCapacity(.{ .uav = umi });6218 coff.nodes.appendAssumeCapacity(.{ .uav = umi });
6221 sym.ni = ni;6219 sym.ni = .wrap(ni);
6222 sym.section_number = sec_si.get(coff).section_number;6220 sym.section_number = sec_si.get(coff).section_number;
6223 },6221 },
6224 else => {6222 else => {
6225 if (si.get(coff).ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte))6223 if (Alignment.compare(
6224 si.get(coff).ni.unwrap().?.alignment(&coff.mf),
6225 .gte,
6226 .fromIp(uav_align),
6227 )) {
6226 return;6228 return;
6229 }
6227 si.deleteLocationRelocs(coff);6230 si.deleteLocationRelocs(coff);
6228 },6231 },
6229 }6232 }
...@@ -6233,7 +6236,7 @@ fn flushUav(...@@ -6233,7 +6236,7 @@ fn flushUav(
6233 if (!isImage(coff) and sym.target_relocs != .none)6236 if (!isImage(coff) and sym.target_relocs != .none)
6234 try coff.pendingSymbolTableEntry(si);6237 try coff.pendingSymbolTableEntry(si);
62356238
6236 break :ni sym.ni;6239 break :ni sym.ni.unwrap().?;
6237 };6240 };
62386241
6239 var nw: MappedFile.Node.Writer = undefined;6242 var nw: MappedFile.Node.Writer = undefined;
...@@ -6497,7 +6500,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6497,7 +6500,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6497 lib_name,6500 lib_name,
6498 ImportTable.Adapter{ .coff = coff },6501 ImportTable.Adapter{ .coff = coff },
6499 );6502 );
6500 const import_hint_name_align: std.mem.Alignment = .@"2";6503 const import_hint_name_align: Alignment = .@"2";
6501 if (!gop.found_existing) {6504 if (!gop.found_existing) {
6502 errdefer _ = coff.import_table.entries.pop();6505 errdefer _ = coff.import_table.entries.pop();
6503 try coff.import_table.ni.resize(6506 try coff.import_table.ni.resize(
...@@ -6507,7 +6510,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6507,7 +6510,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6507 );6510 );
6508 const import_hint_name_table_len =6511 const import_hint_name_table_len =
6509 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);6512 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);
6510 const idata_section_ni = coff.import_table.ni.parent(&coff.mf);6513 const idata_section_ni = coff.import_table.ni.parent(&coff.mf).unwrap().?;
6511 const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{6514 const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{
6512 .size = addr_info.size * 2,6515 .size = addr_info.size * 2,
6513 .alignment = addr_info.alignment,6516 .alignment = addr_info.alignment,
...@@ -6521,7 +6524,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6521,7 +6524,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6521 const import_address_table_si = coff.addSymbolAssumeCapacity();6524 const import_address_table_si = coff.addSymbolAssumeCapacity();
6522 {6525 {
6523 const import_address_table_sym = import_address_table_si.get(coff);6526 const import_address_table_sym = import_address_table_si.get(coff);
6524 import_address_table_sym.ni = import_address_table_ni;6527 import_address_table_sym.ni = .wrap(import_address_table_ni);
6525 assert(import_address_table_sym.loc_relocs == .none);6528 assert(import_address_table_sym.loc_relocs == .none);
6526 import_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));6529 import_address_table_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
6527 import_address_table_sym.section_number =6530 import_address_table_sym.section_number =
...@@ -6648,13 +6651,13 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6648,13 +6651,13 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6648 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));6651 sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
66496652
6650 const target = &comp.root_mod.resolved_target.result;6653 const target = &comp.root_mod.resolved_target.result;
6651 const alignment = switch (comp.root_mod.optimize_mode) {6654 const alignment: Alignment = switch (comp.root_mod.optimize_mode) {
6652 .debug,6655 .debug,
6653 .safe,6656 .safe,
6654 .fast,6657 .fast,
6655 => target_util.defaultFunctionAlignment(target),6658 => .fromIp(target_util.defaultFunctionAlignment(target)),
6656 .small => target_util.minFunctionAlignment(target),6659 .small => .fromIp(target_util.minFunctionAlignment(target)),
6657 }.toStdMem();6660 };
6658 const parent_si = (try coff.pseudoSectionMapIndex(6661 const parent_si = (try coff.pseudoSectionMapIndex(
6659 .@".thunks",6662 .@".thunks",
6660 alignment,6663 alignment,
...@@ -6668,12 +6671,12 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6668,12 +6671,12 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6668 else => |tag| @panic(@tagName(tag)),6671 else => |tag| @panic(@tagName(tag)),
6669 .AMD64 => {6672 .AMD64 => {
6670 const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 };6673 const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 };
6671 const ni = try coff.mf.addLastChildNode(gpa, parent_sym.ni, .{6674 const ni = try coff.mf.addLastChildNode(gpa, parent_sym.ni.unwrap().?, .{
6672 .alignment = alignment,6675 .alignment = alignment,
6673 .size = init.len,6676 .size = init.len,
6674 });6677 });
6675 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);6678 @memcpy(ni.slice(&coff.mf)[0..init.len], &init);
6676 sym.ni = ni;6679 sym.ni = .wrap(ni);
6677 sym.extra.size = init.len;6680 sym.extra.size = init.len;
6678 try coff.addReloc(6681 try coff.addReloc(
6679 si,6682 si,
...@@ -6736,7 +6739,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {...@@ -6736,7 +6739,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
6736 try coff.symbols.ensureUnusedCapacity(gpa, 1);6739 try coff.symbols.ensureUnusedCapacity(gpa, 1);
6737 const optional_hdr_si = coff.addSymbolAssumeCapacity();6740 const optional_hdr_si = coff.addSymbolAssumeCapacity();
6738 const optional_hdr_sym = optional_hdr_si.get(coff);6741 const optional_hdr_sym = optional_hdr_si.get(coff);
6739 optional_hdr_sym.ni = Node.known.optional_header;6742 optional_hdr_sym.ni = .wrap(Node.known.optional_header);
6740 assert(optional_hdr_sym.loc_relocs == .none);6743 assert(optional_hdr_sym.loc_relocs == .none);
6741 optional_hdr_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));6744 optional_hdr_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
67426745
...@@ -6783,7 +6786,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {...@@ -6783,7 +6786,7 @@ fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol {
6783 try coff.symbols.ensureUnusedCapacity(gpa, 1);6786 try coff.symbols.ensureUnusedCapacity(gpa, 1);
6784 const data_dir_si = coff.addSymbolAssumeCapacity();6787 const data_dir_si = coff.addSymbolAssumeCapacity();
6785 const data_dir_sym = data_dir_si.get(coff);6788 const data_dir_sym = data_dir_si.get(coff);
6786 data_dir_sym.ni = Node.known.data_directories;6789 data_dir_sym.ni = .wrap(Node.known.data_directories);
6787 assert(data_dir_sym.loc_relocs == .none);6790 assert(data_dir_sym.loc_relocs == .none);
6788 data_dir_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));6791 data_dir_sym.loc_relocs = @fromBackingInt(@intCast(coff.relocs.items.len));
67896792
...@@ -6826,7 +6829,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6826,7 +6829,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6826 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },6829 .code => .{ .lazy_code = @fromBackingInt(@intCast(lmr.index)) },
6827 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },6830 .const_data => .{ .lazy_const_data = @fromBackingInt(@intCast(lmr.index)) },
6828 });6831 });
6829 sym.ni = ni;6832 sym.ni = .wrap(ni);
6830 sym.section_number = sec_si.get(coff).section_number;6833 sym.section_number = sec_si.get(coff).section_number;
6831 },6834 },
6832 else => si.deleteLocationRelocs(coff),6835 else => si.deleteLocationRelocs(coff),
...@@ -6836,7 +6839,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6836,7 +6839,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6836 if (!isImage(coff) and sym.target_relocs != .none)6839 if (!isImage(coff) and sym.target_relocs != .none)
6837 try coff.pendingSymbolTableEntry(si);6840 try coff.pendingSymbolTableEntry(si);
68386841
6839 break :ni sym.ni;6842 break :ni sym.ni.unwrap().?;
6840 };6843 };
68416844
6842 var required_alignment: InternPool.Alignment = .none;6845 var required_alignment: InternPool.Alignment = .none;
...@@ -6914,7 +6917,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6914,7 +6917,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6914 const flags = coff.targetLoad(&sym.section_number.header(coff).flags);6917 const flags = coff.targetLoad(&sym.section_number.header(coff).flags);
6915 if (!flags.CNT_UNINITIALIZED_DATA) {6918 if (!flags.CNT_UNINITIALIZED_DATA) {
6916 const file_offset = if (isArchive(coff))6919 const file_offset = if (isArchive(coff))
6917 sym.ni.location(&coff.mf).resolve(&coff.mf)[0]6920 sym.ni.unwrap().?.location(&coff.mf).resolve(&coff.mf)[0]
6918 else6921 else
6919 ni.fileLocation(&coff.mf, false).offset;6922 ni.fileLocation(&coff.mf, false).offset;
69206923
...@@ -6927,7 +6930,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6927,7 +6930,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6927 .input_section => |isi| {6930 .input_section => |isi| {
6928 try isi.symbol(coff).flushMoved(coff);6931 try isi.symbol(coff).flushMoved(coff);
6929 for (coff.input_symbols.items[@backingInt(isi.firstSymbol(coff))..]) |input_symbol| {6932 for (coff.input_symbols.items[@backingInt(isi.firstSymbol(coff))..]) |input_symbol| {
6930 if (input_symbol.si.get(coff).ni != ni) break;6933 if (input_symbol.si.get(coff).ni != ni.toOptional()) break;
6931 try input_symbol.si.flushMoved(coff);6934 try input_symbol.si.flushMoved(coff);
6932 }6935 }
6933 },6936 },
...@@ -7062,7 +7065,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -7062,7 +7065,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
7062 if (coff.isArchive() and coff.members.items.len > 0) {7065 if (coff.isArchive() and coff.members.items.len > 0) {
7063 const last_member = coff.members.items[coff.members.items.len - 1];7066 const last_member = coff.members.items[coff.members.items.len - 1];
7064 // See .archive_member branch for reasoning7067 // See .archive_member branch for reasoning
7065 assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni);7068 assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni.toOptional());
7066 try coff.flushResized(last_member.content_ni);7069 try coff.flushResized(last_member.content_ni);
7067 }7070 }
7068 },7071 },
...@@ -7090,19 +7093,15 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -7090,19 +7093,15 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
7090 => unreachable,7093 => unreachable,
7091 .archive_member => |mi| {7094 .archive_member => |mi| {
7092 const content_ni = mi.get(coff).content_ni;7095 const content_ni = mi.get(coff).content_ni;
7093 const next_ni = content_ni.next(&coff.mf);
7094 const content_offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf);7096 const content_offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf);
7095 const next_offset = switch (next_ni) {7097 const next_offset = if (content_ni.next(&coff.mf).unwrap()) |next_ni| offset: {
7096 .none => offset: {7098 assert(coff.getNode(next_ni) == .archive_member_header);
7097 assert(content_ni.parent(&coff.mf) == Node.known.file);7099 break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0];
7098 // This must take into account the final file size. If there are trailing7100 } else offset: {
7099 // bytes, they will be expected to contain another valid member header7101 assert(content_ni.parent(&coff.mf) == Node.known.file.toOptional());
7100 break :offset coff.mf.memory_map.memory.len;7102 // This must take into account the final file size. If there are trailing
7101 },7103 // bytes, they will be expected to contain another valid member header
7102 else => offset: {7104 break :offset coff.mf.memory_map.memory.len;
7103 assert(coff.getNode(next_ni) == .archive_member_header);
7104 break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0];
7105 },
7106 };7105 };
71077106
7108 // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size7107 // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size
...@@ -7356,7 +7355,7 @@ fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {...@@ -7356,7 +7355,7 @@ fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
7356 const section_sym = section.si.get(coff);7355 const section_sym = section.si.get(coff);
7357 section_sym.rva = rva;7356 section_sym.rva = rva;
7358 coff.targetStore(&header.virtual_address, rva);7357 coff.targetStore(&header.virtual_address, rva);
7359 try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf);7358 try section_sym.ni.unwrap().?.childrenMoved(coff.base.comp.gpa, &coff.mf);
7360 rva += coff.targetLoad(&header.virtual_size);7359 rva += coff.targetLoad(&header.virtual_size);
7361 }7360 }
7362 switch (coff.optionalHeaderPtr()) {7361 switch (coff.optionalHeaderPtr()) {
...@@ -7430,7 +7429,7 @@ fn updateExportInner(...@@ -7430,7 +7429,7 @@ fn updateExportInner(
7430 // TODO: add an errMsg if this conflicts with an existing symbol7429 // TODO: add an errMsg if this conflicts with an existing symbol
7431 const export_si = try coff.globalSymbol(.{ .name = name });7430 const export_si = try coff.globalSymbol(.{ .name = name });
7432 const export_sym = export_si.get(coff);7431 const export_sym = export_si.get(coff);
7433 export_sym.ni = exported_ni;7432 export_sym.ni = .wrap(exported_ni);
7434 export_sym.rva = exported_sym.rva;7433 export_sym.rva = exported_sym.rva;
7435 export_sym.section_number = exported_sym.section_number;7434 export_sym.section_number = exported_sym.section_number;
7436 if (@"export".opts.linkage == .weak and !coff.isImage()) {7435 if (@"export".opts.linkage == .weak and !coff.isImage()) {
...@@ -7599,14 +7598,13 @@ fn printSymbol(...@@ -7599,14 +7598,13 @@ fn printSymbol(
7599 si: Symbol.Index,7598 si: Symbol.Index,
7600) !void {7599) !void {
7601 const sym = si.get(coff);7600 const sym = si.get(coff);
7602 const node = coff.getNode(sym.ni);7601 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{s: <26} | {x:08} ", .{
7603 try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{
7604 si,7602 si,
7605 sym.section_number,7603 sym.section_number,
7606 if (sym.flags.extra_tag == .size)7604 if (sym.flags.extra_tag == .size)
7607 @as(u64, sym.extra.size)7605 @as(u64, sym.extra.size)
7608 else if (sym.ni != .none)7606 else if (sym.ni.unwrap()) |ni|
7609 sym.ni.location(&coff.mf).resolve(&coff.mf)[1]7607 ni.location(&coff.mf).resolve(&coff.mf)[1]
7610 else7608 else
7611 0,7609 0,
7612 switch (sym.flags.value_tag) {7610 switch (sym.flags.value_tag) {
...@@ -7627,7 +7625,7 @@ fn printSymbol(...@@ -7627,7 +7625,7 @@ fn printSymbol(
7627 },7625 },
7628 sym.ni,7626 sym.ni,
7629 if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0,7627 if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0,
7630 node,7628 if (sym.ni.unwrap()) |ni| @tagName(coff.getNode(ni)) else "",
7631 sym.rva,7629 sym.rva,
7632 });7630 });
76337631
...@@ -7635,7 +7633,7 @@ fn printSymbol(...@@ -7635,7 +7633,7 @@ fn printSymbol(
7635 try w.print("G {f}\n", .{fmtGlobalName(coff, sym.gmi)});7633 try w.print("G {f}\n", .{fmtGlobalName(coff, sym.gmi)});
7636 } else {7634 } else {
7637 try w.writeAll("| ");7635 try w.writeAll("| ");
7638 try coff.printNodeName(w, tid, node);7636 try coff.printNodeName(w, tid, coff.getNode(sym.ni.unwrap().?));
7639 if (sym.flags.extra_tag == .isli)7637 if (sym.flags.extra_tag == .isli)
7640 try w.print(" | {s}", .{sym.extra.isli.name(coff).toSlice(coff)});7638 try w.print(" | {s}", .{sym.extra.isli.name(coff).toSlice(coff)});
7641 try w.writeByte('\n');7639 try w.writeByte('\n');
...@@ -7672,7 +7670,7 @@ fn printNodeName(...@@ -7672,7 +7670,7 @@ fn printNodeName(
7672 try w.print("({f}{f}, {s}", .{7670 try w.print("({f}{f}, {s}", .{
7673 ioi.path(coff).fmtEscapeString(),7671 ioi.path(coff).fmtEscapeString(),
7674 fmtMemberNameString(ioi.memberName(coff)),7672 fmtMemberNameString(ioi.memberName(coff)),
7675 coff.getNode(is.si.node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff),7673 coff.getNode(is.si.node(coff).parent(&coff.mf).unwrap().?).object_section.name(coff).toSlice(coff),
7676 });7674 });
7677 if (is.comdat_si != .null) {7675 if (is.comdat_si != .null) {
7678 const comdat_sym = is.comdat_si.get(coff);7676 const comdat_sym = is.comdat_si.get(coff);
src/link/Elf2.zig+182-187
...@@ -18,14 +18,16 @@ const tracy = @import("../tracy.zig");...@@ -18,14 +18,16 @@ const tracy = @import("../tracy.zig");
18const Type = @import("../Type.zig");18const Type = @import("../Type.zig");
19const Value = @import("../Value.zig");19const Value = @import("../Value.zig");
20const Zcu = @import("../Zcu.zig");20const Zcu = @import("../Zcu.zig");
21const Alignment = MappedFile.Alignment;
2122
22base: link.File,23base: link.File,
23options: link.File.OpenOptions,24options: link.File.OpenOptions,
24mf: MappedFile,25mf: MappedFile,
25ni: Node.Known,26ni: Node.Known,
26nodes: std.MultiArrayList(Node),27nodes: std.MultiArrayList(Node),
28/// Does not contain an item for `SHN_UNDEF`.
27shdrs: std.ArrayList(Section),29shdrs: std.ArrayList(Section),
28phdrs: std.ArrayList(MappedFile.Node.Index),30phdrs: std.ArrayList(MappedFile.Node.Index.Optional),
29shndx: struct {31shndx: struct {
30 got: Section.Index,32 got: Section.Index,
31 /// Always `.UNDEF` on some targets (e.g. SPARC).33 /// Always `.UNDEF` on some targets (e.g. SPARC).
...@@ -99,7 +101,7 @@ dso_globals: std.array_hash_map.Auto(String(.strtab), struct {...@@ -99,7 +101,7 @@ dso_globals: std.array_hash_map.Auto(String(.strtab), struct {
99 /// the section containing the symbol, and the symbol's offset within the section. I know this101 /// the section containing the symbol, and the symbol's offset within the section. I know this
100 /// sounds like a terrible hack, but it is *genuinely* how you're supposed to do this. Copy102 /// sounds like a terrible hack, but it is *genuinely* how you're supposed to do this. Copy
101 /// relocations suck.103 /// relocations suck.
102 alignment: std.mem.Alignment,104 alignment: Alignment,
103}),105}),
104shstrtab: StringTable,106shstrtab: StringTable,
105strtab: StringTable,107strtab: StringTable,
...@@ -175,7 +177,7 @@ symbol_relocs: std.ArrayList(SymbolReloc),...@@ -175,7 +177,7 @@ symbol_relocs: std.ArrayList(SymbolReloc),
175got_relocs: std.ArrayList(GotReloc),177got_relocs: std.ArrayList(GotReloc),
176/// Set of relocations which must be re-applied if the size of the TLS segment changes.178/// Set of relocations which must be re-applied if the size of the TLS segment changes.
177tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),179tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
178/// Index matches the index into `shdrs`.180/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.
179section_by_name: std.array_hash_map.Auto(String(.shstrtab), void),181section_by_name: std.array_hash_map.Auto(String(.shstrtab), void),
180/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation182/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation
181/// entries which target that symbol must be updated to reference the correct symbol index.183/// entries which target that symbol must be updated to reference the correct symbol index.
...@@ -339,8 +341,6 @@ const Node = union(enum) {...@@ -339,8 +341,6 @@ const Node = union(enum) {
339 };341 };
340342
341 pub const Known = struct {343 pub const Known = struct {
342 archive: MappedFile.Node.Index,
343 archive_header: MappedFile.Node.Index,
344 elf: MappedFile.Node.Index,344 elf: MappedFile.Node.Index,
345 ehdr: MappedFile.Node.Index,345 ehdr: MappedFile.Node.Index,
346 shdr: MappedFile.Node.Index,346 shdr: MappedFile.Node.Index,
...@@ -349,7 +349,7 @@ const Node = union(enum) {...@@ -349,7 +349,7 @@ const Node = union(enum) {
349 text: MappedFile.Node.Index,349 text: MappedFile.Node.Index,
350 data: MappedFile.Node.Index,350 data: MappedFile.Node.Index,
351 data_rel_ro: MappedFile.Node.Index,351 data_rel_ro: MappedFile.Node.Index,
352 tls: MappedFile.Node.Index,352 tls: MappedFile.Node.Index.Optional,
353 };353 };
354354
355 comptime {355 comptime {
...@@ -505,7 +505,7 @@ const Section = struct {...@@ -505,7 +505,7 @@ const Section = struct {
505 }505 }
506506
507 fn get(s: Index, elf: *Elf) *Section {507 fn get(s: Index, elf: *Elf) *Section {
508 return &elf.shdrs.items[@backingInt(s)];508 return &elf.shdrs.items[@backingInt(s) - 1]; // overflow means you tried to get the `.UNDEF` section
509 }509 }
510510
511 fn name(s: Index, elf: *Elf) String(.shstrtab) {511 fn name(s: Index, elf: *Elf) String(.shstrtab) {
...@@ -539,7 +539,7 @@ const Section = struct {...@@ -539,7 +539,7 @@ const Section = struct {
539 }539 }
540 }540 }
541541
542 fn ensureAligned(shndx: Index, elf: *Elf, min_align: std.mem.Alignment) Error!void {542 fn ensureAligned(shndx: Index, elf: *Elf, min_align: Alignment) Error!void {
543 switch (elf.shdrPtr(shndx)) {543 switch (elf.shdrPtr(shndx)) {
544 inline else => |shdr| {544 inline else => |shdr| {
545 if (elf.targetLoad(&shdr.addralign) >= min_align.toByteUnits()) {545 if (elf.targetLoad(&shdr.addralign) >= min_align.toByteUnits()) {
...@@ -552,7 +552,7 @@ const Section = struct {...@@ -552,7 +552,7 @@ const Section = struct {
552 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {552 if (min_align.compare(.gt, ni.alignment(&elf.mf))) {
553 try ni.realign(&elf.mf, elf.base.comp.gpa, min_align, .{});553 try ni.realign(&elf.mf, elf.base.comp.gpa, min_align, .{});
554 }554 }
555 switch (elf.getNode(ni.parent(&elf.mf))) {555 switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
556 .elf => {},556 .elf => {},
557 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),557 .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align),
558 else => unreachable,558 else => unreachable,
...@@ -818,7 +818,7 @@ const GotReloc = struct {...@@ -818,7 +818,7 @@ const GotReloc = struct {
818 /// * A section818 /// * A section
819 /// * A NAV, UAV, or lazy code/data819 /// * A NAV, UAV, or lazy code/data
820 /// * `.none`, if this relocation was deleted (in which case it should be ignored)820 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
821 node: MappedFile.Node.Index,821 node: MappedFile.Node.Index.Optional,
822 /// The offset of the relocation inside of `node`.822 /// The offset of the relocation inside of `node`.
823 offset: u64,823 offset: u64,
824 target: GotKey,824 target: GotKey,
...@@ -942,8 +942,10 @@ const GotReloc = struct {...@@ -942,8 +942,10 @@ const GotReloc = struct {
942942
943 fn apply(reloc: *GotReloc, elf: *Elf) void {943 fn apply(reloc: *GotReloc, elf: *Elf) void {
944 assert(elf.ehdrType() != .REL);944 assert(elf.ehdrType() != .REL);
945 if (reloc.node == .none) return; // deleted945 const node = reloc.node.unwrap() orelse {
946 if (reloc.node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {946 return; // deleted
947 };
948 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
947 // There's no point applying the relocation now, because it will be re-applied by949 // There's no point applying the relocation now, because it will be re-applied by
948 // `flushMoved` at some point anyway.950 // `flushMoved` at some point anyway.
949 return;951 return;
...@@ -968,8 +970,9 @@ const GotReloc = struct {...@@ -968,8 +970,9 @@ const GotReloc = struct {
968 }970 }
969 }971 }
970 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {972 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
971 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;973 const node = reloc.node.unwrap().?;
972 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];974 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
975 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
973976
974 const got_vaddr = elf.shndx.got.vaddr(elf);977 const got_vaddr = elf.shndx.got.vaddr(elf);
975 const got_index: u64 = elf.got.getIndex(reloc.target).?;978 const got_index: u64 = elf.got.getIndex(reloc.target).?;
...@@ -1587,7 +1590,7 @@ const SymbolReloc = struct {...@@ -1587,7 +1590,7 @@ const SymbolReloc = struct {
1587 }1590 }
1588 },1591 },
1589 .sparc_le_hix22 => {1592 .sparc_le_hix22 => {
1590 const tls_phndx = elf.getNode(elf.ni.tls).segment;1593 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1591 const tls_size: u64 = switch (elf.phdrSlice()) {1594 const tls_size: u64 = switch (elf.phdrSlice()) {
1592 inline else => |phdr| tls_size: {1595 inline else => |phdr| tls_size: {
1593 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);1596 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
...@@ -1646,7 +1649,6 @@ const SymbolReloc = struct {...@@ -1646,7 +1649,6 @@ const SymbolReloc = struct {
16461649
1647 fn apply(reloc: *SymbolReloc, elf: *Elf) void {1650 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
1648 assert(elf.ehdrType() != .REL);1651 assert(elf.ehdrType() != .REL);
1649 assert(reloc.node != .none);
1650 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {1652 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
1651 // There's no point applying the relocation now, because it will be re-applied by1653 // There's no point applying the relocation now, because it will be re-applied by
1652 // `flushMoved` at some point anyway.1654 // `flushMoved` at some point anyway.
...@@ -1692,7 +1694,7 @@ const SymbolReloc = struct {...@@ -1692,7 +1694,7 @@ const SymbolReloc = struct {
1692 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,1694 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
1693 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,1695 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
1694 .II => {1696 .II => {
1695 const tls_phndx = elf.getNode(elf.ni.tls).segment;1697 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1696 const tls_size: u64 = switch (elf.phdrSlice()) {1698 const tls_size: u64 = switch (elf.phdrSlice()) {
1697 inline else => |phdr| tls_size: {1699 inline else => |phdr| tls_size: {
1698 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);1700 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
...@@ -2044,7 +2046,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {...@@ -2044,7 +2046,7 @@ fn pltEntryIsDead(elf: *Elf, plt_index: usize) bool {
2044}2046}
20452047
2046const AddLocalSymbolOptions = struct {2048const AddLocalSymbolOptions = struct {
2047 node: MappedFile.Node.Index,2049 node: MappedFile.Node.Index.Optional,
2048 name: String(.strtab),2050 name: String(.strtab),
2049 value: u64,2051 value: u64,
2050 size: u64,2052 size: u64,
...@@ -2126,7 +2128,7 @@ const AddGlobalSymbolOptions = struct {...@@ -2126,7 +2128,7 @@ const AddGlobalSymbolOptions = struct {
2126 }2128 }
2127 };2129 };
21282130
2129 node: MappedFile.Node.Index,2131 node: MappedFile.Node.Index.Optional,
2130 name: Name,2132 name: Name,
2131 lib_name: ?[]const u8 = null,2133 lib_name: ?[]const u8 = null,
2132 value: u64,2134 value: u64,
...@@ -2294,8 +2296,8 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{...@@ -2294,8 +2296,8 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
2294 }2296 }
22952297
2296 const old_head: String(.strtab) = old_head: {2298 const old_head: String(.strtab) = old_head: {
2297 if (opts.node == .none) break :old_head .empty;2299 const node = opts.node.unwrap() orelse break :old_head .empty;
2298 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(opts.node);2300 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(node);
2299 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;2301 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
2300 gop.value_ptr.* = opts.name.strtab;2302 gop.value_ptr.* = opts.name.strtab;
2301 break :old_head old_head;2303 break :old_head old_head;
...@@ -2363,7 +2365,7 @@ fn setGlobalSymbolValue(...@@ -2363,7 +2365,7 @@ fn setGlobalSymbolValue(
2363 global_name: String(.strtab),2365 global_name: String(.strtab),
2364 global_ptr: *Symbol.Global,2366 global_ptr: *Symbol.Global,
2365 new: struct {2367 new: struct {
2366 node: MappedFile.Node.Index,2368 node: MappedFile.Node.Index.Optional,
2367 value: u64,2369 value: u64,
2368 size: u64,2370 size: u64,
2369 type: std.elf.STT,2371 type: std.elf.STT,
...@@ -2371,18 +2373,17 @@ fn setGlobalSymbolValue(...@@ -2371,18 +2373,17 @@ fn setGlobalSymbolValue(
2371 },2373 },
2372) void {2374) void {
2373 assert(new.shndx != .UNDEF);2375 assert(new.shndx != .UNDEF);
2374 const old_node = global_ptr.symtab_index.ptr(elf).node;2376 if (global_ptr.symtab_index.ptr(elf).node.unwrap()) |old_node| {
2375 if (old_node != .none) {
2376 if (global_ptr.next_in_node != .empty) {2377 if (global_ptr.next_in_node != .empty) {
2377 const next = elf.globalByName(global_ptr.next_in_node).?;2378 const next = elf.globalByName(global_ptr.next_in_node).?;
2378 assert(next.prev_in_node == global_name);2379 assert(next.prev_in_node == global_name);
2379 assert(next.symtab_index.ptr(elf).node == old_node);2380 assert(next.symtab_index.ptr(elf).node.unwrap().? == old_node);
2380 next.prev_in_node = global_ptr.prev_in_node;2381 next.prev_in_node = global_ptr.prev_in_node;
2381 }2382 }
2382 if (global_ptr.prev_in_node != .empty) {2383 if (global_ptr.prev_in_node != .empty) {
2383 const prev = elf.globalByName(global_ptr.prev_in_node).?;2384 const prev = elf.globalByName(global_ptr.prev_in_node).?;
2384 assert(prev.next_in_node == global_name);2385 assert(prev.next_in_node == global_name);
2385 assert(prev.symtab_index.ptr(elf).node == old_node);2386 assert(prev.symtab_index.ptr(elf).node.unwrap().? == old_node);
2386 prev.next_in_node = global_ptr.next_in_node;2387 prev.next_in_node = global_ptr.next_in_node;
2387 } else {2388 } else {
2388 // We're the start of the linked list, so we need to change the head.2389 // We're the start of the linked list, so we need to change the head.
...@@ -2417,8 +2418,8 @@ fn setGlobalSymbolValue(...@@ -2417,8 +2418,8 @@ fn setGlobalSymbolValue(
2417 global_ptr.symtab_index.ptr(elf).node = new.node;2418 global_ptr.symtab_index.ptr(elf).node = new.node;
24182419
2419 const old_head: String(.strtab) = old_head: {2420 const old_head: String(.strtab) = old_head: {
2420 if (new.node == .none) break :old_head .empty;2421 const new_node = new.node.unwrap() orelse break :old_head .empty;
2421 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new.node);2422 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new_node);
2422 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;2423 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
2423 gop.value_ptr.* = global_name;2424 gop.value_ptr.* = global_name;
2424 break :old_head old_head;2425 break :old_head old_head;
...@@ -2644,7 +2645,7 @@ const Symbol = struct {...@@ -2644,7 +2645,7 @@ const Symbol = struct {
2644 /// * A section (the symbol's value is some vaddr in that section)2645 /// * A section (the symbol's value is some vaddr in that section)
2645 /// * An input section (the symbol's value is some vaddr in that input section)2646 /// * An input section (the symbol's value is some vaddr in that input section)
2646 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)2647 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)
2647 node: MappedFile.Node.Index,2648 node: MappedFile.Node.Index.Optional,
26482649
2649 /// The head of a linked list of relocations targeting this symbol.2650 /// The head of a linked list of relocations targeting this symbol.
2650 first_target_reloc: SymbolReloc.Index,2651 first_target_reloc: SymbolReloc.Index,
...@@ -2852,8 +2853,7 @@ const Symbol = struct {...@@ -2852,8 +2853,7 @@ const Symbol = struct {
2852 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at2853 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at
2853 /// some point due to a call to `flushMoved`.2854 /// some point due to a call to `flushMoved`.
2854 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {2855 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {
2855 const node = s.index(elf).ptr(elf).node;2856 if (s.index(elf).ptr(elf).node.unwrap()) |node| {
2856 if (node != .none) {
2857 return node.hasMoved(&elf.mf);2857 return node.hasMoved(&elf.mf);
2858 }2858 }
2859 switch (s.unwrap()) {2859 switch (s.unwrap()) {
...@@ -2998,7 +2998,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol...@@ -2998,7 +2998,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
2998 ) catch unreachable;2998 ) catch unreachable;
2999 gop.value_ptr.* = .{2999 gop.value_ptr.* = .{
3000 .lsi = elf.addLocalSymbolAssumeCapacity(.{3000 .lsi = elf.addLocalSymbolAssumeCapacity(.{
3001 .node = node,3001 .node = .wrap(node),
3002 .name = try elf.string(.strtab, name),3002 .name = try elf.string(.strtab, name),
3003 .value = 0,3003 .value = 0,
3004 .size = 0,3004 .size = 0,
...@@ -3349,16 +3349,14 @@ fn create(...@@ -3349,16 +3349,14 @@ fn create(
3349 .options = options,3349 .options = options,
3350 .mf = try .init(file, comp.gpa, io),3350 .mf = try .init(file, comp.gpa, io),
3351 .ni = .{3351 .ni = .{
3352 .archive = .root,3352 .elf = undefined,
3353 .archive_header = .none,3353 .ehdr = undefined,
3354 .elf = .root,3354 .shdr = undefined,
3355 .ehdr = .none,3355 .rodata = undefined,
3356 .shdr = .none,3356 .phdr = undefined,
3357 .rodata = .none,3357 .text = undefined,
3358 .phdr = .none,3358 .data = undefined,
3359 .text = .none,3359 .data_rel_ro = undefined,
3360 .data = .none,
3361 .data_rel_ro = .none,
3362 .tls = .none,3360 .tls = .none,
3363 },3361 },
3364 .nodes = .empty,3362 .nodes = .empty,
...@@ -3489,7 +3487,7 @@ fn initHeaders(...@@ -3489,7 +3487,7 @@ fn initHeaders(
3489 .EXEC => comp.config.link_mode == .dynamic,3487 .EXEC => comp.config.link_mode == .dynamic,
3490 .DYN => true,3488 .DYN => true,
3491 };3489 };
3492 const addr_align: std.mem.Alignment = switch (class) {3490 const addr_align: Alignment = switch (class) {
3493 .NONE, _ => unreachable,3491 .NONE, _ => unreachable,
3494 .@"32" => .@"4",3492 .@"32" => .@"4",
3495 .@"64" => .@"8",3493 .@"64" => .@"8",
...@@ -3503,7 +3501,7 @@ fn initHeaders(...@@ -3503,7 +3501,7 @@ fn initHeaders(
3503 //3501 //
3504 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it3502 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it
3505 // prevents alignment bugs from being hidden by your filesystem's block alignment.3503 // prevents alignment bugs from being hidden by your filesystem's block alignment.
3506 const node_block_align: std.mem.Alignment = elf.mf.flags.block_size;3504 const node_block_align: Alignment = elf.mf.flags.block_size;
35073505
3508 const plt: PltInfo = .fromMachine(machine);3506 const plt: PltInfo = .fromMachine(machine);
35093507
...@@ -3601,18 +3599,19 @@ fn initHeaders(...@@ -3601,18 +3599,19 @@ fn initHeaders(
36013599
3602 const expected_nodes_len = @as(usize, if (is_archive) 2 else 0) + // .archive, .archive_header3600 const expected_nodes_len = @as(usize, if (is_archive) 2 else 0) + // .archive, .archive_header
3603 3 + // `.file`, `.ehdr`, and `.shdr` nodes3601 3 + // `.file`, `.ehdr`, and `.shdr` nodes
3604 (shnum - 1) + // -1 because the null shdr does not have a `.section` node3602 (shnum - 1) + // -1 because the SHN_UNDEF shdr does not have a `.section` node
3605 (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node3603 (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node
36063604
3607 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);3605 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
3608 try elf.shdrs.ensureTotalCapacity(gpa, shnum);3606 try elf.shdrs.ensureTotalCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
3609 try elf.section_by_name.ensureUnusedCapacity(gpa, shnum);3607 try elf.section_by_name.ensureUnusedCapacity(gpa, shnum - 1); // -1 to exclude SHN_UNDEF
3610 try elf.phdrs.resize(gpa, phnum);3608 try elf.phdrs.resize(gpa, phnum);
3611 try elf.symtab.ensureTotalCapacity(gpa, 1);3609 try elf.symtab.ensureTotalCapacity(gpa, 1);
36123610
3613 if (is_archive) {3611 if (is_archive) {
3614 elf.nodes.appendAssumeCapacity(.archive);3612 elf.nodes.appendAssumeCapacity(.archive);
3615 elf.ni.archive_header = try elf.mf.addOnlyChildNode(gpa, elf.ni.archive, .{3613
3614 const archive_header_ni = try elf.mf.addOnlyChildNode(gpa, .root, .{
3616 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2,3615 .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2,
3617 .alignment = .@"2",3616 .alignment = .@"2",
3618 .fixed = true,3617 .fixed = true,
...@@ -3620,7 +3619,8 @@ fn initHeaders(...@@ -3620,7 +3619,8 @@ fn initHeaders(
3620 .bubbles_moved = false,3619 .bubbles_moved = false,
3621 .enable_next_moved = true,3620 .enable_next_moved = true,
3622 });3621 });
3623 const archive_header_slice = elf.ni.archive_header.slice(&elf.mf);3622 elf.nodes.appendAssumeCapacity(.archive_header);
3623 const archive_header_slice = archive_header_ni.slice(&elf.mf);
3624 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);3624 @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG);
3625 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);3625 const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]);
3626 strtab_ar_hdr.* = .{3626 strtab_ar_hdr.* = .{
...@@ -3633,15 +3633,17 @@ fn initHeaders(...@@ -3633,15 +3633,17 @@ fn initHeaders(
3633 .ar_fmag = std.elf.ARFMAG.*,3633 .ar_fmag = std.elf.ARFMAG.*,
3634 };3634 };
36353635
3636 elf.nodes.appendAssumeCapacity(.archive_header);3636 elf.ni.elf = try elf.mf.addLastChildNode(gpa, .root, .{
3637 elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{
3638 .alignment = node_block_align.max(.@"2"),3637 .alignment = node_block_align.max(.@"2"),
3639 .next_moved = true,3638 .next_moved = true,
3640 .bubbles_moved = false,3639 .bubbles_moved = false,
3641 .enable_next_moved = true,3640 .enable_next_moved = true,
3642 });3641 });
3642 elf.nodes.appendAssumeCapacity(.elf);
3643 } else {
3644 elf.ni.elf = .root;
3645 elf.nodes.appendAssumeCapacity(.elf);
3643 }3646 }
3644 elf.nodes.appendAssumeCapacity(.elf);
36453647
3646 const entsize: struct { ph: u32, sh: u32 } = switch (class) {3648 const entsize: struct { ph: u32, sh: u32 } = switch (class) {
3647 .NONE, _ => unreachable,3649 .NONE, _ => unreachable,
...@@ -3665,7 +3667,7 @@ fn initHeaders(...@@ -3665,7 +3667,7 @@ fn initHeaders(
3665 .bubbles_moved = false,3667 .bubbles_moved = false,
3666 });3668 });
3667 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata });3669 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata });
3668 elf.phdrs.items[phndx.rodata] = elf.ni.rodata;3670 elf.phdrs.items[phndx.rodata] = .wrap(elf.ni.rodata);
36693671
3670 elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{3672 elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
3671 .size = @as(u64, phnum) * entsize.ph,3673 .size = @as(u64, phnum) * entsize.ph,
...@@ -3675,7 +3677,7 @@ fn initHeaders(...@@ -3675,7 +3677,7 @@ fn initHeaders(
3675 .bubbles_moved = false,3677 .bubbles_moved = false,
3676 });3678 });
3677 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr });3679 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr });
3678 elf.phdrs.items[phndx.phdr] = elf.ni.phdr;3680 elf.phdrs.items[phndx.phdr] = .wrap(elf.ni.phdr);
36793681
3680 elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{3682 elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
3681 .alignment = node_block_align,3683 .alignment = node_block_align,
...@@ -3683,7 +3685,7 @@ fn initHeaders(...@@ -3683,7 +3685,7 @@ fn initHeaders(
3683 .bubbles_moved = false,3685 .bubbles_moved = false,
3684 });3686 });
3685 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text });3687 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text });
3686 elf.phdrs.items[phndx.text] = elf.ni.text;3688 elf.phdrs.items[phndx.text] = .wrap(elf.ni.text);
36873689
3688 elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{3690 elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
3689 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node3691 // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node
...@@ -3692,7 +3694,7 @@ fn initHeaders(...@@ -3692,7 +3694,7 @@ fn initHeaders(
3692 .bubbles_moved = false,3694 .bubbles_moved = false,
3693 });3695 });
3694 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });3696 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });
3695 elf.phdrs.items[phndx.data] = elf.ni.data;3697 elf.phdrs.items[phndx.data] = .wrap(elf.ni.data);
36963698
3697 if (plt.got_plt == null) {3699 if (plt.got_plt == null) {
3698 const plt_ni = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{3700 const plt_ni = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
...@@ -3701,7 +3703,7 @@ fn initHeaders(...@@ -3701,7 +3703,7 @@ fn initHeaders(
3701 .bubbles_moved = false,3703 .bubbles_moved = false,
3702 });3704 });
3703 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });3705 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });
3704 elf.phdrs.items[phndx.plt] = plt_ni;3706 elf.phdrs.items[phndx.plt] = .wrap(plt_ni);
3705 }3707 }
37063708
3707 elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{3709 elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{
...@@ -3712,14 +3714,14 @@ fn initHeaders(...@@ -3712,14 +3714,14 @@ fn initHeaders(
3712 .bubbles_moved = false,3714 .bubbles_moved = false,
3713 });3715 });
3714 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro });3716 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro });
3715 elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro;3717 elf.phdrs.items[phndx.relro] = .wrap(elf.ni.data_rel_ro);
37163718
3717 if (comp.config.any_non_single_threaded) {3719 if (comp.config.any_non_single_threaded) {
3718 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{3720 elf.ni.tls = .wrap(try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
3719 .alignment = node_block_align,3721 .alignment = node_block_align,
3720 .moved = true,3722 .moved = true,
3721 .bubbles_moved = false,3723 .bubbles_moved = false,
3722 });3724 }));
3723 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls });3725 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls });
3724 elf.phdrs.items[phndx.tls] = elf.ni.tls;3726 elf.phdrs.items[phndx.tls] = elf.ni.tls;
3725 }3727 }
...@@ -3785,14 +3787,14 @@ fn initHeaders(...@@ -3785,14 +3787,14 @@ fn initHeaders(
3785 ehdr.phentsize = @sizeOf(ElfN.Phdr);3787 ehdr.phentsize = @sizeOf(ElfN.Phdr);
3786 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);3788 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
3787 ehdr.shentsize = @sizeOf(ElfN.Shdr);3789 ehdr.shentsize = @sizeOf(ElfN.Shdr);
3788 ehdr.shnum = 1; // Only the null shdr initially---will be incremented by `addSection`3790 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`
3789 ehdr.shstrndx = std.elf.SHN_UNDEF;3791 ehdr.shstrndx = std.elf.SHN_UNDEF;
3790 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);3792 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
3791 },3793 },
3792 }3794 }
37933795
3794 elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{3796 elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
3795 .size = 1 * entsize.sh, // as above, only the null shdr initially3797 .size = 1 * entsize.sh, // as above, only the SHN_UNDEF initially
3796 .alignment = addr_align.max(node_block_align),3798 .alignment = addr_align.max(node_block_align),
3797 .moved = true,3799 .moved = true,
3798 .resized = true,3800 .resized = true,
...@@ -3916,7 +3918,7 @@ fn initHeaders(...@@ -3916,7 +3918,7 @@ fn initHeaders(
3916 };3918 };
3917 }3919 }
39183920
3919 if (comp.config.any_non_single_threaded) {3921 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
3920 const ph_tls = &phdr[phndx.tls];3922 const ph_tls = &phdr[phndx.tls];
3921 ph_tls.* = .{3923 ph_tls.* = .{
3922 .type = .TLS,3924 .type = .TLS,
...@@ -3926,7 +3928,7 @@ fn initHeaders(...@@ -3926,7 +3928,7 @@ fn initHeaders(
3926 .filesz = 0,3928 .filesz = 0,
3927 .memsz = 0,3929 .memsz = 0,
3928 .flags = .{ .R = true },3930 .flags = .{ .R = true },
3929 .@"align" = @intCast(elf.ni.tls.alignment(&elf.mf).toByteUnits()),3931 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
3930 };3932 };
3931 }3933 }
39323934
...@@ -3987,7 +3989,6 @@ fn initHeaders(...@@ -3987,7 +3989,6 @@ fn initHeaders(
3987 .entsize = 0,3989 .entsize = 0,
3988 };3990 };
3989 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);3991 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
3990 elf.shdrs.appendAssumeCapacity(.{ .lsi = .null, .ni = .none, .rela = .{ .shndx = .UNDEF } });
39913992
3992 elf.symtab.addOneAssumeCapacity().* = .{3993 elf.symtab.addOneAssumeCapacity().* = .{
3993 .node = .none,3994 .node = .none,
...@@ -4092,7 +4093,7 @@ fn initHeaders(...@@ -4092,7 +4093,7 @@ fn initHeaders(
4092 .node_align = node_block_align,4093 .node_align = node_block_align,
4093 });4094 });
4094 } else {4095 } else {
4095 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt], .{4096 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{
4096 .name = ".plt",4097 .name = ".plt",
4097 .type = .PROGBITS,4098 .type = .PROGBITS,
4098 .flags = .{ .ALLOC = true, .WRITE = true, .EXECINSTR = true },4099 .flags = .{ .ALLOC = true, .WRITE = true, .EXECINSTR = true },
...@@ -4115,7 +4116,7 @@ fn initHeaders(...@@ -4115,7 +4116,7 @@ fn initHeaders(
4115 .bubbles_moved = false,4116 .bubbles_moved = false,
4116 });4117 });
4117 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp });4118 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.interp });
4118 elf.phdrs.items[phndx.interp] = interp_ni;4119 elf.phdrs.items[phndx.interp] = .wrap(interp_ni);
41194120
4120 const sec_interp_shndx = try elf.addSection(interp_ni, .{4121 const sec_interp_shndx = try elf.addSection(interp_ni, .{
4121 .name = ".interp",4122 .name = ".interp",
...@@ -4135,7 +4136,7 @@ fn initHeaders(...@@ -4135,7 +4136,7 @@ fn initHeaders(
4135 .bubbles_moved = false,4136 .bubbles_moved = false,
4136 });4137 });
4137 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic });4138 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.dynamic });
4138 elf.phdrs.items[phndx.dynamic] = dynamic_ni;4139 elf.phdrs.items[phndx.dynamic] = .wrap(dynamic_ni);
41394140
4140 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{4141 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
4141 .name = ".dynstr",4142 .name = ".dynstr",
...@@ -4347,7 +4348,7 @@ fn initHeaders(...@@ -4347,7 +4348,7 @@ fn initHeaders(
4347 try elf.ensureUnusedSymbolCapacity(10, .maybe_global);4348 try elf.ensureUnusedSymbolCapacity(10, .maybe_global);
4348 // Despite the name, `__dso_handle` is necessary even in static binaries.4349 // Despite the name, `__dso_handle` is necessary even in static binaries.
4349 _ = elf.addGlobalSymbolAssumeCapacity(.{4350 _ = elf.addGlobalSymbolAssumeCapacity(.{
4350 .node = Section.Index.text.get(elf).ni,4351 .node = .wrap(Section.Index.text.get(elf).ni),
4351 .name = try .string(elf, "__dso_handle"),4352 .name = try .string(elf, "__dso_handle"),
4352 .value = Section.Index.text.vaddr(elf),4353 .value = Section.Index.text.vaddr(elf),
4353 .size = 0,4354 .size = 0,
...@@ -4359,7 +4360,7 @@ fn initHeaders(...@@ -4359,7 +4360,7 @@ fn initHeaders(
4359 error.MultipleDefinitions => unreachable, // no inputs are processed yet4360 error.MultipleDefinitions => unreachable, // no inputs are processed yet
4360 };4361 };
4361 _ = elf.addGlobalSymbolAssumeCapacity(.{4362 _ = elf.addGlobalSymbolAssumeCapacity(.{
4362 .node = elf.shndx.plt.get(elf).ni,4363 .node = .wrap(elf.shndx.plt.get(elf).ni),
4363 .name = try .string(elf, "_PROCEDURE_LINKAGE_TABLE_"),4364 .name = try .string(elf, "_PROCEDURE_LINKAGE_TABLE_"),
4364 .value = elf.shndx.plt.vaddr(elf),4365 .value = elf.shndx.plt.vaddr(elf),
4365 .size = 0,4366 .size = 0,
...@@ -4371,7 +4372,7 @@ fn initHeaders(...@@ -4371,7 +4372,7 @@ fn initHeaders(
4371 error.MultipleDefinitions => unreachable, // no inputs are processed yet4372 error.MultipleDefinitions => unreachable, // no inputs are processed yet
4372 };4373 };
4373 _ = elf.addGlobalSymbolAssumeCapacity(.{4374 _ = elf.addGlobalSymbolAssumeCapacity(.{
4374 .node = elf.shndx.got.get(elf).ni,4375 .node = .wrap(elf.shndx.got.get(elf).ni),
4375 .name = try .string(elf, "_GLOBAL_OFFSET_TABLE_"),4376 .name = try .string(elf, "_GLOBAL_OFFSET_TABLE_"),
4376 .value = switch (machine) {4377 .value = switch (machine) {
4377 .AARCH64,4378 .AARCH64,
...@@ -4468,7 +4469,7 @@ fn initHeaders(...@@ -4468,7 +4469,7 @@ fn initHeaders(
4468 };4469 };
4469 if (have_dynamic_section) {4470 if (have_dynamic_section) {
4470 _ = elf.addGlobalSymbolAssumeCapacity(.{4471 _ = elf.addGlobalSymbolAssumeCapacity(.{
4471 .node = elf.shndx.dynamic.get(elf).ni,4472 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
4472 .name = try .string(elf, "_DYNAMIC"),4473 .name = try .string(elf, "_DYNAMIC"),
4473 .value = elf.shndx.dynamic.vaddr(elf),4474 .value = elf.shndx.dynamic.vaddr(elf),
4474 .size = 0,4475 .size = 0,
...@@ -4484,16 +4485,16 @@ fn initHeaders(...@@ -4484,16 +4485,16 @@ fn initHeaders(
4484 assert(maybe_interp == null);4485 assert(maybe_interp == null);
4485 assert(!have_dynamic_section);4486 assert(!have_dynamic_section);
4486 }4487 }
4487 if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{4488 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
4488 .name = ".tdata",4489 .name = ".tdata",
4489 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },4490 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
4490 .node_align = node_block_align,4491 .node_align = node_block_align,
4491 });4492 });
44924493
4493 assert(elf.nodes.len == expected_nodes_len);4494 assert(elf.nodes.len == expected_nodes_len);
4494 assert(elf.shdrs.items.len == shnum);4495 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF
44954496
4496 for (0..shnum) |shndx_raw| {4497 for (1..shnum) |shndx_raw| { // start at 1 to exclude SHN_UNDEF
4497 const shndx: Section.Index = @fromBackingInt(@intCast(shndx_raw));4498 const shndx: Section.Index = @fromBackingInt(@intCast(shndx_raw));
4498 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});4499 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
4499 }4500 }
...@@ -4569,7 +4570,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {...@@ -4569,7 +4570,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
4569 .uav,4570 .uav,
4570 .lazy_code,4571 .lazy_code,
4571 .lazy_const_data,4572 .lazy_const_data,
4572 => elf.getNode(ni.parent(&elf.mf)).section,4573 => elf.getNode(ni.parent(&elf.mf).unwrap().?).section,
4573 };4574 };
4574}4575}
4575fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {4576fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
...@@ -4593,7 +4594,7 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4593,7 +4594,7 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4593 };4594 };
4594}4595}
4595fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {4596fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4596 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) {4597 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {
4597 .archive, .archive_header => unreachable,4598 .archive, .archive_header => unreachable,
4598 .elf => return 0,4599 .elf => return 0,
4599 .ehdr, .shdr => unreachable,4600 .ehdr, .shdr => unreachable,
...@@ -4660,7 +4661,7 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -4660,7 +4661,7 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4660 if (got_relocs) |ptr| {4661 if (got_relocs) |ptr| {
4661 if (ptr.* != .none) {4662 if (ptr.* != .none) {
4662 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {4663 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
4663 if (reloc.node != ni) break;4664 if (reloc.node != ni.toOptional()) break;
4664 reloc.delete(elf);4665 reloc.delete(elf);
4665 }4666 }
4666 }4667 }
...@@ -4691,7 +4692,7 @@ fn flushMovedNodeRelocs(...@@ -4691,7 +4692,7 @@ fn flushMovedNodeRelocs(
46914692
4692 if (first_got_reloc != .none) {4693 if (first_got_reloc != .none) {
4693 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {4694 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {
4694 if (reloc.node != node) break;4695 if (reloc.node != node.toOptional()) break;
4695 reloc.apply(elf);4696 reloc.apply(elf);
4696 }4697 }
4697 }4698 }
...@@ -4756,7 +4757,7 @@ fn targetPtrSize(elf: *const Elf) u8 {...@@ -4756,7 +4757,7 @@ fn targetPtrSize(elf: *const Elf) u8 {
4756/// Page alignment for the target platform.4757/// Page alignment for the target platform.
4757/// Usually this returns the maximum page size supported on the4758/// Usually this returns the maximum page size supported on the
4758/// target to maximize compatibility but there can be exceptions.4759/// target to maximize compatibility but there can be exceptions.
4759fn targetPageAlign(elf: *const Elf) std.mem.Alignment {4760fn targetPageAlign(elf: *const Elf) Alignment {
4760 return .fromByteUnits(switch (elf.ehdrMachine()) {4761 return .fromByteUnits(switch (elf.ehdrMachine()) {
4761 .AARCH64 => 0x10000,4762 .AARCH64 => 0x10000,
4762 .LOONGARCH => 0x10000,4763 .LOONGARCH => 0x10000,
...@@ -4810,7 +4811,7 @@ const PltInfo = struct {...@@ -4810,7 +4811,7 @@ const PltInfo = struct {
4810 /// entry, not the `.plt` entry. The `.plt.sec` section has no header entries, and is aligned to4811 /// entry, not the `.plt` entry. The `.plt.sec` section has no header entries, and is aligned to
4811 /// the same boundary as the `.plt` section.4812 /// the same boundary as the `.plt` section.
4812 plt_sec: ?struct { entry_size: u8 },4813 plt_sec: ?struct { entry_size: u8 },
4813 @"align": std.mem.Alignment,4814 @"align": Alignment,
4814 entry_size: u8,4815 entry_size: u8,
4815 header_entries: u8,4816 header_entries: u8,
48164817
...@@ -4941,8 +4942,9 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {...@@ -4941,8 +4942,9 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
4941 switch (elf.identClass()) {4942 switch (elf.identClass()) {
4942 .NONE, _ => unreachable,4943 .NONE, _ => unreachable,
4943 inline else => |class| {4944 inline else => |class| {
4945 const shdrs_len = elf.shdrs.items.len + 1; // +1 for SHN_UNDEF
4944 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(4946 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(
4945 raw_slice[0 .. elf.shdrs.items.len * @sizeOf(class.ElfN().Shdr)],4947 raw_slice[0 .. shdrs_len * @sizeOf(class.ElfN().Shdr)],
4946 ));4948 ));
4947 const shdr_ptr = &shdr_slice[@backingInt(shndx)];4949 const shdr_ptr = &shdr_slice[@backingInt(shndx)];
4948 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);4950 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
...@@ -4951,7 +4953,7 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {...@@ -4951,7 +4953,7 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
4951}4953}
49524954
4953fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr {4955fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr {
4954 assert(elf.ni.elf != MappedFile.Node.Index.root);4956 assert(elf.ni.elf != .root);
4955 const file_offset = ni.fileLocation(&elf.mf, false).offset;4957 const file_offset = ni.fileLocation(&elf.mf, false).offset;
4956 return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) {4958 return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) {
4957 else => unreachable,4959 else => unreachable,
...@@ -5055,7 +5057,7 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -5055,7 +5057,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
5055 const parent_node: MappedFile.Node.Index = parent: {5057 const parent_node: MappedFile.Node.Index = parent: {
5056 if (!opts.flags.ALLOC) break :parent elf.ni.elf;5058 if (!opts.flags.ALLOC) break :parent elf.ni.elf;
5057 if (opts.flags.EXECINSTR) break :parent elf.ni.text;5059 if (opts.flags.EXECINSTR) break :parent elf.ni.text;
5058 if (opts.flags.TLS) break :parent elf.ni.tls;5060 if (opts.flags.TLS) break :parent elf.ni.tls.unwrap().?;
5059 if (opts.flags.WRITE) break :parent elf.ni.data;5061 if (opts.flags.WRITE) break :parent elf.ni.data;
5060 break :parent elf.ni.rodata;5062 break :parent elf.ni.rodata;
5061 };5063 };
...@@ -5148,12 +5150,12 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5148,12 +5150,12 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5148 break :section .data_rel_ro; // TODO: it would be better to use `.rodata` if the NAV value doesn't have relocs5150 break :section .data_rel_ro; // TODO: it would be better to use `.rodata` if the NAV value doesn't have relocs
5149 }5151 }
5150 };5152 };
5151 const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) {5153 const alignment: Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) {
5152 .@"fn" => a: {5154 .@"fn" => a: {
5153 const mod = zcu.navFileScope(nav_index).mod.?;5155 const mod = zcu.navFileScope(nav_index).mod.?;
5154 const target = &mod.resolved_target.result;5156 const target = &mod.resolved_target.result;
5155 const min = target_util.minFunctionAlignment(target);5157 const min = target_util.minFunctionAlignment(target);
5156 break :a switch (nav.resolved.?.@"align") {5158 break :a .fromIp(switch (nav.resolved.?.@"align") {
5157 else => |a| a.maxStrict(min),5159 else => |a| a.maxStrict(min),
5158 .none => switch (mod.optimize_mode) {5160 .none => switch (mod.optimize_mode) {
5159 .debug,5161 .debug,
...@@ -5162,20 +5164,20 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -5162,20 +5164,20 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
5162 => target_util.defaultFunctionAlignment(target),5164 => target_util.defaultFunctionAlignment(target),
5163 .small => min,5165 .small => min,
5164 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),5166 }.maxStrict(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
5165 };5167 });
5166 },5168 },
5167 else => switch (nav.resolved.?.@"align") {5169 else => switch (nav.resolved.?.@"align") {
5168 .none => Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu),5170 .none => .fromIp(Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu)),
5169 else => |a| a,5171 else => |a| .fromIp(a),
5170 },5172 },
5171 };5173 };
5172 try shndx.ensureAligned(elf, alignment.toStdMem());5174 try shndx.ensureAligned(elf, alignment);
5173 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{5175 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
5174 .alignment = alignment.toStdMem(),5176 .alignment = alignment,
5175 });5177 });
5176 nav_gop.value_ptr.* = .{5178 nav_gop.value_ptr.* = .{
5177 .lsi = elf.addLocalSymbolAssumeCapacity(.{5179 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5178 .node = node,5180 .node = .wrap(node),
5179 .name = try elf.string(.strtab, nav.fqn.toSlice(ip)),5181 .name = try elf.string(.strtab, nav.fqn.toSlice(ip)),
5180 .value = 0,5182 .value = 0,
5181 .size = 0,5183 .size = 0,
...@@ -5204,19 +5206,19 @@ fn uavMapIndex(...@@ -5204,19 +5206,19 @@ fn uavMapIndex(
5204 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);5206 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
52055207
5206 const abi_align = Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu);5208 const abi_align = Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu);
5207 const resolved_align: InternPool.Alignment = switch (uav_align) {5209 const resolved_align: Alignment = switch (uav_align) {
5208 .none => abi_align,5210 .none => .fromIp(abi_align),
5209 else => |a| a.minStrict(abi_align),5211 else => |a| .fromIp(a.minStrict(abi_align)),
5210 };5212 };
52115213
5212 const uav_gop = elf.uavs.getOrPutAssumeCapacity(uav_val);5214 const uav_gop = elf.uavs.getOrPutAssumeCapacity(uav_val);
5213 const umi: Node.UavMapIndex = @fromBackingInt(@intCast(uav_gop.index));5215 const umi: Node.UavMapIndex = @fromBackingInt(@intCast(uav_gop.index));
5214 if (!uav_gop.found_existing) {5216 if (!uav_gop.found_existing) {
5215 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs5217 const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs
5216 try shndx.ensureAligned(elf, resolved_align.toStdMem());5218 try shndx.ensureAligned(elf, resolved_align);
5217 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{5219 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
5218 .moved = true, // see assert at end of `genUav`5220 .moved = true, // see assert at end of `genUav`
5219 .alignment = resolved_align.toStdMem(),5221 .alignment = resolved_align,
5220 });5222 });
5221 var name_buf: [32]u8 = undefined;5223 var name_buf: [32]u8 = undefined;
5222 const name = std.fmt.bufPrint(5224 const name = std.fmt.bufPrint(
...@@ -5226,7 +5228,7 @@ fn uavMapIndex(...@@ -5226,7 +5228,7 @@ fn uavMapIndex(
5226 ) catch unreachable;5228 ) catch unreachable;
5227 uav_gop.value_ptr.* = .{5229 uav_gop.value_ptr.* = .{
5228 .lsi = elf.addLocalSymbolAssumeCapacity(.{5230 .lsi = elf.addLocalSymbolAssumeCapacity(.{
5229 .node = node,5231 .node = .wrap(node),
5230 .name = try elf.string(.strtab, name),5232 .name = try elf.string(.strtab, name),
5231 .value = 0,5233 .value = 0,
5232 .size = 0,5234 .size = 0,
...@@ -5239,11 +5241,11 @@ fn uavMapIndex(...@@ -5239,11 +5241,11 @@ fn uavMapIndex(
5239 elf.const_prog_node.increaseEstimatedTotalItems(1);5241 elf.const_prog_node.increaseEstimatedTotalItems(1);
5240 elf.pending_uavs.appendAssumeCapacity(umi);5242 elf.pending_uavs.appendAssumeCapacity(umi);
5241 } else {5243 } else {
5242 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;5244 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node.unwrap().?;
5243 const shndx = elf.getNode(node.parent(&elf.mf)).section;5245 const shndx = elf.getNode(node.parent(&elf.mf).unwrap().?).section;
5244 try shndx.ensureAligned(elf, resolved_align.toStdMem());5246 try shndx.ensureAligned(elf, resolved_align);
5245 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {5247 if (resolved_align.order(node.alignment(&elf.mf)).compare(.gt)) {
5246 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{});5248 try node.realign(&elf.mf, gpa, resolved_align, .{});
5247 }5249 }
5248 }5250 }
5249 return umi;5251 return umi;
...@@ -5459,7 +5461,7 @@ fn loadObject(...@@ -5459,7 +5461,7 @@ fn loadObject(
5459 .member = if (member) |m| try gpa.dupe(u8, m) else null,5461 .member = if (member) |m| try gpa.dupe(u8, m) else null,
5460 .extra = undefined,5462 .extra = undefined,
5461 };5463 };
5462 if (elf.ni.elf != MappedFile.Node.Index.root) {5464 if (elf.ni.elf != .root) {
5463 try elf.nodes.ensureUnusedCapacity(gpa, 1);5465 try elf.nodes.ensureUnusedCapacity(gpa, 1);
5464 input.extra = .{ .node = try elf.mf.addLastChildNode(gpa, .root, .{5466 input.extra = .{ .node = try elf.mf.addLastChildNode(gpa, .root, .{
5465 .size = fl.size + @sizeOf(std.elf.ar_hdr),5467 .size = fl.size + @sizeOf(std.elf.ar_hdr),
...@@ -5640,7 +5642,7 @@ fn loadObject(...@@ -5640,7 +5642,7 @@ fn loadObject(
5640 .node_fixed = true,5642 .node_fixed = true,
5641 },5643 },
5642 };5644 };
5643 const need_align: std.mem.Alignment = .fromByteUnits(5645 const need_align: Alignment = .fromByteUnits(
5644 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),5646 std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))),
5645 );5647 );
5646 try opts.shndx.ensureAligned(elf, need_align);5648 try opts.shndx.ensureAligned(elf, need_align);
...@@ -5754,7 +5756,7 @@ fn loadObject(...@@ -5754,7 +5756,7 @@ fn loadObject(
5754 ),5756 ),
5755 .LOCAL => {5757 .LOCAL => {
5756 const lsi = elf.addLocalSymbolAssumeCapacity(.{5758 const lsi = elf.addLocalSymbolAssumeCapacity(.{
5757 .node = input_section_node,5759 .node = .wrap(input_section_node),
5758 .name = try elf.string(.strtab, name),5760 .name = try elf.string(.strtab, name),
5759 .value = input_sym.value,5761 .value = input_sym.value,
5760 .size = input_sym.size,5762 .size = input_sym.size,
...@@ -5765,7 +5767,7 @@ fn loadObject(...@@ -5765,7 +5767,7 @@ fn loadObject(
5765 },5767 },
5766 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {5768 .GLOBAL, .WEAK, .GNU_UNIQUE => |bind| {
5767 si.* = elf.addGlobalSymbolAssumeCapacity(.{5769 si.* = elf.addGlobalSymbolAssumeCapacity(.{
5768 .node = input_section_node,5770 .node = .wrap(input_section_node),
5769 .name = try .string(elf, name),5771 .name = try .string(elf, name),
5770 .value = input_sym.value,5772 .value = input_sym.value,
5771 .size = input_sym.size,5773 .size = input_sym.size,
...@@ -5893,7 +5895,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars...@@ -5893,7 +5895,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
5893 return diags.failParse(path, "bad machine", .{});5895 return diags.failParse(path, "bad machine", .{});
5894 if (ehdr.shnum > 0) try fr.seekTo(ehdr.shoff);5896 if (ehdr.shnum > 0) try fr.seekTo(ehdr.shoff);
5895 // We're going to need to know the alignment of every section later.5897 // We're going to need to know the alignment of every section later.
5896 const section_aligns = try gpa.alloc(std.mem.Alignment, ehdr.shnum);5898 const section_aligns = try gpa.alloc(Alignment, ehdr.shnum);
5897 defer gpa.free(section_aligns);5899 defer gpa.free(section_aligns);
5898 const dynamic_sh: ElfN.Shdr, const dynsym_sh: ElfN.Shdr = sh: {5900 const dynamic_sh: ElfN.Shdr, const dynsym_sh: ElfN.Shdr = sh: {
5899 var dynamic_sh: ?ElfN.Shdr = null;5901 var dynamic_sh: ?ElfN.Shdr = null;
...@@ -5999,7 +6001,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars...@@ -5999,7 +6001,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
59996001
6000 // We need to guess the worst-case alignment of the symbol. Yes, I know this seems6002 // We need to guess the worst-case alignment of the symbol. Yes, I know this seems
6001 // insane---refer to the doc comment on `alignment` in `Elf.dso_globals`.6003 // insane---refer to the doc comment on `alignment` in `Elf.dso_globals`.
6002 const sym_align: std.mem.Alignment = switch (sym.value) {6004 const sym_align: Alignment = switch (sym.value) {
6003 0 => section_aligns[sym.shndx],6005 0 => section_aligns[sym.shndx],
6004 else => section_aligns[sym.shndx].min(@fromBackingInt(@intCast(@ctz(sym.value)))),6006 else => section_aligns[sym.shndx].min(@fromBackingInt(@intCast(@ctz(sym.value)))),
6005 };6007 };
...@@ -6158,7 +6160,7 @@ fn createInitFiniArraySection(...@@ -6158,7 +6160,7 @@ fn createInitFiniArraySection(
6158) Error!void {6160) Error!void {
6159 assert(shndx.* == .UNDEF);6161 assert(shndx.* == .UNDEF);
6160 const gpa = elf.base.comp.gpa;6162 const gpa = elf.base.comp.gpa;
6161 const addr_align: std.mem.Alignment = switch (elf.identClass()) {6163 const addr_align: Alignment = switch (elf.identClass()) {
6162 .NONE, _ => unreachable,6164 .NONE, _ => unreachable,
6163 .@"32" => .@"4",6165 .@"32" => .@"4",
6164 .@"64" => .@"8",6166 .@"64" => .@"8",
...@@ -6178,14 +6180,14 @@ fn createInitFiniArraySection(...@@ -6178,14 +6180,14 @@ fn createInitFiniArraySection(
6178 const start_sym_name = try elf.string(.strtab, "__" ++ name ++ "_start");6180 const start_sym_name = try elf.string(.strtab, "__" ++ name ++ "_start");
6179 const end_sym_name = try elf.string(.strtab, "__" ++ name ++ "_end");6181 const end_sym_name = try elf.string(.strtab, "__" ++ name ++ "_end");
6180 elf.setGlobalSymbolValue(start_sym_name, elf.globals.strong_def.getPtr(start_sym_name).?, .{6182 elf.setGlobalSymbolValue(start_sym_name, elf.globals.strong_def.getPtr(start_sym_name).?, .{
6181 .node = shndx.get(elf).ni,6183 .node = .wrap(shndx.get(elf).ni),
6182 .value = shndx.vaddr(elf),6184 .value = shndx.vaddr(elf),
6183 .size = 0,6185 .size = 0,
6184 .type = .NOTYPE,6186 .type = .NOTYPE,
6185 .shndx = shndx.*,6187 .shndx = shndx.*,
6186 });6188 });
6187 elf.setGlobalSymbolValue(end_sym_name, elf.globals.strong_def.getPtr(end_sym_name).?, .{6189 elf.setGlobalSymbolValue(end_sym_name, elf.globals.strong_def.getPtr(end_sym_name).?, .{
6188 .node = shndx.get(elf).ni,6190 .node = .wrap(shndx.get(elf).ni),
6189 .value = shndx.vaddr(elf),6191 .value = shndx.vaddr(elf),
6190 .size = 0,6192 .size = 0,
6191 .type = .NOTYPE,6193 .type = .NOTYPE,
...@@ -6218,7 +6220,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -6218,7 +6220,7 @@ fn prelinkInner(elf: *Elf) Error!void {
6218 const comp = elf.base.comp;6220 const comp = elf.base.comp;
6219 const gpa = comp.gpa;6221 const gpa = comp.gpa;
62206222
6221 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == MappedFile.Node.Index.root) {6223 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == .root) {
6222 // We're using self-hosted codegen---add an input representing the Zig "object".6224 // We're using self-hosted codegen---add an input representing the Zig "object".
6223 try elf.ensureUnusedSymbolCapacity(1, .all_local);6225 try elf.ensureUnusedSymbolCapacity(1, .all_local);
6224 try elf.inputs.ensureUnusedCapacity(gpa, 1);6226 try elf.inputs.ensureUnusedCapacity(gpa, 1);
...@@ -6388,9 +6390,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6388,9 +6390,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6388 size: std.elf.Xword = 0,6390 size: std.elf.Xword = 0,
6389 link: std.elf.Word = 0,6391 link: std.elf.Word = 0,
6390 info: std.elf.Word = 0,6392 info: std.elf.Word = 0,
6391 addralign: std.mem.Alignment = .@"1",6393 addralign: Alignment = .@"1",
6392 entsize: std.elf.Word = 0,6394 entsize: std.elf.Word = 0,
6393 node_align: std.mem.Alignment = .@"1",6395 node_align: Alignment = .@"1",
6394 fixed: bool = false,6396 fixed: bool = false,
6395}) Error!Section.Index {6397}) Error!Section.Index {
6396 switch (opts.type) {6398 switch (opts.type) {
...@@ -6447,7 +6449,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6447,7 +6449,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6447 });6449 });
6448 const addr = elf.computeNodeVAddr(ni);6450 const addr = elf.computeNodeVAddr(ni);
6449 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{6451 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{
6450 .node = ni,6452 .node = .wrap(ni),
6451 .name = .empty,6453 .name = .empty,
6452 .value = addr,6454 .value = addr,
6453 .size = 0,6455 .size = 0,
...@@ -6499,7 +6501,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6499,7 +6501,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
64996501
6500 assert(elf.section_by_name.count() == elf.shdrs.items.len);6502 assert(elf.section_by_name.count() == elf.shdrs.items.len);
6501 try elf.section_by_name.ensureUnusedCapacity(gpa, 1);6503 try elf.section_by_name.ensureUnusedCapacity(gpa, 1);
6502 const rela_shndx = try elf.addSection(.none, .{6504 const rela_shndx = try elf.addSection(elf.ni.elf, .{
6503 .name = rela_name,6505 .name = rela_name,
6504 .type = .RELA,6506 .type = .RELA,
6505 .link = @backingInt(Section.Index.symtab),6507 .link = @backingInt(Section.Index.symtab),
...@@ -6546,7 +6548,6 @@ fn addRelocAssumeCapacity(...@@ -6546,7 +6548,6 @@ fn addRelocAssumeCapacity(
6546 addend: i64,6548 addend: i64,
6547 @"type": MachineRelocType,6549 @"type": MachineRelocType,
6548) (Error || error{ UnknownRelocation, NonStaticRelocation, UnimplementedRelocation })!void {6550) (Error || error{ UnknownRelocation, NonStaticRelocation, UnimplementedRelocation })!void {
6549 assert(node != .none);
6550 switch (elf.ehdrType()) {6551 switch (elf.ehdrType()) {
6551 .REL => {6552 .REL => {
6552 const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx;6553 const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx;
...@@ -6894,7 +6895,6 @@ fn addSymbolRelocAssumeCapacity(...@@ -6894,7 +6895,6 @@ fn addSymbolRelocAssumeCapacity(
6894 @"type": SymbolReloc.Type,6895 @"type": SymbolReloc.Type,
6895) Error!void {6896) Error!void {
6896 assert(elf.ehdrType() != .REL);6897 assert(elf.ehdrType() != .REL);
6897 assert(node != .none);
68986898
6899 const rela_index: Section.RelaIndex.Optional = r: {6899 const rela_index: Section.RelaIndex.Optional = r: {
6900 if (elf.shndx.dynamic == .UNDEF) break :r .none;6900 if (elf.shndx.dynamic == .UNDEF) break :r .none;
...@@ -7089,7 +7089,7 @@ fn addGotRelocAssumeCapacity(...@@ -7089,7 +7089,7 @@ fn addGotRelocAssumeCapacity(
7089 }7089 }
70907090
7091 elf.got_relocs.appendAssumeCapacity(.{7091 elf.got_relocs.appendAssumeCapacity(.{
7092 .node = node,7092 .node = .wrap(node),
7093 .offset = offset,7093 .offset = offset,
7094 .target = target,7094 .target = target,
7095 .addend = addend,7095 .addend = addend,
...@@ -7111,7 +7111,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -7111,7 +7111,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
7111 .tpoff => |sym_id| val: {7111 .tpoff => |sym_id| val: {
7112 // Only the executable's per-module TLS block is at a known offset from the TLS pointer.7112 // Only the executable's per-module TLS block is at a known offset from the TLS pointer.
7113 if (elf.base.comp.config.output_mode == .Exe and elf.classifySymbolValue(sym_id) != .dynamic) {7113 if (elf.base.comp.config.output_mode == .Exe and elf.classifySymbolValue(sym_id) != .dynamic) {
7114 const tls_phndx = elf.getNode(elf.ni.tls).segment;7114 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
7115 const tls_size: u64 = switch (elf.phdrSlice()) {7115 const tls_size: u64 = switch (elf.phdrSlice()) {
7116 inline else => |phdr| tls_size: {7116 inline else => |phdr| tls_size: {
7117 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);7117 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
...@@ -7336,7 +7336,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7336,7 +7336,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
7336 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;7336 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
73377337
7338 const nmi = try elf.navMapIndex(zcu, nav_index);7338 const nmi = try elf.navMapIndex(zcu, nav_index);
7339 const ni = nmi.symbol(elf).index().ptr(elf).node;7339 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7340 elf.resetNodeRelocs(ni);7340 elf.resetNodeRelocs(ni);
73417341
7342 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be7342 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
...@@ -7392,7 +7392,7 @@ fn updateFuncInner(...@@ -7392,7 +7392,7 @@ fn updateFuncInner(
73927392
7393 const nmi = try elf.navMapIndex(zcu, func.owner_nav);7393 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
7394 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });7394 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
7395 const ni = nmi.symbol(elf).index().ptr(elf).node;7395 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7396 elf.resetNodeRelocs(ni);7396 elf.resetNodeRelocs(ni);
73977397
7398 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be7398 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
...@@ -7677,7 +7677,7 @@ fn idleProgNode(...@@ -7677,7 +7677,7 @@ fn idleProgNode(
7677 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{7677 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
7678 ii.path(elf).fmtEscapeString(),7678 ii.path(elf).fmtEscapeString(),
7679 fmtMemberString(ii.member(elf)),7679 fmtMemberString(ii.member(elf)),
7680 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),7680 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
7681 }) catch &name;7681 }) catch &name;
7682 },7682 },
7683 .nav => |nmi| {7683 .nav => |nmi| {
...@@ -7737,7 +7737,7 @@ fn genUav(...@@ -7737,7 +7737,7 @@ fn genUav(
7737 const gpa = comp.gpa;7737 const gpa = comp.gpa;
77387738
7739 const uav_val = umi.uavValue(elf);7739 const uav_val = umi.uavValue(elf);
7740 const ni = umi.symbol(elf).index().ptr(elf).node;7740 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;
7741 elf.resetNodeRelocs(ni);7741 elf.resetNodeRelocs(ni);
77427742
7743 var nw: MappedFile.Node.Writer = undefined;7743 var nw: MappedFile.Node.Writer = undefined;
...@@ -7766,7 +7766,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {...@@ -7766,7 +7766,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
7766 const gpa = zcu.gpa;7766 const gpa = zcu.gpa;
77677767
7768 const lazy = lmr.lazySymbol(elf);7768 const lazy = lmr.lazySymbol(elf);
7769 const ni = lmr.symbol(elf).index().ptr(elf).node;7769 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;
7770 elf.resetNodeRelocs(ni);7770 elf.resetNodeRelocs(ni);
77717771
7772 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually7772 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
...@@ -7842,7 +7842,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -7842,7 +7842,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
7842 fr.seekTo(file_loc.offset) catch |err| switch (err) {7842 fr.seekTo(file_loc.offset) catch |err| switch (err) {
7843 error.Canceled => |e| return e,7843 error.Canceled => |e| return e,
7844 else => |e| return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{7844 else => |e| return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
7845 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),7845 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
7846 path.fmtEscapeString(),7846 path.fmtEscapeString(),
7847 fmtMemberString(ii.member(elf)),7847 fmtMemberString(ii.member(elf)),
7848 e,7848 e,
...@@ -7853,7 +7853,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -7853,7 +7853,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
7853 defer nw.deinit();7853 defer nw.deinit();
7854 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {7854 const n_bytes = nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) catch |err| switch (err) {
7855 error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{7855 error.ReadFailed => return diags.fail("failed to read input section '{s}' from \"{f}{f}\": {t}", .{
7856 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),7856 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
7857 path.fmtEscapeString(),7857 path.fmtEscapeString(),
7858 fmtMemberString(ii.member(elf)),7858 fmtMemberString(ii.member(elf)),
7859 fr.err orelse (fr.seek_err orelse fr.size_err.?),7859 fr.err orelse (fr.seek_err orelse fr.size_err.?),
...@@ -7861,7 +7861,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {...@@ -7861,7 +7861,7 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void {
7861 error.WriteFailed => return nw.err.?,7861 error.WriteFailed => return nw.err.?,
7862 };7862 };
7863 if (n_bytes != file_loc.size) return diags.fail("failed to read input section '{s}' from \"{f}{f}\": unexpected eof", .{7863 if (n_bytes != file_loc.size) return diags.fail("failed to read input section '{s}' from \"{f}{f}\": unexpected eof", .{
7864 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),7864 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
7865 path.fmtEscapeString(),7865 path.fmtEscapeString(),
7866 fmtMemberString(ii.member(elf)),7866 fmtMemberString(ii.member(elf)),
7867 });7867 });
...@@ -7994,7 +7994,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -7994,7 +7994,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
7994 const ii = isi.input(elf);7994 const ii = isi.input(elf);
7995 var lsi, const end_lsi = ii.localSymbolRange(elf);7995 var lsi, const end_lsi = ii.localSymbolRange(elf);
7996 while (lsi != end_lsi) : (lsi = @fromBackingInt(@backingInt(lsi) + 1)) {7996 while (lsi != end_lsi) : (lsi = @fromBackingInt(@backingInt(lsi) + 1)) {
7997 if (lsi.index().ptr(elf).node != ni) continue;7997 if (lsi.index().ptr(elf).node != ni.toOptional()) continue;
7998 const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) {7998 const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) {
7999 inline else => |sym| elf.targetLoad(&sym.other).visibility,7999 inline else => |sym| elf.targetLoad(&sym.other).visibility,
8000 };8000 };
...@@ -8079,7 +8079,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8079,7 +8079,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8079/// moving or resizing of a segment could reorder them and thereby affect how we handle *future*8079/// moving or resizing of a segment could reorder them and thereby affect how we handle *future*
8080/// changes to segments.8080/// changes to segments.
8081fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Error!void {8081fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Error!void {
8082 const segment_ni = elf.phdrs.items[orig_phndx];8082 const segment_ni = elf.phdrs.items[orig_phndx].unwrap().?;
8083 assert(elf.getNode(segment_ni).segment == orig_phndx);8083 assert(elf.getNode(segment_ni).segment == orig_phndx);
8084 const page_align = elf.targetPageAlign();8084 const page_align = elf.targetPageAlign();
8085 const node_align = segment_ni.alignment(&elf.mf);8085 const node_align = segment_ni.alignment(&elf.mf);
...@@ -8165,7 +8165,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro...@@ -8165,7 +8165,7 @@ fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Erro
8165 const next_ni = elf.phdrs.items[next_phndx];8165 const next_ni = elf.phdrs.items[next_phndx];
8166 elf.phdrs.items[phndx] = next_ni;8166 elf.phdrs.items[phndx] = next_ni;
8167 elf.nodes.items(.data)[@backingInt(next_ni)] = .{ .segment = phndx };8167 elf.nodes.items(.data)[@backingInt(next_ni)] = .{ .segment = phndx };
8168 elf.phdrs.items[next_phndx] = segment_ni;8168 elf.phdrs.items[next_phndx] = .wrap(segment_ni);
8169 elf.nodes.items(.data)[@backingInt(segment_ni)] = .{ .segment = @intCast(next_phndx) };8169 elf.nodes.items(.data)[@backingInt(segment_ni)] = .{ .segment = @intCast(next_phndx) };
8170 phndx = @intCast(next_phndx);8170 phndx = @intCast(next_phndx);
8171 }8171 }
...@@ -8203,7 +8203,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8203,7 +8203,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8203 .shdr => {},8203 .shdr => {},
8204 .segment => |phndx| switch (elf.phdrSlice()) {8204 .segment => |phndx| switch (elf.phdrSlice()) {
8205 inline else => |phdr| {8205 inline else => |phdr| {
8206 assert(elf.phdrs.items[phndx] == ni);8206 assert(elf.phdrs.items[phndx].unwrap().? == ni);
8207 const ph = &phdr[phndx];8207 const ph = &phdr[phndx];
8208 elf.targetStore(&ph.filesz, @intCast(size));8208 elf.targetStore(&ph.filesz, @intCast(size));
8209 switch (elf.targetLoad(&ph.type)) {8209 switch (elf.targetLoad(&ph.type)) {
...@@ -8301,51 +8301,45 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!...@@ -8301,51 +8301,45 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
8301 break :member_offset switch (tag) {8301 break :member_offset switch (tag) {
8302 else => unreachable,8302 else => unreachable,
8303 .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true },8303 .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true },
8304 .elf, .input_member => .{ offset, switch (ni.prev(&elf.mf)) {8304 .elf, .input_member => .{ offset, !ni.prev(&elf.mf).unwrap().?.hasNextMoved(&elf.mf) },
8305 .none => unreachable,
8306 else => |prev_ni| !prev_ni.hasNextMoved(&elf.mf),
8307 } },
8308 };8305 };
8309 };8306 };
8310 const member_size = member_end: switch (ni.next(&elf.mf)) {8307 const member_size = if (ni.next(&elf.mf).unwrap()) |next_ni| member_size: {
8311 else => |next_ni| {8308 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
8312 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);8309 const next_member_size = if (next_ni.next(&elf.mf).unwrap()) |next_next_ni| next_member_size: {
8313 const next_member_size = next_member_end: switch (next_ni.next(&elf.mf)) {8310 const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf);
8314 else => |next_next_ni| {8311 const next_member_end = next_next_offset - @sizeOf(std.elf.ar_hdr);
8315 const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf);8312 break :next_member_size next_member_end - next_offset;
8316 break :next_member_end next_next_offset - @sizeOf(std.elf.ar_hdr);8313 } else next_member_size: {
8317 },8314 _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf);
8318 .none => {8315 const next_member_end = parent_size;
8319 _, const parent_size =8316 break :next_member_size next_member_end - next_offset;
8320 ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf);8317 };
8321 break :next_member_end parent_size;8318 const ar_hdr = elf.arHdrPtr(next_ni);
8322 },8319 var name_buf: [16]u8 = undefined;
8323 } - next_offset;8320 _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{
8324 const ar_hdr = elf.arHdrPtr(next_ni);8321 switch (elf.getNode(next_ni)) {
8325 var name_buf: [16]u8 = undefined;8322 else => unreachable,
8326 _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{8323 .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}),
8327 switch (elf.getNode(next_ni)) {8324 .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{
8328 else => unreachable,8325 std.fs.path.basename(ii.path(elf).sub_path),
8329 .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}),8326 }),
8330 .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{8327 } catch @panic("TODO: long archive member names"),
8331 std.fs.path.basename(ii.path(elf).sub_path),8328 }) catch @panic("TODO: long archive member names");
8332 }),8329 ar_hdr.ar_date = "0 ".*;
8333 } catch @panic("TODO: long archive member names"),8330 ar_hdr.ar_uid = "0 ".*;
8334 }) catch @panic("TODO: long archive member names");8331 ar_hdr.ar_gid = "0 ".*;
8335 ar_hdr.ar_date = "0 ".*;8332 ar_hdr.ar_mode = "644 ".*;
8336 ar_hdr.ar_uid = "0 ".*;8333 _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch
8337 ar_hdr.ar_gid = "0 ".*;8334 @panic("archive member too large");
8338 ar_hdr.ar_mode = "644 ".*;8335 ar_hdr.ar_fmag = std.elf.ARFMAG.*;
8339 _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch8336 const member_end = next_offset - @sizeOf(std.elf.ar_hdr);
8340 @panic("archive member too large");8337 break :member_size member_end - member_offset;
8341 ar_hdr.ar_fmag = std.elf.ARFMAG.*;8338 } else member_size: {
8342 break :member_end next_offset - @sizeOf(std.elf.ar_hdr);8339 _, const parent_size = ni.parent(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf);
8343 },8340 const member_end = parent_size;
8344 .none => {8341 break :member_size member_end - member_offset;
8345 _, const parent_size = ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf);8342 };
8346 break :member_end parent_size;
8347 },
8348 } - member_offset;
8349 if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{8343 if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{
8350 member_size,8344 member_size,
8351 }) catch @panic("archive member too large");8345 }) catch @panic("archive member too large");
...@@ -8775,12 +8769,13 @@ fn updateExportInner(...@@ -8775,12 +8769,13 @@ fn updateExportInner(
8775 // only emitting this error if the symbol we're conflicting with comes from an input8769 // only emitting this error if the symbol we're conflicting with comes from an input
8776 // section (as opposed to the ZCU).8770 // section (as opposed to the ZCU).
8777 const conflicting_global = elf.globalByName(try elf.string(.strtab, name)).?;8771 const conflicting_global = elf.globalByName(try elf.string(.strtab, name)).?;
8778 const conflicting_node = conflicting_global.symtab_index.ptr(elf).node;8772 if (conflicting_global.symtab_index.ptr(elf).node.unwrap()) |conflicting_node| {
8779 if (elf.getNode(conflicting_node) == .input_section) {8773 if (elf.getNode(conflicting_node) == .input_section) {
8780 return elf.base.comp.link_diags.fail(8774 return elf.base.comp.link_diags.fail(
8781 "multiple definitions of '{s}'",8775 "multiple definitions of '{s}'",
8782 .{name},8776 .{name},
8783 );8777 );
8778 }
8784 }8779 }
8785 },8780 },
8786 };8781 };
...@@ -8842,7 +8837,7 @@ pub fn printNode(...@@ -8842,7 +8837,7 @@ pub fn printNode(
8842 try w.print("({f}{f}, {s})", .{8837 try w.print("({f}{f}, {s})", .{
8843 ii.path(elf).fmtEscapeString(),8838 ii.path(elf).fmtEscapeString(),
8844 fmtMemberString(ii.member(elf)),8839 fmtMemberString(ii.member(elf)),
8845 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf),8840 elf.getNode(isi.node(elf).parent(&elf.mf).unwrap().?).section.name(elf).slice(elf),
8846 });8841 });
8847 },8842 },
8848 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),8843 .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}),
...@@ -8916,14 +8911,14 @@ pub fn printNode(...@@ -8916,14 +8911,14 @@ pub fn printNode(
8916 }8911 }
8917}8912}
89188913
8919fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignment) Error!void {8914fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: Alignment) Error!void {
8920 const gpa = elf.base.comp.gpa;8915 const gpa = elf.base.comp.gpa;
8921 // We need to loop through parent nodes because segments may be nested (e.g. a PT_TLS segment8916 // We need to loop through parent nodes because segments may be nested (e.g. a PT_TLS segment
8922 // inside a PT_LOAD segment).8917 // inside a PT_LOAD segment).
8923 var phndx = start_phndx;8918 var phndx = start_phndx;
8924 while (true) {8919 while (true) {
8925 // Align the actual node8920 // Align the actual node
8926 const seg_ni = elf.phdrs.items[phndx];8921 const seg_ni = elf.phdrs.items[phndx].unwrap().?;
8927 if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) {8922 if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) {
8928 try seg_ni.realign(&elf.mf, gpa, min_align, .{});8923 try seg_ni.realign(&elf.mf, gpa, min_align, .{});
8929 }8924 }
...@@ -8948,7 +8943,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen...@@ -8948,7 +8943,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen
8948 },8943 },
8949 }8944 }
8950 // Continue on to the parent segment, if any8945 // Continue on to the parent segment, if any
8951 switch (elf.getNode(seg_ni.parent(&elf.mf))) {8946 switch (elf.getNode(seg_ni.parent(&elf.mf).unwrap().?)) {
8952 .segment => |parent_phndx| phndx = parent_phndx,8947 .segment => |parent_phndx| phndx = parent_phndx,
8953 .elf => return,8948 .elf => return,
8954 else => unreachable,8949 else => unreachable,
...@@ -8959,7 +8954,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen...@@ -8959,7 +8954,7 @@ fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignmen
8959/// Must be called deterministically after any call to `MappedFile.Node.Index.resize`8954/// Must be called deterministically after any call to `MappedFile.Node.Index.resize`
8960/// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`.8955/// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`.
8961fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void {8956fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void {
8962 if (elf.ni.elf == MappedFile.Node.Index.root) return;8957 if (elf.ni.elf == .root) return;
8963 var child_it = elf.ni.elf.reverseChildren(&elf.mf);8958 var child_it = elf.ni.elf.reverseChildren(&elf.mf);
8964 const last_end = if (child_it.next()) |last_ni| last_end: {8959 const last_end = if (child_it.next()) |last_ni| last_end: {
8965 const last_offset, const last_size = last_ni.location(&elf.mf).resolve(&elf.mf);8960 const last_offset, const last_size = last_ni.location(&elf.mf).resolve(&elf.mf);
src/link/MappedFile.zig+298-187
...@@ -13,14 +13,14 @@ const windows = std.os.windows;...@@ -13,14 +13,14 @@ const windows = std.os.windows;
1313
14io: Io,14io: Io,
15flags: packed struct {15flags: packed struct {
16 block_size: std.mem.Alignment,16 block_size: Alignment,
17 copy_file_range_unsupported: bool,17 copy_file_range_unsupported: bool,
18 fallocate_punch_hole_unsupported: bool,18 fallocate_punch_hole_unsupported: bool,
19 fallocate_insert_range_unsupported: bool,19 fallocate_insert_range_unsupported: bool,
20},20},
21memory_map: Io.File.MemoryMap,21memory_map: Io.File.MemoryMap,
22nodes: std.ArrayList(Node),22nodes: std.ArrayList(Node),
23free_ni: Node.Index,23free_ni: Node.Index.Optional,
24large: std.ArrayList(u64),24large: std.ArrayList(u64),
25updates: std.ArrayList(Node.Index),25updates: std.ArrayList(Node.Index),
26/// This progress node's estimated total items is increased once for each node appended to `updates`.26/// This progress node's estimated total items is increased once for each node appended to `updates`.
...@@ -62,6 +62,94 @@ pub const Error = Allocator.Error || Io.Cancelable || error{...@@ -62,6 +62,94 @@ pub const Error = Allocator.Error || Io.Cancelable || error{
62 MappedFileIo,62 MappedFileIo,
63};63};
6464
65/// This separate `Alignment` type exists because neither of the other options is really suitable:
66///
67/// * `std.mem.Alignment` is based on `usize`, which---while technically okay since the file is
68/// memory-mapped---is in practice very annoying to work with in linker implementations
69///
70/// * `InternPool.Alignment` is based on `u64`, which is better, but it has the value `.none`, which
71/// is also really annoying to handle, because no alignment is ever nullable in this API
72///
73/// At some point we should probably just change `InternPool.Alignment` to be non-optional, and add
74/// a new `InternPool.Alignment.Optional` type for the case where it can actually be `.none`. At
75/// that point we can transition this code to using `InternPool.Alignment` (although it should
76/// probably be namespaced elsewhere, it has nothing to do with the `InternPool`!).
77pub const Alignment = enum(u6) {
78 @"1" = 0,
79 @"2" = 1,
80 @"4" = 2,
81 @"8" = 3,
82 @"16" = 4,
83 @"32" = 5,
84 @"64" = 6,
85 _,
86
87 pub fn fromIp(a: @import("../InternPool.zig").Alignment) Alignment {
88 assert(a != .none);
89 return @bitCast(a);
90 }
91
92 pub fn toLog2Units(a: Alignment) u6 {
93 return @backingInt(a);
94 }
95
96 pub fn fromLog2Units(a: u6) Alignment {
97 return @fromBackingInt(a);
98 }
99
100 pub fn toByteUnits(a: Alignment) u64 {
101 return @as(u64, 1) << @backingInt(a);
102 }
103
104 pub fn fromByteUnits(n: u64) Alignment {
105 assert(std.math.isPowerOfTwo(n));
106 return @fromBackingInt(@intCast(@ctz(n)));
107 }
108
109 pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {
110 return std.math.order(@backingInt(lhs), @backingInt(rhs));
111 }
112
113 pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
114 return std.math.compare(@backingInt(lhs), op, @backingInt(rhs));
115 }
116
117 pub fn max(lhs: Alignment, rhs: Alignment) Alignment {
118 return @fromBackingInt(@max(@backingInt(lhs), @backingInt(rhs)));
119 }
120
121 pub fn min(lhs: Alignment, rhs: Alignment) Alignment {
122 return @fromBackingInt(@min(@backingInt(lhs), @backingInt(rhs)));
123 }
124
125 pub inline fn of(comptime T: type) Alignment {
126 return comptime .fromByteUnits(@alignOf(T));
127 }
128
129 /// Given that a base address is known to be aligned to `a`, computes the known alignment of
130 /// that base address plus `off`.
131 pub fn offset(a: Alignment, off: u64) Alignment {
132 return .fromLog2Units(@min(a.toLog2Units(), @ctz(off)));
133 }
134
135 /// Align an address forwards to this alignment.
136 pub fn forward(a: Alignment, addr: u64) u64 {
137 const x = (@as(u64, 1) << @backingInt(a)) - 1;
138 return (addr + x) & ~x;
139 }
140
141 /// Align an address backwards to this alignment.
142 pub fn backward(a: Alignment, addr: u64) u64 {
143 const x = (@as(u64, 1) << @backingInt(a)) - 1;
144 return addr & ~x;
145 }
146
147 /// Check if an address is aligned to this amount.
148 pub fn check(a: Alignment, addr: u64) bool {
149 return @ctz(addr) >= @backingInt(a);
150 }
151};
152
65pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancelable || IoError)!MappedFile {153pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancelable || IoError)!MappedFile {
66 var mf: MappedFile = .{154 var mf: MappedFile = .{
67 .io = io,155 .io = io,
...@@ -101,7 +189,7 @@ pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancel...@@ -101,7 +189,7 @@ pub fn init(file: Io.File, gpa: Allocator, io: Io) (Allocator.Error || Io.Cancel
101 .alignment = mf.flags.block_size,189 .alignment = mf.flags.block_size,
102 .fixed = true,190 .fixed = true,
103 } });191 } });
104 assert(root_ni == Node.Index.root);192 assert(root_ni == .root);
105 try mf.ensureTotalCapacityInner(@intCast(size));193 try mf.ensureTotalCapacityInner(@intCast(size));
106 return mf;194 return mf;
107}195}
...@@ -117,17 +205,17 @@ pub fn deinit(mf: *MappedFile, gpa: Allocator) void {...@@ -117,17 +205,17 @@ pub fn deinit(mf: *MappedFile, gpa: Allocator) void {
117}205}
118206
119pub const Node = extern struct {207pub const Node = extern struct {
120 parent: Node.Index,208 parent: Node.Index.Optional,
121 prev: Node.Index,209 prev: Node.Index.Optional,
122 next: Node.Index,210 next: Node.Index.Optional,
123 first: Node.Index,211 first: Node.Index.Optional,
124 last: Node.Index,212 last: Node.Index.Optional,
125 flags: Flags,213 flags: Flags,
126 location_payload: Location.Payload,214 location_payload: Location.Payload,
127215
128 pub const Flags = packed struct(u32) {216 pub const Flags = packed struct(u32) {
129 location_tag: Location.Tag,217 location_tag: Location.Tag,
130 alignment: std.mem.Alignment,218 alignment: Alignment,
131 /// Whether this node can be moved.219 /// Whether this node can be moved.
132 fixed: bool,220 fixed: bool,
133 /// Whether this node has been moved.221 /// Whether this node has been moved.
...@@ -142,7 +230,7 @@ pub const Node = extern struct {...@@ -142,7 +230,7 @@ pub const Node = extern struct {
142 bubbles_moved: bool,230 bubbles_moved: bool,
143 /// Whether `next_moved` events are reported in `updates`.231 /// Whether `next_moved` events are reported in `updates`.
144 enable_next_moved: bool,232 enable_next_moved: bool,
145 unused: @Int(.unsigned, 32 - @bitSizeOf(std.mem.Alignment) - 8) = 0,233 unused: u18 = 0,
146 };234 };
147235
148 pub const Location = union(enum(u1)) {236 pub const Location = union(enum(u1)) {
...@@ -180,46 +268,62 @@ pub const Node = extern struct {...@@ -180,46 +268,62 @@ pub const Node = extern struct {
180 };268 };
181269
182 pub const Index = enum(u32) {270 pub const Index = enum(u32) {
183 none,271 root,
184 _,272 _,
185273
186 pub const root: Node.Index = .none;274 pub const Optional = enum(u32) {
275 none = std.math.maxInt(u32),
276 _,
277
278 pub fn unwrap(oi: Optional) ?Index {
279 return switch (oi) {
280 _ => @fromBackingInt(@backingInt(oi)),
281 .none => null,
282 };
283 }
284 pub fn wrap(i: Index) Optional {
285 const oi: Optional = @bitCast(i);
286 assert(oi != .none);
287 return oi;
288 }
289 };
187290
188 fn get(ni: Node.Index, mf: *const MappedFile) *Node {291 fn get(ni: Node.Index, mf: *const MappedFile) *Node {
189 return &mf.nodes.items[@backingInt(ni)];292 return &mf.nodes.items[@backingInt(ni)];
190 }293 }
191294
192 pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index {295 /// Alias for `Optional.wrap`, provided for convenience when a result type is not available.
296 pub const toOptional = Optional.wrap;
297
298 pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
193 return ni.get(mf).parent;299 return ni.get(mf).parent;
194 }300 }
195301
196 pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index {302 pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
197 return ni.get(mf).next;303 return ni.get(mf).next;
198 }304 }
199 fn setNext(305 fn setNext(
200 prev_ni: Node.Index,306 prev_ni: Node.Index,
201 gpa: Allocator,307 gpa: Allocator,
202 next_ni: Node.Index,308 next_ni: Node.Index.Optional,
203 mf: *MappedFile,309 mf: *MappedFile,
204 ) Allocator.Error!void {310 ) Allocator.Error!void {
205 assert(prev_ni != .none);
206 const prev_next = &prev_ni.get(mf).next;311 const prev_next = &prev_ni.get(mf).next;
207 if (prev_next.* == next_ni) return;312 if (prev_next.* == next_ni) return;
208 prev_next.* = next_ni;313 prev_next.* = next_ni;
209 try prev_ni.nextMoved(gpa, mf);314 try prev_ni.nextMoved(gpa, mf);
210 }315 }
211316
212 pub fn prev(ni: Node.Index, mf: *const MappedFile) Node.Index {317 pub fn prev(ni: Node.Index, mf: *const MappedFile) Node.Index.Optional {
213 return ni.get(mf).prev;318 return ni.get(mf).prev;
214 }319 }
215320
216 pub fn ChildIterator(comptime direction: enum { prev, next }) type {321 pub fn ChildIterator(comptime direction: enum { prev, next }) type {
217 return struct {322 return struct {
218 mf: *const MappedFile,323 mf: *const MappedFile,
219 ni: Node.Index,324 ni: Node.Index.Optional,
220 pub fn next(it: *@This()) ?Node.Index {325 pub fn next(it: *@This()) ?Node.Index {
221 const ni = it.ni;326 const ni = it.ni.unwrap() orelse return null;
222 if (ni == .none) return null;
223 it.ni = @field(ni.get(it.mf), @tagName(direction));327 it.ni = @field(ni.get(it.mf), @tagName(direction));
224 return ni;328 return ni;
225 }329 }
...@@ -233,20 +337,20 @@ pub const Node = extern struct {...@@ -233,20 +337,20 @@ pub const Node = extern struct {
233 }337 }
234338
235 pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {339 pub fn childrenMoved(ni: Node.Index, gpa: Allocator, mf: *MappedFile) Allocator.Error!void {
236 var child_ni = ni.get(mf).last;340 var child_oni = ni.get(mf).last;
237 while (child_ni != .none) {341 while (child_oni.unwrap()) |child_ni| {
238 try child_ni.moved(gpa, mf);342 try child_ni.moved(gpa, mf);
239 child_ni = child_ni.get(mf).prev;343 child_oni = child_ni.get(mf).prev;
240 }344 }
241 }345 }
242346
243 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {347 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
244 var parent_ni = ni;348 var parent_ni = ni;
245 while (parent_ni != Node.Index.root) {349 while (parent_ni != .root) {
246 const parent_node = parent_ni.get(mf);350 const parent_node = parent_ni.get(mf);
247 if (!parent_node.flags.bubbles_moved) break;351 if (!parent_node.flags.bubbles_moved) break;
248 if (parent_node.flags.moved) return true;352 if (parent_node.flags.moved) return true;
249 parent_ni = parent_node.parent;353 parent_ni = parent_node.parent.unwrap().?;
250 }354 }
251 return false;355 return false;
252 }356 }
...@@ -263,9 +367,8 @@ pub const Node = extern struct {...@@ -263,9 +367,8 @@ pub const Node = extern struct {
263 if (ni.hasMoved(mf)) return;367 if (ni.hasMoved(mf)) return;
264 const node = ni.get(mf);368 const node = ni.get(mf);
265 node.flags.moved = true;369 node.flags.moved = true;
266 switch (node.prev) {370 if (node.prev.unwrap()) |prev_ni| {
267 .none => {},371 prev_ni.nextMovedAssumeCapacity(mf);
268 else => |prev_ni| prev_ni.nextMovedAssumeCapacity(mf),
269 }372 }
270 if (node.flags.resized or node.flags.next_moved) return;373 if (node.flags.resized or node.flags.next_moved) return;
271 mf.updates.appendAssumeCapacity(ni);374 mf.updates.appendAssumeCapacity(ni);
...@@ -314,7 +417,7 @@ pub const Node = extern struct {...@@ -314,7 +417,7 @@ pub const Node = extern struct {
314 mf.update_prog_node.increaseEstimatedTotalItems(1);417 mf.update_prog_node.increaseEstimatedTotalItems(1);
315 }418 }
316419
317 pub fn alignment(ni: Node.Index, mf: *const MappedFile) std.mem.Alignment {420 pub fn alignment(ni: Node.Index, mf: *const MappedFile) Alignment {
318 return ni.get(mf).flags.alignment;421 return ni.get(mf).flags.alignment;
319 }422 }
320423
...@@ -361,8 +464,11 @@ pub const Node = extern struct {...@@ -361,8 +464,11 @@ pub const Node = extern struct {
361 while (true) {464 while (true) {
362 const parent_node = parent_ni.get(mf);465 const parent_node = parent_ni.get(mf);
363 if (set_has_content) parent_node.flags.has_content = true;466 if (set_has_content) parent_node.flags.has_content = true;
364 if (parent_ni == .none) break;467 if (parent_ni == .root) {
365 parent_ni = parent_node.parent;468 assert(parent_node.parent == .none);
469 break;
470 }
471 parent_ni = parent_node.parent.unwrap().?;
366 const parent_offset, _ = parent_ni.location(mf).resolve(mf);472 const parent_offset, _ = parent_ni.location(mf).resolve(mf);
367 offset += parent_offset;473 offset += parent_offset;
368 }474 }
...@@ -402,12 +508,12 @@ pub const Node = extern struct {...@@ -402,12 +508,12 @@ pub const Node = extern struct {
402 };508 };
403509
404 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.510 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.
405 /// Asserts that `ni` is not `Node.Index.root`.511 /// Asserts that `ni` is not `.root`.
406 pub fn realign(512 pub fn realign(
407 ni: Node.Index,513 ni: Node.Index,
408 mf: *MappedFile,514 mf: *MappedFile,
409 gpa: Allocator,515 gpa: Allocator,
410 new_alignment: std.mem.Alignment,516 new_alignment: Alignment,
411 opts: RealignNodeOptions,517 opts: RealignNodeOptions,
412 ) Error!void {518 ) Error!void {
413 mf.realignNode(gpa, ni, new_alignment, opts) catch |err| switch (err) {519 mf.realignNode(gpa, ni, new_alignment, opts) catch |err| switch (err) {
...@@ -590,9 +696,9 @@ pub const Node = extern struct {...@@ -590,9 +696,9 @@ pub const Node = extern struct {
590};696};
591697
592fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {698fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
593 parent: Node.Index = .none,699 parent: Node.Index.Optional = .none,
594 prev: Node.Index = .none,700 prev: Node.Index.Optional = .none,
595 next: Node.Index = .none,701 next: Node.Index.Optional = .none,
596 offset: u64 = 0,702 offset: u64 = 0,
597 add_node: AddNodeOptions,703 add_node: AddNodeOptions,
598}) (Allocator.Error || Io.Cancelable || IoError)!Node.Index {704}) (Allocator.Error || Io.Cancelable || IoError)!Node.Index {
...@@ -605,22 +711,32 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {...@@ -605,22 +711,32 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
605 defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 });711 defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 });
606 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };712 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };
607 };713 };
608 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {714
609 .none => .{ @fromBackingInt(@intCast(mf.nodes.items.len)), mf.nodes.addOneAssumeCapacity() },715 const free_ni: Node.Index, const free_node: *Node = if (mf.free_ni.unwrap()) |free_ni| free: {
610 else => |free_ni| {716 const free_node = free_ni.get(mf);
611 const free_node = free_ni.get(mf);717 mf.free_ni = free_node.next;
612 mf.free_ni = free_node.next;718 break :free .{ free_ni, free_node };
613 break :free .{ free_ni, free_node };719 } else .{
614 },720 @fromBackingInt(@intCast(mf.nodes.items.len)),
721 mf.nodes.addOneAssumeCapacity(),
615 };722 };
616 switch (opts.prev) {723
617 .none => opts.parent.get(mf).first = free_ni,724 if (opts.prev.unwrap()) |prev_ni| {
618 else => |prev_ni| try prev_ni.setNext(gpa, free_ni, mf),725 try prev_ni.setNext(gpa, .wrap(free_ni), mf);
726 } else if (opts.parent.unwrap()) |parent_ni| {
727 parent_ni.get(mf).first = .wrap(free_ni);
728 } else {
729 assert(free_ni == .root);
619 }730 }
620 switch (opts.next) {731
621 .none => opts.parent.get(mf).last = free_ni,732 if (opts.next.unwrap()) |next_ni| {
622 else => |next_ni| next_ni.get(mf).prev = free_ni,733 next_ni.get(mf).prev = .wrap(free_ni);
734 } else if (opts.parent.unwrap()) |parent_ni| {
735 parent_ni.get(mf).last = .wrap(free_ni);
736 } else {
737 assert(free_ni == .root);
623 }738 }
739
624 free_node.* = .{740 free_node.* = .{
625 .parent = opts.parent,741 .parent = opts.parent,
626 .prev = opts.prev,742 .prev = opts.prev,
...@@ -659,7 +775,7 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {...@@ -659,7 +775,7 @@ fn addNode(mf: *MappedFile, gpa: Allocator, opts: struct {
659775
660pub const AddNodeOptions = struct {776pub const AddNodeOptions = struct {
661 size: u64 = 0,777 size: u64 = 0,
662 alignment: std.mem.Alignment = .@"1",778 alignment: Alignment = .@"1",
663 fixed: bool = false,779 fixed: bool = false,
664 moved: bool = false,780 moved: bool = false,
665 resized: bool = false,781 resized: bool = false,
...@@ -678,7 +794,7 @@ pub fn addOnlyChildNode(...@@ -678,7 +794,7 @@ pub fn addOnlyChildNode(
678 const parent = parent_ni.get(mf);794 const parent = parent_ni.get(mf);
679 assert(parent.first == .none and parent.last == .none);795 assert(parent.first == .none and parent.last == .none);
680 return mf.addNode(gpa, .{796 return mf.addNode(gpa, .{
681 .parent = parent_ni,797 .parent = .wrap(parent_ni),
682 .add_node = opts,798 .add_node = opts,
683 }) catch |err| switch (err) {799 }) catch |err| switch (err) {
684 error.OutOfMemory,800 error.OutOfMemory,
...@@ -700,7 +816,7 @@ pub fn addFirstChildNode(...@@ -700,7 +816,7 @@ pub fn addFirstChildNode(
700 try mf.nodes.ensureUnusedCapacity(gpa, 1);816 try mf.nodes.ensureUnusedCapacity(gpa, 1);
701 const parent = parent_ni.get(mf);817 const parent = parent_ni.get(mf);
702 return mf.addNode(gpa, .{818 return mf.addNode(gpa, .{
703 .parent = parent_ni,819 .parent = .wrap(parent_ni),
704 .next = parent.first,820 .next = parent.first,
705 .add_node = opts,821 .add_node = opts,
706 }) catch |err| switch (err) {822 }) catch |err| switch (err) {
...@@ -723,14 +839,12 @@ pub fn addLastChildNode(...@@ -723,14 +839,12 @@ pub fn addLastChildNode(
723 try mf.nodes.ensureUnusedCapacity(gpa, 1);839 try mf.nodes.ensureUnusedCapacity(gpa, 1);
724 const parent = parent_ni.get(mf);840 const parent = parent_ni.get(mf);
725 return mf.addNode(gpa, .{841 return mf.addNode(gpa, .{
726 .parent = parent_ni,842 .parent = .wrap(parent_ni),
727 .prev = parent.last,843 .prev = parent.last,
728 .offset = offset: switch (parent.last) {844 .offset = offset: {
729 .none => 0,845 const last_ni = parent.last.unwrap() orelse break :offset 0;
730 else => |last_ni| {846 const last_offset, const last_size = last_ni.location(mf).resolve(mf);
731 const last_offset, const last_size = last_ni.location(mf).resolve(mf);847 break :offset last_offset + last_size;
732 break :offset last_offset + last_size;
733 },
734 },848 },
735 .add_node = opts,849 .add_node = opts,
736 }) catch |err| switch (err) {850 }) catch |err| switch (err) {
...@@ -750,13 +864,12 @@ pub fn addNodeAfter(...@@ -750,13 +864,12 @@ pub fn addNodeAfter(
750 prev_ni: Node.Index,864 prev_ni: Node.Index,
751 opts: AddNodeOptions,865 opts: AddNodeOptions,
752) Error!Node.Index {866) Error!Node.Index {
753 assert(prev_ni != .none);
754 try mf.nodes.ensureUnusedCapacity(gpa, 1);867 try mf.nodes.ensureUnusedCapacity(gpa, 1);
755 const prev = prev_ni.get(mf);868 const prev = prev_ni.get(mf);
756 const prev_offset, const prev_size = prev.location().resolve(mf);869 const prev_offset, const prev_size = prev.location().resolve(mf);
757 return mf.addNode(gpa, .{870 return mf.addNode(gpa, .{
758 .parent = prev.parent,871 .parent = prev.parent,
759 .prev = prev_ni,872 .prev = .wrap(prev_ni),
760 .next = prev.next,873 .next = prev.next,
761 .offset = prev_offset + prev_size,874 .offset = prev_offset + prev_size,
762 .add_node = opts,875 .add_node = opts,
...@@ -783,10 +896,10 @@ fn shrinkNode(...@@ -783,10 +896,10 @@ fn shrinkNode(
783 const old_offset, _ = node.location().resolve(mf);896 const old_offset, _ = node.location().resolve(mf);
784897
785 // This would require unmapping first898 // This would require unmapping first
786 assert(ni != Node.Index.root);899 assert(ni != .root);
787900
788 if (node.last != .none) {901 if (node.last.unwrap()) |last_ni| {
789 const last = node.last.get(mf);902 const last = last_ni.get(mf);
790 const last_offset, const last_size = last.location().resolve(mf);903 const last_offset, const last_size = last.location().resolve(mf);
791 assert(last_offset + last_size > size);904 assert(last_offset + last_size > size);
792 }905 }
...@@ -795,15 +908,16 @@ fn shrinkNode(...@@ -795,15 +908,16 @@ fn shrinkNode(
795 try mf.updates.ensureUnusedCapacity(gpa, 4);908 try mf.updates.ensureUnusedCapacity(gpa, 4);
796909
797 ni.setLocationAssumeCapacity(mf, old_offset, size);910 ni.setLocationAssumeCapacity(mf, old_offset, size);
798 if (!shift_next or node.next == .none) return;911 if (!shift_next) return;
912 const next_ni = node.next.unwrap() orelse return;
799913
800 const next = node.next.get(mf);914 const next = next_ni.get(mf);
801 const old_next_offset, const next_size = next.location().resolve(mf);915 const old_next_offset, const next_size = next.location().resolve(mf);
802 const padding = old_next_offset - (old_offset + size);916 const padding = old_next_offset - (old_offset + size);
803 const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding));917 const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding));
804918
805 if (next.flags.has_content and new_next_offset < old_next_offset) {919 if (next.flags.has_content and new_next_offset < old_next_offset) {
806 const old_file_offset = node.next.fileLocation(mf, false).offset;920 const old_file_offset = next_ni.fileLocation(mf, false).offset;
807 const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset;921 const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset;
808 @memmove(922 @memmove(
809 mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(next_size)],923 mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(next_size)],
...@@ -812,7 +926,7 @@ fn shrinkNode(...@@ -812,7 +926,7 @@ fn shrinkNode(
812 @memset(mf.memory_map.memory[@intCast(new_file_offset + next_size)..@intCast(old_file_offset + next_size)], 0);926 @memset(mf.memory_map.memory[@intCast(new_file_offset + next_size)..@intCast(old_file_offset + next_size)], 0);
813 }927 }
814928
815 node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size);929 next_ni.setLocationAssumeCapacity(mf, new_next_offset, next_size);
816}930}
817931
818fn resizeNode(932fn resizeNode(
...@@ -828,7 +942,8 @@ fn resizeNode(...@@ -828,7 +942,8 @@ fn resizeNode(
828 const new_size = node.flags.alignment.forward(@intCast(requested_size));942 const new_size = node.flags.alignment.forward(@intCast(requested_size));
829943
830 // Resize the entire file944 // Resize the entire file
831 if (ni == Node.Index.root) {945 const parent_ni = node.parent.unwrap() orelse {
946 assert(ni == .root);
832 try mf.ensureCapacityForSetLocation(gpa);947 try mf.ensureCapacityForSetLocation(gpa);
833 mf.memory_map.write(io) catch |err| switch (err) {948 mf.memory_map.write(io) catch |err| switch (err) {
834 error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking949 error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking
...@@ -839,15 +954,13 @@ fn resizeNode(...@@ -839,15 +954,13 @@ fn resizeNode(
839 try mf.ensureTotalCapacityInner(@intCast(new_size));954 try mf.ensureTotalCapacityInner(@intCast(new_size));
840 ni.setLocationAssumeCapacity(mf, old_offset, new_size);955 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
841 return;956 return;
842 }957 };
843 const parent = node.parent.get(mf);958 const parent = parent_ni.get(mf);
844 _, var old_parent_size = parent.location().resolve(mf);959 _, var old_parent_size = parent.location().resolve(mf);
845 const trailing_end = trailing_end: switch (node.next) {960 const trailing_end = trailing_end: {
846 .none => old_parent_size,961 const next_ni = node.next.unwrap() orelse break :trailing_end old_parent_size;
847 else => |next_ni| {962 const next_offset, _ = next_ni.location(mf).resolve(mf);
848 const next_offset, _ = next_ni.location(mf).resolve(mf);963 break :trailing_end next_offset;
849 break :trailing_end next_offset;
850 },
851 };964 };
852 assert(old_offset + old_size <= trailing_end);965 assert(old_offset + old_size <= trailing_end);
853 if (old_offset + new_size <= trailing_end) {966 if (old_offset + new_size <= trailing_end) {
...@@ -877,7 +990,7 @@ fn resizeNode(...@@ -877,7 +990,7 @@ fn resizeNode(
877 else => |e| return e,990 else => |e| return e,
878 };991 };
879 // Ask the filesystem driver to insert extents into the file without copying any data992 // Ask the filesystem driver to insert extents into the file without copying any data
880 const last_offset, const last_size = parent.last.location(mf).resolve(mf);993 const last_offset, const last_size = parent.last.unwrap().?.location(mf).resolve(mf);
881 const last_end = last_offset + last_size;994 const last_end = last_offset + last_size;
882 assert(last_end <= old_parent_size);995 assert(last_end <= old_parent_size);
883 _, const file_size = Node.Index.root.location(mf).resolve(mf);996 _, const file_size = Node.Index.root.location(mf).resolve(mf);
...@@ -900,13 +1013,13 @@ fn resizeNode(...@@ -900,13 +1013,13 @@ fn resizeNode(
900 enclosing.location().resolve(mf);1013 enclosing.location().resolve(mf);
901 const new_enclosing_size = old_enclosing_size + range_size;1014 const new_enclosing_size = old_enclosing_size + range_size;
902 enclosing_ni.setLocationAssumeCapacity(mf, enclosing_offset, new_enclosing_size);1015 enclosing_ni.setLocationAssumeCapacity(mf, enclosing_offset, new_enclosing_size);
903 if (enclosing_ni == Node.Index.root) {1016 if (enclosing_ni == .root) {
904 assert(enclosing_offset == 0);1017 assert(enclosing_offset == 0);
905 try mf.ensureTotalCapacityInner(@intCast(new_enclosing_size));1018 try mf.ensureTotalCapacityInner(@intCast(new_enclosing_size));
906 break;1019 break;
907 }1020 }
908 var after_ni = enclosing.next;1021 var after_oni = enclosing.next;
909 while (after_ni != .none) {1022 while (after_oni.unwrap()) |after_ni| {
910 try mf.ensureCapacityForSetLocation(gpa);1023 try mf.ensureCapacityForSetLocation(gpa);
911 const after = after_ni.get(mf);1024 const after = after_ni.get(mf);
912 const after_offset, const after_size = after.location().resolve(mf);1025 const after_offset, const after_size = after.location().resolve(mf);
...@@ -915,9 +1028,9 @@ fn resizeNode(...@@ -915,9 +1028,9 @@ fn resizeNode(
915 range_size + after_offset,1028 range_size + after_offset,
916 after_size,1029 after_size,
917 );1030 );
918 after_ni = after.next;1031 after_oni = after.next;
919 }1032 }
920 enclosing_ni = enclosing.parent;1033 enclosing_ni = enclosing.parent.unwrap().?;
921 }1034 }
922 return;1035 return;
923 },1036 },
...@@ -939,32 +1052,33 @@ fn resizeNode(...@@ -939,32 +1052,33 @@ fn resizeNode(
939 if (node.next == .none) {1052 if (node.next == .none) {
940 // As this is the last node, we simply need more space in the parent1053 // As this is the last node, we simply need more space in the parent
941 const new_parent_size = old_offset + new_size;1054 const new_parent_size = old_offset + new_size;
942 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);1055 try mf.resizeNode(gpa, parent_ni, new_parent_size +| new_parent_size / growth_factor);
943 try mf.ensureCapacityForSetLocation(gpa);1056 try mf.ensureCapacityForSetLocation(gpa);
944 ni.setLocationAssumeCapacity(mf, old_offset, new_size);1057 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
945 return;1058 return;
946 }1059 }
947 if (!node.flags.fixed) {1060 if (!node.flags.fixed) {
948 // Make space at the end of the parent for this floating node1061 // Make space at the end of the parent for this floating node
949 const last = parent.last.get(mf);1062 const last = parent.last.unwrap().?.get(mf);
950 const last_offset, const last_size = last.location().resolve(mf);1063 const last_offset, const last_size = last.location().resolve(mf);
951 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));1064 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));
952 const new_parent_size = new_offset + new_size;1065 const new_parent_size = new_offset + new_size;
953 if (new_parent_size > old_parent_size)1066 if (new_parent_size > old_parent_size)
954 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);1067 try mf.resizeNode(gpa, parent_ni, new_parent_size +| new_parent_size / growth_factor);
955 try mf.ensureCapacityForSetLocation(gpa);1068 try mf.ensureCapacityForSetLocation(gpa);
956 const next_ni = node.next;1069 const next_ni = node.next.unwrap().?;
957 next_ni.get(mf).prev = node.prev;1070 next_ni.get(mf).prev = node.prev;
958 switch (node.prev) {1071 if (node.prev.unwrap()) |prev_ni| {
959 .none => parent.first = next_ni,1072 try prev_ni.setNext(gpa, .wrap(next_ni), mf);
960 else => |prev_ni| try prev_ni.setNext(gpa, next_ni, mf),1073 } else {
1074 parent.first = .wrap(next_ni);
961 }1075 }
962 try parent.last.setNext(gpa, ni, mf);1076 try parent.last.unwrap().?.setNext(gpa, .wrap(ni), mf);
963 node.prev = parent.last;1077 node.prev = parent.last;
964 try ni.setNext(gpa, .none, mf);1078 try ni.setNext(gpa, .none, mf);
965 parent.last = ni;1079 parent.last = .wrap(ni);
966 if (node.flags.has_content) {1080 if (node.flags.has_content) {
967 const parent_file_offset = node.parent.fileLocation(mf, false).offset;1081 const parent_file_offset = parent_ni.fileLocation(mf, false).offset;
968 try mf.moveRange(1082 try mf.moveRange(
969 parent_file_offset + old_offset,1083 parent_file_offset + old_offset,
970 parent_file_offset + new_offset,1084 parent_file_offset + new_offset,
...@@ -976,94 +1090,89 @@ fn resizeNode(...@@ -976,94 +1090,89 @@ fn resizeNode(
976 }1090 }
977 // Search for the first floating node following this fixed node1091 // Search for the first floating node following this fixed node
978 var last_fixed_ni = ni;1092 var last_fixed_ni = ni;
979 var first_floating_ni = node.next;1093 var first_floating_oni = node.next;
980 var shift = new_size - old_size;1094 var shift = new_size - old_size;
981 var max_shift_align: std.mem.Alignment = .@"1";1095 var max_shift_align: Alignment = .@"1";
982 var direction: enum { forward, reverse } = .forward;1096 var direction: enum { forward, reverse } = .forward;
983 while (true) {1097 while (true) {
984 assert(last_fixed_ni != .none);
985 const last_fixed = last_fixed_ni.get(mf);1098 const last_fixed = last_fixed_ni.get(mf);
986 assert(last_fixed.flags.fixed);1099 assert(last_fixed.flags.fixed);
987 const old_last_fixed_offset, const last_fixed_size = last_fixed.location().resolve(mf);1100 const old_last_fixed_offset, const last_fixed_size = last_fixed.location().resolve(mf);
988 const new_last_fixed_offset = old_last_fixed_offset + shift;1101 const new_last_fixed_offset = old_last_fixed_offset + shift;
989 make_space: switch (first_floating_ni) {1102 if (first_floating_oni.unwrap()) |first_floating_ni| make_space: {
990 else => {1103 const first_floating = first_floating_ni.get(mf);
991 const first_floating = first_floating_ni.get(mf);1104 const old_first_floating_offset, const first_floating_size =
992 const old_first_floating_offset, const first_floating_size =1105 first_floating.location().resolve(mf);
993 first_floating.location().resolve(mf);1106 assert(old_last_fixed_offset + last_fixed_size <= old_first_floating_offset);
994 assert(old_last_fixed_offset + last_fixed_size <= old_first_floating_offset);1107 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)
995 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)1108 break :make_space;
996 break :make_space;1109 assert(direction == .forward);
997 assert(direction == .forward);1110 max_shift_align = max_shift_align.max(first_floating.flags.alignment.max(last_fixed.flags.alignment));
998 max_shift_align = max_shift_align.max(first_floating.flags.alignment.max(last_fixed.flags.alignment));1111 if (first_floating.flags.fixed) {
999 if (first_floating.flags.fixed) {1112 shift = max_shift_align.forward(@intCast(
1000 shift = max_shift_align.forward(@intCast(1113 @max(shift, first_floating_size),
1001 @max(shift, first_floating_size),1114 ));
1002 ));1115
10031116 // Not enough space, try the next node
1004 // Not enough space, try the next node1117 last_fixed_ni = first_floating_ni;
1005 last_fixed_ni = first_floating_ni;1118 first_floating_oni = first_floating.next;
1006 first_floating_ni = first_floating.next;1119 continue;
1007 continue;1120 }
1008 }1121 // Move the found floating node to make space for preceding fixed nodes
1009 // Move the found floating node to make space for preceding fixed nodes1122 const last = parent.last.unwrap().?.get(mf);
1010 const last = parent.last.get(mf);1123 const last_offset, const last_size = last.location().resolve(mf);
1011 const last_offset, const last_size = last.location().resolve(mf);1124 const new_first_floating_offset = max_shift_align.forward(
1012 const new_first_floating_offset = max_shift_align.forward(1125 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),
1013 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),1126 );
1127 const new_parent_size = new_first_floating_offset + first_floating_size;
1128 if (new_parent_size > old_parent_size) {
1129 try mf.resizeNode(
1130 gpa,
1131 parent_ni,
1132 new_parent_size +| new_parent_size / growth_factor,
1014 );1133 );
1015 const new_parent_size = new_first_floating_offset + first_floating_size;1134 _, old_parent_size = parent.location().resolve(mf);
1016 if (new_parent_size > old_parent_size) {1135 }
1017 try mf.resizeNode(1136 try mf.ensureCapacityForSetLocation(gpa);
1018 gpa,1137 if (parent.last.unwrap().? != first_floating_ni) {
1019 node.parent,1138 const old_last = parent.last.unwrap().?;
1020 new_parent_size +| new_parent_size / growth_factor,1139 first_floating.prev = .wrap(old_last);
1021 );1140 parent.last = .wrap(first_floating_ni);
1022 _, old_parent_size = parent.location().resolve(mf);1141 try old_last.setNext(gpa, .wrap(first_floating_ni), mf);
1023 }1142 try last_fixed_ni.setNext(gpa, first_floating.next, mf);
1024 try mf.ensureCapacityForSetLocation(gpa);1143 if (first_floating.next.unwrap()) |next_ni| {
1025 if (parent.last != first_floating_ni) {1144 next_ni.get(mf).prev = .wrap(last_fixed_ni);
1026 const old_last = parent.last;
1027 first_floating.prev = old_last;
1028 parent.last = first_floating_ni;
1029 try old_last.setNext(gpa, first_floating_ni, mf);
1030 try last_fixed_ni.setNext(gpa, first_floating.next, mf);
1031 switch (first_floating.next) {
1032 .none => {},
1033 else => |next_ni| next_ni.get(mf).prev = last_fixed_ni,
1034 }
1035 try first_floating_ni.setNext(gpa, .none, mf);
1036 }
1037 if (first_floating.flags.has_content) {
1038 const parent_file_offset =
1039 node.parent.fileLocation(mf, false).offset;
1040 try mf.moveRange(
1041 parent_file_offset + old_first_floating_offset,
1042 parent_file_offset + new_first_floating_offset,
1043 first_floating_size,
1044 );
1045 }1145 }
1046 first_floating_ni.setLocationAssumeCapacity(1146 try first_floating_ni.setNext(gpa, .none, mf);
1047 mf,1147 }
1048 new_first_floating_offset,1148 if (first_floating.flags.has_content) {
1149 const parent_file_offset =
1150 parent_ni.fileLocation(mf, false).offset;
1151 try mf.moveRange(
1152 parent_file_offset + old_first_floating_offset,
1153 parent_file_offset + new_first_floating_offset,
1049 first_floating_size,1154 first_floating_size,
1050 );1155 );
1051 // Continue the search after the just-moved floating node1156 }
1052 first_floating_ni = last_fixed.next;1157 first_floating_ni.setLocationAssumeCapacity(
1053 continue;1158 mf,
1054 },1159 new_first_floating_offset,
1055 .none => {1160 first_floating_size,
1056 assert(direction == .forward);1161 );
1057 const new_parent_size = new_last_fixed_offset + last_fixed_size;1162 // Continue the search after the just-moved floating node
1058 if (new_parent_size > old_parent_size) {1163 first_floating_oni = last_fixed.next;
1059 try mf.resizeNode(1164 continue;
1060 gpa,1165 } else {
1061 node.parent,1166 assert(direction == .forward);
1062 new_parent_size +| new_parent_size / growth_factor,1167 const new_parent_size = new_last_fixed_offset + last_fixed_size;
1063 );1168 if (new_parent_size > old_parent_size) {
1064 _, old_parent_size = parent.location().resolve(mf);1169 try mf.resizeNode(
1065 }1170 gpa,
1066 },1171 parent_ni,
1172 new_parent_size +| new_parent_size / growth_factor,
1173 );
1174 _, old_parent_size = parent.location().resolve(mf);
1175 }
1067 }1176 }
1068 try mf.ensureCapacityForSetLocation(gpa);1177 try mf.ensureCapacityForSetLocation(gpa);
1069 if (last_fixed_ni == ni) {1178 if (last_fixed_ni == ni) {
...@@ -1077,7 +1186,7 @@ fn resizeNode(...@@ -1077,7 +1186,7 @@ fn resizeNode(
1077 }1186 }
1078 // Move a fixed node into trailing free space1187 // Move a fixed node into trailing free space
1079 if (last_fixed.flags.has_content) {1188 if (last_fixed.flags.has_content) {
1080 const parent_file_offset = node.parent.fileLocation(mf, false).offset;1189 const parent_file_offset = parent_ni.fileLocation(mf, false).offset;
1081 try mf.moveRange(1190 try mf.moveRange(
1082 parent_file_offset + old_last_fixed_offset,1191 parent_file_offset + old_last_fixed_offset,
1083 parent_file_offset + new_last_fixed_offset,1192 parent_file_offset + new_last_fixed_offset,
...@@ -1086,8 +1195,8 @@ fn resizeNode(...@@ -1086,8 +1195,8 @@ fn resizeNode(
1086 }1195 }
1087 last_fixed_ni.setLocationAssumeCapacity(mf, new_last_fixed_offset, last_fixed_size);1196 last_fixed_ni.setLocationAssumeCapacity(mf, new_last_fixed_offset, last_fixed_size);
1088 // Retry the previous nodes now that there is enough space1197 // Retry the previous nodes now that there is enough space
1089 first_floating_ni = last_fixed_ni;1198 first_floating_oni = .wrap(last_fixed_ni);
1090 last_fixed_ni = last_fixed.prev;1199 last_fixed_ni = last_fixed.prev.unwrap().?;
1091 direction = .reverse;1200 direction = .reverse;
1092 }1201 }
1093}1202}
...@@ -1096,7 +1205,7 @@ fn realignNode(...@@ -1096,7 +1205,7 @@ fn realignNode(
1096 mf: *MappedFile,1205 mf: *MappedFile,
1097 gpa: Allocator,1206 gpa: Allocator,
1098 ni: Node.Index,1207 ni: Node.Index,
1099 new_alignment: std.mem.Alignment,1208 new_alignment: Alignment,
1100 opts: Node.Index.RealignNodeOptions,1209 opts: Node.Index.RealignNodeOptions,
1101) (Allocator.Error || Io.Cancelable || IoError)!void {1210) (Allocator.Error || Io.Cancelable || IoError)!void {
1102 mf.nodes_lock.assertUnlocked();1211 mf.nodes_lock.assertUnlocked();
...@@ -1109,25 +1218,27 @@ fn realignNode(...@@ -1109,25 +1218,27 @@ fn realignNode(
1109 }1218 }
11101219
1111 const old_offset, const size = node.location().resolve(mf);1220 const old_offset, const size = node.location().resolve(mf);
1112 if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size);1221 const parent_ni = node.parent.unwrap() orelse {
1222 assert(ni == .root);
1223 return mf.resizeNode(gpa, ni, size);
1224 };
11131225
1114 const new_size = new_alignment.forward(@intCast(size));1226 const new_size = new_alignment.forward(@intCast(size));
1115 if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size);1227 if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size);
11161228
1117 _, const parent_size = node.parent.location(mf).resolve(mf);1229 _, const parent_size = parent_ni.location(mf).resolve(mf);
1118 const trailing_end = trailing_end: switch (node.next) {1230 const trailing_end = trailing_end: {
1119 .none => parent_size,1231 const next_ni = node.next.unwrap() orelse break :trailing_end parent_size;
1120 else => |next_ni| {1232 const next_offset, _ = next_ni.location(mf).resolve(mf);
1121 const next_offset, _ = next_ni.location(mf).resolve(mf);1233 break :trailing_end next_offset;
1122 break :trailing_end next_offset;
1123 },
1124 };1234 };
11251235
1126 if (opts.try_backwards) {1236 if (opts.try_backwards) {
1127 const backward_offset = new_alignment.backward(@intCast(old_offset));1237 const backward_offset = new_alignment.backward(@intCast(old_offset));
1128 const prev_end = if (node.prev == .none) 0 else prev: {1238 const prev_end = prev_end: {
1129 const prev_offset, const prev_size = node.prev.location(mf).resolve(mf);1239 const prev_ni = node.prev.unwrap() orelse break :prev_end 0;
1130 break :prev prev_offset + prev_size;1240 const prev_offset, const prev_size = prev_ni.location(mf).resolve(mf);
1241 break :prev_end prev_offset + prev_size;
1131 };1242 };
11321243
1133 if (backward_offset >= prev_end) {1244 if (backward_offset >= prev_end) {
...@@ -1399,7 +1510,7 @@ fn verify(mf: *MappedFile) void {...@@ -1399,7 +1510,7 @@ fn verify(mf: *MappedFile) void {
1399 assert(root.parent == .none);1510 assert(root.parent == .none);
1400 assert(root.prev == .none);1511 assert(root.prev == .none);
1401 assert(root.next == .none);1512 assert(root.next == .none);
1402 mf.verifyNode(Node.Index.root);1513 mf.verifyNode(.root);
1403}1514}
14041515
1405fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void {1516fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void {
...@@ -1517,7 +1628,7 @@ test {...@@ -1517,7 +1628,7 @@ test {
1517 try testVerifyContent(&mf, d, 0xdd, d_init_size);1628 try testVerifyContent(&mf, d, 0xdd, d_init_size);
1518 }1629 }
15191630
1520 const child_init: []const struct { std.mem.Alignment, usize } = &.{1631 const child_init: []const struct { Alignment, usize } = &.{
1521 .{ .@"16", 16 },1632 .{ .@"16", 16 },
1522 .{ .@"1", 1 },1633 .{ .@"1", 1 },
1523 .{ .@"1", 19 },1634 .{ .@"1", 19 },