From 877d6df8f75a7fcfacea572d38f74ac66d045f32 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 8 Sep 2025 18:19:38 -0700 Subject: [PATCH] fix linker code writing undefined memory to the output file missing `extern` on a struct. but also all these instances that call pwriteAll with a `@ptrCast` are endianness bugs. this should be changed to use File.Writer and call writeSliceEndian instead. this commit fixes one immediate problem but does not fix everything. --- src/link/Coff.zig | 73 ++++++++++++++--------------- src/link/Elf.zig | 18 +++---- src/link/Elf/eh_frame.zig | 4 +- src/link/Elf/relocatable.zig | 4 +- src/link/Elf/synthetic_sections.zig | 10 ++-- src/link/MachO.zig | 2 +- src/link/MachO/DebugSymbols.zig | 2 +- src/link/MachO/UnwindInfo.zig | 2 +- src/link/MachO/relocatable.zig | 4 +- src/link/SpirV.zig | 3 +- 10 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index be9c4ff389..e016473531 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1,4 +1,38 @@ //! The main driver of the self-hosted COFF linker. +const Coff = @This(); + +const std = @import("std"); +const build_options = @import("build_options"); +const builtin = @import("builtin"); +const assert = std.debug.assert; +const coff_util = std.coff; +const fmt = std.fmt; +const fs = std.fs; +const log = std.log.scoped(.link); +const math = std.math; +const mem = std.mem; + +const Allocator = std.mem.Allocator; +const Path = std.Build.Cache.Path; +const Directory = std.Build.Cache.Directory; +const Cache = std.Build.Cache; + +const aarch64_util = link.aarch64; +const allocPrint = std.fmt.allocPrint; +const codegen = @import("../codegen.zig"); +const link = @import("../link.zig"); +const target_util = @import("../target.zig"); +const trace = @import("../tracy.zig").trace; + +const Compilation = @import("../Compilation.zig"); +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const TableSection = @import("table_section.zig").TableSection; +const StringTable = @import("StringTable.zig"); +const Type = @import("../Type.zig"); +const Value = @import("../Value.zig"); +const AnalUnit = InternPool.AnalUnit; +const dev = @import("../dev.zig"); base: link.File, image_base: u64, @@ -2168,12 +2202,12 @@ fn writeStrtab(coff: *Coff) !void { fn writeSectionHeaders(coff: *Coff) !void { const offset = coff.getSectionHeadersOffset(); - try coff.pwriteAll(mem.sliceAsBytes(coff.sections.items(.header)), offset); + try coff.pwriteAll(@ptrCast(coff.sections.items(.header)), offset); } fn writeDataDirectoriesHeaders(coff: *Coff) !void { const offset = coff.getDataDirectoryHeadersOffset(); - try coff.pwriteAll(mem.sliceAsBytes(&coff.data_directories), offset); + try coff.pwriteAll(@ptrCast(&coff.data_directories), offset); } fn writeHeader(coff: *Coff) !void { @@ -3068,41 +3102,6 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi }; } -const Coff = @This(); - -const std = @import("std"); -const build_options = @import("build_options"); -const builtin = @import("builtin"); -const assert = std.debug.assert; -const coff_util = std.coff; -const fmt = std.fmt; -const fs = std.fs; -const log = std.log.scoped(.link); -const math = std.math; -const mem = std.mem; - -const Allocator = std.mem.Allocator; -const Path = std.Build.Cache.Path; -const Directory = std.Build.Cache.Directory; -const Cache = std.Build.Cache; - -const aarch64_util = link.aarch64; -const allocPrint = std.fmt.allocPrint; -const codegen = @import("../codegen.zig"); -const link = @import("../link.zig"); -const target_util = @import("../target.zig"); -const trace = @import("../tracy.zig").trace; - -const Compilation = @import("../Compilation.zig"); -const Zcu = @import("../Zcu.zig"); -const InternPool = @import("../InternPool.zig"); -const TableSection = @import("table_section.zig").TableSection; -const StringTable = @import("StringTable.zig"); -const Type = @import("../Type.zig"); -const Value = @import("../Value.zig"); -const AnalUnit = InternPool.AnalUnit; -const dev = @import("../dev.zig"); - /// This is the start of a Portable Executable (PE) file. /// It starts with a MS-DOS header followed by a MS-DOS stub program. /// This data does not change so we include it as follows in all binaries. diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1c3d7c4267..f64e9c337b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1465,7 +1465,7 @@ pub fn writeShdrTable(self: *Elf) !void { mem.byteSwapAllFields(elf.Elf32_Shdr, shdr); } } - try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); + try self.pwriteAll(@ptrCast(buf), self.shdr_table_offset.?); }, .p64 => { const buf = try gpa.alloc(elf.Elf64_Shdr, self.sections.items(.shdr).len); @@ -1478,7 +1478,7 @@ pub fn writeShdrTable(self: *Elf) !void { mem.byteSwapAllFields(elf.Elf64_Shdr, shdr); } } - try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); + try self.pwriteAll(@ptrCast(buf), self.shdr_table_offset.?); }, } } @@ -1505,7 +1505,7 @@ fn writePhdrTable(self: *Elf) !void { mem.byteSwapAllFields(elf.Elf32_Phdr, phdr); } } - try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset); + try self.pwriteAll(@ptrCast(buf), phdr_table.p_offset); }, .p64 => { const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len); @@ -1517,7 +1517,7 @@ fn writePhdrTable(self: *Elf) !void { mem.byteSwapAllFields(elf.Elf64_Phdr, phdr); } } - try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset); + try self.pwriteAll(@ptrCast(buf), phdr_table.p_offset); }, } } @@ -3157,7 +3157,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.versym) |shndx| { const shdr = slice.items(.shdr)[shndx]; - try self.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset); + try self.pwriteAll(@ptrCast(self.versym.items), shdr.sh_offset); } if (self.section_indexes.verneed) |shndx| { @@ -3226,7 +3226,7 @@ fn writeSyntheticSections(self: *Elf) !void { try self.got.addRela(self); try self.copy_rel.addRela(self); self.sortRelaDyn(); - try self.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); + try self.pwriteAll(@ptrCast(self.rela_dyn.items), shdr.sh_offset); } if (self.section_indexes.plt) |shndx| { @@ -3256,7 +3256,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.rela_plt) |shndx| { const shdr = slice.items(.shdr)[shndx]; try self.plt.addRela(self); - try self.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset); + try self.pwriteAll(@ptrCast(self.rela_plt.items), shdr.sh_offset); } try self.writeSymtab(); @@ -3364,13 +3364,13 @@ pub fn writeSymtab(self: *Elf) !void { }; if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out); } - try self.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset); + try self.pwriteAll(@ptrCast(buf), symtab_shdr.sh_offset); }, .p64 => { if (foreign_endian) { for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym); } - try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset); + try self.pwriteAll(@ptrCast(self.symtab.items), symtab_shdr.sh_offset); }, } diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 9276692f13..03ab9b5ae0 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -482,7 +482,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { ); try writer.writeInt(u32, num_fdes, .little); - const Entry = struct { + const Entry = extern struct { init_addr: u32, fde_addr: u32, @@ -520,7 +520,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { } std.mem.sort(Entry, entries.items, {}, Entry.lessThan); - try writer.writeAll(std.mem.sliceAsBytes(entries.items)); + try writer.writeSliceEndian(Entry, entries.items, .little); } const eh_frame_hdr_header_size: usize = 12; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 4dd6e0370d..7adeecdcde 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -397,7 +397,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { shdr.sh_offset + shdr.sh_size, }); - try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); + try elf_file.base.file.?.pwriteAll(@ptrCast(relocs.items), shdr.sh_offset); } if (elf_file.section_indexes.eh_frame) |shndx| { @@ -435,7 +435,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { shdr.sh_offset, shdr.sh_offset + shdr.sh_size, }); - try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); + try elf_file.base.file.?.pwriteAll(@ptrCast(relocs.items), shdr.sh_offset); } try writeGroups(elf_file); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 2ff7302410..839d10dfbc 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1265,7 +1265,7 @@ pub const GnuHashSection = struct { bloom[idx] |= @as(u64, 1) << @as(u6, @intCast((h >> bloom_shift) % 64)); } - try writer.writeAll(mem.sliceAsBytes(bloom)); + try writer.writeSliceEndian(u64, bloom, .little); // Fill in the hash bucket indices const buckets = try gpa.alloc(u32, hash.num_buckets); @@ -1278,7 +1278,7 @@ pub const GnuHashSection = struct { } } - try writer.writeAll(mem.sliceAsBytes(buckets)); + try writer.writeSliceEndian(u32, buckets, .little); // Finally, write the hash table const table = try gpa.alloc(u32, hash.num_exports); @@ -1294,7 +1294,7 @@ pub const GnuHashSection = struct { } } - try writer.writeAll(mem.sliceAsBytes(table)); + try writer.writeSliceEndian(u32, table, .little); } pub fn hasher(name: [:0]const u8) u32 { @@ -1442,8 +1442,8 @@ pub const VerneedSection = struct { } pub fn write(vern: VerneedSection, writer: *std.Io.Writer) !void { - try writer.writeAll(mem.sliceAsBytes(vern.verneed.items)); - try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items)); + try writer.writeSliceEndian(elf.Elf64_Verneed, vern.verneed.items, .little); + try writer.writeSliceEndian(elf.Vernaux, vern.vernaux.items, .little); } }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 9205d51981..d819e39097 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2711,7 +2711,7 @@ pub fn writeSymtabToFile(self: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); const cmd = self.symtab_cmd; - try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); + try self.pwriteAll(@ptrCast(self.symtab.items), cmd.symoff); try self.pwriteAll(self.strtab.items, cmd.stroff); } diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 550dd3d63d..a7aea586ad 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -403,7 +403,7 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { internal.writeSymtab(macho_file, self); } - try self.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); + try self.file.?.pwriteAll(@ptrCast(self.symtab.items), cmd.symoff); return off + cmd.nsyms * @sizeOf(macho.nlist_64); } diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index 5dff5450f5..adfdcba81c 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -311,7 +311,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { .indexCount = indexes_count, }), .little); - try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count])); + try writer.writeSliceEndian(Encoding, info.common_encodings[0..info.common_encodings_count], .little); for (info.personalities[0..info.personalities_count]) |ref| { const sym = ref.getSymbol(macho_file).?; diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 77ee587b75..920125136b 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -676,11 +676,11 @@ fn writeSectionsToFile(macho_file: *MachO) !void { const slice = macho_file.sections.slice(); for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| { try macho_file.pwriteAll(out.items, header.offset); - try macho_file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); + try macho_file.pwriteAll(@ptrCast(relocs.items), header.reloff); } try macho_file.writeDataInCode(); - try macho_file.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); + try macho_file.pwriteAll(@ptrCast(macho_file.symtab.items), macho_file.symtab_cmd.symoff); try macho_file.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); } diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 34356b5e86..7e28dc0a8b 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -285,7 +285,8 @@ pub fn flush( else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}), }; - linker.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)) catch |err| + // TODO endianness bug. use file writer and call writeSliceEndian instead + linker.base.file.?.writeAll(@ptrCast(linked_module)) catch |err| return diags.fail("failed to write: {s}", .{@errorName(err)}); }