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.
This commit is contained in:
Andrew Kelley 2025-09-08 18:19:38 -07:00
parent eac2bbfec9
commit 877d6df8f7
10 changed files with 61 additions and 61 deletions

View file

@ -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.

View file

@ -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);
},
}

View file

@ -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;

View file

@ -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);

View file

@ -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);
}
};

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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).?;

View file

@ -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);
}

View file

@ -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)});
}