Commit a5b76d2474

Noam Preil <noam@pixelhero.dev>
2020-08-03 02:46:06
Stage2: minor File.ELF refactor
1 parent cf4936b
Changed files (3)
src-self-hosted
src-self-hosted/codegen/c.zig
@@ -44,8 +44,8 @@ fn renderType(file: *C, writer: std.ArrayList(u8).Writer, T: Type, src: usize) !
 fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *Decl) !void {
     const tv = decl.typed_value.most_recent.typed_value;
     try renderType(file, writer, tv.ty.fnReturnType(), decl.src());
-    const name = try map(file.allocator, mem.spanZ(decl.name));
-    defer file.allocator.free(name);
+    const name = try map(file.base.allocator, mem.spanZ(decl.name));
+    defer file.base.allocator.free(name);
     try writer.print(" {}(", .{name});
     if (tv.ty.fnParamLen() == 0)
         try writer.writeAll("void)")
@@ -64,8 +64,8 @@ pub fn generate(file: *C, decl: *Decl) !void {
 fn genArray(file: *C, decl: *Decl) !void {
     const tv = decl.typed_value.most_recent.typed_value;
     // TODO: prevent inline asm constants from being emitted
-    const name = try map(file.allocator, mem.span(decl.name));
-    defer file.allocator.free(name);
+    const name = try map(file.base.allocator, mem.span(decl.name));
+    defer file.base.allocator.free(name);
     if (tv.val.cast(Value.Payload.Bytes)) |payload|
         if (tv.ty.arraySentinel()) |sentinel|
             if (sentinel.toUnsignedInt() == 0)
src-self-hosted/codegen.zig
@@ -134,7 +134,7 @@ pub fn generateSymbol(
             }
             return Result{
                 .fail = try ErrorMsg.create(
-                    bin_file.allocator,
+                    bin_file.base.allocator,
                     src,
                     "TODO implement generateSymbol for more kinds of arrays",
                     .{},
@@ -150,21 +150,22 @@ pub fn generateSymbol(
                 // If the decl changes vaddr, then this symbol needs to get regenerated.
                 const vaddr = bin_file.local_symbols.items[decl.link.local_sym_index].st_value;
                 const endian = bin_file.base.options.target.cpu.arch.endian();
-                switch (bin_file.ptr_width) {
-                    .p32 => {
+                switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {
+                    32 => {
                         try code.resize(4);
                         mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian);
                     },
-                    .p64 => {
+                    64 => {
                         try code.resize(8);
                         mem.writeInt(u64, code.items[0..8], vaddr, endian);
                     },
+                    else => unreachable,
                 }
                 return Result{ .appended = {} };
             }
             return Result{
                 .fail = try ErrorMsg.create(
-                    bin_file.allocator,
+                    bin_file.base.allocator,
                     src,
                     "TODO implement generateSymbol for pointer {}",
                     .{typed_value.val},
@@ -180,7 +181,7 @@ pub fn generateSymbol(
             }
             return Result{
                 .fail = try ErrorMsg.create(
-                    bin_file.allocator,
+                    bin_file.base.allocator,
                     src,
                     "TODO implement generateSymbol for int type '{}'",
                     .{typed_value.ty},
@@ -190,7 +191,7 @@ pub fn generateSymbol(
         else => |t| {
             return Result{
                 .fail = try ErrorMsg.create(
-                    bin_file.allocator,
+                    bin_file.base.allocator,
                     src,
                     "TODO implement generateSymbol for type '{}'",
                     .{@tagName(t)},
@@ -387,10 +388,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
 
             const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
 
-            var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
+            var branch_stack = std.ArrayList(Branch).init(bin_file.base.allocator);
             defer {
                 assert(branch_stack.items.len == 1);
-                branch_stack.items[0].deinit(bin_file.allocator);
+                branch_stack.items[0].deinit(bin_file.base.allocator);
                 branch_stack.deinit();
             }
             const branch = try branch_stack.addOne();
@@ -413,7 +414,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
             };
 
             var function = Self{
-                .gpa = bin_file.allocator,
+                .gpa = bin_file.base.allocator,
                 .target = &bin_file.base.options.target,
                 .bin_file = bin_file,
                 .mod_fn = module_fn,
@@ -432,7 +433,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                 .rbrace_src = src_data.rbrace_src,
                 .source = src_data.source,
             };
-            defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
+            defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator);
 
             var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
                 error.CodegenFail => return Result{ .fail = function.err_msg.? },
@@ -2054,7 +2055,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
         fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) error{ CodegenFail, OutOfMemory } {
             @setCold(true);
             assert(self.err_msg == null);
-            self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args);
+            self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args);
             return error.CodegenFail;
         }
 
src-self-hosted/link.zig
@@ -36,9 +36,12 @@ pub const Options = struct {
     program_code_size_hint: u64 = 256 * 1024,
 };
 
+
 pub const File = struct {
     tag: Tag,
     options: Options,
+    file: ?fs.File,
+    allocator: *Allocator,
 
     /// Attempts incremental linking, if the file already exists. If
     /// incremental linking fails, falls back to truncating the file and
@@ -66,15 +69,23 @@ pub const File = struct {
 
     pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void {
         switch (base.tag) {
-            .elf => return @fieldParentPtr(Elf, "base", base).makeWritable(dir, sub_path),
+            .elf => {
+                if (base.file != null) return;
+                base.file = try dir.createFile(sub_path, .{
+                    .truncate = false,
+                    .read = true,
+                    .mode = determineMode(base.options),
+                });
+            },
             .c => {},
         }
     }
 
     pub fn makeExecutable(base: *File) !void {
-        switch (base.tag) {
-            .elf => return @fieldParentPtr(Elf, "base", base).makeExecutable(),
-            .c => unreachable,
+        std.debug.assert(base.tag != .c);
+        if (base.file) |f| {
+            f.close();
+            base.file = null;
         }
     }
 
@@ -100,6 +111,7 @@ pub const File = struct {
     }
 
     pub fn deinit(base: *File) void {
+        if (base.file) |f| f.close();
         switch (base.tag) {
             .elf => @fieldParentPtr(Elf, "base", base).deinit(),
             .c => @fieldParentPtr(C, "base", base).deinit(),
@@ -111,12 +123,12 @@ pub const File = struct {
             .elf => {
                 const parent = @fieldParentPtr(Elf, "base", base);
                 parent.deinit();
-                parent.allocator.destroy(parent);
+                base.allocator.destroy(parent);
             },
             .c => {
                 const parent = @fieldParentPtr(C, "base", base);
                 parent.deinit();
-                parent.allocator.destroy(parent);
+                base.allocator.destroy(parent);
             },
         }
     }
@@ -172,11 +184,10 @@ pub const File = struct {
 
         base: File,
 
-        allocator: *Allocator,
         header: std.ArrayList(u8),
         constants: std.ArrayList(u8),
         main: std.ArrayList(u8),
-        file: ?fs.File,
+
         called: std.StringHashMap(void),
         need_stddef: bool = false,
         need_stdint: bool = false,
@@ -196,9 +207,9 @@ pub const File = struct {
                 .base = .{
                     .tag = .c,
                     .options = options,
+                    .file = file,
+                    .allocator = allocator,
                 },
-                .allocator = allocator,
-                .file = file,
                 .main = std.ArrayList(u8).init(allocator),
                 .header = std.ArrayList(u8).init(allocator),
                 .constants = std.ArrayList(u8).init(allocator),
@@ -209,7 +220,7 @@ pub const File = struct {
         }
 
         pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
-            self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);
+            self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
             return error.AnalysisFail;
         }
 
@@ -218,8 +229,6 @@ pub const File = struct {
             self.header.deinit();
             self.constants.deinit();
             self.called.deinit();
-            if (self.file) |f|
-                f.close();
         }
 
         pub fn updateDecl(self: *File.C, module: *Module, decl: *Module.Decl) !void {
@@ -232,7 +241,7 @@ pub const File = struct {
         }
 
         pub fn flush(self: *File.C) !void {
-            const writer = self.file.?.writer();
+            const writer = self.base.file.?.writer();
             try writer.writeAll(@embedFile("cbe.h"));
             var includes = false;
             if (self.need_stddef) {
@@ -259,8 +268,8 @@ pub const File = struct {
                 }
             }
             try writer.writeAll(self.main.items);
-            self.file.?.close();
-            self.file = null;
+            self.base.file.?.close();
+            self.base.file = null;
         }
     };
 
@@ -269,9 +278,6 @@ pub const File = struct {
 
         base: File,
 
-        allocator: *Allocator,
-        file: ?fs.File,
-        owns_file_handle: bool,
         ptr_width: enum { p32, p64 },
 
         /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
@@ -454,7 +460,6 @@ pub const File = struct {
                 else => |e| return e,
             };
 
-            elf_file.owns_file_handle = true;
             return &elf_file.base;
         }
 
@@ -467,12 +472,11 @@ pub const File = struct {
             }
             var self: Elf = .{
                 .base = .{
+                    .file = file,
                     .tag = .elf,
                     .options = options,
+                    .allocator = allocator,
                 },
-                .allocator = allocator,
-                .file = file,
-                .owns_file_handle = false,
                 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
                     32 => .p32,
                     64 => .p64,
@@ -499,16 +503,15 @@ pub const File = struct {
                 .base = .{
                     .tag = .elf,
                     .options = options,
+                    .allocator = allocator,
+                    .file = file,
                 },
-                .allocator = allocator,
-                .file = file,
                 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
                     32 => .p32,
                     64 => .p64,
                     else => return error.UnsupportedELFArchitecture,
                 },
                 .shdr_table_dirty = true,
-                .owns_file_handle = false,
             };
             errdefer self.deinit();
 
@@ -542,39 +545,18 @@ pub const File = struct {
         }
 
         pub fn deinit(self: *Elf) void {
-            self.sections.deinit(self.allocator);
-            self.program_headers.deinit(self.allocator);
-            self.shstrtab.deinit(self.allocator);
-            self.debug_strtab.deinit(self.allocator);
-            self.local_symbols.deinit(self.allocator);
-            self.global_symbols.deinit(self.allocator);
-            self.global_symbol_free_list.deinit(self.allocator);
-            self.local_symbol_free_list.deinit(self.allocator);
-            self.offset_table_free_list.deinit(self.allocator);
-            self.text_block_free_list.deinit(self.allocator);
-            self.dbg_line_fn_free_list.deinit(self.allocator);
-            self.offset_table.deinit(self.allocator);
-            if (self.owns_file_handle) {
-                if (self.file) |f| f.close();
-            }
-        }
-
-        pub fn makeExecutable(self: *Elf) !void {
-            assert(self.owns_file_handle);
-            if (self.file) |f| {
-                f.close();
-                self.file = null;
-            }
-        }
-
-        pub fn makeWritable(self: *Elf, dir: fs.Dir, sub_path: []const u8) !void {
-            assert(self.owns_file_handle);
-            if (self.file != null) return;
-            self.file = try dir.createFile(sub_path, .{
-                .truncate = false,
-                .read = true,
-                .mode = determineMode(self.base.options),
-            });
+            self.sections.deinit(self.base.allocator);
+            self.program_headers.deinit(self.base.allocator);
+            self.shstrtab.deinit(self.base.allocator);
+            self.debug_strtab.deinit(self.base.allocator);
+            self.local_symbols.deinit(self.base.allocator);
+            self.global_symbols.deinit(self.base.allocator);
+            self.global_symbol_free_list.deinit(self.base.allocator);
+            self.local_symbol_free_list.deinit(self.base.allocator);
+            self.offset_table_free_list.deinit(self.base.allocator);
+            self.text_block_free_list.deinit(self.base.allocator);
+            self.dbg_line_fn_free_list.deinit(self.base.allocator);
+            self.offset_table.deinit(self.base.allocator);
         }
 
         fn getDebugLineProgramOff(self: Elf) u32 {
@@ -662,7 +644,7 @@ pub const File = struct {
 
         /// TODO Improve this to use a table.
         fn makeString(self: *Elf, bytes: []const u8) !u32 {
-            try self.shstrtab.ensureCapacity(self.allocator, self.shstrtab.items.len + bytes.len + 1);
+            try self.shstrtab.ensureCapacity(self.base.allocator, self.shstrtab.items.len + bytes.len + 1);
             const result = self.shstrtab.items.len;
             self.shstrtab.appendSliceAssumeCapacity(bytes);
             self.shstrtab.appendAssumeCapacity(0);
@@ -671,7 +653,7 @@ pub const File = struct {
 
         /// TODO Improve this to use a table.
         fn makeDebugString(self: *Elf, bytes: []const u8) !u32 {
-            try self.debug_strtab.ensureCapacity(self.allocator, self.debug_strtab.items.len + bytes.len + 1);
+            try self.debug_strtab.ensureCapacity(self.base.allocator, self.debug_strtab.items.len + bytes.len + 1);
             const result = self.debug_strtab.items.len;
             self.debug_strtab.appendSliceAssumeCapacity(bytes);
             self.debug_strtab.appendAssumeCapacity(0);
@@ -703,7 +685,7 @@ pub const File = struct {
                 const p_align = 0x1000;
                 const off = self.findFreeSpace(file_size, p_align);
                 log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
-                try self.program_headers.append(self.allocator, .{
+                try self.program_headers.append(self.base.allocator, .{
                     .p_type = elf.PT_LOAD,
                     .p_offset = off,
                     .p_filesz = file_size,
@@ -721,14 +703,14 @@ pub const File = struct {
                 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
                 // We really only need ptr alignment but since we are using PROGBITS, linux requires
                 // page align.
-                const p_align = 0x1000;
+                const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
                 const off = self.findFreeSpace(file_size, p_align);
                 log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
                 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
                 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
                 // else in virtual memory.
-                const default_got_addr = 0x4000000;
-                try self.program_headers.append(self.allocator, .{
+                const default_got_addr = if (ptr_size == 2) @as(u32, 0x8000) else 0x4000000;
+                try self.program_headers.append(self.base.allocator, .{
                     .p_type = elf.PT_LOAD,
                     .p_offset = off,
                     .p_filesz = file_size,
@@ -743,10 +725,10 @@ pub const File = struct {
             if (self.shstrtab_index == null) {
                 self.shstrtab_index = @intCast(u16, self.sections.items.len);
                 assert(self.shstrtab.items.len == 0);
-                try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
+                try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0
                 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
                 log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".shstrtab"),
                     .sh_type = elf.SHT_STRTAB,
                     .sh_flags = 0,
@@ -765,7 +747,7 @@ pub const File = struct {
                 self.text_section_index = @intCast(u16, self.sections.items.len);
                 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
 
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".text"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
@@ -783,7 +765,7 @@ pub const File = struct {
                 self.got_section_index = @intCast(u16, self.sections.items.len);
                 const phdr = &self.program_headers.items[self.phdr_got_index.?];
 
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".got"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = elf.SHF_ALLOC,
@@ -805,7 +787,7 @@ pub const File = struct {
                 const off = self.findFreeSpace(file_size, min_align);
                 log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
 
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".symtab"),
                     .sh_type = elf.SHT_SYMTAB,
                     .sh_flags = 0,
@@ -824,7 +806,7 @@ pub const File = struct {
             if (self.debug_str_section_index == null) {
                 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
                 assert(self.debug_strtab.items.len == 0);
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".debug_str"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
@@ -849,7 +831,7 @@ pub const File = struct {
                     off,
                     off + file_size_hint,
                 });
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".debug_info"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = 0,
@@ -874,7 +856,7 @@ pub const File = struct {
                     off,
                     off + file_size_hint,
                 });
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".debug_abbrev"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = 0,
@@ -899,7 +881,7 @@ pub const File = struct {
                     off,
                     off + file_size_hint,
                 });
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".debug_aranges"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = 0,
@@ -924,7 +906,7 @@ pub const File = struct {
                     off,
                     off + file_size_hint,
                 });
-                try self.sections.append(self.allocator, .{
+                try self.sections.append(self.base.allocator, .{
                     .sh_name = try self.makeString(".debug_line"),
                     .sh_type = elf.SHT_PROGBITS,
                     .sh_flags = 0,
@@ -1019,7 +1001,7 @@ pub const File = struct {
 
                 const abbrev_offset = 0;
                 self.debug_abbrev_table_offset = abbrev_offset;
-                try self.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset);
+                try self.base.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset);
                 if (!self.shdr_table_dirty) {
                     // Then it won't get written with the others and we need to do it.
                     try self.writeSectHeader(self.debug_abbrev_section_index.?);
@@ -1030,7 +1012,7 @@ pub const File = struct {
             if (self.debug_info_section_dirty) {
                 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
 
-                var di_buf = std.ArrayList(u8).init(self.allocator);
+                var di_buf = std.ArrayList(u8).init(self.base.allocator);
                 defer di_buf.deinit();
 
                 // Enough for a 64-bit header and main compilation unit without resizing.
@@ -1101,7 +1083,7 @@ pub const File = struct {
                     debug_info_sect.sh_offset + needed_size,
                 });
 
-                try self.file.?.pwriteAll(di_buf.items, debug_info_sect.sh_offset);
+                try self.base.file.?.pwriteAll(di_buf.items, debug_info_sect.sh_offset);
                 if (!self.shdr_table_dirty) {
                     // Then it won't get written with the others and we need to do it.
                     try self.writeSectHeader(self.debug_info_section_index.?);
@@ -1112,7 +1094,7 @@ pub const File = struct {
             if (self.debug_aranges_section_dirty) {
                 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
 
-                var di_buf = std.ArrayList(u8).init(self.allocator);
+                var di_buf = std.ArrayList(u8).init(self.base.allocator);
                 defer di_buf.deinit();
 
                 // Enough for all the data without resizing. When support for more compilation units
@@ -1172,7 +1154,7 @@ pub const File = struct {
                     debug_aranges_sect.sh_offset + needed_size,
                 });
 
-                try self.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset);
+                try self.base.file.?.pwriteAll(di_buf.items, debug_aranges_sect.sh_offset);
                 if (!self.shdr_table_dirty) {
                     // Then it won't get written with the others and we need to do it.
                     try self.writeSectHeader(self.debug_aranges_section_index.?);
@@ -1187,7 +1169,7 @@ pub const File = struct {
 
                 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
 
-                var di_buf = std.ArrayList(u8).init(self.allocator);
+                var di_buf = std.ArrayList(u8).init(self.base.allocator);
                 defer di_buf.deinit();
 
                 // The size of this header is variable, depending on the number of directories,
@@ -1294,8 +1276,8 @@ pub const File = struct {
 
                 switch (self.ptr_width) {
                     .p32 => {
-                        const buf = try self.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
-                        defer self.allocator.free(buf);
+                        const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
+                        defer self.base.allocator.free(buf);
 
                         for (buf) |*phdr, i| {
                             phdr.* = progHeaderTo32(self.program_headers.items[i]);
@@ -1303,11 +1285,11 @@ pub const File = struct {
                                 bswapAllFields(elf.Elf32_Phdr, phdr);
                             }
                         }
-                        try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
+                        try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
                     },
                     .p64 => {
-                        const buf = try self.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
-                        defer self.allocator.free(buf);
+                        const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
+                        defer self.base.allocator.free(buf);
 
                         for (buf) |*phdr, i| {
                             phdr.* = self.program_headers.items[i];
@@ -1315,7 +1297,7 @@ pub const File = struct {
                                 bswapAllFields(elf.Elf64_Phdr, phdr);
                             }
                         }
-                        try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
+                        try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
                     },
                 }
                 self.phdr_table_dirty = false;
@@ -1334,7 +1316,7 @@ pub const File = struct {
                     shstrtab_sect.sh_size = needed_size;
                     log.debug(.link, "writing shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
 
-                    try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
+                    try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
                     if (!self.shdr_table_dirty) {
                         // Then it won't get written with the others and we need to do it.
                         try self.writeSectHeader(self.shstrtab_index.?);
@@ -1355,7 +1337,7 @@ pub const File = struct {
                     debug_strtab_sect.sh_size = needed_size;
                     log.debug(.link, "debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size });
 
-                    try self.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset);
+                    try self.base.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset);
                     if (!self.shdr_table_dirty) {
                         // Then it won't get written with the others and we need to do it.
                         try self.writeSectHeader(self.debug_str_section_index.?);
@@ -1382,20 +1364,21 @@ pub const File = struct {
 
                 switch (self.ptr_width) {
                     .p32 => {
-                        const buf = try self.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
-                        defer self.allocator.free(buf);
+                        const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
+                        defer self.base.allocator.free(buf);
 
                         for (buf) |*shdr, i| {
                             shdr.* = sectHeaderTo32(self.sections.items[i]);
+                            std.log.debug(.link, "writing section {}\n", .{shdr.*});
                             if (foreign_endian) {
                                 bswapAllFields(elf.Elf32_Shdr, shdr);
                             }
                         }
-                        try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
+                        try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
                     },
                     .p64 => {
-                        const buf = try self.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
-                        defer self.allocator.free(buf);
+                        const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
+                        defer self.base.allocator.free(buf);
 
                         for (buf) |*shdr, i| {
                             shdr.* = self.sections.items[i];
@@ -1404,7 +1387,7 @@ pub const File = struct {
                                 bswapAllFields(elf.Elf64_Shdr, shdr);
                             }
                         }
-                        try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
+                        try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
                     },
                 }
                 self.shdr_table_dirty = false;
@@ -1557,7 +1540,7 @@ pub const File = struct {
 
             assert(index == e_ehsize);
 
-            try self.file.?.pwriteAll(hdr_buf[0..index], 0);
+            try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
         }
 
         fn freeTextBlock(self: *Elf, text_block: *TextBlock) void {
@@ -1587,7 +1570,7 @@ pub const File = struct {
                 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
                     // The free list is heuristics, it doesn't have to be perfect, so we can
                     // ignore the OOM here.
-                    self.text_block_free_list.append(self.allocator, prev) catch {};
+                    self.text_block_free_list.append(self.base.allocator, prev) catch {};
                 }
             } else {
                 text_block.prev = null;
@@ -1688,7 +1671,7 @@ pub const File = struct {
                         const sym = self.local_symbols.items[last.local_sym_index];
                         break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
                     } else 0;
-                    const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);
+                    const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size);
                     if (amt != text_size) return error.InputOutput;
                     shdr.sh_offset = new_offset;
                     phdr.p_offset = new_offset;
@@ -1739,8 +1722,8 @@ pub const File = struct {
         pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
             if (decl.link.local_sym_index != 0) return;
 
-            try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
-            try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
+            try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
+            try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
 
             if (self.local_symbol_free_list.popOrNull()) |i| {
                 log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name });
@@ -1776,8 +1759,8 @@ pub const File = struct {
             // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
             self.freeTextBlock(&decl.link);
             if (decl.link.local_sym_index != 0) {
-                self.local_symbol_free_list.append(self.allocator, decl.link.local_sym_index) catch {};
-                self.offset_table_free_list.append(self.allocator, decl.link.offset_table_index) catch {};
+                self.local_symbol_free_list.append(self.base.allocator, decl.link.local_sym_index) catch {};
+                self.offset_table_free_list.append(self.base.allocator, decl.link.offset_table_index) catch {};
 
                 self.local_symbols.items[decl.link.local_sym_index].st_info = 0;
 
@@ -1787,7 +1770,7 @@ pub const File = struct {
             // is desired for both.
             _ = self.dbg_line_fn_free_list.remove(&decl.fn_link);
             if (decl.fn_link.prev) |prev| {
-                _ = self.dbg_line_fn_free_list.put(self.allocator, prev, {}) catch {};
+                _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
                 prev.next = decl.fn_link.next;
                 if (decl.fn_link.next) |next| {
                     next.prev = prev;
@@ -1810,10 +1793,10 @@ pub const File = struct {
             const tracy = trace(@src());
             defer tracy.end();
 
-            var code_buffer = std.ArrayList(u8).init(self.allocator);
+            var code_buffer = std.ArrayList(u8).init(self.base.allocator);
             defer code_buffer.deinit();
 
-            var dbg_line_buffer = std.ArrayList(u8).init(self.allocator);
+            var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
             defer dbg_line_buffer.deinit();
 
             const typed_value = decl.typed_value.most_recent.typed_value;
@@ -1936,7 +1919,7 @@ pub const File = struct {
 
             const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr;
             const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
-            try self.file.?.pwriteAll(code, file_offset);
+            try self.base.file.?.pwriteAll(code, file_offset);
 
             // If the Decl is a function, we need to update the .debug_line program.
             if (is_fn) {
@@ -1966,7 +1949,7 @@ pub const File = struct {
                         if (src_fn.off + src_fn.len + min_nop_size > next.off) {
                             // It grew too big, so we move it to a new location.
                             if (src_fn.prev) |prev| {
-                                _ = self.dbg_line_fn_free_list.put(self.allocator, prev, {}) catch {};
+                                _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
                                 prev.next = src_fn.next;
                             }
                             next.prev = src_fn.prev;
@@ -2009,7 +1992,7 @@ pub const File = struct {
                             debug_line_sect.sh_offset,
                             new_offset,
                         });
-                        const amt = try self.file.?.copyRangeAll(debug_line_sect.sh_offset, self.file.?, new_offset, existing_size);
+                        const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
                         if (amt != existing_size) return error.InputOutput;
                         debug_line_sect.sh_offset = new_offset;
                     }
@@ -2041,7 +2024,7 @@ pub const File = struct {
             const tracy = trace(@src());
             defer tracy.end();
 
-            try self.global_symbols.ensureCapacity(self.allocator, self.global_symbols.items.len + exports.len);
+            try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
             const typed_value = decl.typed_value.most_recent.typed_value;
             if (decl.link.local_sym_index == 0) return;
             const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
@@ -2052,7 +2035,7 @@ pub const File = struct {
                         try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
                         module.failed_exports.putAssumeCapacityNoClobber(
                             exp,
-                            try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
+                            try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
                         );
                         continue;
                     }
@@ -2070,7 +2053,7 @@ pub const File = struct {
                         try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
                         module.failed_exports.putAssumeCapacityNoClobber(
                             exp,
-                            try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
+                            try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
                         );
                         continue;
                     },
@@ -2125,12 +2108,12 @@ pub const File = struct {
             const file_pos = shdr.sh_offset + decl.fn_link.off + self.getRelocDbgLineOff();
             var data: [4]u8 = undefined;
             leb128.writeUnsignedFixed(4, &data, casted_line_off);
-            try self.file.?.pwriteAll(&data, file_pos);
+            try self.base.file.?.pwriteAll(&data, file_pos);
         }
 
         pub fn deleteExport(self: *Elf, exp: Export) void {
             const sym_index = exp.sym_index orelse return;
-            self.global_symbol_free_list.append(self.allocator, sym_index) catch {};
+            self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
             self.global_symbols.items[sym_index].st_info = 0;
         }
 
@@ -2143,14 +2126,14 @@ pub const File = struct {
                     if (foreign_endian) {
                         bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
                     }
-                    return self.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
+                    return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
                 },
                 64 => {
                     var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
                     if (foreign_endian) {
                         bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
                     }
-                    return self.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
+                    return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
                 },
                 else => return error.UnsupportedArchitecture,
             }
@@ -2166,7 +2149,7 @@ pub const File = struct {
                         bswapAllFields(elf.Elf32_Shdr, &shdr[0]);
                     }
                     const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);
-                    return self.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
+                    return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
                 },
                 64 => {
                     var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
@@ -2174,7 +2157,7 @@ pub const File = struct {
                         bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
                     }
                     const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);
-                    return self.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
+                    return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
                 },
                 else => return error.UnsupportedArchitecture,
             }
@@ -2191,7 +2174,7 @@ pub const File = struct {
                 if (needed_size > allocated_size) {
                     // Must move the entire got section.
                     const new_offset = self.findFreeSpace(needed_size, entry_size);
-                    const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
+                    const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size);
                     if (amt != shdr.sh_size) return error.InputOutput;
                     shdr.sh_offset = new_offset;
                     phdr.p_offset = new_offset;
@@ -2211,12 +2194,12 @@ pub const File = struct {
                 .p32 => {
                     var buf: [4]u8 = undefined;
                     mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian);
-                    try self.file.?.pwriteAll(&buf, off);
+                    try self.base.file.?.pwriteAll(&buf, off);
                 },
                 .p64 => {
                     var buf: [8]u8 = undefined;
                     mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
-                    try self.file.?.pwriteAll(&buf, off);
+                    try self.base.file.?.pwriteAll(&buf, off);
                 },
             }
         }
@@ -2239,7 +2222,7 @@ pub const File = struct {
                     // Move all the symbols to a new file location.
                     const new_offset = self.findFreeSpace(needed_size, sym_align);
                     const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
-                    const amt = try self.file.?.copyRangeAll(syms_sect.sh_offset, self.file.?, new_offset, existing_size);
+                    const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size);
                     if (amt != existing_size) return error.InputOutput;
                     syms_sect.sh_offset = new_offset;
                 }
@@ -2264,7 +2247,7 @@ pub const File = struct {
                         bswapAllFields(elf.Elf32_Sym, &sym[0]);
                     }
                     const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;
-                    try self.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
+                    try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
                 },
                 .p64 => {
                     var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
@@ -2272,7 +2255,7 @@ pub const File = struct {
                         bswapAllFields(elf.Elf64_Sym, &sym[0]);
                     }
                     const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;
-                    try self.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
+                    try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
                 },
             }
         }
@@ -2287,8 +2270,8 @@ pub const File = struct {
             const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
             switch (self.ptr_width) {
                 .p32 => {
-                    const buf = try self.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len);
-                    defer self.allocator.free(buf);
+                    const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len);
+                    defer self.base.allocator.free(buf);
 
                     for (buf) |*sym, i| {
                         sym.* = .{
@@ -2303,11 +2286,11 @@ pub const File = struct {
                             bswapAllFields(elf.Elf32_Sym, sym);
                         }
                     }
-                    try self.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
+                    try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
                 },
                 .p64 => {
-                    const buf = try self.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
-                    defer self.allocator.free(buf);
+                    const buf = try self.base.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
+                    defer self.base.allocator.free(buf);
 
                     for (buf) |*sym, i| {
                         sym.* = .{
@@ -2322,7 +2305,7 @@ pub const File = struct {
                             bswapAllFields(elf.Elf64_Sym, sym);
                         }
                     }
-                    try self.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
+                    try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
                 },
             }
         }
@@ -2437,7 +2420,7 @@ pub const File = struct {
                     vec_index += 1;
                 }
             }
-            try self.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
+            try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
         }
 
         const min_nop_size = 2;