Skip to content

Commit d12e327

Browse files
committed
Coff: implement threadlocal variables
1 parent 529aa9f commit d12e327

File tree

13 files changed

+951
-551
lines changed

13 files changed

+951
-551
lines changed

lib/std/coff.zig

Lines changed: 40 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -249,55 +249,6 @@ pub const OptionalHeader = extern struct {
249249

250250
pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
251251

252-
pub 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-
301252
pub const ImageDataDirectory = extern struct {
302253
virtual_address: u32,
303254
size: u32,
@@ -1054,9 +1005,9 @@ pub const Coff = struct {
10541005
assert(self.is_image);
10551006

10561007
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)];
10601011
var reader: std.Io.Reader = .fixed(self.data);
10611012

10621013
if (self.is_loaded) {
@@ -1400,6 +1351,44 @@ pub const Relocation = extern struct {
14001351
};
14011352

14021353
pub 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+
14031392
pub const FILE = struct {
14041393
/// Machine Types
14051394
/// The Machine field has one of the following values, which specify the CPU type.

lib/std/debug.zig

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,6 @@ const use_trap_panic = switch (builtin.zig_backend) {
465465
.stage2_wasm,
466466
.stage2_x86,
467467
=> true,
468-
.stage2_x86_64 => switch (builtin.target.ofmt) {
469-
.elf, .macho => false,
470-
else => true,
471-
},
472468
else => false,
473469
};
474470

@@ -481,22 +477,6 @@ pub fn defaultPanic(
481477

482478
if (use_trap_panic) @trap();
483479

484-
switch (builtin.zig_backend) {
485-
.stage2_aarch64,
486-
.stage2_arm,
487-
.stage2_powerpc,
488-
.stage2_riscv64,
489-
.stage2_spirv,
490-
.stage2_wasm,
491-
.stage2_x86,
492-
=> @trap(),
493-
.stage2_x86_64 => switch (builtin.target.ofmt) {
494-
.elf, .macho => {},
495-
else => @trap(),
496-
},
497-
else => {},
498-
}
499-
500480
switch (builtin.os.tag) {
501481
.freestanding, .other => {
502482
@trap();

lib/std/math/isnan.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ test isNan {
2828
}
2929

3030
test isSignalNan {
31+
if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
32+
3133
inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
3234
// TODO: Signalling NaN values get converted to quiet NaN values in
3335
// some cases where they shouldn't such that this can fail.

lib/ubsan_rt.zig

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,6 @@ const Value = extern struct {
120120
}
121121

122122
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-
129123
switch (value.td.kind) {
130124
.integer => {
131125
if (value.td.isSigned()) {
@@ -624,27 +618,28 @@ fn exportHandler(
624618
handler: anytype,
625619
comptime sym_name: []const u8,
626620
) void {
627-
// Work around x86_64 backend limitation.
628-
const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak;
629-
const N = "__ubsan_handle_" ++ sym_name;
630-
@export(handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });
621+
@export(handler, .{
622+
.name = "__ubsan_handle_" ++ sym_name,
623+
.linkage = .weak,
624+
.visibility = .hidden,
625+
});
631626
}
632627

633628
fn exportHandlerWithAbort(
634629
handler: anytype,
635630
abort_handler: anytype,
636631
comptime sym_name: []const u8,
637632
) void {
638-
// Work around x86_64 backend limitation.
639-
const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak;
640-
{
641-
const N = "__ubsan_handle_" ++ sym_name;
642-
@export(handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });
643-
}
644-
{
645-
const N = "__ubsan_handle_" ++ sym_name ++ "_abort";
646-
@export(abort_handler, .{ .name = N, .linkage = linkage, .visibility = if (linkage == .internal) .default else .hidden });
647-
}
633+
@export(handler, .{
634+
.name = "__ubsan_handle_" ++ sym_name,
635+
.linkage = .weak,
636+
.visibility = .hidden,
637+
});
638+
@export(abort_handler, .{
639+
.name = "__ubsan_handle_" ++ sym_name ++ "_abort",
640+
.linkage = .weak,
641+
.visibility = .hidden,
642+
});
648643
}
649644

650645
const can_build_ubsan = switch (builtin.zig_backend) {

src/Compilation.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
19851985
switch (target_util.zigBackend(target, use_llvm)) {
19861986
else => {},
19871987
.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;
19891989
},
19901990
}
19911991
if (options.config.use_new_linker) break :s .zcu;

src/codegen/x86_64/CodeGen.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173685,7 +173685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
173685173685
const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
173686173686
const nav = ip.getNav(ty_nav.nav);
173687173687
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) {
173689173689
try cg.spillRegisters(&.{ .rdi, .rax });
173690173690
} else {
173691173691
try cg.spillRegisters(&.{.rax});

src/codegen/x86_64/Emit.zig

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,82 @@ pub fn emitMir(emit: *Emit) Error!void {
386386
}, emit.lower.target), &.{});
387387
},
388388
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+
}
389465
} else return emit.fail("TODO implement relocs for {s}", .{
390466
@tagName(emit.bin_file.tag),
391467
});
@@ -870,7 +946,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
870946
.symbolnum = @intCast(reloc.target.index),
871947
},
872948
});
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}", .{
874956
@tagName(reloc.target.type), @tagName(emit.bin_file.tag),
875957
}),
876958
};

0 commit comments

Comments
 (0)