diff --git a/lib/std/os/windows/tls.zig b/lib/std/os/windows/tls.zig new file mode 100644 index 0000000000000000000000000000000000000000..f98e22b620c10a746b77e0467c37a0c2b71de19c --- /dev/null +++ b/lib/std/os/windows/tls.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const windows = std.os.windows; + +export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; +export var _tls_start: ?*anyopaque linksection(".tls") = null; +export var _tls_end: ?*anyopaque linksection(".tls$ZZZ") = null; +export var __xl_a: windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; +export var __xl_z: windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; + +comptime { + if (builtin.cpu.arch == .x86 and builtin.abi == .msvc and builtin.zig_backend != .stage2_c) { + // The __tls_array is the offset of the ThreadLocalStoragePointer field + // in the TEB block whose base address held in the %fs segment. + asm ( + \\ .global __tls_array + \\ __tls_array = 0x2C + ); + } +} + +// TODO this is how I would like it to be expressed +//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { +// .StartAddressOfRawData = @intFromPtr(&_tls_start), +// .EndAddressOfRawData = @intFromPtr(&_tls_end), +// .AddressOfIndex = @intFromPtr(&_tls_index), +// .AddressOfCallBacks = @intFromPtr(__xl_a), +// .SizeOfZeroFill = 0, +// .Characteristics = 0, +//}; +// This is the workaround because we can't do @intFromPtr at comptime like that. +pub const IMAGE_TLS_DIRECTORY = extern struct { + StartAddressOfRawData: *?*anyopaque, + EndAddressOfRawData: *?*anyopaque, + AddressOfIndex: *u32, + AddressOfCallBacks: [*:null]windows.PIMAGE_TLS_CALLBACK, + SizeOfZeroFill: u32, + Characteristics: u32, +}; +export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ + .StartAddressOfRawData = &_tls_start, + .EndAddressOfRawData = &_tls_end, + .AddressOfIndex = &_tls_index, + // __xl_a is just a global variable containing a null pointer; the actual callbacks sit in + // between __xl_a and __xl_z. So we need to skip over __xl_a here. If there are no callbacks, + // this just means we point to __xl_z (the null terminator). + .AddressOfCallBacks = @as([*:null]windows.PIMAGE_TLS_CALLBACK, @ptrCast(&__xl_a)) + 1, + .SizeOfZeroFill = 0, + .Characteristics = 0, +}; diff --git a/lib/std/start.zig b/lib/std/start.zig index 2a072832bb9ccd50af11eabb85ca7740158aea58..ca6a5416eb57689a349f63fd9a159fefdc337e29 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -176,7 +176,7 @@ fn _DllMainCRTStartup( lpReserved: std.os.windows.LPVOID, ) callconv(std.os.windows.WINAPI) std.os.windows.BOOL { if (!builtin.single_threaded and !builtin.link_libc) { - _ = @import("start_windows_tls.zig"); + _ = @import("os/windows/tls.zig"); } if (@hasDecl(root, "DllMain")) { @@ -434,7 +434,7 @@ fn _start() callconv(.Naked) noreturn { fn WinStartup() callconv(std.os.windows.WINAPI) noreturn { @setAlignStack(16); if (!builtin.single_threaded and !builtin.link_libc) { - _ = @import("start_windows_tls.zig"); + _ = @import("os/windows/tls.zig"); } std.debug.maybeEnableSegfaultHandler(); @@ -445,7 +445,7 @@ fn WinStartup() callconv(std.os.windows.WINAPI) noreturn { fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn { @setAlignStack(16); if (!builtin.single_threaded and !builtin.link_libc) { - _ = @import("start_windows_tls.zig"); + _ = @import("os/windows/tls.zig"); } std.debug.maybeEnableSegfaultHandler(); diff --git a/lib/std/start_windows_tls.zig b/lib/std/start_windows_tls.zig deleted file mode 100644 index 48880b4811d3536a78b6e7dccbf48bf561fbc282..0000000000000000000000000000000000000000 --- a/lib/std/start_windows_tls.zig +++ /dev/null @@ -1,48 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; -export var _tls_start: u8 linksection(".tls") = 0; -export var _tls_end: u8 linksection(".tls$ZZZ") = 0; -export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; -export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; - -comptime { - if (builtin.target.cpu.arch == .x86 and builtin.zig_backend != .stage2_c) { - // The __tls_array is the offset of the ThreadLocalStoragePointer field - // in the TEB block whose base address held in the %fs segment. - asm ( - \\ .global __tls_array - \\ __tls_array = 0x2C - ); - } -} - -// TODO this is how I would like it to be expressed -// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate -// why they do that. -//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { -// .StartAddressOfRawData = @intFromPtr(&_tls_start), -// .EndAddressOfRawData = @intFromPtr(&_tls_end), -// .AddressOfIndex = @intFromPtr(&_tls_index), -// .AddressOfCallBacks = @intFromPtr(__xl_a), -// .SizeOfZeroFill = 0, -// .Characteristics = 0, -//}; -// This is the workaround because we can't do @intFromPtr at comptime like that. -pub const IMAGE_TLS_DIRECTORY = extern struct { - StartAddressOfRawData: *anyopaque, - EndAddressOfRawData: *anyopaque, - AddressOfIndex: *anyopaque, - AddressOfCallBacks: *anyopaque, - SizeOfZeroFill: u32, - Characteristics: u32, -}; -export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ - .StartAddressOfRawData = &_tls_start, - .EndAddressOfRawData = &_tls_end, - .AddressOfIndex = &_tls_index, - .AddressOfCallBacks = @as(*anyopaque, @ptrCast(&__xl_a)), - .SizeOfZeroFill = 0, - .Characteristics = 0, -};