Coff2: create a new linker from scratch

This commit is contained in:
Jacob Young 2025-09-21 23:14:28 -04:00
parent d5f09f56e0
commit e1f3fc6ce2
58 changed files with 3493 additions and 911 deletions

View File

@ -1082,7 +1082,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
}; };
} }
pub fn toCoffMachine(target: *const Target) std.coff.MachineType { pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
return switch (target.cpu.arch) { return switch (target.cpu.arch) {
.arm => .ARM, .arm => .ARM,
.thumb => .ARMNT, .thumb => .ARMNT,
@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
.riscv32 => .RISCV32, .riscv32 => .RISCV32,
.riscv64 => .RISCV64, .riscv64 => .RISCV64,
.x86 => .I386, .x86 => .I386,
.x86_64 => .X64, .x86_64 => .AMD64,
.amdgcn, .amdgcn,
.arc, .arc,

View File

@ -50,7 +50,7 @@ pub fn eqlString(a: []const u8, b: []const u8) bool {
} }
pub fn hashString(s: []const u8) u32 { pub fn hashString(s: []const u8) u32 {
return @as(u32, @truncate(std.hash.Wyhash.hash(0, s))); return @truncate(std.hash.Wyhash.hash(0, s));
} }
/// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed) /// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed)

File diff suppressed because it is too large Load Diff

View File

@ -78,13 +78,15 @@ pub fn defaultQueryPageSize() usize {
}; };
var size = global.cached_result.load(.unordered); var size = global.cached_result.load(.unordered);
if (size > 0) return size; if (size > 0) return size;
size = switch (builtin.os.tag) { size = size: switch (builtin.os.tag) {
.linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ), .linux => if (builtin.link_libc)
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: { @max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0)
else
std.os.linux.getauxval(std.elf.AT_PAGESZ),
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
const task_port = std.c.mach_task_self(); const task_port = std.c.mach_task_self();
// mach_task_self may fail "if there are any resource failures or other errors". // mach_task_self may fail "if there are any resource failures or other errors".
if (task_port == std.c.TASK.NULL) if (task_port == std.c.TASK.NULL) break :size 0;
break :blk 0;
var info_count = std.c.TASK.VM.INFO_COUNT; var info_count = std.c.TASK.VM.INFO_COUNT;
var vm_info: std.c.task_vm_info_data_t = undefined; var vm_info: std.c.task_vm_info_data_t = undefined;
vm_info.page_size = 0; vm_info.page_size = 0;
@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize {
@as(std.c.task_info_t, @ptrCast(&vm_info)), @as(std.c.task_info_t, @ptrCast(&vm_info)),
&info_count, &info_count,
); );
assert(vm_info.page_size != 0); break :size @intCast(vm_info.page_size);
break :blk @intCast(vm_info.page_size);
}, },
.windows => blk: { .windows => {
var info: std.os.windows.SYSTEM_INFO = undefined; var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
std.os.windows.kernel32.GetSystemInfo(&info); switch (windows.ntdll.NtQuerySystemInformation(
break :blk info.dwPageSize; .SystemBasicInformation,
&sbi,
@sizeOf(windows.SYSTEM_BASIC_INFORMATION),
null,
)) {
.SUCCESS => break :size sbi.PageSize,
else => break :size 0,
}
}, },
else => if (builtin.link_libc) else => if (builtin.link_libc)
@intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) @max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0)
else if (builtin.os.tag == .freestanding or builtin.os.tag == .other) else if (builtin.os.tag == .freestanding or builtin.os.tag == .other)
@compileError("unsupported target: freestanding/other") @compileError("unsupported target: freestanding/other")
else else
@compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"), @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"),
}; };
if (size == 0) size = page_size_max;
assert(size >= page_size_min); assert(size >= page_size_min);
assert(size <= page_size_max); assert(size <= page_size_max);

View File

@ -256,8 +256,8 @@ test_filters: []const []const u8,
link_task_wait_group: WaitGroup = .{}, link_task_wait_group: WaitGroup = .{},
link_prog_node: std.Progress.Node = .none, link_prog_node: std.Progress.Node = .none,
link_uav_prog_node: std.Progress.Node = .none, link_const_prog_node: std.Progress.Node = .none,
link_lazy_prog_node: std.Progress.Node = .none, link_synth_prog_node: std.Progress.Node = .none,
llvm_opt_bisect_limit: c_int, llvm_opt_bisect_limit: c_int,
@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
}; };
if (have_zcu and (!need_llvm or use_llvm)) { if (have_zcu and (!need_llvm or use_llvm)) {
if (output_mode == .Obj) break :s .zcu; if (output_mode == .Obj) break :s .zcu;
if (options.config.use_new_linker) break :s .zcu;
switch (target_util.zigBackend(target, use_llvm)) { switch (target_util.zigBackend(target, use_llvm)) {
else => {}, else => {},
.stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
}, },
} }
if (options.config.use_new_linker) break :s .zcu;
} }
if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
if (is_exe_or_dyn_lib) break :s .lib; if (is_exe_or_dyn_lib) break :s .lib;
@ -3081,22 +3081,30 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
comp.link_prog_node = main_progress_node.start("Linking", 0); comp.link_prog_node = main_progress_node.start("Linking", 0);
if (lf.cast(.elf2)) |elf| { if (lf.cast(.elf2)) |elf| {
comp.link_prog_node.increaseEstimatedTotalItems(3); comp.link_prog_node.increaseEstimatedTotalItems(3);
comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0); comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0); comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len); elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);
} else if (lf.cast(.coff2)) |coff| {
comp.link_prog_node.increaseEstimatedTotalItems(3);
comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
coff.mf.update_prog_node = comp.link_prog_node.start("Relocations", coff.mf.updates.items.len);
} }
} }
defer { defer {
comp.link_prog_node.end(); comp.link_prog_node.end();
comp.link_prog_node = .none; comp.link_prog_node = .none;
comp.link_uav_prog_node.end(); comp.link_const_prog_node.end();
comp.link_uav_prog_node = .none; comp.link_const_prog_node = .none;
comp.link_lazy_prog_node.end(); comp.link_synth_prog_node.end();
comp.link_lazy_prog_node = .none; comp.link_synth_prog_node = .none;
if (comp.bin_file) |lf| { if (comp.bin_file) |lf| {
if (lf.cast(.elf2)) |elf| { if (lf.cast(.elf2)) |elf| {
elf.mf.update_prog_node.end(); elf.mf.update_prog_node.end();
elf.mf.update_prog_node = .none; elf.mf.update_prog_node = .none;
} else if (lf.cast(.coff2)) |coff| {
coff.mf.update_prog_node.end();
coff.mf.update_prog_node = .none;
} }
} }
} }

View File

@ -438,6 +438,8 @@ pub fn resolve(options: Options) ResolveError!Config {
if (options.use_new_linker) |x| break :b x; if (options.use_new_linker) |x| break :b x;
if (target.ofmt == .coff) break :b true;
break :b options.incremental; break :b options.incremental;
}; };

View File

@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString
var map_index = hash; var map_index = hash;
while (true) : (map_index += 1) { while (true) : (map_index += 1) {
map_index &= map_mask; map_index &= map_mask;
const entry = map.at(map_index); const entry = &map.entries[map_index];
const index = entry.acquire().unwrap() orelse return null; const index = entry.value.unwrap() orelse return .none;
if (entry.hash != hash) continue; if (entry.hash != hash) continue;
if (index.eqlSlice(key, ip)) return index; if (index.eqlSlice(key, ip)) return index.toOptional();
} }
} }

View File

@ -993,6 +993,8 @@ pub fn genNavRef(
}, },
.link_once => unreachable, .link_once => unreachable,
} }
} else if (lf.cast(.coff2)) |coff| {
return .{ .sym_index = @intFromEnum(try coff.navSymbol(zcu, nav_index)) };
} else { } else {
const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target}); const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
return .{ .fail = msg }; return .{ .fail = msg };

View File

