authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-08 16:08:05-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-10 22:47:47-07:00
log2e31077fe0e021858cf2f92f85e5fcfd12c41501
tree5f1e04aebfe2e0f440cd3d8426c645d1a723b97b
parentb2bc6073c8ada065906da9e3b5a4a2e7db04c21d

Coff: implement threadlocal variables


13 files changed, 951 insertions(+), 551 deletions(-)

lib/std/coff.zig+40-51
...@@ -249,55 +249,6 @@ pub const OptionalHeader = extern struct {...@@ -249,55 +249,6 @@ pub const OptionalHeader = extern struct {
249249
250pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;250pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
251251
252pub const DirectoryEntry = enum(u16) {
253 /// Export Directory
254 EXPORT = 0,
255
256 /// Import Directory
257 IMPORT = 1,
258
259 /// Resource Directory
260 RESOURCE = 2,
261
262 /// Exception Directory
263 EXCEPTION = 3,
264
265 /// Security Directory
266 SECURITY = 4,
267
268 /// Base Relocation Table
269 BASERELOC = 5,
270
271 /// Debug Directory
272 DEBUG = 6,
273
274 /// Architecture Specific Data
275 ARCHITECTURE = 7,
276
277 /// RVA of GP
278 GLOBALPTR = 8,
279
280 /// TLS Directory
281 TLS = 9,
282
283 /// Load Configuration Directory
284 LOAD_CONFIG = 10,
285
286 /// Bound Import Directory in headers
287 BOUND_IMPORT = 11,
288
289 /// Import Address Table
290 IAT = 12,
291
292 /// Delay Load Import Descriptors
293 DELAY_IMPORT = 13,
294
295 /// COM Runtime descriptor
296 COM_DESCRIPTOR = 14,
297
298 _,
299};
300
301pub const ImageDataDirectory = extern struct {252pub const ImageDataDirectory = extern struct {
302 virtual_address: u32,253 virtual_address: u32,
303 size: u32,254 size: u32,
...@@ -1054,9 +1005,9 @@ pub const Coff = struct {...@@ -1054,9 +1005,9 @@ pub const Coff = struct {
1054 assert(self.is_image);1005 assert(self.is_image);
10551006
1056 const data_dirs = self.getDataDirectories();1007 const data_dirs = self.getDataDirectories();
1057 if (@intFromEnum(DirectoryEntry.DEBUG) >= data_dirs.len) return null;1008 if (@intFromEnum(IMAGE.DIRECTORY_ENTRY.DEBUG) >= data_dirs.len) return null;
10581009
1059 const debug_dir = data_dirs[@intFromEnum(DirectoryEntry.DEBUG)];1010 const debug_dir = data_dirs[@intFromEnum(IMAGE.DIRECTORY_ENTRY.DEBUG)];
1060 var reader: std.Io.Reader = .fixed(self.data);1011 var reader: std.Io.Reader = .fixed(self.data);
10611012
1062 if (self.is_loaded) {1013 if (self.is_loaded) {
...@@ -1400,6 +1351,44 @@ pub const Relocation = extern struct {...@@ -1400,6 +1351,44 @@ pub const Relocation = extern struct {
1400};1351};
14011352
1402pub const IMAGE = struct {1353pub const IMAGE = struct {
1354 pub const DIRECTORY_ENTRY = enum(u32) {
1355 /// Export Directory
1356 EXPORT = 0,
1357 /// Import Directory
1358 IMPORT = 1,
1359 /// Resource Directory
1360 RESOURCE = 2,
1361 /// Exception Directory
1362 EXCEPTION = 3,
1363 /// Security Directory
1364 SECURITY = 4,
1365 /// Base Relocation Table
1366 BASERELOC = 5,
1367 /// Debug Directory
1368 DEBUG = 6,
1369 /// Architecture Specific Data
1370 ARCHITECTURE = 7,
1371 /// RVA of GP
1372 GLOBALPTR = 8,
1373 /// TLS Directory
1374 TLS = 9,
1375 /// Load Configuration Directory
1376 LOAD_CONFIG = 10,
1377 /// Bound Import Directory in headers
1378 BOUND_IMPORT = 11,
1379 /// Import Address Table
1380 IAT = 12,
1381 /// Delay Load Import Descriptors
1382 DELAY_IMPORT = 13,
1383 /// COM Runtime descriptor
1384 COM_DESCRIPTOR = 14,
1385 /// must be zero
1386 RESERVED = 15,
1387 _,
1388
1389 pub const len = @typeInfo(IMAGE.DIRECTORY_ENTRY).@"enum".fields.len;
1390 };
1391
1403 pub const FILE = struct {1392 pub const FILE = struct {
1404 /// Machine Types1393 /// Machine Types
1405 /// The Machine field has one of the following values, which specify the CPU type.1394 /// The Machine field has one of the following values, which specify the CPU type.
lib/std/debug.zig-20
...@@ -468,10 +468,6 @@ const use_trap_panic = switch (builtin.zig_backend) {...@@ -468,10 +468,6 @@ const use_trap_panic = switch (builtin.zig_backend) {
468 .stage2_wasm,468 .stage2_wasm,
469 .stage2_x86,469 .stage2_x86,
470 => true,470 => true,
471 .stage2_x86_64 => switch (builtin.target.ofmt) {
472 .elf, .macho => false,
473 else => true,
474 },
475 else => false,471 else => false,
476};472};
477473
...@@ -484,22 +480,6 @@ pub fn defaultPanic(...@@ -484,22 +480,6 @@ pub fn defaultPanic(
484480
485 if (use_trap_panic) @trap();481 if (use_trap_panic) @trap();
486482
487 switch (builtin.zig_backend) {
488 .stage2_aarch64,
489 .stage2_arm,
490 .stage2_powerpc,
491 .stage2_riscv64,
492 .stage2_spirv,
493 .stage2_wasm,
494 .stage2_x86,
495 => @trap(),
496 .stage2_x86_64 => switch (builtin.target.ofmt) {
497 .elf, .macho => {},
498 else => @trap(),
499 },
500 else => {},
501 }
502
503 switch (builtin.os.tag) {483 switch (builtin.os.tag) {
504 .freestanding, .other => {484 .freestanding, .other => {
505 @trap();485 @trap();
lib/std/math/isnan.zig+2
...@@ -28,6 +28,8 @@ test isNan {...@@ -28,6 +28,8 @@ test isNan {
28}28}
2929
30test isSignalNan {30test isSignalNan {
31 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
32
31 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {33 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
32 // TODO: Signalling NaN values get converted to quiet NaN values in34 // TODO: Signalling NaN values get converted to quiet NaN values in
33 // some cases where they shouldn't such that this can fail.35 // some cases where they shouldn't such that this can fail.
lib/ubsan_rt.zig+15-20
...@@ -120,12 +120,6 @@ const Value = extern struct {...@@ -120,12 +120,6 @@ const Value = extern struct {
120 }120 }
121121
122 pub fn format(value: Value, writer: *std.Io.Writer) std.Io.Writer.Error!void {122 pub fn format(value: Value, writer: *std.Io.Writer) std.Io.Writer.Error!void {
123 // Work around x86_64 backend limitation.
124 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) {
125 try writer.writeAll("(unknown)");
126 return;
127 }
128
129 switch (value.td.kind) {123 switch (value.td.kind) {
130 .integer => {124 .integer => {
131 if (value.td.isSigned()) {125 if (value.td.isSigned()) {
...@@ -624,10 +618,11 @@ fn exportHandler(...@@ -624,10 +618,11 @@ fn exportHandler(
624 handler: anytype,618 handler: anytype,
625 comptime sym_name: []const u8,619 comptime sym_name: []const u8,
626) void {620) void {
627 // Work around x86_64 backend limitation.621 @export(handler, .{
628 const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak;622 .name = "__ubsan_handle_" ++ sym_name,
629 const N = "__ubsan_handle_" ++ sym_name;623 .linkage = .weak,
630 @export(handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });624 .visibility = .hidden,
625 });
631}626}
632627
633fn exportHandlerWithAbort(628fn exportHandlerWithAbort(
...@@ -635,16 +630,16 @@ fn exportHandlerWithAbort(...@@ -635,16 +630,16 @@ fn exportHandlerWithAbort(
635 abort_handler: anytype,630 abort_handler: anytype,
636 comptime sym_name: []const u8,631 comptime sym_name: []const u8,
637) void {632) void {
638 // Work around x86_64 backend limitation.633 @export(handler, .{
639 const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak;634 .name = "__ubsan_handle_" ++ sym_name,
640 {635 .linkage = .weak,
641 const N = "__ubsan_handle_" ++ sym_name;636 .visibility = .hidden,
642 @export(handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });637 });
643 }638 @export(abort_handler, .{
644 {639 .name = "__ubsan_handle_" ++ sym_name ++ "_abort",
645 const N = "__ubsan_handle_" ++ sym_name ++ "_abort";640 .linkage = .weak,
646 @export(abort_handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });641 .visibility = .hidden,
647 }642 });
648}643}
649644
650const can_build_ubsan = switch (builtin.zig_backend) {645const can_build_ubsan = switch (builtin.zig_backend) {
src/Compilation.zig+1-1
...@@ -1985,7 +1985,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -1985,7 +1985,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
1985 switch (target_util.zigBackend(target, use_llvm)) {1985 switch (target_util.zigBackend(target, use_llvm)) {
1986 else => {},1986 else => {},
1987 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {1987 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
1988 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;1988 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;
1989 },1989 },
1990 }1990 }
1991 if (options.config.use_new_linker) break :s .zcu;1991 if (options.config.use_new_linker) break :s .zcu;
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -173685,7 +173685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -173685,7 +173685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
173685 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;173685 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
173686 const nav = ip.getNav(ty_nav.nav);173686 const nav = ip.getNav(ty_nav.nav);
173687 const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);173687 const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);
173688 if (is_threadlocal) if (cg.mod.pic) {173688 if (is_threadlocal) if (cg.target.ofmt == .coff or cg.mod.pic) {
173689 try cg.spillRegisters(&.{ .rdi, .rax });173689 try cg.spillRegisters(&.{ .rdi, .rax });
173690 } else {173690 } else {
173691 try cg.spillRegisters(&.{.rax});173691 try cg.spillRegisters(&.{.rax});
src/codegen/x86_64/Emit.zig+83-1
...@@ -386,6 +386,82 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -386,6 +386,82 @@ pub fn emitMir(emit: *Emit) Error!void {
386 }, emit.lower.target), &.{});386 }, emit.lower.target), &.{});
387 },387 },
388 else => unreachable,388 else => unreachable,
389 } else if (emit.bin_file.cast(.coff2)) |coff| {
390 switch (emit.lower.target.cpu.arch) {
391 else => unreachable,
392 .x86 => {
393 try emit.encodeInst(try .new(.none, .mov, &.{
394 .{ .reg = .eax },
395 .{ .mem = .initSib(.qword, .{
396 .base = .{ .reg = .fs },
397 .disp = 4 * 11,
398 }) },
399 }, emit.lower.target), &.{});
400 try emit.encodeInst(try .new(.none, .mov, &.{
401 .{ .reg = .edi },
402 .{ .mem = .initSib(.dword, .{}) },
403 }, emit.lower.target), &.{.{
404 .op_index = 1,
405 .target = .{
406 .index = @intFromEnum(
407 try coff.globalSymbol("__tls_index", null),
408 ),
409 .is_extern = false,
410 .type = .symbol,
411 },
412 }});
413 try emit.encodeInst(try .new(.none, .mov, &.{
414 .{ .reg = .eax },
415 .{ .mem = .initSib(.dword, .{
416 .base = .{ .reg = .eax },
417 .scale_index = .{ .index = .edi, .scale = 4 },
418 }) },
419 }, emit.lower.target), &.{});
420 try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{
421 lowered_inst.ops[0],
422 .{ .mem = .initSib(lowered_inst.ops[1].mem.sib.ptr_size, .{
423 .base = .{ .reg = .eax },
424 .disp = std.math.minInt(i32),
425 }) },
426 }, emit.lower.target), reloc_info);
427 },
428 .x86_64 => {
429 try emit.encodeInst(try .new(.none, .mov, &.{
430 .{ .reg = .rax },
431 .{ .mem = .initSib(.qword, .{
432 .base = .{ .reg = .gs },
433 .disp = 8 * 11,
434 }) },
435 }, emit.lower.target), &.{});
436 try emit.encodeInst(try .new(.none, .mov, &.{
437 .{ .reg = .edi },
438 .{ .mem = .initRip(.dword, 0) },
439 }, emit.lower.target), &.{.{
440 .op_index = 1,
441 .target = .{
442 .index = @intFromEnum(
443 try coff.globalSymbol("_tls_index", null),
444 ),
445 .is_extern = false,
446 .type = .symbol,
447 },
448 }});
449 try emit.encodeInst(try .new(.none, .mov, &.{
450 .{ .reg = .rax },
451 .{ .mem = .initSib(.qword, .{
452 .base = .{ .reg = .rax },
453 .scale_index = .{ .index = .rdi, .scale = 8 },
454 }) },
455 }, emit.lower.target), &.{});
456 try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{
457 lowered_inst.ops[0],
458 .{ .mem = .initSib(lowered_inst.ops[1].mem.sib.ptr_size, .{
459 .base = .{ .reg = .rax },
460 .disp = std.math.minInt(i32),
461 }) },
462 }, emit.lower.target), reloc_info);
463 },
464 }
389 } else return emit.fail("TODO implement relocs for {s}", .{465 } else return emit.fail("TODO implement relocs for {s}", .{
390 @tagName(emit.bin_file.tag),466 @tagName(emit.bin_file.tag),
391 });467 });
...@@ -870,7 +946,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -870,7 +946,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
870 .symbolnum = @intCast(reloc.target.index),946 .symbolnum = @intCast(reloc.target.index),
871 },947 },
872 });948 });
873 } else return emit.fail("TODO implement {s} reloc for {s}", .{949 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
950 @enumFromInt(emit.atom_index),
951 end_offset - 4,
952 @enumFromInt(reloc.target.index),
953 reloc.off,
954 .{ .AMD64 = .SECREL },
955 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
874 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),956 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
875 }),957 }),
876 };958 };
src/link/Coff.zig+473-226
...@@ -9,7 +9,9 @@ strings: std.HashMapUnmanaged(...@@ -9,7 +9,9 @@ strings: std.HashMapUnmanaged(
9 std.hash_map.default_max_load_percentage,9 std.hash_map.default_max_load_percentage,
10),10),
11string_bytes: std.ArrayList(u8),11string_bytes: std.ArrayList(u8),
12section_table: std.ArrayList(Symbol.Index),12image_section_table: std.ArrayList(Symbol.Index),
13pseudo_section_table: std.AutoArrayHashMapUnmanaged(String, Symbol.Index),
14object_section_table: std.AutoArrayHashMapUnmanaged(String, Symbol.Index),
13symbol_table: std.ArrayList(Symbol),15symbol_table: std.ArrayList(Symbol),
14globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index),16globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index),
15global_pending_index: u32,17global_pending_index: u32,
...@@ -24,8 +26,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -24,8 +26,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
24 src_loc: Zcu.LazySrcLoc,26 src_loc: Zcu.LazySrcLoc,
25}),27}),
26relocs: std.ArrayList(Reloc),28relocs: std.ArrayList(Reloc),
27/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
28entry_hack: Symbol.Index,
2929
30pub const default_file_alignment: u16 = 0x200;30pub const default_file_alignment: u16 = 0x200;
31pub const default_size_of_stack_reserve: u32 = 0x1000000;31pub const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -102,17 +102,45 @@ pub const Node = union(enum) {...@@ -102,17 +102,45 @@ pub const Node = union(enum) {
102 optional_header,102 optional_header,
103 data_directories,103 data_directories,
104 section_table,104 section_table,
105 section: Symbol.Index,105 image_section: Symbol.Index,
106
106 import_directory_table,107 import_directory_table,
107 import_lookup_table: ImportTable.Index,108 import_lookup_table: ImportTable.Index,
108 import_address_table: ImportTable.Index,109 import_address_table: ImportTable.Index,
109 import_hint_name_table: ImportTable.Index,110 import_hint_name_table: ImportTable.Index,
111
112 pseudo_section: PseudoSectionMapIndex,
113 object_section: ObjectSectionMapIndex,
110 global: GlobalMapIndex,114 global: GlobalMapIndex,
111 nav: NavMapIndex,115 nav: NavMapIndex,
112 uav: UavMapIndex,116 uav: UavMapIndex,
113 lazy_code: LazyMapRef.Index(.code),117 lazy_code: LazyMapRef.Index(.code),
114 lazy_const_data: LazyMapRef.Index(.const_data),118 lazy_const_data: LazyMapRef.Index(.const_data),
115119
120 pub const PseudoSectionMapIndex = enum(u32) {
121 _,
122
123 pub fn name(psmi: PseudoSectionMapIndex, coff: *const Coff) String {
124 return coff.pseudo_section_table.keys()[@intFromEnum(psmi)];
125 }
126
127 pub fn symbol(psmi: PseudoSectionMapIndex, coff: *const Coff) Symbol.Index {
128 return coff.pseudo_section_table.values()[@intFromEnum(psmi)];
129 }
130 };
131
132 pub const ObjectSectionMapIndex = enum(u32) {
133 _,
134
135 pub fn name(osmi: ObjectSectionMapIndex, coff: *const Coff) String {
136 return coff.object_section_table.keys()[@intFromEnum(osmi)];
137 }
138
139 pub fn symbol(osmi: ObjectSectionMapIndex, coff: *const Coff) Symbol.Index {
140 return coff.object_section_table.values()[@intFromEnum(osmi)];
141 }
142 };
143
116 pub const GlobalMapIndex = enum(u32) {144 pub const GlobalMapIndex = enum(u32) {
117 _,145 _,
118146
...@@ -204,27 +232,6 @@ pub const Node = union(enum) {...@@ -204,27 +232,6 @@ pub const Node = union(enum) {
204 }232 }
205};233};
206234
207pub const DataDirectory = enum {
208 export_table,
209 import_table,
210 resorce_table,
211 exception_table,
212 certificate_table,
213 base_relocation_table,
214 debug,
215 architecture,
216 global_ptr,
217 tls_table,
218 load_config_table,
219 bound_import,
220 import_address_table,
221 delay_import_descriptor,
222 clr_runtime_header,
223 reserved,
224
225 pub const len = @typeInfo(DataDirectory).@"enum".fields.len;
226};
227
228pub const ImportTable = struct {235pub const ImportTable = struct {
229 ni: MappedFile.Node.Index,236 ni: MappedFile.Node.Index,
230 entries: std.AutoArrayHashMapUnmanaged(void, Entry),237 entries: std.AutoArrayHashMapUnmanaged(void, Entry),
...@@ -264,9 +271,18 @@ pub const ImportTable = struct {...@@ -264,9 +271,18 @@ pub const ImportTable = struct {
264};271};
265272
266pub const String = enum(u32) {273pub const String = enum(u32) {
274 @".data" = 0,
275 @".idata" = 6,
276 @".rdata" = 13,
277 @".text" = 20,
278 @".tls$" = 26,
267 _,279 _,
268280
269 pub const Optional = enum(u32) {281 pub const Optional = enum(u32) {
282 @".data" = @intFromEnum(String.@".data"),
283 @".rdata" = @intFromEnum(String.@".rdata"),
284 @".text" = @intFromEnum(String.@".text"),
285 @".tls$" = @intFromEnum(String.@".tls$"),
270 none = std.math.maxInt(u32),286 none = std.math.maxInt(u32),
271 _,287 _,
272288
...@@ -318,7 +334,7 @@ pub const Symbol = struct {...@@ -318,7 +334,7 @@ pub const Symbol = struct {
318 }334 }
319335
320 pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index {336 pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index {
321 return coff.section_table.items[sn.toIndex()];337 return coff.image_section_table.items[sn.toIndex()];
322 }338 }
323339
324 pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader {340 pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader {
...@@ -329,7 +345,6 @@ pub const Symbol = struct {...@@ -329,7 +345,6 @@ pub const Symbol = struct {
329 pub const Index = enum(u32) {345 pub const Index = enum(u32) {
330 null,346 null,
331 data,347 data,
332 idata,
333 rdata,348 rdata,
334 text,349 text,
335 _,350 _,
...@@ -349,10 +364,6 @@ pub const Symbol = struct {...@@ -349,10 +364,6 @@ pub const Symbol = struct {
349 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {364 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {
350 const sym = si.get(coff);365 const sym = si.get(coff);
351 sym.rva = coff.computeNodeRva(sym.ni);366 sym.rva = coff.computeNodeRva(sym.ni);
352 if (si == coff.entry_hack) {
353 @branchHint(.unlikely);
354 coff.targetStore(&coff.optionalHeaderStandardPtr().address_of_entry_point, sym.rva);
355 }
356 si.applyLocationRelocs(coff);367 si.applyLocationRelocs(coff);
357 si.applyTargetRelocs(coff);368 si.applyTargetRelocs(coff);
358 }369 }
...@@ -493,6 +504,12 @@ pub const Reloc = extern struct {...@@ -493,6 +504,12 @@ pub const Reloc = extern struct {
493 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),504 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),
494 target_endian,505 target_endian,
495 ),506 ),
507 .SECREL => std.mem.writeInt(
508 u32,
509 loc_slice[0..4],
510 coff.computeNodeSectionOffset(target_sym.ni),
511 target_endian,
512 ),
496 },513 },
497 .I386 => switch (reloc.type.I386) {514 .I386 => switch (reloc.type.I386) {
498 else => |kind| @panic(@tagName(kind)),515 else => |kind| @panic(@tagName(kind)),
...@@ -527,6 +544,12 @@ pub const Reloc = extern struct {...@@ -527,6 +544,12 @@ pub const Reloc = extern struct {
527 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),544 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
528 target_endian,545 target_endian,
529 ),546 ),
547 .SECREL => std.mem.writeInt(
548 u32,
549 loc_slice[0..4],
550 coff.computeNodeSectionOffset(target_sym.ni),
551 target_endian,
552 ),
530 },553 },
531 }554 }
532 }555 }
...@@ -634,7 +657,9 @@ fn create(...@@ -634,7 +657,9 @@ fn create(
634 },657 },
635 .strings = .empty,658 .strings = .empty,
636 .string_bytes = .empty,659 .string_bytes = .empty,
637 .section_table = .empty,660 .image_section_table = .empty,
661 .pseudo_section_table = .empty,
662 .object_section_table = .empty,
638 .symbol_table = .empty,663 .symbol_table = .empty,
639 .globals = .empty,664 .globals = .empty,
640 .global_pending_index = 0,665 .global_pending_index = 0,
...@@ -646,10 +671,17 @@ fn create(...@@ -646,10 +671,17 @@ fn create(
646 }),671 }),
647 .pending_uavs = .empty,672 .pending_uavs = .empty,
648 .relocs = .empty,673 .relocs = .empty,
649 .entry_hack = .null,
650 };674 };
651 errdefer coff.deinit();675 errdefer coff.deinit();
652676
677 {
678 const strings = std.enums.values(String);
679 try coff.strings.ensureTotalCapacityContext(comp.gpa, @intCast(strings.len), .{
680 .bytes = &coff.string_bytes,
681 });
682 for (strings) |string| assert(try coff.getOrPutString(@tagName(string)) == string);
683 }
684
653 try coff.initHeaders(685 try coff.initHeaders(
654 is_image,686 is_image,
655 machine,687 machine,
...@@ -669,7 +701,9 @@ pub fn deinit(coff: *Coff) void {...@@ -669,7 +701,9 @@ pub fn deinit(coff: *Coff) void {
669 coff.import_table.entries.deinit(gpa);701 coff.import_table.entries.deinit(gpa);
670 coff.strings.deinit(gpa);702 coff.strings.deinit(gpa);
671 coff.string_bytes.deinit(gpa);703 coff.string_bytes.deinit(gpa);
672 coff.section_table.deinit(gpa);704 coff.image_section_table.deinit(gpa);
705 coff.pseudo_section_table.deinit(gpa);
706 coff.object_section_table.deinit(gpa);
673 coff.symbol_table.deinit(gpa);707 coff.symbol_table.deinit(gpa);
674 coff.globals.deinit(gpa);708 coff.globals.deinit(gpa);
675 coff.navs.deinit(gpa);709 coff.navs.deinit(gpa);
...@@ -692,19 +726,21 @@ fn initHeaders(...@@ -692,19 +726,21 @@ fn initHeaders(
692) !void {726) !void {
693 const comp = coff.base.comp;727 const comp = coff.base.comp;
694 const gpa = comp.gpa;728 const gpa = comp.gpa;
695 const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment);
696 const target_endian = coff.targetEndian();729 const target_endian = coff.targetEndian();
730 const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment);
697731
698 const optional_header_size: u16 = if (is_image) switch (magic) {732 const optional_header_size: u16 = if (is_image) switch (magic) {
699 _ => unreachable,733 _ => unreachable,
700 inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))),734 inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))),
701 } else 0;735 } else 0;
702 const data_directories_size: u16 = if (is_image)736 const data_directories_size: u16 = if (is_image)
703 @sizeOf(std.coff.ImageDataDirectory) * DataDirectory.len737 @sizeOf(std.coff.ImageDataDirectory) * std.coff.IMAGE.DIRECTORY_ENTRY.len
704 else738 else
705 0;739 0;
706740
707 try coff.nodes.ensureTotalCapacity(gpa, Node.known_count);741 const expected_nodes_len = Node.known_count + 6 +
742 @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2;
743 try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
708 coff.nodes.appendAssumeCapacity(.file);744 coff.nodes.appendAssumeCapacity(.file);
709745
710 const header_ni = Node.known.header;746 const header_ni = Node.known.header;
...@@ -762,108 +798,110 @@ fn initHeaders(...@@ -762,108 +798,110 @@ fn initHeaders(
762 .fixed = true,798 .fixed = true,
763 }));799 }));
764 coff.nodes.appendAssumeCapacity(.optional_header);800 coff.nodes.appendAssumeCapacity(.optional_header);
765 coff.targetStore(&coff.optionalHeaderStandardPtr().magic, magic);801 if (is_image) {
766 if (is_image) switch (coff.optionalHeaderPtr()) {802 coff.targetStore(&coff.optionalHeaderStandardPtr().magic, magic);
767 .PE32 => |optional_header| {803 switch (coff.optionalHeaderPtr()) {
768 optional_header.* = .{804 .PE32 => |optional_header| {
769 .standard = .{805 optional_header.* = .{
770 .magic = .PE32,806 .standard = .{
771 .major_linker_version = 0,807 .magic = .PE32,
772 .minor_linker_version = 0,808 .major_linker_version = 0,
773 .size_of_code = 0,809 .minor_linker_version = 0,
774 .size_of_initialized_data = 0,810 .size_of_code = 0,
775 .size_of_uninitialized_data = 0,811 .size_of_initialized_data = 0,
776 .address_of_entry_point = 0,812 .size_of_uninitialized_data = 0,
777 .base_of_code = 0,813 .address_of_entry_point = 0,
778 },814 .base_of_code = 0,
779 .base_of_data = 0,
780 .image_base = switch (coff.base.comp.config.output_mode) {
781 .Exe => 0x400000,
782 .Lib => switch (coff.base.comp.config.link_mode) {
783 .static => 0,
784 .dynamic => 0x10000000,
785 },815 },
786 .Obj => 0,816 .base_of_data = 0,
787 },817 .image_base = switch (coff.base.comp.config.output_mode) {
788 .section_alignment = @intCast(section_align.toByteUnits()),818 .Exe => 0x400000,
789 .file_alignment = @intCast(file_align.toByteUnits()),819 .Lib => switch (coff.base.comp.config.link_mode) {
790 .major_operating_system_version = 6,820 .static => 0,
791 .minor_operating_system_version = 0,821 .dynamic => 0x10000000,
792 .major_image_version = 0,822 },
793 .minor_image_version = 0,823 .Obj => 0,
794 .major_subsystem_version = major_subsystem_version,
795 .minor_subsystem_version = minor_subsystem_version,
796 .win32_version_value = 0,
797 .size_of_image = 0,
798 .size_of_headers = 0,
799 .checksum = 0,
800 .subsystem = .WINDOWS_CUI,
801 .dll_flags = .{
802 .HIGH_ENTROPY_VA = true,
803 .DYNAMIC_BASE = true,
804 .TERMINAL_SERVER_AWARE = true,
805 .NX_COMPAT = true,
806 },
807 .size_of_stack_reserve = default_size_of_stack_reserve,
808 .size_of_stack_commit = default_size_of_stack_commit,
809 .size_of_heap_reserve = default_size_of_heap_reserve,
810 .size_of_heap_commit = default_size_of_heap_commit,
811 .loader_flags = 0,
812 .number_of_rva_and_sizes = DataDirectory.len,
813 };
814 if (target_endian != native_endian)
815 std.mem.byteSwapAllFields(std.coff.OptionalHeader.PE32, optional_header);
816 },
817 .@"PE32+" => |optional_header| {
818 optional_header.* = .{
819 .standard = .{
820 .magic = .@"PE32+",
821 .major_linker_version = 0,
822 .minor_linker_version = 0,
823 .size_of_code = 0,
824 .size_of_initialized_data = 0,
825 .size_of_uninitialized_data = 0,
826 .address_of_entry_point = 0,
827 .base_of_code = 0,
828 },
829 .image_base = switch (coff.base.comp.config.output_mode) {
830 .Exe => 0x140000000,
831 .Lib => switch (coff.base.comp.config.link_mode) {
832 .static => 0,
833 .dynamic => 0x180000000,
834 },824 },
835 .Obj => 0,825 .section_alignment = @intCast(section_align.toByteUnits()),
836 },826 .file_alignment = @intCast(file_align.toByteUnits()),
837 .section_alignment = @intCast(section_align.toByteUnits()),827 .major_operating_system_version = 6,
838 .file_alignment = @intCast(file_align.toByteUnits()),828 .minor_operating_system_version = 0,
839 .major_operating_system_version = 6,829 .major_image_version = 0,
840 .minor_operating_system_version = 0,830 .minor_image_version = 0,
841 .major_image_version = 0,831 .major_subsystem_version = major_subsystem_version,
842 .minor_image_version = 0,832 .minor_subsystem_version = minor_subsystem_version,
843 .major_subsystem_version = major_subsystem_version,833 .win32_version_value = 0,
844 .minor_subsystem_version = minor_subsystem_version,834 .size_of_image = 0,
845 .win32_version_value = 0,835 .size_of_headers = 0,
846 .size_of_image = 0,836 .checksum = 0,
847 .size_of_headers = 0,837 .subsystem = .WINDOWS_CUI,
848 .checksum = 0,838 .dll_flags = .{
849 .subsystem = .WINDOWS_CUI,839 .HIGH_ENTROPY_VA = true,
850 .dll_flags = .{840 .DYNAMIC_BASE = true,
851 .HIGH_ENTROPY_VA = true,841 .TERMINAL_SERVER_AWARE = true,
852 .DYNAMIC_BASE = true,842 .NX_COMPAT = true,
853 .TERMINAL_SERVER_AWARE = true,843 },
854 .NX_COMPAT = true,844 .size_of_stack_reserve = default_size_of_stack_reserve,
855 },845 .size_of_stack_commit = default_size_of_stack_commit,
856 .size_of_stack_reserve = default_size_of_stack_reserve,846 .size_of_heap_reserve = default_size_of_heap_reserve,
857 .size_of_stack_commit = default_size_of_stack_commit,847 .size_of_heap_commit = default_size_of_heap_commit,
858 .size_of_heap_reserve = default_size_of_heap_reserve,848 .loader_flags = 0,
859 .size_of_heap_commit = default_size_of_heap_commit,849 .number_of_rva_and_sizes = std.coff.IMAGE.DIRECTORY_ENTRY.len,
860 .loader_flags = 0,850 };
861 .number_of_rva_and_sizes = DataDirectory.len,851 if (target_endian != native_endian)
862 };852 std.mem.byteSwapAllFields(std.coff.OptionalHeader.PE32, optional_header);
863 if (target_endian != native_endian)853 },
864 std.mem.byteSwapAllFields(std.coff.OptionalHeader.@"PE32+", optional_header);854 .@"PE32+" => |optional_header| {
865 },855 optional_header.* = .{
866 };856 .standard = .{
857 .magic = .@"PE32+",
858 .major_linker_version = 0,
859 .minor_linker_version = 0,
860 .size_of_code = 0,
861 .size_of_initialized_data = 0,
862 .size_of_uninitialized_data = 0,
863 .address_of_entry_point = 0,
864 .base_of_code = 0,
865 },
866 .image_base = switch (coff.base.comp.config.output_mode) {
867 .Exe => 0x140000000,
868 .Lib => switch (coff.base.comp.config.link_mode) {
869 .static => 0,
870 .dynamic => 0x180000000,
871 },
872 .Obj => 0,
873 },
874 .section_alignment = @intCast(section_align.toByteUnits()),
875 .file_alignment = @intCast(file_align.toByteUnits()),
876 .major_operating_system_version = 6,
877 .minor_operating_system_version = 0,
878 .major_image_version = 0,
879 .minor_image_version = 0,
880 .major_subsystem_version = major_subsystem_version,
881 .minor_subsystem_version = minor_subsystem_version,
882 .win32_version_value = 0,
883 .size_of_image = 0,
884 .size_of_headers = 0,
885 .checksum = 0,
886 .subsystem = .WINDOWS_CUI,
887 .dll_flags = .{
888 .HIGH_ENTROPY_VA = true,
889 .DYNAMIC_BASE = true,
890 .TERMINAL_SERVER_AWARE = true,
891 .NX_COMPAT = true,
892 },
893 .size_of_stack_reserve = default_size_of_stack_reserve,
894 .size_of_stack_commit = default_size_of_stack_commit,
895 .size_of_heap_reserve = default_size_of_heap_reserve,
896 .size_of_heap_commit = default_size_of_heap_commit,
897 .loader_flags = 0,
898 .number_of_rva_and_sizes = std.coff.IMAGE.DIRECTORY_ENTRY.len,
899 };
900 if (target_endian != native_endian)
901 std.mem.byteSwapAllFields(std.coff.OptionalHeader.@"PE32+", optional_header);
902 },
903 }
904 }
867905
868 const data_directories_ni = Node.known.data_directories;906 const data_directories_ni = Node.known.data_directories;
869 assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{907 assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{
...@@ -875,8 +913,10 @@ fn initHeaders(...@@ -875,8 +913,10 @@ fn initHeaders(
875 {913 {
876 const data_directories = coff.dataDirectorySlice();914 const data_directories = coff.dataDirectorySlice();
877 @memset(data_directories, .{ .virtual_address = 0, .size = 0 });915 @memset(data_directories, .{ .virtual_address = 0, .size = 0 });
878 if (target_endian != native_endian)916 if (target_endian != native_endian) std.mem.byteSwapAllFields(
879 std.mem.byteSwapAllFields([DataDirectory.len]std.coff.ImageDataDirectory, data_directories);917 [std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory,
918 data_directories,
919 );
880 }920 }
881921
882 const section_table_ni = Node.known.section_table;922 const section_table_ni = Node.known.section_table;
...@@ -902,10 +942,6 @@ fn initHeaders(...@@ -902,10 +942,6 @@ fn initHeaders(
902 .MEM_READ = true,942 .MEM_READ = true,
903 .MEM_WRITE = true,943 .MEM_WRITE = true,
904 }) == .data);944 }) == .data);
905 assert(try coff.addSection(".idata", .{
906 .CNT_INITIALIZED_DATA = true,
907 .MEM_READ = true,
908 }) == .idata);
909 assert(try coff.addSection(".rdata", .{945 assert(try coff.addSection(".rdata", .{
910 .CNT_INITIALIZED_DATA = true,946 .CNT_INITIALIZED_DATA = true,
911 .MEM_READ = true,947 .MEM_READ = true,
...@@ -915,13 +951,26 @@ fn initHeaders(...@@ -915,13 +951,26 @@ fn initHeaders(
915 .MEM_EXECUTE = true,951 .MEM_EXECUTE = true,
916 .MEM_READ = true,952 .MEM_READ = true,
917 }) == .text);953 }) == .text);
954
918 coff.import_table.ni = try coff.mf.addLastChildNode(955 coff.import_table.ni = try coff.mf.addLastChildNode(
919 gpa,956 gpa,
920 Symbol.Index.idata.node(coff),957 (try coff.objectSectionMapIndex(
921 .{ .alignment = .@"4" },958 .@".idata",
959 coff.mf.flags.block_size,
960 .{ .read = true },
961 )).symbol(coff).node(coff),
962 .{ .alignment = .@"4", .moved = true },
922 );963 );
923 coff.nodes.appendAssumeCapacity(.import_directory_table);964 coff.nodes.appendAssumeCapacity(.import_directory_table);
924 assert(coff.symbol_table.items.len == Symbol.Index.known_count);965
966 // While tls variables allocated at runtime are writable, the template itself is not
967 if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex(
968 .@".tls$",
969 coff.mf.flags.block_size,
970 .{ .read = true },
971 );
972
973 assert(coff.nodes.len == expected_nodes_len);
925}974}
926975
927fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {976fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
...@@ -938,8 +987,10 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -938,8 +987,10 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
938 .data_directories,987 .data_directories,
939 .section_table,988 .section_table,
940 => unreachable,989 => unreachable,
941 .section => |si| si,990 .image_section => |si| si,
942 .import_directory_table => unreachable,991 .import_directory_table => break :parent_rva coff.targetLoad(
992 &coff.dataDirectoryPtr(.IMPORT).virtual_address,
993 ),
943 .import_lookup_table => |import_index| break :parent_rva coff.targetLoad(994 .import_lookup_table => |import_index| break :parent_rva coff.targetLoad(
944 &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva,995 &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva,
945 ),996 ),
...@@ -949,13 +1000,34 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {...@@ -949,13 +1000,34 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 {
949 .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad(1000 .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad(
950 &coff.importDirectoryEntryPtr(import_index).name_rva,1001 &coff.importDirectoryEntryPtr(import_index).name_rva,
951 ),1002 ),
952 inline .global, .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(coff),1003 inline .pseudo_section,
1004 .object_section,
1005 .global,
1006 .nav,
1007 .uav,
1008 .lazy_code,
1009 .lazy_const_data,
1010 => |mi| mi.symbol(coff),
953 };1011 };
954 break :parent_rva parent_si.get(coff).rva;1012 break :parent_rva parent_si.get(coff).rva;
955 };1013 };
956 const offset, _ = ni.location(&coff.mf).resolve(&coff.mf);1014 const offset, _ = ni.location(&coff.mf).resolve(&coff.mf);
957 return @intCast(parent_rva + offset);1015 return @intCast(parent_rva + offset);
958}1016}
1017fn computeNodeSectionOffset(coff: *Coff, ni: MappedFile.Node.Index) u32 {
1018 var section_offset: u32 = 0;
1019 var parent_ni = ni;
1020 while (true) {
1021 const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf);
1022 section_offset += @intCast(offset);
1023 parent_ni = parent_ni.parent(&coff.mf);
1024 switch (coff.getNode(parent_ni)) {
1025 else => unreachable,
1026 .image_section, .pseudo_section => return section_offset,
1027 .object_section => {},
1028 }
1029 }
1030}
9591031
960pub inline fn targetEndian(_: *const Coff) std.builtin.Endian {1032pub inline fn targetEndian(_: *const Coff) std.builtin.Endian {
961 return .little;1033 return .little;
...@@ -1021,11 +1093,16 @@ pub fn optionalHeaderField(...@@ -1021,11 +1093,16 @@ pub fn optionalHeaderField(
1021 };1093 };
1022}1094}
10231095
1024pub fn dataDirectorySlice(coff: *Coff) *[DataDirectory.len]std.coff.ImageDataDirectory {1096pub fn dataDirectorySlice(
1097 coff: *Coff,
1098) *[std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory {
1025 return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf)));1099 return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf)));
1026}1100}
1027pub fn dataDirectoryPtr(coff: *Coff, data_directory: DataDirectory) *std.coff.ImageDataDirectory {1101pub fn dataDirectoryPtr(
1028 return &coff.dataDirectorySlice()[@intFromEnum(data_directory)];1102 coff: *Coff,
1103 entry: std.coff.IMAGE.DIRECTORY_ENTRY,
1104) *std.coff.ImageDataDirectory {
1105 return &coff.dataDirectorySlice()[@intFromEnum(entry)];
1029}1106}
10301107
1031pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {1108pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
...@@ -1060,13 +1137,22 @@ fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index {...@@ -1060,13 +1137,22 @@ fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index {
1060}1137}
10611138
1062fn getOrPutString(coff: *Coff, string: []const u8) !String {1139fn getOrPutString(coff: *Coff, string: []const u8) !String {
1140 try coff.ensureUnusedStringCapacity(string.len);
1141 return coff.getOrPutStringAssumeCapacity(string);
1142}
1143fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {
1144 return (try coff.getOrPutString(string orelse return .none)).toOptional();
1145}
1146
1147fn ensureUnusedStringCapacity(coff: *Coff, len: usize) !void {
1063 const gpa = coff.base.comp.gpa;1148 const gpa = coff.base.comp.gpa;
1064 try coff.string_bytes.ensureUnusedCapacity(gpa, string.len + 1);1149 try coff.strings.ensureUnusedCapacityContext(gpa, 1, .{ .bytes = &coff.string_bytes });
1065 const gop = try coff.strings.getOrPutContextAdapted(1150 try coff.string_bytes.ensureUnusedCapacity(gpa, len + 1);
1066 gpa,1151}
1152fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
1153 const gop = coff.strings.getOrPutAssumeCapacityAdapted(
1067 string,1154 string,
1068 std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes },1155 std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes },
1069 .{ .bytes = &coff.string_bytes },
1070 );1156 );
1071 if (!gop.found_existing) {1157 if (!gop.found_existing) {
1072 gop.key_ptr.* = @intCast(coff.string_bytes.items.len);1158 gop.key_ptr.* = @intCast(coff.string_bytes.items.len);
...@@ -1077,10 +1163,6 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {...@@ -1077,10 +1163,6 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String {
1077 return @enumFromInt(gop.key_ptr.*);1163 return @enumFromInt(gop.key_ptr.*);
1078}1164}
10791165
1080fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {
1081 return (try coff.getOrPutString(string orelse return .none)).toOptional();
1082}
1083
1084pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {1166pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
1085 const gpa = coff.base.comp.gpa;1167 const gpa = coff.base.comp.gpa;
1086 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);1168 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
...@@ -1095,6 +1177,43 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo...@@ -1095,6 +1177,43 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo
1095 return sym_gop.value_ptr.*;1177 return sym_gop.value_ptr.*;
1096}1178}
10971179
1180fn navSection(
1181 coff: *Coff,
1182 zcu: *Zcu,
1183 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
1184) !Symbol.Index {
1185 const ip = &zcu.intern_pool;
1186 const default: String, const attributes: ObjectSectionAttributes =
1187 switch (ip.indexToKey(nav_fr.val)) {
1188 else => .{ .@".rdata", .{ .read = true } },
1189 .variable => |variable| if (variable.is_threadlocal and
1190 coff.base.comp.config.any_non_single_threaded)
1191 .{ .@".tls$", .{ .read = true, .write = true } }
1192 else
1193 .{ .@".data", .{ .read = true, .write = true } },
1194 .@"extern" => |@"extern"| if (@"extern".is_threadlocal and
1195 coff.base.comp.config.any_non_single_threaded)
1196 .{ .@".tls$", .{ .read = true, .write = true } }
1197 else if (ip.isFunctionType(@"extern".ty))
1198 .{ .@".text", .{ .read = true, .execute = true } }
1199 else if (@"extern".is_const)
1200 .{ .@".rdata", .{ .read = true } }
1201 else
1202 .{ .@".data", .{ .read = true, .write = true } },
1203 .func => .{ .@".text", .{ .read = true, .execute = true } },
1204 };
1205 return (try coff.objectSectionMapIndex(
1206 (try coff.getOrPutOptionalString(nav_fr.@"linksection".toSlice(ip))).unwrap() orelse default,
1207 switch (nav_fr.@"linksection") {
1208 .none => coff.mf.flags.block_size,
1209 else => switch (nav_fr.alignment) {
1210 .none => Type.fromInterned(ip.typeOf(nav_fr.val)).abiAlignment(zcu),
1211 else => |alignment| alignment,
1212 }.toStdMem(),
1213 },
1214 attributes,
1215 )).symbol(coff);
1216}
1098fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {1217fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
1099 const gpa = zcu.gpa;1218 const gpa = zcu.gpa;
1100 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);1219 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
...@@ -1171,7 +1290,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol....@@ -1171,7 +1290,7 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.
1171fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {1290fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
1172 const gpa = coff.base.comp.gpa;1291 const gpa = coff.base.comp.gpa;
1173 try coff.nodes.ensureUnusedCapacity(gpa, 1);1292 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1174 try coff.section_table.ensureUnusedCapacity(gpa, 1);1293 try coff.image_section_table.ensureUnusedCapacity(gpa, 1);
1175 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);1294 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
11761295
1177 const coff_header = coff.headerPtr();1296 const coff_header = coff.headerPtr();
...@@ -1189,13 +1308,13 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags...@@ -1189,13 +1308,13 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
1189 .bubbles_moved = false,1308 .bubbles_moved = false,
1190 });1309 });
1191 const si = coff.addSymbolAssumeCapacity();1310 const si = coff.addSymbolAssumeCapacity();
1192 coff.section_table.appendAssumeCapacity(si);1311 coff.image_section_table.appendAssumeCapacity(si);
1193 coff.nodes.appendAssumeCapacity(.{ .section = si });1312 coff.nodes.appendAssumeCapacity(.{ .image_section = si });
1194 const section_table = coff.sectionTableSlice();1313 const section_table = coff.sectionTableSlice();
1195 const virtual_size = coff.optionalHeaderField(.section_alignment);1314 const virtual_size = coff.optionalHeaderField(.section_alignment);
1196 const rva: u32 = switch (section_index) {1315 const rva: u32 = switch (section_index) {
1197 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]),1316 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]),
1198 else => coff.section_table.items[section_index - 1].get(coff).rva +1317 else => coff.image_section_table.items[section_index - 1].get(coff).rva +
1199 coff.targetLoad(&section_table[section_index - 1].virtual_size),1318 coff.targetLoad(&section_table[section_index - 1].virtual_size),
1200 };1319 };
1201 {1320 {
...@@ -1230,6 +1349,99 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags...@@ -1230,6 +1349,99 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags
1230 return si;1349 return si;
1231}1350}
12321351
1352const ObjectSectionAttributes = packed struct {
1353 read: bool = false,
1354 write: bool = false,
1355 execute: bool = false,
1356 shared: bool = false,
1357 nopage: bool = false,
1358 nocache: bool = false,
1359 discard: bool = false,
1360 remove: bool = false,
1361};
1362fn pseudoSectionMapIndex(
1363 coff: *Coff,
1364 name: String,
1365 alignment: std.mem.Alignment,
1366 attributes: ObjectSectionAttributes,
1367) !Node.PseudoSectionMapIndex {
1368 const gpa = coff.base.comp.gpa;
1369 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);
1370 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);
1371 if (!pseudo_section_gop.found_existing) {
1372 const parent: Symbol.Index = if (attributes.execute)
1373 .text
1374 else if (attributes.write)
1375 .data
1376 else
1377 .rdata;
1378 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1379 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1380 const ni = try coff.mf.addLastChildNode(gpa, parent.node(coff), .{ .alignment = alignment });
1381 const si = coff.addSymbolAssumeCapacity();
1382 pseudo_section_gop.value_ptr.* = si;
1383 const sym = si.get(coff);
1384 sym.ni = ni;
1385 sym.rva = coff.computeNodeRva(ni);
1386 sym.section_number = parent.get(coff).section_number;
1387 assert(sym.loc_relocs == .none);
1388 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1389 coff.nodes.appendAssumeCapacity(.{ .pseudo_section = psmi });
1390 }
1391 return psmi;
1392}
1393fn objectSectionMapIndex(
1394 coff: *Coff,
1395 name: String,
1396 alignment: std.mem.Alignment,
1397 attributes: ObjectSectionAttributes,
1398) !Node.ObjectSectionMapIndex {
1399 const gpa = coff.base.comp.gpa;
1400 const object_section_gop = try coff.object_section_table.getOrPut(gpa, name);
1401 const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index);
1402 if (!object_section_gop.found_existing) {
1403 try coff.ensureUnusedStringCapacity(name.toSlice(coff).len);
1404 const name_slice = name.toSlice(coff);
1405 const parent = (try coff.pseudoSectionMapIndex(coff.getOrPutStringAssumeCapacity(
1406 name_slice[0 .. std.mem.indexOfScalar(u8, name_slice, '$') orelse name_slice.len],
1407 ), alignment, attributes)).symbol(coff);
1408 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1409 try coff.symbol_table.ensureUnusedCapacity(gpa, 1);
1410 const parent_ni = parent.node(coff);
1411 var prev_ni: MappedFile.Node.Index = .none;
1412 var next_it = parent_ni.children(&coff.mf);
1413 while (next_it.next()) |next_ni| switch (std.mem.order(
1414 u8,
1415 name_slice,
1416 coff.getNode(next_ni).object_section.name(coff).toSlice(coff),
1417 )) {
1418 .lt => break,
1419 .eq => unreachable,
1420 .gt => prev_ni = next_ni,
1421 };
1422 const ni = switch (prev_ni) {
1423 .none => try coff.mf.addFirstChildNode(gpa, parent_ni, .{
1424 .alignment = alignment,
1425 .fixed = true,
1426 }),
1427 else => try coff.mf.addNodeAfter(gpa, prev_ni, .{
1428 .alignment = alignment,
1429 .fixed = true,
1430 }),
1431 };
1432 const si = coff.addSymbolAssumeCapacity();
1433 object_section_gop.value_ptr.* = si;
1434 const sym = si.get(coff);
1435 sym.ni = ni;
1436 sym.rva = coff.computeNodeRva(ni);
1437 sym.section_number = parent.get(coff).section_number;
1438 assert(sym.loc_relocs == .none);
1439 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1440 coff.nodes.appendAssumeCapacity(.{ .object_section = osmi });
1441 }
1442 return osmi;
1443}
1444
1233pub fn addReloc(1445pub fn addReloc(
1234 coff: *Coff,1446 coff: *Coff,
1235 loc_si: Symbol.Index,1447 loc_si: Symbol.Index,
...@@ -1279,53 +1491,73 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -1279,53 +1491,73 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
12791491
1280 const nav = ip.getNav(nav_index);1492 const nav = ip.getNav(nav_index);
1281 const nav_val = nav.status.fully_resolved.val;1493 const nav_val = nav.status.fully_resolved.val;
1282 const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) {1494 const nav_init = switch (ip.indexToKey(nav_val)) {
1283 else => .{ nav_val, false },1495 else => nav_val,
1284 .variable => |variable| .{ variable.init, variable.is_threadlocal },1496 .variable => |variable| variable.init,
1285 .@"extern" => return,1497 .@"extern", .func => .none,
1286 .func => .{ .none, false },
1287 };1498 };
1288 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;1499 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
12891500
1290 const nmi = try coff.navMapIndex(zcu, nav_index);1501 const nmi = try coff.navMapIndex(zcu, nav_index);
1291 const si = nmi.symbol(coff);1502 const si = nmi.symbol(coff);
1292 const ni = ni: {1503 const ni = ni: {
1293 const sym = si.get(coff);1504 switch (si.get(coff).ni) {
1294 switch (sym.ni) {
1295 .none => {1505 .none => {
1506 const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
1296 try coff.nodes.ensureUnusedCapacity(gpa, 1);1507 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1297 _ = is_threadlocal;1508 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
1298 const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{
1299 .alignment = pt.navAlignment(nav_index).toStdMem(),1509 .alignment = pt.navAlignment(nav_index).toStdMem(),
1300 .moved = true,1510 .moved = true,
1301 });1511 });
1302 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });1512 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
1513 const sym = si.get(coff);
1303 sym.ni = ni;1514 sym.ni = ni;
1304 sym.section_number = Symbol.Index.data.get(coff).section_number;1515 sym.section_number = sec_si.get(coff).section_number;
1305 },1516 },
1306 else => si.deleteLocationRelocs(coff),1517 else => si.deleteLocationRelocs(coff),
1307 }1518 }
1519 const sym = si.get(coff);
1308 assert(sym.loc_relocs == .none);1520 assert(sym.loc_relocs == .none);
1309 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);1521 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1310 break :ni sym.ni;1522 break :ni sym.ni;
1311 };1523 };
13121524
1313 var nw: MappedFile.Node.Writer = undefined;1525 {
1314 ni.writer(&coff.mf, gpa, &nw);1526 var nw: MappedFile.Node.Writer = undefined;
1315 defer nw.deinit();1527 ni.writer(&coff.mf, gpa, &nw);
1316 codegen.generateSymbol(1528 defer nw.deinit();
1317 &coff.base,1529 codegen.generateSymbol(
1318 pt,1530 &coff.base,
1319 zcu.navSrcLoc(nav_index),1531 pt,
1320 .fromInterned(nav_init),1532 zcu.navSrcLoc(nav_index),
1321 &nw.interface,1533 .fromInterned(nav_init),
1322 .{ .atom_index = @intFromEnum(si) },1534 &nw.interface,
1323 ) catch |err| switch (err) {1535 .{ .atom_index = @intFromEnum(si) },
1324 error.WriteFailed => return error.OutOfMemory,1536 ) catch |err| switch (err) {
1325 else => |e| return e,1537 error.WriteFailed => return error.OutOfMemory,
1326 };1538 else => |e| return e,
1327 si.get(coff).size = @intCast(nw.interface.end);1539 };
1328 si.applyLocationRelocs(coff);1540 si.get(coff).size = @intCast(nw.interface.end);
1541 si.applyLocationRelocs(coff);
1542 }
1543
1544 if (nav.status.fully_resolved.@"linksection".unwrap()) |_| {
1545 try ni.resize(&coff.mf, gpa, si.get(coff).size);
1546 var parent_ni = ni;
1547 while (true) {
1548 parent_ni = parent_ni.parent(&coff.mf);
1549 switch (coff.getNode(parent_ni)) {
1550 else => unreachable,
1551 .image_section, .pseudo_section => break,
1552 .object_section => {
1553 var child_it = parent_ni.reverseChildren(&coff.mf);
1554 const last_offset, const last_size =
1555 child_it.next().?.location(&coff.mf).resolve(&coff.mf);
1556 try parent_ni.resize(&coff.mf, gpa, last_offset + last_size);
1557 },
1558 }
1559 }
1560 }
1329}1561}
13301562
1331pub fn lowerUav(1563pub fn lowerUav(
...@@ -1394,13 +1626,13 @@ fn updateFuncInner(...@@ -1394,13 +1626,13 @@ fn updateFuncInner(
1394 const si = nmi.symbol(coff);1626 const si = nmi.symbol(coff);
1395 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });1627 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
1396 const ni = ni: {1628 const ni = ni: {
1397 const sym = si.get(coff);1629 switch (si.get(coff).ni) {
1398 switch (sym.ni) {
1399 .none => {1630 .none => {
1631 const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
1400 try coff.nodes.ensureUnusedCapacity(gpa, 1);1632 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1401 const mod = zcu.navFileScope(func.owner_nav).mod.?;1633 const mod = zcu.navFileScope(func.owner_nav).mod.?;
1402 const target = &mod.resolved_target.result;1634 const target = &mod.resolved_target.result;
1403 const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{1635 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
1404 .alignment = switch (nav.status.fully_resolved.alignment) {1636 .alignment = switch (nav.status.fully_resolved.alignment) {
1405 .none => switch (mod.optimize_mode) {1637 .none => switch (mod.optimize_mode) {
1406 .Debug,1638 .Debug,
...@@ -1414,11 +1646,13 @@ fn updateFuncInner(...@@ -1414,11 +1646,13 @@ fn updateFuncInner(
1414 .moved = true,1646 .moved = true,
1415 });1647 });
1416 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });1648 coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
1649 const sym = si.get(coff);
1417 sym.ni = ni;1650 sym.ni = ni;
1418 sym.section_number = Symbol.Index.text.get(coff).section_number;1651 sym.section_number = sec_si.get(coff).section_number;
1419 },1652 },
1420 else => si.deleteLocationRelocs(coff),1653 else => si.deleteLocationRelocs(coff),
1421 }1654 }
1655 const sym = si.get(coff);
1422 assert(sym.loc_relocs == .none);1656 assert(sym.loc_relocs == .none);
1423 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);1657 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1424 break :ni sym.ni;1658 break :ni sym.ni;
...@@ -1492,11 +1726,8 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1492,11 +1726,8 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1492 const comp = coff.base.comp;1726 const comp = coff.base.comp;
1493 task: {1727 task: {
1494 while (coff.pending_uavs.pop()) |pending_uav| {1728 while (coff.pending_uavs.pop()) |pending_uav| {
1495 const sub_prog_node = coff.idleProgNode(1729 const sub_prog_node =
1496 tid,1730 coff.idleProgNode(tid, comp.link_const_prog_node, .{ .uav = pending_uav.key });
1497 comp.link_const_prog_node,
1498 .{ .uav = pending_uav.key },
1499 );
1500 defer sub_prog_node.end();1731 defer sub_prog_node.end();
1501 coff.flushUav(1732 coff.flushUav(
1502 .{ .zcu = coff.base.comp.zcu.?, .tid = tid },1733 .{ .zcu = coff.base.comp.zcu.?, .tid = tid },
...@@ -1561,7 +1792,8 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {...@@ -1561,7 +1792,8 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool {
1561 const clean_moved = ni.cleanMoved(&coff.mf);1792 const clean_moved = ni.cleanMoved(&coff.mf);
1562 const clean_resized = ni.cleanResized(&coff.mf);1793 const clean_resized = ni.cleanResized(&coff.mf);
1563 if (clean_moved or clean_resized) {1794 if (clean_moved or clean_resized) {
1564 const sub_prog_node = coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));1795 const sub_prog_node =
1796 coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni));
1565 defer sub_prog_node.end();1797 defer sub_prog_node.end();
1566 if (clean_moved) try coff.flushMoved(ni);1798 if (clean_moved) try coff.flushMoved(ni);
1567 if (clean_resized) try coff.flushResized(ni);1799 if (clean_resized) try coff.flushResized(ni);
...@@ -1584,7 +1816,9 @@ fn idleProgNode(...@@ -1584,7 +1816,9 @@ fn idleProgNode(
1584 var name: [std.Progress.Node.max_name_len]u8 = undefined;1816 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1585 return prog_node.start(name: switch (node) {1817 return prog_node.start(name: switch (node) {
1586 else => |tag| @tagName(tag),1818 else => |tag| @tagName(tag),
1587 .section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),1819 .image_section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),
1820 inline .pseudo_section, .object_section => |smi| smi.name(coff).toSlice(coff),
1821 .global => |gmi| gmi.globalName(coff).name.toSlice(coff),
1588 .nav => |nmi| {1822 .nav => |nmi| {
1589 const ip = &coff.base.comp.zcu.?.intern_pool;1823 const ip = &coff.base.comp.zcu.?.intern_pool;
1590 break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip);1824 break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip);
...@@ -1611,23 +1845,30 @@ fn flushUav(...@@ -1611,23 +1845,30 @@ fn flushUav(
1611 const uav_val = umi.uavValue(coff);1845 const uav_val = umi.uavValue(coff);
1612 const si = umi.symbol(coff);1846 const si = umi.symbol(coff);
1613 const ni = ni: {1847 const ni = ni: {
1614 const sym = si.get(coff);1848 switch (si.get(coff).ni) {
1615 switch (sym.ni) {
1616 .none => {1849 .none => {
1850 const sec_si = (try coff.objectSectionMapIndex(
1851 .@".rdata",
1852 coff.mf.flags.block_size,
1853 .{ .read = true },
1854 )).symbol(coff);
1617 try coff.nodes.ensureUnusedCapacity(gpa, 1);1855 try coff.nodes.ensureUnusedCapacity(gpa, 1);
1618 const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{1856 const sym = si.get(coff);
1857 const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
1619 .alignment = uav_align.toStdMem(),1858 .alignment = uav_align.toStdMem(),
1620 .moved = true,1859 .moved = true,
1621 });1860 });
1622 coff.nodes.appendAssumeCapacity(.{ .uav = umi });1861 coff.nodes.appendAssumeCapacity(.{ .uav = umi });
1623 sym.ni = ni;1862 sym.ni = ni;
1624 sym.section_number = Symbol.Index.data.get(coff).section_number;1863 sym.section_number = sec_si.get(coff).section_number;
1625 },1864 },
1626 else => {1865 else => {
1627 if (sym.ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte)) return;1866 if (si.get(coff).ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte))
1867 return;
1628 si.deleteLocationRelocs(coff);1868 si.deleteLocationRelocs(coff);
1629 },1869 },
1630 }1870 }
1871 const sym = si.get(coff);
1631 assert(sym.loc_relocs == .none);1872 assert(sym.loc_relocs == .none);
1632 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);1873 sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1633 break :ni sym.ni;1874 break :ni sym.ni;
...@@ -1684,7 +1925,7 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -1684,7 +1925,7 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
1684 );1925 );
1685 const import_hint_name_table_len =1926 const import_hint_name_table_len =
1686 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);1927 import_hint_name_align.forward(lib_name.len + ".dll".len + 1);
1687 const idata_section_ni = Symbol.Index.idata.node(coff);1928 const idata_section_ni = coff.import_table.ni.parent(&coff.mf);
1688 const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{1929 const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{
1689 .size = addr_size * 2,1930 .size = addr_size * 2,
1690 .alignment = addr_align,1931 .alignment = addr_align,
...@@ -1701,7 +1942,8 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {...@@ -1701,7 +1942,8 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void {
1701 import_address_table_sym.ni = import_address_table_ni;1942 import_address_table_sym.ni = import_address_table_ni;
1702 assert(import_address_table_sym.loc_relocs == .none);1943 assert(import_address_table_sym.loc_relocs == .none);
1703 import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len);1944 import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len);
1704 import_address_table_sym.section_number = Symbol.Index.idata.get(coff).section_number;1945 import_address_table_sym.section_number =
1946 coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number;
1705 }1947 }
1706 const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{1948 const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{
1707 .size = import_hint_name_table_len,1949 .size = import_hint_name_table_len,
...@@ -1873,12 +2115,12 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -1873,12 +2115,12 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
1873 .data_directories,2115 .data_directories,
1874 .section_table,2116 .section_table,
1875 => unreachable,2117 => unreachable,
1876 .section => |si| return coff.targetStore(2118 .image_section => |si| return coff.targetStore(
1877 &si.get(coff).section_number.header(coff).pointer_to_raw_data,2119 &si.get(coff).section_number.header(coff).pointer_to_raw_data,
1878 @intCast(ni.fileLocation(&coff.mf, false).offset),2120 @intCast(ni.fileLocation(&coff.mf, false).offset),
1879 ),2121 ),
1880 .import_directory_table => coff.targetStore(2122 .import_directory_table => coff.targetStore(
1881 &coff.dataDirectoryPtr(.import_table).virtual_address,2123 &coff.dataDirectoryPtr(.IMPORT).virtual_address,
1882 coff.computeNodeRva(ni),2124 coff.computeNodeRva(ni),
1883 ),2125 ),
1884 .import_lookup_table => |import_index| coff.targetStore(2126 .import_lookup_table => |import_index| coff.targetStore(
...@@ -1939,7 +2181,9 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -1939,7 +2181,9 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
1939 import_hint_name_index += 2;2181 import_hint_name_index += 2;
1940 }2182 }
1941 },2183 },
1942 inline .global,2184 inline .pseudo_section,
2185 .object_section,
2186 .global,
1943 .nav,2187 .nav,
1944 .uav,2188 .uav,
1945 .lazy_code,2189 .lazy_code,
...@@ -1960,7 +2204,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -1960,7 +2204,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
1960 @intCast(size),2204 @intCast(size),
1961 ),2205 ),
1962 }2206 }
1963 if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide(2207 if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide(
1964 0,2208 0,
1965 std.mem.alignForward(2209 std.mem.alignForward(
1966 u32,2210 u32,
...@@ -1971,7 +2215,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -1971,7 +2215,7 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
1971 },2215 },
1972 .signature, .coff_header, .optional_header, .data_directories => unreachable,2216 .signature, .coff_header, .optional_header, .data_directories => unreachable,
1973 .section_table => {},2217 .section_table => {},
1974 .section => |si| {2218 .image_section => |si| {
1975 const sym = si.get(coff);2219 const sym = si.get(coff);
1976 const section_index = sym.section_number.toIndex();2220 const section_index = sym.section_number.toIndex();
1977 const section = &coff.sectionTableSlice()[section_index];2221 const section = &coff.sectionTableSlice()[section_index];
...@@ -1987,24 +2231,20 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -1987,24 +2231,20 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void {
1987 }2231 }
1988 },2232 },
1989 .import_directory_table => coff.targetStore(2233 .import_directory_table => coff.targetStore(
1990 &coff.dataDirectoryPtr(.import_table).size,2234 &coff.dataDirectoryPtr(.IMPORT).size,
1991 @intCast(size),2235 @intCast(size),
1992 ),2236 ),
1993 .import_lookup_table,2237 .import_lookup_table, .import_address_table, .import_hint_name_table => {},
1994 .import_address_table,2238 inline .pseudo_section,
1995 .import_hint_name_table,2239 .object_section,
1996 .global,2240 => |smi| smi.symbol(coff).get(coff).size = @intCast(size),
1997 .nav,2241 .global, .nav, .uav, .lazy_code, .lazy_const_data => {},
1998 .uav,
1999 .lazy_code,
2000 .lazy_const_data,
2001 => {},
2002 }2242 }
2003}2243}
2004fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {2244fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void {
2005 var rva = start_rva;2245 var rva = start_rva;
2006 for (2246 for (
2007 coff.section_table.items[start_section_index..],2247 coff.image_section_table.items[start_section_index..],
2008 coff.sectionTableSlice()[start_section_index..],2248 coff.sectionTableSlice()[start_section_index..],
2009 ) |section_si, *section| {2249 ) |section_si, *section| {
2010 const section_sym = section_si.get(coff);2250 const section_sym = section_si.get(coff);
...@@ -2078,8 +2318,12 @@ fn updateExportsInner(...@@ -2078,8 +2318,12 @@ fn updateExportsInner(
2078 export_sym.section_number = exported_sym.section_number;2318 export_sym.section_number = exported_sym.section_number;
2079 export_si.applyTargetRelocs(coff);2319 export_si.applyTargetRelocs(coff);
2080 if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) {2320 if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) {
2081 coff.entry_hack = exported_si;
2082 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;2321 coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva;
2322 } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) {
2323 const tls_directory = coff.dataDirectoryPtr(.TLS);
2324 tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.size };
2325 if (coff.targetEndian() != native_endian)
2326 std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory);
2083 }2327 }
2084 }2328 }
2085}2329}
...@@ -2108,7 +2352,7 @@ pub fn printNode(...@@ -2108,7 +2352,7 @@ pub fn printNode(
2108 try w.writeAll(@tagName(node));2352 try w.writeAll(@tagName(node));
2109 switch (node) {2353 switch (node) {
2110 else => {},2354 else => {},
2111 .section => |si| try w.print("({s})", .{2355 .image_section => |si| try w.print("({s})", .{
2112 std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),2356 std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0),
2113 }),2357 }),
2114 .import_lookup_table,2358 .import_lookup_table,
...@@ -2117,6 +2361,9 @@ pub fn printNode(...@@ -2117,6 +2361,9 @@ pub fn printNode(
2117 => |import_index| try w.print("({s})", .{2361 => |import_index| try w.print("({s})", .{
2118 std.mem.sliceTo(import_index.get(coff).import_hint_name_table_ni.sliceConst(&coff.mf), 0),2362 std.mem.sliceTo(import_index.get(coff).import_hint_name_table_ni.sliceConst(&coff.mf), 0),
2119 }),2363 }),
2364 inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{
2365 smi.name(coff).toSlice(coff),
2366 }),
2120 .global => |gmi| {2367 .global => |gmi| {
2121 const gn = gmi.globalName(coff);2368 const gn = gmi.globalName(coff);
2122 try w.writeByte('(');2369 try w.writeByte('(');
src/link/Elf2.zig+54-30
...@@ -546,7 +546,7 @@ fn initHeaders(...@@ -546,7 +546,7 @@ fn initHeaders(
546 break :phndx phnum;546 break :phndx phnum;
547 } else undefined;547 } else undefined;
548548
549 const expected_nodes_len = 15;549 const expected_nodes_len = 5 + phnum * 2;
550 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);550 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
551 try elf.phdrs.resize(gpa, phnum);551 try elf.phdrs.resize(gpa, phnum);
552 elf.nodes.appendAssumeCapacity(.file);552 elf.nodes.appendAssumeCapacity(.file);
...@@ -808,25 +808,6 @@ fn initHeaders(...@@ -808,25 +808,6 @@ fn initHeaders(
808 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;808 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
809 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;809 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
810810
811 if (maybe_interp) |interp| {
812 try elf.nodes.ensureUnusedCapacity(gpa, 1);
813 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
814 .size = interp.len + 1,
815 .moved = true,
816 .resized = true,
817 });
818 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
819 elf.phdrs.items[interp_phndx] = interp_ni;
820
821 const sec_interp_si = try elf.addSection(interp_ni, .{
822 .name = ".interp",
823 .size = @intCast(interp.len + 1),
824 .flags = .{ .ALLOC = true },
825 });
826 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
827 @memcpy(sec_interp[0..interp.len], interp);
828 sec_interp[interp.len] = 0;
829 }
830 assert(try elf.addSection(Node.Known.rodata, .{811 assert(try elf.addSection(Node.Known.rodata, .{
831 .name = ".rodata",812 .name = ".rodata",
832 .flags = .{ .ALLOC = true },813 .flags = .{ .ALLOC = true },
...@@ -857,6 +838,25 @@ fn initHeaders(...@@ -857,6 +838,25 @@ fn initHeaders(
857 .addralign = elf.mf.flags.block_size,838 .addralign = elf.mf.flags.block_size,
858 }) == .tdata);839 }) == .tdata);
859 }840 }
841 if (maybe_interp) |interp| {
842 try elf.nodes.ensureUnusedCapacity(gpa, 1);
843 const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{
844 .size = interp.len + 1,
845 .moved = true,
846 .resized = true,
847 });
848 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
849 elf.phdrs.items[interp_phndx] = interp_ni;
850
851 const sec_interp_si = try elf.addSection(interp_ni, .{
852 .name = ".interp",
853 .size = @intCast(interp.len + 1),
854 .flags = .{ .ALLOC = true },
855 });
856 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
857 @memcpy(sec_interp[0..interp.len], interp);
858 sec_interp[interp.len] = 0;
859 }
860 assert(elf.nodes.len == expected_nodes_len);860 assert(elf.nodes.len == expected_nodes_len);
861}861}
862862
...@@ -1072,6 +1072,32 @@ fn navType(...@@ -1072,6 +1072,32 @@ fn navType(
1072 },1072 },
1073 };1073 };
1074}1074}
1075fn navSection(
1076 elf: *Elf,
1077 ip: *const InternPool,
1078 nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
1079) Symbol.Index {
1080 if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| {
1081 if (std.mem.eql(u8, @"linksection", ".rodata") or
1082 std.mem.startsWith(u8, @"linksection", ".rodata.")) return .rodata;
1083 if (std.mem.eql(u8, @"linksection", ".text") or
1084 std.mem.startsWith(u8, @"linksection", ".text.")) return .text;
1085 if (std.mem.eql(u8, @"linksection", ".data") or
1086 std.mem.startsWith(u8, @"linksection", ".data.")) return .data;
1087 if (std.mem.eql(u8, @"linksection", ".tdata") or
1088 std.mem.startsWith(u8, @"linksection", ".tdata.")) return .tdata;
1089 }
1090 return switch (navType(
1091 ip,
1092 .{ .fully_resolved = nav_fr },
1093 elf.base.comp.config.any_non_single_threaded,
1094 )) {
1095 else => unreachable,
1096 .FUNC => .text,
1097 .OBJECT => .data,
1098 .TLS => .tdata,
1099 };
1100}
1075fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {1101fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
1076 const gpa = zcu.gpa;1102 const gpa = zcu.gpa;
1077 const ip = &zcu.intern_pool;1103 const ip = &zcu.intern_pool;
...@@ -1312,18 +1338,16 @@ pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -1312,18 +1338,16 @@ pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1312 };1338 };
1313}1339}
1314fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {1340fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
1315 const comp = elf.base.comp;
1316 const zcu = pt.zcu;1341 const zcu = pt.zcu;
1317 const gpa = zcu.gpa;1342 const gpa = zcu.gpa;
1318 const ip = &zcu.intern_pool;1343 const ip = &zcu.intern_pool;
13191344
1320 const nav = ip.getNav(nav_index);1345 const nav = ip.getNav(nav_index);
1321 const nav_val = nav.status.fully_resolved.val;1346 const nav_val = nav.status.fully_resolved.val;
1322 const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) {1347 const nav_init = switch (ip.indexToKey(nav_val)) {
1323 else => .{ nav_val, false },1348 else => nav_val,
1324 .variable => |variable| .{ variable.init, variable.is_threadlocal },1349 .variable => |variable| variable.init,
1325 .@"extern" => return,1350 .@"extern", .func => .none,
1326 .func => .{ .none, false },
1327 };1351 };
1328 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;1352 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
13291353
...@@ -1334,8 +1358,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -1334,8 +1358,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1334 switch (sym.ni) {1358 switch (sym.ni) {
1335 .none => {1359 .none => {
1336 try elf.nodes.ensureUnusedCapacity(gpa, 1);1360 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1337 const sec_si: Symbol.Index =1361 const sec_si = elf.navSection(ip, nav.status.fully_resolved);
1338 if (is_threadlocal and comp.config.any_non_single_threaded) .tdata else .data;
1339 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{1362 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
1340 .alignment = pt.navAlignment(nav_index).toStdMem(),1363 .alignment = pt.navAlignment(nav_index).toStdMem(),
1341 .moved = true,1364 .moved = true,
...@@ -1452,9 +1475,10 @@ fn updateFuncInner(...@@ -1452,9 +1475,10 @@ fn updateFuncInner(
1452 switch (sym.ni) {1475 switch (sym.ni) {
1453 .none => {1476 .none => {
1454 try elf.nodes.ensureUnusedCapacity(gpa, 1);1477 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1478 const sec_si = elf.navSection(ip, nav.status.fully_resolved);
1455 const mod = zcu.navFileScope(func.owner_nav).mod.?;1479 const mod = zcu.navFileScope(func.owner_nav).mod.?;
1456 const target = &mod.resolved_target.result;1480 const target = &mod.resolved_target.result;
1457 const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.text.node(elf), .{1481 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
1458 .alignment = switch (nav.status.fully_resolved.alignment) {1482 .alignment = switch (nav.status.fully_resolved.alignment) {
1459 .none => switch (mod.optimize_mode) {1483 .none => switch (mod.optimize_mode) {
1460 .Debug,1484 .Debug,
...@@ -1471,7 +1495,7 @@ fn updateFuncInner(...@@ -1471,7 +1495,7 @@ fn updateFuncInner(
1471 sym.ni = ni;1495 sym.ni = ni;
1472 switch (elf.symPtr(si)) {1496 switch (elf.symPtr(si)) {
1473 inline else => |sym_ptr, class| sym_ptr.shndx =1497 inline else => |sym_ptr, class| sym_ptr.shndx =
1474 @field(elf.symPtr(.text), @tagName(class)).shndx,1498 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
1475 }1499 }
1476 },1500 },
1477 else => si.deleteLocationRelocs(elf),1501 else => si.deleteLocationRelocs(elf),
src/link/MappedFile.zig+267-168
...@@ -14,6 +14,8 @@ updates: std.ArrayList(Node.Index),...@@ -14,6 +14,8 @@ updates: std.ArrayList(Node.Index),
14update_prog_node: std.Progress.Node,14update_prog_node: std.Progress.Node,
15writers: std.SinglyLinkedList,15writers: std.SinglyLinkedList,
1616
17pub const growth_factor = 4;
18
17pub const Error = std.posix.MMapError ||19pub const Error = std.posix.MMapError ||
18 std.posix.MRemapError ||20 std.posix.MRemapError ||
19 std.fs.File.SetEndPosError ||21 std.fs.File.SetEndPosError ||
...@@ -64,6 +66,7 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {...@@ -64,6 +66,7 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
64 assert(try mf.addNode(gpa, .{66 assert(try mf.addNode(gpa, .{
65 .add_node = .{67 .add_node = .{
66 .size = size,68 .size = size,
69 .alignment = mf.flags.block_size,
67 .fixed = true,70 .fixed = true,
68 },71 },
69 }) == Node.Index.root);72 }) == Node.Index.root);
...@@ -153,20 +156,24 @@ pub const Node = extern struct {...@@ -153,20 +156,24 @@ pub const Node = extern struct {
153 return ni.get(mf).parent;156 return ni.get(mf).parent;
154 }157 }
155158
156 pub const ChildIterator = struct {159 pub fn ChildIterator(comptime direction: enum { prev, next }) type {
157 mf: *const MappedFile,160 return struct {
158 ni: Node.Index,161 mf: *const MappedFile,
159162 ni: Node.Index,
160 pub fn next(it: *ChildIterator) ?Node.Index {163 pub fn next(it: *@This()) ?Node.Index {
161 const ni = it.ni;164 const ni = it.ni;
162 if (ni == .none) return null;165 if (ni == .none) return null;
163 it.ni = ni.get(it.mf).next;166 it.ni = @field(ni.get(it.mf), @tagName(direction));
164 return ni;167 return ni;
165 }168 }
166 };169 };
167 pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator {170 }
171 pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator(.next) {
168 return .{ .mf = mf, .ni = ni.get(mf).first };172 return .{ .mf = mf, .ni = ni.get(mf).first };
169 }173 }
174 pub fn reverseChildren(ni: Node.Index, mf: *const MappedFile) ChildIterator(.prev) {
175 return .{ .mf = mf, .ni = ni.get(mf).last };
176 }
170177
171 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {178 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
172 var child_ni = ni.get(mf).last;179 var child_ni = ni.get(mf).last;
...@@ -274,7 +281,8 @@ pub const Node = extern struct {...@@ -274,7 +281,8 @@ pub const Node = extern struct {
274 if (set_has_content) parent_node.flags.has_content = true;281 if (set_has_content) parent_node.flags.has_content = true;
275 if (parent_ni == .none) break;282 if (parent_ni == .none) break;
276 parent_ni = parent_node.parent;283 parent_ni = parent_node.parent;
277 offset += parent_ni.location(mf).resolve(mf)[0];284 const parent_offset, _ = parent_ni.location(mf).resolve(mf);
285 offset += parent_offset;
278 }286 }
279 return .{ .offset = offset, .size = size };287 return .{ .offset = offset, .size = size };
280 }288 }
...@@ -428,7 +436,7 @@ pub const Node = extern struct {...@@ -428,7 +436,7 @@ pub const Node = extern struct {
428 const total_capacity = interface.end + unused_capacity;436 const total_capacity = interface.end + unused_capacity;
429 if (interface.buffer.len >= total_capacity) return;437 if (interface.buffer.len >= total_capacity) return;
430 const w: *Writer = @fieldParentPtr("interface", interface);438 const w: *Writer = @fieldParentPtr("interface", interface);
431 w.ni.resize(w.mf, w.gpa, total_capacity +| total_capacity / 2) catch |err| {439 w.ni.resize(w.mf, w.gpa, total_capacity +| total_capacity / growth_factor) catch |err| {
432 w.err = err;440 w.err = err;
433 return error.WriteFailed;441 return error.WriteFailed;
434 };442 };
...@@ -487,7 +495,8 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -487,7 +495,8 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
487 free_node.flags.moved = false;495 free_node.flags.moved = false;
488 free_node.flags.resized = false;496 free_node.flags.resized = false;
489 }497 }
490 if (offset > opts.parent.location(mf).resolve(mf)[1]) try opts.parent.resize(mf, gpa, offset);498 _, const parent_size = opts.parent.location(mf).resolve(mf);
499 if (offset > parent_size) try opts.parent.resize(mf, gpa, offset);
491 try free_ni.resize(mf, gpa, opts.add_node.size);500 try free_ni.resize(mf, gpa, opts.add_node.size);
492 }501 }
493 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);502 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);
...@@ -522,6 +531,27 @@ pub fn addOnlyChildNode(...@@ -522,6 +531,27 @@ pub fn addOnlyChildNode(
522 return ni;531 return ni;
523}532}
524533
534pub fn addFirstChildNode(
535 mf: *MappedFile,
536 gpa: std.mem.Allocator,
537 parent_ni: Node.Index,
538 opts: AddNodeOptions,
539) !Node.Index {
540 try mf.nodes.ensureUnusedCapacity(gpa, 1);
541 const parent = parent_ni.get(mf);
542 const ni = try mf.addNode(gpa, .{
543 .parent = parent_ni,
544 .next = parent.first,
545 .add_node = opts,
546 });
547 switch (parent.first) {
548 .none => parent.last = ni,
549 else => |first_ni| first_ni.get(mf).prev = ni,
550 }
551 parent.first = ni;
552 return ni;
553}
554
525pub fn addLastChildNode(555pub fn addLastChildNode(
526 mf: *MappedFile,556 mf: *MappedFile,
527 gpa: std.mem.Allocator,557 gpa: std.mem.Allocator,
...@@ -577,7 +607,7 @@ pub fn addNodeAfter(...@@ -577,7 +607,7 @@ pub fn addNodeAfter(
577607
578fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {608fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {
579 const node = ni.get(mf);609 const node = ni.get(mf);
580 var old_offset, const old_size = node.location().resolve(mf);610 const old_offset, const old_size = node.location().resolve(mf);
581 const new_size = node.flags.alignment.forward(@intCast(requested_size));611 const new_size = node.flags.alignment.forward(@intCast(requested_size));
582 // Resize the entire file612 // Resize the entire file
583 if (ni == Node.Index.root) {613 if (ni == Node.Index.root) {
...@@ -587,169 +617,238 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested...@@ -587,169 +617,238 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
587 ni.setLocationAssumeCapacity(mf, old_offset, new_size);617 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
588 return;618 return;
589 }619 }
590 while (true) {620 const parent = node.parent.get(mf);
591 const parent = node.parent.get(mf);621 _, var old_parent_size = parent.location().resolve(mf);
592 _, const old_parent_size = parent.location().resolve(mf);622 const trailing_end = trailing_end: switch (node.next) {
593 const trailing_end = switch (node.next) {623 .none => old_parent_size,
594 .none => parent.location().resolve(mf)[1],624 else => |next_ni| {
595 else => |next_ni| next_ni.location(mf).resolve(mf)[0],625 const next_offset, _ = next_ni.location(mf).resolve(mf);
596 };626 break :trailing_end next_offset;
597 assert(old_offset + old_size <= trailing_end);627 },
598 // Expand the node into available trailing free space628 };
599 if (old_offset + new_size <= trailing_end) {629 assert(old_offset + old_size <= trailing_end);
600 try mf.ensureCapacityForSetLocation(gpa);630 if (old_offset + new_size <= trailing_end) {
601 ni.setLocationAssumeCapacity(mf, old_offset, new_size);631 // Expand the node into trailing free space
602 return;632 try mf.ensureCapacityForSetLocation(gpa);
603 }633 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
604 // Ask the filesystem driver to insert an extent into the file without copying any data634 return;
605 if (is_linux and !mf.flags.fallocate_insert_range_unsupported and635 }
606 node.flags.alignment.order(mf.flags.block_size).compare(.gte))636 if (is_linux and !mf.flags.fallocate_insert_range_unsupported and
607 insert_range: {637 node.flags.alignment.order(mf.flags.block_size).compare(.gte))
608 const last_offset, const last_size = parent.last.location(mf).resolve(mf);638 insert_range: {
609 const last_end = last_offset + last_size;639 // Ask the filesystem driver to insert extents into the file without copying any data
610 assert(last_end <= old_parent_size);640 const last_offset, const last_size = parent.last.location(mf).resolve(mf);
611 const range_size =641 const last_end = last_offset + last_size;
612 node.flags.alignment.forward(@intCast(requested_size +| requested_size / 2)) - old_size;642 assert(last_end <= old_parent_size);
613 const new_parent_size = last_end + range_size;643 const range_file_offset = ni.fileLocation(mf, false).offset + old_size;
614 if (new_parent_size > old_parent_size) {644 const range_size = node.flags.alignment.forward(
615 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2);645 @intCast(requested_size +| requested_size / growth_factor),
616 continue;646 ) - old_size;
617 }647 _, const file_size = Node.Index.root.location(mf).resolve(mf);
618 const range_file_offset = ni.fileLocation(mf, false).offset + old_size;648 while (true) switch (linux.E.init(switch (std.math.order(range_file_offset, file_size)) {
619 while (true) switch (linux.E.init(linux.fallocate(649 .lt => linux.fallocate(
620 mf.file.handle,650 mf.file.handle,
621 linux.FALLOC.FL_INSERT_RANGE,651 linux.FALLOC.FL_INSERT_RANGE,
622 @intCast(range_file_offset),652 @intCast(range_file_offset),
623 @intCast(range_size),653 @intCast(range_size),
624 ))) {654 ),
625 .SUCCESS => {655 .eq => linux.ftruncate(mf.file.handle, @intCast(range_file_offset + range_size)),
626 var enclosing_ni = ni;656 .gt => unreachable,
627 while (true) {657 })) {
628 try mf.ensureCapacityForSetLocation(gpa);658 .SUCCESS => {
629 const enclosing = enclosing_ni.get(mf);659 var enclosing_ni = ni;
630 const enclosing_offset, const old_enclosing_size =660 while (true) {
631 enclosing.location().resolve(mf);661 try mf.ensureCapacityForSetLocation(gpa);
632 const new_enclosing_size = old_enclosing_size + range_size;662 const enclosing = enclosing_ni.get(mf);
633 enclosing_ni.setLocationAssumeCapacity(mf, enclosing_offset, new_enclosing_size);663 const enclosing_offset, const old_enclosing_size =
634 if (enclosing_ni == Node.Index.root) {664 enclosing.location().resolve(mf);
635 assert(enclosing_offset == 0);665 const new_enclosing_size = old_enclosing_size + range_size;
636 try mf.ensureTotalCapacity(@intCast(new_enclosing_size));666 enclosing_ni.setLocationAssumeCapacity(mf, enclosing_offset, new_enclosing_size);
637 break;667 if (enclosing_ni == Node.Index.root) {
638 }668 assert(enclosing_offset == 0);
639 var after_ni = enclosing.next;669 try mf.ensureTotalCapacity(@intCast(new_enclosing_size));
640 while (after_ni != .none) {670 break;
641 try mf.ensureCapacityForSetLocation(gpa);
642 const after = after_ni.get(mf);
643 const after_offset, const after_size = after.location().resolve(mf);
644 after_ni.setLocationAssumeCapacity(
645 mf,
646 range_size + after_offset,
647 after_size,
648 );
649 after_ni = after.next;
650 }
651 enclosing_ni = enclosing.parent;
652 }
653 return;
654 },
655 .INTR => continue,
656 .BADF, .FBIG, .INVAL => unreachable,
657 .IO => return error.InputOutput,
658 .NODEV => return error.NotFile,
659 .NOSPC => return error.NoSpaceLeft,
660 .NOSYS, .OPNOTSUPP => {
661 mf.flags.fallocate_insert_range_unsupported = true;
662 break :insert_range;
663 },
664 .PERM => return error.PermissionDenied,
665 .SPIPE => return error.Unseekable,
666 .TXTBSY => return error.FileBusy,
667 else => |e| return std.posix.unexpectedErrno(e),
668 };
669 }
670 switch (node.next) {
671 .none => {
672 // As this is the last node, we simply need more space in the parent
673 const new_parent_size = old_offset + new_size;
674 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2);
675 },
676 else => |*next_ni_ptr| switch (node.flags.fixed) {
677 false => {
678 // Make space at the end of the parent for this floating node
679 const last = parent.last.get(mf);
680 const last_offset, const last_size = last.location().resolve(mf);
681 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));
682 const new_parent_size = new_offset + new_size;
683 if (new_parent_size > old_parent_size) {
684 try mf.resizeNode(
685 gpa,
686 node.parent,
687 new_parent_size +| new_parent_size / 2,
688 );
689 continue;
690 }
691 const next_ni = next_ni_ptr.*;
692 next_ni.get(mf).prev = node.prev;
693 switch (node.prev) {
694 .none => parent.first = next_ni,
695 else => |prev_ni| prev_ni.get(mf).next = next_ni,
696 }671 }
697 last.next = ni;672 var after_ni = enclosing.next;
698 node.prev = parent.last;673 while (after_ni != .none) {
699 next_ni_ptr.* = .none;674 try mf.ensureCapacityForSetLocation(gpa);
700 parent.last = ni;675 const after = after_ni.get(mf);
701 if (node.flags.has_content) {676 const after_offset, const after_size = after.location().resolve(mf);
702 const parent_file_offset = node.parent.fileLocation(mf, false).offset;677 after_ni.setLocationAssumeCapacity(
703 try mf.moveRange(678 mf,
704 parent_file_offset + old_offset,679 range_size + after_offset,
705 parent_file_offset + new_offset,680 after_size,
706 old_size,
707 );681 );
682 after_ni = after.next;
708 }683 }
709 old_offset = new_offset;684 enclosing_ni = enclosing.parent;
710 },685 }
711 true => {686 return;
712 // Move the next floating node to make space for this fixed node687 },
713 const next_ni = next_ni_ptr.*;688 .INTR => continue,
714 const next = next_ni.get(mf);689 .BADF, .FBIG, .INVAL => unreachable,
715 assert(!next.flags.fixed);690 .IO => return error.InputOutput,
716 const next_offset, const next_size = next.location().resolve(mf);691 .NODEV => return error.NotFile,
717 const last = parent.last.get(mf);692 .NOSPC => return error.NoSpaceLeft,
718 const last_offset, const last_size = last.location().resolve(mf);693 .NOSYS, .OPNOTSUPP => {
719 const new_offset = next.flags.alignment.forward(@intCast(694 mf.flags.fallocate_insert_range_unsupported = true;
720 @max(old_offset + new_size, last_offset + last_size),695 break :insert_range;
696 },
697 .PERM => return error.PermissionDenied,
698 .SPIPE => return error.Unseekable,
699 .TXTBSY => return error.FileBusy,
700 else => |e| return std.posix.unexpectedErrno(e),
701 };
702 }
703 if (node.next == .none) {
704 // As this is the last node, we simply need more space in the parent
705 const new_parent_size = old_offset + new_size;
706 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);
707 try mf.ensureCapacityForSetLocation(gpa);
708 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
709 return;
710 }
711 if (!node.flags.fixed) {
712 // Make space at the end of the parent for this floating node
713 const last = parent.last.get(mf);
714 const last_offset, const last_size = last.location().resolve(mf);
715 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));
716 const new_parent_size = new_offset + new_size;
717 if (new_parent_size > old_parent_size)
718 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / growth_factor);
719 try mf.ensureCapacityForSetLocation(gpa);
720 const next_ni = node.next;
721 next_ni.get(mf).prev = node.prev;
722 switch (node.prev) {
723 .none => parent.first = next_ni,
724 else => |prev_ni| prev_ni.get(mf).next = next_ni,
725 }
726 last.next = ni;
727 node.prev = parent.last;
728 node.next = .none;
729 parent.last = ni;
730 if (node.flags.has_content) {
731 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
732 try mf.moveRange(
733 parent_file_offset + old_offset,
734 parent_file_offset + new_offset,
735 old_size,
736 );
737 }
738 ni.setLocationAssumeCapacity(mf, new_offset, new_size);
739 return;
740 }
741 // Search for the first floating node following this fixed node
742 var last_fixed_ni = ni;
743 var first_floating_ni = node.next;
744 var shift = new_size - old_size;
745 var direction: enum { forward, reverse } = .forward;
746 while (true) {
747 assert(last_fixed_ni != .none);
748 const last_fixed = last_fixed_ni.get(mf);
749 assert(last_fixed.flags.fixed);
750 const old_last_fixed_offset, const last_fixed_size = last_fixed.location().resolve(mf);
751 const new_last_fixed_offset = old_last_fixed_offset + shift;
752 make_space: switch (first_floating_ni) {
753 else => {
754 const first_floating = first_floating_ni.get(mf);
755 const old_first_floating_offset, const first_floating_size =
756 first_floating.location().resolve(mf);
757 assert(old_last_fixed_offset + last_fixed_size <= old_first_floating_offset);
758 if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset)
759 break :make_space;
760 assert(direction == .forward);
761 if (first_floating.flags.fixed) {
762 shift = first_floating.flags.alignment.forward(@intCast(
763 @max(shift, first_floating_size),
721 ));764 ));
722 const new_parent_size = new_offset + next_size;765 // Not enough space, try the next node
723 if (new_parent_size > old_parent_size) {766 last_fixed_ni = first_floating_ni;
724 try mf.resizeNode(767 first_floating_ni = first_floating.next;
725 gpa,768 continue;
726 node.parent,769 }
727 new_parent_size +| new_parent_size / 2,770 // Move the found floating node to make space for preceding fixed nodes
728 );771 const last = parent.last.get(mf);
729 continue;772 const last_offset, const last_size = last.location().resolve(mf);
730 }773 const new_first_floating_offset = first_floating.flags.alignment.forward(
731 try mf.ensureCapacityForSetLocation(gpa);774 @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)),
732 next.prev = parent.last;775 );
733 parent.last = next_ni;776 const new_parent_size = new_first_floating_offset + first_floating_size;
734 last.next = next_ni;777 if (new_parent_size > old_parent_size) {
735 next_ni_ptr.* = next.next;778 try mf.resizeNode(
736 switch (next.next) {779 gpa,
780 node.parent,
781 new_parent_size +| new_parent_size / growth_factor,
782 );
783 _, old_parent_size = parent.location().resolve(mf);
784 }
785 try mf.ensureCapacityForSetLocation(gpa);
786 if (parent.last != first_floating_ni) {
787 first_floating.prev = parent.last;
788 parent.last = first_floating_ni;
789 last.next = first_floating_ni;
790 last_fixed.next = first_floating.next;
791 switch (first_floating.next) {
737 .none => {},792 .none => {},
738 else => |next_next_ni| next_next_ni.get(mf).prev = ni,793 else => |next_ni| next_ni.get(mf).prev = last_fixed_ni,
739 }794 }
740 next.next = .none;795 first_floating.next = .none;
741 if (node.flags.has_content) {796 }
742 const parent_file_offset = node.parent.fileLocation(mf, false).offset;797 if (first_floating.flags.has_content) {
743 try mf.moveRange(798 const parent_file_offset =
744 parent_file_offset + next_offset,799 node.parent.fileLocation(mf, false).offset;
745 parent_file_offset + new_offset,800 try mf.moveRange(
746 next_size,801 parent_file_offset + old_first_floating_offset,
747 );802 parent_file_offset + new_first_floating_offset,
748 }803 first_floating_size,
749 next_ni.setLocationAssumeCapacity(mf, new_offset, next_size);804 );
750 },805 }
806 first_floating_ni.setLocationAssumeCapacity(
807 mf,
808 new_first_floating_offset,
809 first_floating_size,
810 );
811 // Continue the search after the just-moved floating node
812 first_floating_ni = last_fixed.next;
813 continue;
814 },
815 .none => {
816 assert(direction == .forward);
817 const new_parent_size = new_last_fixed_offset + last_fixed_size;
818 if (new_parent_size > old_parent_size) {
819 try mf.resizeNode(
820 gpa,
821 node.parent,
822 new_parent_size +| new_parent_size / growth_factor,
823 );
824 _, old_parent_size = parent.location().resolve(mf);
825 }
751 },826 },
752 }827 }
828 try mf.ensureCapacityForSetLocation(gpa);
829 if (last_fixed_ni == ni) {
830 // The original fixed node now has enough space
831 last_fixed_ni.setLocationAssumeCapacity(
832 mf,
833 old_last_fixed_offset,
834 last_fixed_size + shift,
835 );
836 return;
837 }
838 // Move a fixed node into trailing free space
839 if (last_fixed.flags.has_content) {
840 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
841 try mf.moveRange(
842 parent_file_offset + old_last_fixed_offset,
843 parent_file_offset + new_last_fixed_offset,
844 last_fixed_size,
845 );
846 }
847 last_fixed_ni.setLocationAssumeCapacity(mf, new_last_fixed_offset, last_fixed_size);
848 // Retry the previous nodes now that there is enough space
849 first_floating_ni = last_fixed_ni;
850 last_fixed_ni = last_fixed.prev;
851 direction = .reverse;
753 }852 }
754}853}
755854
...@@ -843,7 +942,7 @@ fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) !void {...@@ -843,7 +942,7 @@ fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) !void {
843942
844pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) !void {943pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) !void {
845 if (mf.contents.len >= new_capacity) return;944 if (mf.contents.len >= new_capacity) return;
846 try mf.ensureTotalCapacityPrecise(new_capacity +| new_capacity / 2);945 try mf.ensureTotalCapacityPrecise(new_capacity +| new_capacity / growth_factor);
847}946}
848947
849pub fn ensureTotalCapacityPrecise(mf: *MappedFile, new_capacity: usize) !void {948pub fn ensureTotalCapacityPrecise(mf: *MappedFile, new_capacity: usize) !void {
src/target.zig+2-6
...@@ -389,10 +389,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only,...@@ -389,10 +389,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only,
389 }389 }
390 return switch (zigBackend(target, false)) {390 return switch (zigBackend(target, false)) {
391 .stage2_wasm => .llvm_lld_only,391 .stage2_wasm => .llvm_lld_only,
392 .stage2_x86_64 => switch (target.ofmt) {392 .stage2_x86_64 => .yes,
393 .elf, .macho => .yes,
394 else => .llvm_only,
395 },
396 else => .llvm_only,393 else => .llvm_only,
397 };394 };
398}395}
...@@ -776,10 +773,9 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler...@@ -776,10 +773,9 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler
776}773}
777774
778pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {775pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
776 _ = target;
779 return switch (backend) {777 return switch (backend) {
780 .stage2_aarch64 => false,778 .stage2_aarch64 => false,
781 .stage2_powerpc => true,
782 .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,
783 else => true,779 else => true,
784 };780 };
785}781}
test/behavior/threadlocal.zig+5-7
...@@ -7,7 +7,6 @@ test "thread local variable" {...@@ -7,7 +7,6 @@ test "thread local variable" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1211
13 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {12 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) {
...@@ -27,7 +26,6 @@ test "pointer to thread local array" {...@@ -27,7 +26,6 @@ test "pointer to thread local array" {
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
3129
32 const s = "Hello world";30 const s = "Hello world";
33 @memcpy(buffer[0..s.len], s);31 @memcpy(buffer[0..s.len], s);
...@@ -41,9 +39,8 @@ test "reference a global threadlocal variable" {...@@ -41,9 +39,8 @@ test "reference a global threadlocal variable" {
41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; // TODO
4542
46 _ = nrfx_uart_rx(&g_uart0);43 try nrfx_uart_rx(&g_uart0);
47}44}
4845
49const nrfx_uart_t = extern struct {46const nrfx_uart_t = extern struct {
...@@ -51,11 +48,12 @@ const nrfx_uart_t = extern struct {...@@ -51,11 +48,12 @@ const nrfx_uart_t = extern struct {
51 drv_inst_idx: u8,48 drv_inst_idx: u8,
52};49};
5350
54pub fn nrfx_uart_rx(p_instance: [*c]const nrfx_uart_t) void {51pub fn nrfx_uart_rx(p_instance: [*c]const nrfx_uart_t) !void {
55 _ = p_instance;52 try expect(p_instance.*.p_reg == 0);
53 try expect(p_instance.*.drv_inst_idx == 0xab);
56}54}
5755
58threadlocal var g_uart0 = nrfx_uart_t{56threadlocal var g_uart0 = nrfx_uart_t{
59 .p_reg = 0,57 .p_reg = 0,
60 .drv_inst_idx = 0,58 .drv_inst_idx = 0xab,
61};59};
test/tests.zig+8-20
...@@ -2291,24 +2291,12 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2291,24 +2291,12 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2291 if (options.skip_single_threaded and test_target.single_threaded == true)2291 if (options.skip_single_threaded and test_target.single_threaded == true)
2292 continue;2292 continue;
22932293
2294 // TODO get compiler-rt tests passing for self-hosted backends.2294 if (!would_use_llvm and target.cpu.arch == .aarch64) {
2295 if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and2295 // TODO get std tests passing for the aarch64 self-hosted backend.
2296 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))2296 if (mem.eql(u8, options.name, "std")) continue;
2297 continue;2297 // TODO get zigc tests passing for the aarch64 self-hosted backend.
22982298 if (mem.eql(u8, options.name, "zigc")) continue;
2299 // TODO get zigc tests passing for other self-hosted backends.2299 }
2300 if (target.cpu.arch != .x86_64 and
2301 test_target.use_llvm == false and mem.eql(u8, options.name, "zigc"))
2302 continue;
2303
2304 // TODO get std lib tests passing for other self-hosted backends.
2305 if ((target.cpu.arch != .x86_64 or target.os.tag != .linux) and
2306 test_target.use_llvm == false and mem.eql(u8, options.name, "std"))
2307 continue;
2308
2309 if (target.cpu.arch != .x86_64 and
2310 test_target.use_llvm == false and mem.eql(u8, options.name, "c-import"))
2311 continue;
23122300
2313 const want_this_mode = for (options.optimize_modes) |m| {2301 const want_this_mode = for (options.optimize_modes) |m| {
2314 if (m == test_target.optimize_mode) break true;2302 if (m == test_target.optimize_mode) break true;
...@@ -2362,7 +2350,7 @@ fn addOneModuleTest(...@@ -2362,7 +2350,7 @@ fn addOneModuleTest(
2362 const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else "";2350 const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else "";
2363 const backend_suffix = if (test_target.use_llvm == true)2351 const backend_suffix = if (test_target.use_llvm == true)
2364 "-llvm"2352 "-llvm"
2365 else if (target.ofmt == std.Target.ObjectFormat.c)2353 else if (target.ofmt == .c)
2366 "-cbe"2354 "-cbe"
2367 else if (test_target.use_llvm == false)2355 else if (test_target.use_llvm == false)
2368 "-selfhosted"2356 "-selfhosted"
...@@ -2389,7 +2377,7 @@ fn addOneModuleTest(...@@ -2389,7 +2377,7 @@ fn addOneModuleTest(
2389 use_pic,2377 use_pic,
2390 });2378 });
23912379
2392 if (target.ofmt == std.Target.ObjectFormat.c) {2380 if (target.ofmt == .c) {
2393 var altered_query = test_target.target;2381 var altered_query = test_target.target;
2394 altered_query.ofmt = null;2382 altered_query.ofmt = null;
23952383