@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void {
} }
var reloc_info_buf: [2]RelocInfo = undefined; var reloc_info_buf: [2]RelocInfo = undefined;
var reloc_info_index: usize = 0; var reloc_info_index: usize = 0;
const ip = &emit.pt.zcu.intern_pool;
while (lowered_relocs.len > 0 and while (lowered_relocs.len > 0 and
lowered_relocs[0].lowered_inst_index == lowered_index) : ({ lowered_relocs[0].lowered_inst_index == lowered_index) : ({
lowered_relocs = lowered_relocs[1..]; lowered_relocs = lowered_relocs[1..];
@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void {
return error.EmitFail; return error.EmitFail;
}, },
}; };
const ip = &emit.pt.zcu.intern_pool;
break :target switch (ip.getNav(nav).status) { break :target switch (ip.getNav(nav).status) {
.unresolved => unreachable, .unresolved => unreachable,
.type_resolved => |type_resolved| .{ .type_resolved => |type_resolved| .{
@ -175,6 +175,8 @@ pub fn emitMir(emit: *Emit) Error!void {
coff_file.getAtom(atom).getSymbolIndex().? coff_file.getAtom(atom).getSymbolIndex().?
else |err| else |err|
return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
else if (emit.bin_file.cast(.coff2)) |elf|
@intFromEnum(try elf.lazySymbol(lazy_sym))
else else
return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
.is_extern = false, .is_extern = false,
@ -190,8 +192,13 @@ pub fn emitMir(emit: *Emit) Error!void {
try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
else if (emit.bin_file.cast(.coff)) |coff_file| else if (emit.bin_file.cast(.coff)) |coff_file|
try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt") try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")
else else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(
return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), extern_func.toSlice(&emit.lower.mir).?,
switch (comp.compiler_rt_strat) {
.none, .lib, .obj, .zcu => null,
.dyn_lib => "compiler_rt",
},
)) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
.is_extern = true, .is_extern = true,
.type = .symbol, .type = .symbol,
}, },
@ -314,6 +321,18 @@ pub fn emitMir(emit: *Emit) Error!void {
}, emit.lower.target), reloc_info), }, emit.lower.target), reloc_info),
else => unreachable, else => unreachable,
} }
} else if (emit.bin_file.cast(.coff2)) |_| {
switch (lowered_inst.encoding.mnemonic) {
.lea => try emit.encodeInst(try .new(.none, .lea, &.{
lowered_inst.ops[0],
.{ .mem = .initRip(.none, 0) },
}, emit.lower.target), reloc_info),
.mov => try emit.encodeInst(try .new(.none, .mov, &.{
lowered_inst.ops[0],
.{ .mem = .initRip(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, 0) },
}, emit.lower.target), reloc_info),
else => unreachable,
}
} else return emit.fail("TODO implement relocs for {s}", .{ } else return emit.fail("TODO implement relocs for {s}", .{
@tagName(emit.bin_file.tag), @tagName(emit.bin_file.tag),
}); });
@ -683,7 +702,7 @@ pub fn emitMir(emit: *Emit) Error!void {
table_reloc.source_offset, table_reloc.source_offset,
@enumFromInt(emit.atom_index), @enumFromInt(emit.atom_index),
@as(i64, table_offset) + table_reloc.target_offset, @as(i64, table_offset) + table_reloc.target_offset,
.{ .x86_64 = .@"32" }, .{ .X86_64 = .@"32" },
); );
for (emit.lower.mir.table) |entry| { for (emit.lower.mir.table) |entry| {
try elf.addReloc( try elf.addReloc(
@ -691,7 +710,7 @@ pub fn emitMir(emit: *Emit) Error!void {
table_offset, table_offset,
@enumFromInt(emit.atom_index), @enumFromInt(emit.atom_index),
emit.code_offset_mapping.items[entry], emit.code_offset_mapping.items[entry],
.{ .x86_64 = .@"64" }, .{ .X86_64 = .@"64" },
); );
table_offset += ptr_size; table_offset += ptr_size;
} }
@ -800,7 +819,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4, end_offset - 4,
@enumFromInt(reloc.target.index), @enumFromInt(reloc.target.index),
reloc.off, reloc.off,
.{ .x86_64 = .@"32" }, .{ .X86_64 = .@"32" },
) else if (emit.bin_file.cast(.coff)) |coff_file| { ) else if (emit.bin_file.cast(.coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol( const atom_index = coff_file.getAtomIndexForSymbol(
.{ .sym_index = emit.atom_index, .file = null }, .{ .sym_index = emit.atom_index, .file = null },
@ -816,7 +835,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
.pcrel = true, .pcrel = true,
.length = 2, .length = 2,
}); });
} else unreachable, } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
@enumFromInt(emit.atom_index),
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .AMD64 = .REL32 },
) else unreachable,
.branch => if (emit.bin_file.cast(.elf)) |elf_file| { .branch => if (emit.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?; const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
@ -831,7 +856,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4, end_offset - 4,
@enumFromInt(reloc.target.index), @enumFromInt(reloc.target.index),
reloc.off - 4, reloc.off - 4,
.{ .x86_64 = .PC32 }, .{ .X86_64 = .PC32 },
) else if (emit.bin_file.cast(.macho)) |macho_file| { ) else if (emit.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?; const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
@ -863,7 +888,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
.pcrel = true, .pcrel = true,
.length = 2, .length = 2,
}); });
} else return emit.fail("TODO implement {s} reloc for {s}", .{ } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
@enumFromInt(emit.atom_index),
end_offset - 4,
@enumFromInt(reloc.target.index),
reloc.off,
.{ .AMD64 = .REL32 },
) else return emit.fail("TODO implement {s} reloc for {s}", .{
@tagName(reloc.target.type), @tagName(emit.bin_file.tag), @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
}), }),
.tls => if (emit.bin_file.cast(.elf)) |elf_file| { .tls => if (emit.bin_file.cast(.elf)) |elf_file| {
@ -892,7 +923,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
end_offset - 4, end_offset - 4,
@enumFromInt(reloc.target.index), @enumFromInt(reloc.target.index),
reloc.off, reloc.off,
.{ .x86_64 = .TPOFF32 }, .{ .X86_64 = .TPOFF32 },
) else if (emit.bin_file.cast(.macho)) |macho_file| { ) else if (emit.bin_file.cast(.macho)) |macho_file| {
const zo = macho_file.getZigObject().?; const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;

View File

@ -96,6 +96,7 @@ pub const Env = enum {
.spirv_backend, .spirv_backend,
.lld_linker, .lld_linker,
.coff_linker, .coff_linker,
.coff2_linker,
.elf_linker, .elf_linker,
.elf2_linker, .elf2_linker,
.macho_linker, .macho_linker,
@ -284,6 +285,7 @@ pub const Feature = enum {
lld_linker, lld_linker,
coff_linker, coff_linker,
coff2_linker,
elf_linker, elf_linker,
elf2_linker, elf2_linker,
macho_linker, macho_linker,

View File

@ -610,27 +610,20 @@ pub const File = struct {
} }
} }
} }
const output_mode = comp.config.output_mode; base.file = try emit.root_dir.handle.openFile(emit.sub_path, .{ .mode = .read_write });
const link_mode = comp.config.link_mode;
base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
.truncate = false,
.read = true,
.mode = determineMode(output_mode, link_mode),
});
}, },
.elf2 => { .elf2, .coff2 => if (base.file == null) {
const elf = base.cast(.elf2).?; const mf = if (base.cast(.elf2)) |elf|
if (base.file == null) { &elf.mf
elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{ else if (base.cast(.coff2)) |coff|
.truncate = false, &coff.mf
.read = true, else
.mode = determineMode(comp.config.output_mode, comp.config.link_mode), unreachable;
mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
.mode = .read_write,
}); });
base.file = elf.mf.file; base.file = mf.file;
try elf.mf.ensureTotalCapacity( try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
@intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]),
);
}
}, },
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
.plan9 => unreachable, .plan9 => unreachable,
@ -654,12 +647,9 @@ pub const File = struct {
pub fn makeExecutable(base: *File) !void { pub fn makeExecutable(base: *File) !void {
dev.check(.make_executable); dev.check(.make_executable);
const comp = base.comp; const comp = base.comp;
const output_mode = comp.config.output_mode; switch (comp.config.output_mode) {
const link_mode = comp.config.link_mode;
switch (output_mode) {
.Obj => return, .Obj => return,
.Lib => switch (link_mode) { .Lib => switch (comp.config.link_mode) {
.static => return, .static => return,
.dynamic => {}, .dynamic => {},
}, },
@ -702,15 +692,18 @@ pub const File = struct {
} }
} }
}, },
.elf2 => { .elf2, .coff2 => if (base.file) |f| {
const elf = base.cast(.elf2).?; const mf = if (base.cast(.elf2)) |elf|
if (base.file) |f| { &elf.mf
elf.mf.unmap(); else if (base.cast(.coff2)) |coff|
assert(elf.mf.file.handle == f.handle); &coff.mf
elf.mf.file = undefined; else
unreachable;
mf.unmap();
assert(mf.file.handle == f.handle);
mf.file = undefined;
f.close(); f.close();
base.file = null; base.file = null;
}
}, },
.c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
.plan9 => unreachable, .plan9 => unreachable,
@ -828,7 +821,7 @@ pub const File = struct {
.spirv => {}, .spirv => {},
.goff, .xcoff => {}, .goff, .xcoff => {},
.plan9 => unreachable, .plan9 => unreachable,
.elf2 => {}, .elf2, .coff2 => {},
inline else => |tag| { inline else => |tag| {
dev.check(tag.devFeature()); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
@ -864,7 +857,7 @@ pub const File = struct {
pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool { pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {
switch (base.tag) { switch (base.tag) {
else => return false, else => return false,
inline .elf2 => |tag| { inline .elf2, .coff2 => |tag| {
dev.check(tag.devFeature()); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid); return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);
}, },
@ -874,7 +867,7 @@ pub const File = struct {
pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void { pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {
switch (base.tag) { switch (base.tag) {
else => {}, else => {},
inline .elf2 => |tag| { inline .elf2, .coff2 => |tag| {
dev.check(tag.devFeature()); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);
}, },
@ -1155,7 +1148,7 @@ pub const File = struct {
if (base.zcu_object_basename != null) return; if (base.zcu_object_basename != null) return;
switch (base.tag) { switch (base.tag) {
inline .elf2, .wasm => |tag| { inline .elf2, .coff2, .wasm => |tag| {
dev.check(tag.devFeature()); dev.check(tag.devFeature());
return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);
}, },
@ -1165,6 +1158,7 @@ pub const File = struct {
pub const Tag = enum { pub const Tag = enum {
coff, coff,
coff2,
elf, elf,
elf2, elf2,
macho, macho,
@ -1179,6 +1173,7 @@ pub const File = struct {
pub fn Type(comptime tag: Tag) type { pub fn Type(comptime tag: Tag) type {
return switch (tag) { return switch (tag) {
.coff => Coff, .coff => Coff,
.coff2 => Coff2,
.elf => Elf, .elf => Elf,
.elf2 => Elf2, .elf2 => Elf2,
.macho => MachO, .macho => MachO,
@ -1194,7 +1189,7 @@ pub const File = struct {
fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag { fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {
return switch (ofmt) { return switch (ofmt) {
.coff => .coff, .coff => if (use_new_linker) .coff2 else .coff,
.elf => if (use_new_linker) .elf2 else .elf, .elf => if (use_new_linker) .elf2 else .elf,
.macho => .macho, .macho => .macho,
.wasm => .wasm, .wasm => .wasm,
@ -1280,6 +1275,7 @@ pub const File = struct {
pub const Lld = @import("link/Lld.zig"); pub const Lld = @import("link/Lld.zig");
pub const C = @import("link/C.zig"); pub const C = @import("link/C.zig");
pub const Coff = @import("link/Coff.zig"); pub const Coff = @import("link/Coff.zig");
pub const Coff2 = @import("link/Coff2.zig");
pub const Elf = @import("link/Elf.zig"); pub const Elf = @import("link/Elf.zig");
pub const Elf2 = @import("link/Elf2.zig"); pub const Elf2 = @import("link/Elf2.zig");
pub const MachO = @import("link/MachO.zig"); pub const MachO = @import("link/MachO.zig");

View File

@ -125,11 +125,11 @@ const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
const default_file_alignment: u16 = 0x200; pub const default_file_alignment: u16 = 0x200;
const default_size_of_stack_reserve: u32 = 0x1000000; pub const default_size_of_stack_reserve: u32 = 0x1000000;
const default_size_of_stack_commit: u32 = 0x1000; pub const default_size_of_stack_commit: u32 = 0x1000;
const default_size_of_heap_reserve: u32 = 0x100000; pub const default_size_of_heap_reserve: u32 = 0x100000;
const default_size_of_heap_commit: u32 = 0x1000; pub const default_size_of_heap_commit: u32 = 0x1000;
const Section = struct { const Section = struct {
header: coff_util.SectionHeader, header: coff_util.SectionHeader,
@ -334,51 +334,51 @@ pub fn createEmpty(
if (coff.text_section_index == null) { if (coff.text_section_index == null) {
const file_size: u32 = @intCast(options.program_code_size_hint); const file_size: u32 = @intCast(options.program_code_size_hint);
coff.text_section_index = try coff.allocateSection(".text", file_size, .{ coff.text_section_index = try coff.allocateSection(".text", file_size, .{
.CNT_CODE = 1, .CNT_CODE = true,
.MEM_EXECUTE = 1, .MEM_EXECUTE = true,
.MEM_READ = 1, .MEM_READ = true,
}); });
} }
if (coff.got_section_index == null) { if (coff.got_section_index == null) {
const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
coff.got_section_index = try coff.allocateSection(".got", file_size, .{ coff.got_section_index = try coff.allocateSection(".got", file_size, .{
.CNT_INITIALIZED_DATA = 1, .CNT_INITIALIZED_DATA = true,
.MEM_READ = 1, .MEM_READ = true,
}); });
} }
if (coff.rdata_section_index == null) { if (coff.rdata_section_index == null) {
const file_size: u32 = coff.page_size; const file_size: u32 = coff.page_size;
coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{ coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{
.CNT_INITIALIZED_DATA = 1, .CNT_INITIALIZED_DATA = true,
.MEM_READ = 1, .MEM_READ = true,
}); });
} }
if (coff.data_section_index == null) { if (coff.data_section_index == null) {
const file_size: u32 = coff.page_size; const file_size: u32 = coff.page_size;
coff.data_section_index = try coff.allocateSection(".data", file_size, .{ coff.data_section_index = try coff.allocateSection(".data", file_size, .{
.CNT_INITIALIZED_DATA = 1, .CNT_INITIALIZED_DATA = true,
.MEM_READ = 1, .MEM_READ = true,
.MEM_WRITE = 1, .MEM_WRITE = true,
}); });
} }
if (coff.idata_section_index == null) { if (coff.idata_section_index == null) {
const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{ coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{
.CNT_INITIALIZED_DATA = 1, .CNT_INITIALIZED_DATA = true,
.MEM_READ = 1, .MEM_READ = true,
}); });
} }
if (coff.reloc_section_index == null) { if (coff.reloc_section_index == null) {
const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation); const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);
coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{ coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{
.CNT_INITIALIZED_DATA = 1, .CNT_INITIALIZED_DATA = true,
.MEM_DISCARDABLE = 1, .MEM_DISCARDABLE = true,
.MEM_READ = 1, .MEM_READ = true,
}); });
} }
@ -477,7 +477,7 @@ pub fn deinit(coff: *Coff) void {
coff.base_relocs.deinit(gpa); coff.base_relocs.deinit(gpa);
} }
fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 { fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeader.Flags) !u16 {
const index = @as(u16, @intCast(coff.sections.slice().len)); const index = @as(u16, @intCast(coff.sections.slice().len));
const off = coff.findFreeSpace(size, default_file_alignment); const off = coff.findFreeSpace(size, default_file_alignment);
// Memory is always allocated in sequence // Memory is always allocated in sequence
@ -836,7 +836,7 @@ fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8, resolve_relocs: bo
try debugMem(gpa, handle, pvaddr, mem_code); try debugMem(gpa, handle, pvaddr, mem_code);
} }
if (section.header.flags.MEM_WRITE == 0) { if (!section.header.flags.MEM_WRITE) {
writeMemProtected(handle, pvaddr, mem_code) catch |err| { writeMemProtected(handle, pvaddr, mem_code) catch |err| {
log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)}); log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
}; };
@ -2227,21 +2227,21 @@ fn writeHeader(coff: *Coff) !void {
mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little); mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little);
writer.writeAll("PE\x00\x00") catch unreachable; writer.writeAll("PE\x00\x00") catch unreachable;
var flags = coff_util.CoffHeaderFlags{ var flags: coff_util.Header.Flags = .{
.EXECUTABLE_IMAGE = 1, .EXECUTABLE_IMAGE = true,
.DEBUG_STRIPPED = 1, // TODO .DEBUG_STRIPPED = true, // TODO
}; };
switch (coff.ptr_width) { switch (coff.ptr_width) {
.p32 => flags.@"32BIT_MACHINE" = 1, .p32 => flags.@"32BIT_MACHINE" = true,
.p64 => flags.LARGE_ADDRESS_AWARE = 1, .p64 => flags.LARGE_ADDRESS_AWARE = true,
} }
if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) { if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) {
flags.DLL = 1; flags.DLL = true;
} }
const timestamp = if (coff.repro) 0 else std.time.timestamp(); const timestamp = if (coff.repro) 0 else std.time.timestamp();
const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize())); const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize()));
var coff_header = coff_util.CoffHeader{ var coff_header: coff_util.Header = .{
.machine = target.toCoffMachine(), .machine = target.toCoffMachine(),
.number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section
.time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))), .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
@ -2254,10 +2254,10 @@ fn writeHeader(coff: *Coff) !void {
writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
const dll_flags: coff_util.DllFlags = .{ const dll_flags: coff_util.DllFlags = .{
.HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? .HIGH_ENTROPY_VA = true, // TODO do we want to permit non-PIE builds at all?
.DYNAMIC_BASE = 1, .DYNAMIC_BASE = true,
.TERMINAL_SERVER_AWARE = 1, // We are not a legacy app .TERMINAL_SERVER_AWARE = true, // We are not a legacy app
.NX_COMPAT = 1, // We are compatible with Data Execution Prevention .NX_COMPAT = true, // We are compatible with Data Execution Prevention
}; };
const subsystem: coff_util.Subsystem = .WINDOWS_CUI; const subsystem: coff_util.Subsystem = .WINDOWS_CUI;
const size_of_image: u32 = coff.getSizeOfImage(); const size_of_image: u32 = coff.getSizeOfImage();
@ -2269,13 +2269,13 @@ fn writeHeader(coff: *Coff) !void {
var size_of_initialized_data: u32 = 0; var size_of_initialized_data: u32 = 0;
var size_of_uninitialized_data: u32 = 0; var size_of_uninitialized_data: u32 = 0;
for (coff.sections.items(.header)) |header| { for (coff.sections.items(.header)) |header| {
if (header.flags.CNT_CODE == 1) { if (header.flags.CNT_CODE) {
size_of_code += header.size_of_raw_data; size_of_code += header.size_of_raw_data;
} }
if (header.flags.CNT_INITIALIZED_DATA == 1) { if (header.flags.CNT_INITIALIZED_DATA) {
size_of_initialized_data += header.size_of_raw_data; size_of_initialized_data += header.size_of_raw_data;
} }
if (header.flags.CNT_UNINITIALIZED_DATA == 1) { if (header.flags.CNT_UNINITIALIZED_DATA) {
size_of_uninitialized_data += header.size_of_raw_data; size_of_uninitialized_data += header.size_of_raw_data;
} }
} }
@ -2283,7 +2283,7 @@ fn writeHeader(coff: *Coff) !void {
switch (coff.ptr_width) { switch (coff.ptr_width) {
.p32 => { .p32 => {
var opt_header = coff_util.OptionalHeaderPE32{ var opt_header = coff_util.OptionalHeaderPE32{
.magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC, .magic = .PE32,
.major_linker_version = 0, .major_linker_version = 0,
.minor_linker_version = 0, .minor_linker_version = 0,
.size_of_code = size_of_code, .size_of_code = size_of_code,
@ -2318,7 +2318,7 @@ fn writeHeader(coff: *Coff) !void {
}, },
.p64 => { .p64 => {
var opt_header = coff_util.OptionalHeaderPE64{ var opt_header = coff_util.OptionalHeaderPE64{
.magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC, .magic = .@"PE32+",
.major_linker_version = 0, .major_linker_version = 0,
.minor_linker_version = 0, .minor_linker_version = 0,
.size_of_code = size_of_code, .size_of_code = size_of_code,
@ -2422,7 +2422,7 @@ fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {
fn getSizeOfHeaders(coff: Coff) u32 { fn getSizeOfHeaders(coff: Coff) u32 {
const msdos_hdr_size = msdos_stub.len + 4; const msdos_hdr_size = msdos_stub.len + 4;
return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() + return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.Header) + coff.getOptionalHeaderSize() +
coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize())); coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));
} }
@ -2443,7 +2443,7 @@ fn getSectionHeadersSize(coff: Coff) u32 {
fn getDataDirectoryHeadersOffset(coff: Coff) u32 { fn getDataDirectoryHeadersOffset(coff: Coff) u32 {
const msdos_hdr_size = msdos_stub.len + 4; const msdos_hdr_size = msdos_stub.len + 4;
return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize())); return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.Header) + coff.getOptionalHeaderSize()));
} }
fn getSectionHeadersOffset(coff: Coff) u32 { fn getSectionHeadersOffset(coff: Coff) u32 {
@ -3116,7 +3116,7 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi
/// A "page" is 512 bytes. /// A "page" is 512 bytes.
/// A "long" is 4 bytes. /// A "long" is 4 bytes.
/// A "word" is 2 bytes. /// A "word" is 2 bytes.
const msdos_stub: [120]u8 = .{ pub const msdos_stub: [120]u8 = .{
'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format). 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format).
0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub. 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub.
0x01, 0x00, // Number of pages. 0x01, 0x00, // Number of pages.

2128
src/link/Coff2.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
pending_index: u32, pending_index: u32,
}), }),
pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
alignment: InternPool.Alignment, alignment: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc, src_loc: Zcu.LazySrcLoc,
}), }),
@ -25,10 +25,65 @@ pub const Node = union(enum) {
shdr, shdr,
segment: u32, segment: u32,
section: Symbol.Index, section: Symbol.Index,
nav: InternPool.Nav.Index, nav: NavMapIndex,
uav: InternPool.Index, uav: UavMapIndex,
lazy_code: InternPool.Index, lazy_code: LazyMapRef.Index(.code),
lazy_const_data: InternPool.Index, lazy_const_data: LazyMapRef.Index(.const_data),
pub const NavMapIndex = enum(u32) {
_,
pub fn navIndex(nmi: NavMapIndex, elf: *const Elf) InternPool.Nav.Index {
return elf.navs.keys()[@intFromEnum(nmi)];
}
pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index {
return elf.navs.values()[@intFromEnum(nmi)];
}
};
pub const UavMapIndex = enum(u32) {
_,
pub fn uavValue(umi: UavMapIndex, elf: *const Elf) InternPool.Index {
return elf.uavs.keys()[@intFromEnum(umi)];
}
pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index {
return elf.uavs.values()[@intFromEnum(umi)];
}
};
pub const LazyMapRef = struct {
kind: link.File.LazySymbol.Kind,
index: u32,
pub fn Index(comptime kind: link.File.LazySymbol.Kind) type {
return enum(u32) {
_,
pub fn ref(lmi: @This()) LazyMapRef {
return .{ .kind = kind, .index = @intFromEnum(lmi) };
}
pub fn lazySymbol(lmi: @This(), elf: *const Elf) link.File.LazySymbol {
return lmi.ref().lazySymbol(elf);
}
pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index {
return lmi.ref().symbol(elf);
}
};
}
pub fn lazySymbol(lmr: LazyMapRef, elf: *const Elf) link.File.LazySymbol {
return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] };
}
pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index {
return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index];
}
};
pub const Tag = @typeInfo(Node).@"union".tag_type.?; pub const Tag = @typeInfo(Node).@"union".tag_type.?;
@ -43,11 +98,7 @@ pub const Node = union(enum) {
seg_text, seg_text,
seg_data, seg_data,
}; };
var mut_known: std.enums.EnumFieldStruct( var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;
Known,
MappedFile.Node.Index,
null,
) = undefined;
for (@typeInfo(Known).@"enum".fields) |field| for (@typeInfo(Known).@"enum".fields) |field|
@field(mut_known, field.name) = @enumFromInt(field.value); @field(mut_known, field.name) = @enumFromInt(field.value);
break :known mut_known; break :known mut_known;
@ -223,10 +274,10 @@ pub const Reloc = extern struct {
addend: i64, addend: i64,
pub const Type = extern union { pub const Type = extern union {
x86_64: std.elf.R_X86_64, X86_64: std.elf.R_X86_64,
aarch64: std.elf.R_AARCH64, AARCH64: std.elf.R_AARCH64,
riscv: std.elf.R_RISCV, RISCV: std.elf.R_RISCV,
ppc64: std.elf.R_PPC64, PPC64: std.elf.R_PPC64,
}; };
pub const Index = enum(u32) { pub const Index = enum(u32) {
@ -239,7 +290,7 @@ pub const Reloc = extern struct {
}; };
pub fn apply(reloc: *const Reloc, elf: *Elf) void { pub fn apply(reloc: *const Reloc, elf: *Elf) void {
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
switch (reloc.loc.get(elf).ni) { switch (reloc.loc.get(elf).ni) {
.none => return, .none => return,
else => |ni| if (ni.hasMoved(&elf.mf)) return, else => |ni| if (ni.hasMoved(&elf.mf)) return,
@ -274,7 +325,7 @@ pub const Reloc = extern struct {
) +% @as(u64, @bitCast(reloc.addend)); ) +% @as(u64, @bitCast(reloc.addend));
switch (elf.ehdrField(.machine)) { switch (elf.ehdrField(.machine)) {
else => |machine| @panic(@tagName(machine)), else => |machine| @panic(@tagName(machine)),
.X86_64 => switch (reloc.type.x86_64) { .X86_64 => switch (reloc.type.X86_64) {
else => |kind| @panic(@tagName(kind)), else => |kind| @panic(@tagName(kind)),
.@"64" => std.mem.writeInt( .@"64" => std.mem.writeInt(
u64, u64,
@ -394,37 +445,7 @@ fn create(
}, },
.Obj => .REL, .Obj => .REL,
}; };
const machine: std.elf.EM = switch (target.cpu.arch) { const machine = target.toElfMachine();
.spirv32, .spirv64, .wasm32, .wasm64 => .NONE,
.sparc => .SPARC,
.x86 => .@"386",
.m68k => .@"68K",
.mips, .mipsel, .mips64, .mips64el => .MIPS,
.powerpc, .powerpcle => .PPC,
.powerpc64, .powerpc64le => .PPC64,
.s390x => .S390,
.arm, .armeb, .thumb, .thumbeb => .ARM,
.hexagon => .SH,
.sparc64 => .SPARCV9,
.arc => .ARC,
.x86_64 => .X86_64,
.or1k => .OR1K,
.xtensa => .XTENSA,
.msp430 => .MSP430,
.avr => .AVR,
.nvptx, .nvptx64 => .CUDA,
.kalimba => .CSR_KALIMBA,
.aarch64, .aarch64_be => .AARCH64,
.xcore => .XCORE,
.amdgcn => .AMDGPU,
.riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV,
.lanai => .LANAI,
.bpfel, .bpfeb => .BPF,
.ve => .VE,
.csky => .CSKY,
.loongarch32, .loongarch64 => .LOONGARCH,
.propeller => if (target.cpu.has(.propeller, .p2)) .PROPELLER2 else .PROPELLER,
};
const maybe_interp = switch (comp.config.output_mode) { const maybe_interp = switch (comp.config.output_mode) {
.Exe, .Lib => switch (comp.config.link_mode) { .Exe, .Lib => switch (comp.config.link_mode) {
.static => null, .static => null,
@ -479,7 +500,7 @@ fn create(
switch (class) { switch (class) {
.NONE, _ => unreachable, .NONE, _ => unreachable,
inline .@"32", .@"64" => |ct_class| try elf.initHeaders( inline else => |ct_class| try elf.initHeaders(
ct_class, ct_class,
data, data,
osabi, osabi,
@ -567,7 +588,7 @@ fn initHeaders(
.fixed = true, .fixed = true,
})); }));
elf.nodes.appendAssumeCapacity(.ehdr); elf.nodes.appendAssumeCapacity(.ehdr);
{
const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf)));
const EI = std.elf.EI; const EI = std.elf.EI;
@memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
@ -591,6 +612,7 @@ fn initHeaders(
ehdr.shnum = 1; ehdr.shnum = 1;
ehdr.shstrndx = 0; ehdr.shstrndx = 0;
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
}
const phdr_ni = Node.known.phdr; const phdr_ni = Node.known.phdr;
assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
@ -750,7 +772,10 @@ fn initHeaders(
}, },
.shndx = std.elf.SHN_UNDEF, .shndx = std.elf.SHN_UNDEF,
}; };
{
const ehdr = @field(elf.ehdrPtr(), @tagName(class));
ehdr.shstrndx = ehdr.shnum; ehdr.shstrndx = ehdr.shnum;
}
assert(try elf.addSection(seg_rodata_ni, .{ assert(try elf.addSection(seg_rodata_ni, .{
.type = std.elf.SHT_STRTAB, .type = std.elf.SHT_STRTAB,
.addralign = elf.mf.flags.block_size, .addralign = elf.mf.flags.block_size,
@ -821,37 +846,6 @@ fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node {
return elf.nodes.get(@intFromEnum(ni)); return elf.nodes.get(@intFromEnum(ni));
} }
pub const EhdrPtr = union(std.elf.CLASS) {
NONE: noreturn,
@"32": *std.elf.Elf32.Ehdr,
@"64": *std.elf.Elf64.Ehdr,
};
pub fn ehdrPtr(elf: *Elf) EhdrPtr {
const slice = Node.known.ehdr.slice(&elf.mf);
return switch (elf.identClass()) {
.NONE, _ => unreachable,
inline .@"32", .@"64" => |class| @unionInit(
EhdrPtr,
@tagName(class),
@ptrCast(@alignCast(slice)),
),
};
}
pub fn ehdrField(
elf: *Elf,
comptime field: enum { type, machine },
) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) {
const Field = @FieldType(std.elf.Elf32.Ehdr, @tagName(field));
comptime assert(@FieldType(std.elf.Elf64.Ehdr, @tagName(field)) == Field);
return @enumFromInt(std.mem.toNative(
@typeInfo(Field).@"enum".tag_type,
@intFromEnum(switch (elf.ehdrPtr()) {
inline else => |ehdr| @field(ehdr, @tagName(field)),
}),
elf.endian(),
));
}
pub fn identClass(elf: *Elf) std.elf.CLASS { pub fn identClass(elf: *Elf) std.elf.CLASS {
return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]);
} }
@ -866,10 +860,39 @@ fn endianForData(data: std.elf.DATA) std.builtin.Endian {
.@"2MSB" => .big, .@"2MSB" => .big,
}; };
} }
pub fn endian(elf: *Elf) std.builtin.Endian { pub fn targetEndian(elf: *Elf) std.builtin.Endian {
return endianForData(elf.identData()); return endianForData(elf.identData());
} }
pub const EhdrPtr = union(std.elf.CLASS) {
NONE: noreturn,
@"32": *std.elf.Elf32.Ehdr,
@"64": *std.elf.Elf64.Ehdr,
};
pub fn ehdrPtr(elf: *Elf) EhdrPtr {
const slice = Node.known.ehdr.slice(&elf.mf);
return switch (elf.identClass()) {
.NONE, _ => unreachable,
inline else => |class| @unionInit(
EhdrPtr,
@tagName(class),
@ptrCast(@alignCast(slice)),
),
};
}
pub fn ehdrField(
elf: *Elf,
comptime field: enum { type, machine },
) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) {
return @enumFromInt(std.mem.toNative(
@typeInfo(@FieldType(std.elf.Elf32.Ehdr, @tagName(field))).@"enum".tag_type,
@intFromEnum(switch (elf.ehdrPtr()) {
inline else => |ehdr| @field(ehdr, @tagName(field)),
}),
elf.targetEndian(),
));
}
fn baseAddrForType(@"type": std.elf.ET) u64 { fn baseAddrForType(@"type": std.elf.ET) u64 {
return switch (@"type") { return switch (@"type") {
else => 0, else => 0,
@ -889,7 +912,7 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
const slice = Node.known.phdr.slice(&elf.mf); const slice = Node.known.phdr.slice(&elf.mf);
return switch (elf.identClass()) { return switch (elf.identClass()) {
.NONE, _ => unreachable, .NONE, _ => unreachable,
inline .@"32", .@"64" => |class| @unionInit( inline else => |class| @unionInit(
PhdrSlice, PhdrSlice,
@tagName(class), @tagName(class),
@ptrCast(@alignCast(slice)), @ptrCast(@alignCast(slice)),
@ -906,7 +929,7 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
const slice = Node.known.shdr.slice(&elf.mf); const slice = Node.known.shdr.slice(&elf.mf);
return switch (elf.identClass()) { return switch (elf.identClass()) {
.NONE, _ => unreachable, .NONE, _ => unreachable,
inline .@"32", .@"64" => |class| @unionInit( inline else => |class| @unionInit(
ShdrSlice, ShdrSlice,
@tagName(class), @tagName(class),
@ptrCast(@alignCast(slice)), @ptrCast(@alignCast(slice)),
@ -923,7 +946,7 @@ pub fn symSlice(elf: *Elf) SymSlice {
const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);
return switch (elf.identClass()) { return switch (elf.identClass()) {
.NONE, _ => unreachable, .NONE, _ => unreachable,
inline .@"32", .@"64" => |class| @unionInit( inline else => |class| @unionInit(
SymSlice, SymSlice,
@tagName(class), @tagName(class),
@ptrCast(@alignCast(slice)), @ptrCast(@alignCast(slice)),
@ -942,7 +965,7 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
}; };
} }
fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index { fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
defer elf.symtab.addOneAssumeCapacity().* = .{ defer elf.symtab.addOneAssumeCapacity().* = .{
.ni = .none, .ni = .none,
.loc_relocs = .none, .loc_relocs = .none,
@ -953,30 +976,27 @@ fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {
} }
fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index { fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
const si = try elf.addSymbolAssumeCapacity(); const si = elf.addSymbolAssumeCapacity();
try si.init(elf, opts); try si.init(elf, opts);
return si; return si;
} }
pub fn globalSymbol( pub fn globalSymbol(elf: *Elf, opts: struct {
elf: *Elf,
opts: struct {
name: []const u8, name: []const u8,
type: std.elf.STT, type: std.elf.STT,
bind: std.elf.STB = .GLOBAL, bind: std.elf.STB = .GLOBAL,
visibility: std.elf.STV = .DEFAULT, visibility: std.elf.STV = .DEFAULT,
}, }) !Symbol.Index {
) !Symbol.Index {
const gpa = elf.base.comp.gpa; const gpa = elf.base.comp.gpa;
try elf.symtab.ensureUnusedCapacity(gpa, 1); try elf.symtab.ensureUnusedCapacity(gpa, 1);
const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
if (!sym_gop.found_existing) sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
.name = opts.name, .name = opts.name,
.type = opts.type, .type = opts.type,
.bind = opts.bind, .bind = opts.bind,
.visibility = opts.visibility, .visibility = opts.visibility,
}); });
return sym_gop.value_ptr.*; return global_gop.value_ptr.*;
} }
fn navType( fn navType(
@ -1008,8 +1028,19 @@ fn navType(
}, },
}; };
} }
pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
const gpa = zcu.gpa; const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
try elf.symtab.ensureUnusedCapacity(gpa, 1);
const nav_gop = try elf.navs.getOrPut(gpa, nav_index);
if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
.name = nav.fqn.toSlice(ip),
.type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
});
return @enumFromInt(nav_gop.index);
}
pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index); const nav = ip.getNav(nav_index);
if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
@ -1027,40 +1058,37 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
.protected => .PROTECTED, .protected => .PROTECTED,
}, },
}); });
try elf.symtab.ensureUnusedCapacity(gpa, 1); const nmi = try elf.navMapIndex(zcu, nav_index);
const sym_gop = try elf.navs.getOrPut(gpa, nav_index); return nmi.symbol(elf);
if (!sym_gop.found_existing) {
sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
.name = nav.fqn.toSlice(ip),
.type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
});
}
return sym_gop.value_ptr.*;
} }
pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {
const gpa = elf.base.comp.gpa; const gpa = elf.base.comp.gpa;
try elf.symtab.ensureUnusedCapacity(gpa, 1); try elf.symtab.ensureUnusedCapacity(gpa, 1);
const sym_gop = try elf.uavs.getOrPut(gpa, uav_val); const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);
if (!sym_gop.found_existing) if (!uav_gop.found_existing)
sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
return sym_gop.value_ptr.*; return @enumFromInt(uav_gop.index);
}
pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
const umi = try elf.uavMapIndex(uav_val);
return umi.symbol(elf);
} }
pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
const gpa = elf.base.comp.gpa; const gpa = elf.base.comp.gpa;
try elf.symtab.ensureUnusedCapacity(gpa, 1); try elf.symtab.ensureUnusedCapacity(gpa, 1);
const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
if (!sym_gop.found_existing) { if (!lazy_gop.found_existing) {
sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
.type = switch (lazy.kind) { .type = switch (lazy.kind) {
.code => .FUNC, .code => .FUNC,
.const_data => .OBJECT, .const_data => .OBJECT,
}, },
}); });
elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1); elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
} }
return sym_gop.value_ptr.*; return lazy_gop.value_ptr.*;
} }
pub fn getNavVAddr( pub fn getNavVAddr(
@ -1088,7 +1116,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
reloc_info.addend, reloc_info.addend,
switch (elf.ehdrField(.machine)) { switch (elf.ehdrField(.machine)) {
else => unreachable, else => unreachable,
.X86_64 => .{ .x86_64 = switch (elf.identClass()) { .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
.NONE, _ => unreachable, .NONE, _ => unreachable,
.@"32" => .@"32", .@"32" => .@"32",
.@"64" => .@"64", .@"64" => .@"64",
@ -1107,7 +1135,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
entsize: std.elf.Word = 0, entsize: std.elf.Word = 0,
}) !Symbol.Index { }) !Symbol.Index {
const gpa = elf.base.comp.gpa; const gpa = elf.base.comp.gpa;
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
try elf.nodes.ensureUnusedCapacity(gpa, 1); try elf.nodes.ensureUnusedCapacity(gpa, 1);
try elf.symtab.ensureUnusedCapacity(gpa, 1); try elf.symtab.ensureUnusedCapacity(gpa, 1);
@ -1127,7 +1155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
.size = opts.size, .size = opts.size,
.moved = true, .moved = true,
}); });
const si = try elf.addSymbolAssumeCapacity(); const si = elf.addSymbolAssumeCapacity();
elf.nodes.appendAssumeCapacity(.{ .section = si }); elf.nodes.appendAssumeCapacity(.{ .section = si });
si.get(elf).ni = ni; si.get(elf).ni = ni;
try si.init(elf, .{ try si.init(elf, .{
@ -1160,7 +1188,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
const strtab_entry = try elf.string(.strtab, name); const strtab_entry = try elf.string(.strtab, name);
const shstrtab_entry = try elf.string(.shstrtab, name); const shstrtab_entry = try elf.string(.shstrtab, name);
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
switch (elf.shdrSlice()) { switch (elf.shdrSlice()) {
inline else => |shdr, class| { inline else => |shdr, class| {
const sym = @field(elf.symPtr(si), @tagName(class)); const sym = @field(elf.symPtr(si), @tagName(class));
@ -1173,7 +1201,7 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
} }
fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
switch (elf.shdrSlice()) { switch (elf.shdrSlice()) {
inline else => |shdr, class| { inline else => |shdr, class| {
const sym = @field(elf.symPtr(si), @tagName(class)); const sym = @field(elf.symPtr(si), @tagName(class));
@ -1184,7 +1212,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
} }
fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) { const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) {
inline else => |shndx, class| { inline else => |shndx, class| {
const sym = @field(elf.symPtr(si), @tagName(class)); const sym = @field(elf.symPtr(si), @tagName(class));
@ -1263,7 +1291,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
}; };
if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
const si = try elf.navSymbol(zcu, nav_index); const nmi = try elf.navMapIndex(zcu, nav_index);
const si = nmi.symbol(elf);
const ni = ni: { const ni = ni: {
const sym = si.get(elf); const sym = si.get(elf);
switch (sym.ni) { switch (sym.ni) {
@ -1275,7 +1304,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
.alignment = pt.navAlignment(nav_index).toStdMem(), .alignment = pt.navAlignment(nav_index).toStdMem(),
.moved = true, .moved = true,
}); });
elf.nodes.appendAssumeCapacity(.{ .nav = nav_index }); elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
sym.ni = ni; sym.ni = ni;
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym_ptr, class| sym_ptr.shndx = inline else => |sym_ptr, class| sym_ptr.shndx =
@ -1289,7 +1318,6 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
break :ni sym.ni; break :ni sym.ni;
}; };
const size = size: {
var nw: MappedFile.Node.Writer = undefined; var nw: MappedFile.Node.Writer = undefined;
ni.writer(&elf.mf, gpa, &nw); ni.writer(&elf.mf, gpa, &nw);
defer nw.deinit(); defer nw.deinit();
@ -1304,13 +1332,10 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
error.WriteFailed => return error.OutOfMemory, error.WriteFailed => return error.OutOfMemory,
else => |e| return e, else => |e| return e,
}; };
break :size nw.interface.end; const target_endian = elf.targetEndian();
};
const target_endian = elf.endian();
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym| sym.size = inline else => |sym| sym.size =
std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian),
} }
si.applyLocationRelocs(elf); si.applyLocationRelocs(elf);
} }
@ -1326,7 +1351,7 @@ pub fn lowerUav(
const gpa = zcu.gpa; const gpa = zcu.gpa;
try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
const si = elf.uavSymbol(uav_val) catch |err| switch (err) { const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
else => |e| return .{ .fail = try Zcu.ErrorMsg.create( else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
gpa, gpa,
@ -1335,11 +1360,12 @@ pub fn lowerUav(
.{@errorName(e)}, .{@errorName(e)},
) }, ) },
}; };
const si = umi.symbol(elf);
if (switch (si.get(elf).ni) { if (switch (si.get(elf).ni) {
.none => true, .none => true,
else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt), else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
}) { }) {
const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val); const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi);
if (gop.found_existing) { if (gop.found_existing) {
gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
} else { } else {
@ -1347,7 +1373,7 @@ pub fn lowerUav(
.alignment = uav_align, .alignment = uav_align,
.src_loc = src_loc, .src_loc = src_loc,
}; };
elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1); elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);
} }
} }
return .{ .sym_index = @intFromEnum(si) }; return .{ .sym_index = @intFromEnum(si) };
@ -1384,7 +1410,8 @@ fn updateFuncInner(
const func = zcu.funcInfo(func_index); const func = zcu.funcInfo(func_index);
const nav = ip.getNav(func.owner_nav); const nav = ip.getNav(func.owner_nav);
const si = try elf.navSymbol(zcu, func.owner_nav); const nmi = try elf.navMapIndex(zcu, func.owner_nav);
const si = nmi.symbol(elf);
log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
const ni = ni: { const ni = ni: {
const sym = si.get(elf); const sym = si.get(elf);
@ -1406,7 +1433,7 @@ fn updateFuncInner(
}.toStdMem(), }.toStdMem(),
.moved = true, .moved = true,
}); });
elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav }); elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
sym.ni = ni; sym.ni = ni;
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym_ptr, class| sym_ptr.shndx = inline else => |sym_ptr, class| sym_ptr.shndx =
@ -1420,7 +1447,6 @@ fn updateFuncInner(
break :ni sym.ni; break :ni sym.ni;
}; };
const size = size: {
var nw: MappedFile.Node.Writer = undefined; var nw: MappedFile.Node.Writer = undefined;
ni.writer(&elf.mf, gpa, &nw); ni.writer(&elf.mf, gpa, &nw);
defer nw.deinit(); defer nw.deinit();
@ -1437,20 +1463,19 @@ fn updateFuncInner(
error.WriteFailed => return nw.err.?, error.WriteFailed => return nw.err.?,
else => |e| return e, else => |e| return e,
}; };
break :size nw.interface.end; const target_endian = elf.targetEndian();
};
const target_endian = elf.endian();
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym| sym.size = inline else => |sym| sym.size =
std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian),
} }
si.applyLocationRelocs(elf); si.applyLocationRelocs(elf);
} }
pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return; elf.flushLazy(pt, .{
elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) { .kind = .const_data,
.index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
}) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
error.CodegenFail => return error.LinkFailure, error.CodegenFail => return error.LinkFailure,
else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}),
@ -1472,14 +1497,13 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
const comp = elf.base.comp; const comp = elf.base.comp;
task: { task: {
while (elf.pending_uavs.pop()) |pending_uav| { while (elf.pending_uavs.pop()) |pending_uav| {
const sub_prog_node = const sub_prog_node = elf.idleProgNode(
elf.idleProgNode(
tid, tid,
comp.link_uav_prog_node, comp.link_const_prog_node,
.{ .uav = pending_uav.key }, .{ .uav = pending_uav.key },
); );
defer sub_prog_node.end(); defer sub_prog_node.end();
break :task elf.flushUav( elf.flushUav(
.{ .zcu = elf.base.comp.zcu.?, .tid = tid }, .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
pending_uav.key, pending_uav.key,
pending_uav.value.alignment, pending_uav.value.alignment,
@ -1491,37 +1515,34 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
.{e}, .{e},
), ),
}; };
break :task;
} }
var lazy_it = elf.lazy.iterator(); var lazy_it = elf.lazy.iterator();
while (lazy_it.next()) |lazy| for ( while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
lazy.value.map.keys()[lazy.value.pending_index..],
lazy.value.map.values()[lazy.value.pending_index..],
) |ty, si| {
lazy.value.pending_index += 1;
const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid };
const kind = switch (lazy.key) { const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index };
lazy.value.pending_index += 1;
const kind = switch (lmr.kind) {
.code => "code", .code => "code",
.const_data => "data", .const_data => "data",
}; };
var name: [std.Progress.Node.max_name_len]u8 = undefined; var name: [std.Progress.Node.max_name_len]u8 = undefined;
const sub_prog_node = comp.link_lazy_prog_node.start( const sub_prog_node = comp.link_synth_prog_node.start(
std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
kind, kind,
Type.fromInterned(ty).fmt(pt), Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
}) catch &name, }) catch &name,
0, 0,
); );
defer sub_prog_node.end(); defer sub_prog_node.end();
break :task elf.flushLazy(pt, .{ elf.flushLazy(pt, lmr) catch |err| switch (err) {
.kind = lazy.key,
.ty = ty,
}, si) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
else => |e| return elf.base.comp.link_diags.fail( else => |e| return elf.base.comp.link_diags.fail(
"linker failed to lower lazy {s}: {t}", "linker failed to lower lazy {s}: {t}",
.{ kind, e }, .{ kind, e },
), ),
}; };
break :task;
}; };
while (elf.mf.updates.pop()) |ni| { while (elf.mf.updates.pop()) |ni| {
const clean_moved = ni.cleanMoved(&elf.mf); const clean_moved = ni.cleanMoved(&elf.mf);
@ -1551,12 +1572,12 @@ fn idleProgNode(
return prog_node.start(name: switch (node) { return prog_node.start(name: switch (node) {
else => |tag| @tagName(tag), else => |tag| @tagName(tag),
.section => |si| elf.sectionName(si), .section => |si| elf.sectionName(si),
.nav => |nav| { .nav => |nmi| {
const ip = &elf.base.comp.zcu.?.intern_pool; const ip = &elf.base.comp.zcu.?.intern_pool;
break :name ip.getNav(nav).fqn.toSlice(ip); break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip);
}, },
.uav => |uav| std.fmt.bufPrint(&name, "{f}", .{ .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{
Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
}) catch &name, }) catch &name,
}, 0); }, 0);
} }
@ -1564,14 +1585,15 @@ fn idleProgNode(
fn flushUav( fn flushUav(
elf: *Elf, elf: *Elf,
pt: Zcu.PerThread, pt: Zcu.PerThread,
uav_val: InternPool.Index, umi: Node.UavMapIndex,
uav_align: InternPool.Alignment, uav_align: InternPool.Alignment,
src_loc: Zcu.LazySrcLoc, src_loc: Zcu.LazySrcLoc,
) !void { ) !void {
const zcu = pt.zcu; const zcu = pt.zcu;
const gpa = zcu.gpa; const gpa = zcu.gpa;
const si = try elf.uavSymbol(uav_val); const uav_val = umi.uavValue(elf);
const si = umi.symbol(elf);
const ni = ni: { const ni = ni: {
const sym = si.get(elf); const sym = si.get(elf);
switch (sym.ni) { switch (sym.ni) {
@ -1581,7 +1603,7 @@ fn flushUav(
.alignment = uav_align.toStdMem(), .alignment = uav_align.toStdMem(),
.moved = true, .moved = true,
}); });
elf.nodes.appendAssumeCapacity(.{ .uav = uav_val }); elf.nodes.appendAssumeCapacity(.{ .uav = umi });
sym.ni = ni; sym.ni = ni;
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym_ptr, class| sym_ptr.shndx = inline else => |sym_ptr, class| sym_ptr.shndx =
@ -1598,7 +1620,6 @@ fn flushUav(
break :ni sym.ni; break :ni sym.ni;
}; };
const size = size: {
var nw: MappedFile.Node.Writer = undefined; var nw: MappedFile.Node.Writer = undefined;
ni.writer(&elf.mf, gpa, &nw); ni.writer(&elf.mf, gpa, &nw);
defer nw.deinit(); defer nw.deinit();
@ -1613,21 +1634,20 @@ fn flushUav(
error.WriteFailed => return error.OutOfMemory, error.WriteFailed => return error.OutOfMemory,
else => |e| return e, else => |e| return e,
}; };
break :size nw.interface.end; const target_endian = elf.targetEndian();
};
const target_endian = elf.endian();
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym| sym.size = inline else => |sym| sym.size =
std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian),
} }
si.applyLocationRelocs(elf); si.applyLocationRelocs(elf);
} }
fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void { fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
const zcu = pt.zcu; const zcu = pt.zcu;
const gpa = zcu.gpa; const gpa = zcu.gpa;
const lazy = lmr.lazySymbol(elf);
const si = lmr.symbol(elf);
const ni = ni: { const ni = ni: {
const sym = si.get(elf); const sym = si.get(elf);
switch (sym.ni) { switch (sym.ni) {
@ -1639,8 +1659,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
}; };
const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true }); const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
elf.nodes.appendAssumeCapacity(switch (lazy.kind) { elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
.code => .{ .lazy_code = lazy.ty }, .code => .{ .lazy_code = @enumFromInt(lmr.index) },
.const_data => .{ .lazy_const_data = lazy.ty }, .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
}); });
sym.ni = ni; sym.ni = ni;
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
@ -1655,7 +1675,6 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
break :ni sym.ni; break :ni sym.ni;
}; };
const size = size: {
var required_alignment: InternPool.Alignment = .none; var required_alignment: InternPool.Alignment = .none;
var nw: MappedFile.Node.Writer = undefined; var nw: MappedFile.Node.Writer = undefined;
ni.writer(&elf.mf, gpa, &nw); ni.writer(&elf.mf, gpa, &nw);
@ -1670,19 +1689,16 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
.none, .none,
.{ .atom_index = @intFromEnum(si) }, .{ .atom_index = @intFromEnum(si) },
); );
break :size nw.interface.end; const target_endian = elf.targetEndian();
};
const target_endian = elf.endian();
switch (elf.symPtr(si)) { switch (elf.symPtr(si)) {
inline else => |sym| sym.size = inline else => |sym| sym.size =
std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian),
} }
si.applyLocationRelocs(elf); si.applyLocationRelocs(elf);
} }
fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
const file_offset = ni.fileLocation(&elf.mf, false).offset; const file_offset = ni.fileLocation(&elf.mf, false).offset;
const node = elf.getNode(ni); const node = elf.getNode(ni);
switch (node) { switch (node) {
@ -1738,11 +1754,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
.nav, .uav, .lazy_code, .lazy_const_data => { .nav, .uav, .lazy_code, .lazy_const_data => {
const si = switch (node) { const si = switch (node) {
else => unreachable, else => unreachable,
.nav => |nav| elf.navs.get(nav), inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
.uav => |uav| elf.uavs.get(uav), };
.lazy_code => |ty| elf.lazy.getPtr(.code).map.get(ty),
.lazy_const_data => |ty| elf.lazy.getPtr(.const_data).map.get(ty),
}.?;
switch (elf.shdrSlice()) { switch (elf.shdrSlice()) {
inline else => |shdr, class| { inline else => |shdr, class| {
const sym = @field(elf.symPtr(si), @tagName(class)); const sym = @field(elf.symPtr(si), @tagName(class));
@ -1773,7 +1786,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
} }
fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
const target_endian = elf.endian(); const target_endian = elf.targetEndian();
_, const size = ni.location(&elf.mf).resolve(&elf.mf); _, const size = ni.location(&elf.mf).resolve(&elf.mf);
const node = elf.getNode(ni); const node = elf.getNode(ni);
switch (node) { switch (node) {
@ -1957,31 +1970,38 @@ pub fn printNode(
indent: usize, indent: usize,
) !void { ) !void {
const node = elf.getNode(ni); const node = elf.getNode(ni);
const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)];
const off, const size = mf_node.location().resolve(&elf.mf);
try w.splatByteAll(' ', indent); try w.splatByteAll(' ', indent);
try w.writeAll(@tagName(node)); try w.writeAll(@tagName(node));
switch (node) { switch (node) {
else => {}, else => {},
.section => |si| try w.print("({s})", .{elf.sectionName(si)}), .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
.nav => |nav_index| { .nav => |nmi| {
const zcu = elf.base.comp.zcu.?; const zcu = elf.base.comp.zcu.?;
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index); const nav = ip.getNav(nmi.navIndex(elf));
try w.print("({f}, {f})", .{ try w.print("({f}, {f})", .{
Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }),
nav.fqn.fmt(ip), nav.fqn.fmt(ip),
}); });
}, },
.uav => |uav| { .uav => |umi| {
const zcu = elf.base.comp.zcu.?; const zcu = elf.base.comp.zcu.?;
const val: Value = .fromInterned(uav); const val: Value = .fromInterned(umi.uavValue(elf));
try w.print("({f}, {f})", .{ try w.print("({f}, {f})", .{
val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }),
val.fmtValue(.{ .zcu = zcu, .tid = tid }), val.fmtValue(.{ .zcu = zcu, .tid = tid }),
}); });
}, },
inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{
Type.fromInterned(lmi.lazySymbol(elf).ty).fmt(.{
.zcu = elf.base.comp.zcu.?,
.tid = tid,
}),
}),
} }
{
const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)];
const off, const size = mf_node.location().resolve(&elf.mf);
try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{
@intFromEnum(ni), @intFromEnum(ni),
off, off,
@ -1992,9 +2012,14 @@ pub fn printNode(
if (mf_node.flags.resized) " resized" else "", if (mf_node.flags.resized) " resized" else "",
if (mf_node.flags.has_content) " has_content" else "", if (mf_node.flags.has_content) " has_content" else "",
}); });
var child_ni = mf_node.first; }
switch (child_ni) { var leaf = true;
.none => { var child_it = ni.children(&elf.mf);
while (child_it.next()) |child_ni| {
leaf = false;
try elf.printNode(tid, w, child_ni, indent + 1);
}
if (leaf) {
const file_loc = ni.fileLocation(&elf.mf, false); const file_loc = ni.fileLocation(&elf.mf, false);
if (file_loc.size == 0) return; if (file_loc.size == 0) return;
var address = file_loc.offset; var address = file_loc.offset;
@ -2009,13 +2034,10 @@ pub fn printNode(
try w.splatByteAll(' ', indent + 1); try w.splatByteAll(' ', indent + 1);
try w.print("{x:0>8} ", .{address}); try w.print("{x:0>8} ", .{address});
for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
try w.writeByte('\n'); try w.writeByte('\n');
} }
},
else => while (child_ni != .none) {
try elf.printNode(tid, w, child_ni, indent + 1);
child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next;
},
} }
} }

View File

@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
.writers = .{}, .writers = .{},
}; };
errdefer mf.deinit(gpa); errdefer mf.deinit(gpa);
const size: u64, const blksize = if (is_windows) const size: u64, const block_size = stat: {
.{ try windows.GetFileSizeEx(file.handle), 1 } if (is_windows) {
else stat: { var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
break :stat .{
try windows.GetFileSizeEx(file.handle),
switch (windows.ntdll.NtQuerySystemInformation(
.SystemBasicInformation,
&sbi,
@sizeOf(windows.SYSTEM_BASIC_INFORMATION),
null,
)) {
.SUCCESS => @max(sbi.PageSize, sbi.AllocationGranularity),
else => std.heap.page_size_max,
},
};
}
const stat = try std.posix.fstat(mf.file.handle); const stat = try std.posix.fstat(mf.file.handle);
if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists; if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;
break :stat .{ @bitCast(stat.size), stat.blksize }; break :stat .{ @bitCast(stat.size), @max(std.heap.pageSize(), stat.blksize) };
}; };
mf.flags = .{ mf.flags = .{
.block_size = .fromByteUnits( .block_size = .fromByteUnits(std.math.ceilPowerOfTwoAssert(usize, block_size)),
std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)),
),
.copy_file_range_unsupported = false, .copy_file_range_unsupported = false,
.fallocate_insert_range_unsupported = false, .fallocate_insert_range_unsupported = false,
.fallocate_punch_hole_unsupported = false, .fallocate_punch_hole_unsupported = false,
@ -90,9 +101,11 @@ pub const Node = extern struct {
resized: bool, resized: bool,
/// Whether this node might contain non-zero bytes. /// Whether this node might contain non-zero bytes.
has_content: bool, has_content: bool,
/// Whether a moved event on this node bubbles down to children.
bubbles_moved: bool,
unused: @Type(.{ .int = .{ unused: @Type(.{ .int = .{
.signedness = .unsigned, .signedness = .unsigned,
.bits = 32 - @bitSizeOf(std.mem.Alignment) - 5, .bits = 32 - @bitSizeOf(std.mem.Alignment) - 6,
} }) = 0, } }) = 0,
}; };
@ -136,6 +149,25 @@ pub const Node = extern struct {
return &mf.nodes.items[@intFromEnum(ni)]; return &mf.nodes.items[@intFromEnum(ni)];
} }
pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index {
return ni.get(mf).parent;
}
pub const ChildIterator = struct {
mf: *const MappedFile,
ni: Node.Index,
pub fn next(it: *ChildIterator) ?Node.Index {
const ni = it.ni;
if (ni == .none) return null;
it.ni = ni.get(it.mf).next;
return ni;
}
};
pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator {
return .{ .mf = mf, .ni = ni.get(mf).first };
}
pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
var child_ni = ni.get(mf).last; var child_ni = ni.get(mf).last;
while (child_ni != .none) { while (child_ni != .none) {
@ -147,9 +179,10 @@ pub const Node = extern struct {
pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
var parent_ni = ni; var parent_ni = ni;
while (parent_ni != Node.Index.root) { while (parent_ni != Node.Index.root) {
const parent = parent_ni.get(mf); const parent_node = parent_ni.get(mf);
if (parent.flags.moved) return true; if (!parent_node.flags.bubbles_moved) break;
parent_ni = parent.parent; if (parent_node.flags.moved) return true;
parent_ni = parent_node.parent;
} }
return false; return false;
} }
@ -163,12 +196,7 @@ pub const Node = extern struct {
return node_moved.*; return node_moved.*;
} }
fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
var parent_ni = ni; if (ni.hasMoved(mf)) return;
while (parent_ni != Node.Index.root) {
const parent_node = parent_ni.get(mf);
if (parent_node.flags.moved) return;
parent_ni = parent_node.parent;
}
const node = ni.get(mf); const node = ni.get(mf);
node.flags.moved = true; node.flags.moved = true;
if (node.flags.resized) return; if (node.flags.resized) return;
@ -242,10 +270,10 @@ pub const Node = extern struct {
var offset, const size = ni.location(mf).resolve(mf); var offset, const size = ni.location(mf).resolve(mf);
var parent_ni = ni; var parent_ni = ni;
while (true) { while (true) {
const parent = parent_ni.get(mf); const parent_node = parent_ni.get(mf);
if (set_has_content) parent.flags.has_content = true; if (set_has_content) parent_node.flags.has_content = true;
if (parent_ni == .none) break; if (parent_ni == .none) break;
parent_ni = parent.parent; parent_ni = parent_node.parent;
offset += parent_ni.location(mf).resolve(mf)[0]; offset += parent_ni.location(mf).resolve(mf)[0];
} }
return .{ .offset = offset, .size = size }; return .{ .offset = offset, .size = size };
@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
.moved = true, .moved = true,
.resized = true, .resized = true,
.has_content = false, .has_content = false,
.bubbles_moved = opts.add_node.bubbles_moved,
}, },
.location_payload = location_payload, .location_payload = location_payload,
}; };
@ -471,6 +500,7 @@ pub const AddNodeOptions = struct {
fixed: bool = false, fixed: bool = false,
moved: bool = false, moved: bool = false,
resized: bool = false, resized: bool = false,
bubbles_moved: bool = true,
}; };
pub fn addOnlyChildNode( pub fn addOnlyChildNode(

View File

@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool { pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool {
return switch (ofmt) { return switch (ofmt) {
.elf => switch (backend) { .elf, .coff => switch (backend) {
.stage2_x86_64 => true, .stage2_x86_64 => true,
else => false, else => false,
}, },

View File

@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" {
if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
const S = struct { const S = struct {
fn case(comptime I: type, unshifted_inputs: [2]f32, expected: [2]I) !void { fn case(comptime I: type, unshifted_inputs: [2]f32, expected: [2]I) !void {

View File

@ -43,7 +43,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
} }
test "export function alias" { test "export function alias" {
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
_ = struct { _ = struct {

View File

@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234;
test "function extern symbol" { test "function extern symbol" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" }); const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" });
@ -29,7 +28,6 @@ export fn a_mystery_function() i32 {
test "function extern symbol matches extern decl" { test "function extern symbol matches extern decl" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const S = struct { const S = struct {

View File

@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" {
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCmp(f80); try testCmp(f80);
try comptime testCmp(f80); try comptime testCmp(f80);
@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCmpVector(f80); try testCmpVector(f80);
try comptime testCmpVector(f80); try comptime testCmpVector(f80);
@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.os.tag == .freebsd) { if (builtin.os.tag == .freebsd) {
// TODO https://github.com/ziglang/zig/issues/10875 // TODO https://github.com/ziglang/zig/issues/10875
@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testSin(f80); try testSin(f80);
comptime try testSin(f80); comptime try testSin(f80);
@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testCos(f80); try testCos(f80);
try comptime testCos(f80); try comptime testCos(f80);
@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testTan(f80); try testTan(f80);
try comptime testTan(f80); try comptime testTan(f80);
@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testExp(f80); try testExp(f80);
try comptime testExp(f80); try comptime testExp(f80);
@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testExp2(f80); try testExp2(f80);
try comptime testExp2(f80); try comptime testExp2(f80);
@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog(f80); try testLog(f80);
try comptime testLog(f80); try comptime testLog(f80);
@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog2(f80); try testLog2(f80);
try comptime testLog2(f80); try comptime testLog2(f80);
@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testLog10(f80); try testLog10(f80);
try comptime testLog10(f80); try comptime testLog10(f80);
@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testFabs(f80); try testFabs(f80);
try comptime testFabs(f80); try comptime testFabs(f80);
@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
// https://github.com/ziglang/zig/issues/12602 // https://github.com/ziglang/zig/issues/12602
@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
try testNeg(f80); try testNeg(f80);
try comptime testNeg(f80); try comptime testNeg(f80);
@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
test "result location forwarded through unary float builtins" { test "result location forwarded through unary float builtins" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

View File

@ -31,7 +31,6 @@ test "import c keywords" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
try std.testing.expect(int == .c_keyword_variable); try std.testing.expect(int == .c_keyword_variable);

View File

@ -1416,7 +1416,6 @@ test "remainder division" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@ -1425,6 +1424,8 @@ test "remainder division" {
return error.SkipZigTest; return error.SkipZigTest;
} }
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
try comptime remdiv(f16); try comptime remdiv(f16);
try comptime remdiv(f32); try comptime remdiv(f32);
try comptime remdiv(f64); try comptime remdiv(f64);
@ -1496,9 +1497,10 @@ test "float modulo division using @mod" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
try comptime fmod(f16); try comptime fmod(f16);
try comptime fmod(f32); try comptime fmod(f32);
try comptime fmod(f64); try comptime fmod(f64);
@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
const S = struct { const S = struct {
fn doTheTest() !void { fn doTheTest() !void {
@ -1824,7 +1825,8 @@ test "float divide by zero" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
const S = struct { const S = struct {
fn doTheTest(comptime F: type, zero: F, one: F) !void { fn doTheTest(comptime F: type, zero: F, one: F) !void {

View File

@ -14,7 +14,6 @@ test "call extern function defined with conflicting type" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@import("conflicting_externs/a.zig").issue529(null); @import("conflicting_externs/a.zig").issue529(null);

View File

@ -5255,7 +5255,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type {
return @mod(lhs, rhs); return @mod(lhs, rhs);
} }
test mod { test mod {
if (@import("builtin").object_format == .coff and @import("builtin").target.abi != .gnu) return error.SkipZigTest; const builtin = @import("builtin");
if (builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
const test_mod = binary(mod, .{}); const test_mod = binary(mod, .{});
try test_mod.testInts(); try test_mod.testInts();
try test_mod.testIntVectors(); try test_mod.testIntVectors();

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted //#target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted //#target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#update=initial version #update=initial version

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted
#update=initial version #update=initial version
#file=main.zig #file=main.zig

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted
#update=initial version #update=initial version
#file=main.zig #file=main.zig

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#update=initial version #update=initial version

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#update=initial version #update=initial version

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted //#target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted //#target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#update=non-inline version #update=non-inline version

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
//#target=wasm32-wasi-selfhosted //#target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted

View File

@ -1,4 +1,5 @@
#target=x86_64-linux-selfhosted #target=x86_64-linux-selfhosted
#target=x86_64-windows-selfhosted
#target=x86_64-linux-cbe #target=x86_64-linux-cbe
#target=x86_64-windows-cbe #target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted #target=wasm32-wasi-selfhosted