authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-21 23:52:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-22 14:26:17-07:00
logbde8c4a46ac924504ef851c733947cb6364d8add
tree91373889b3b57f5992c8c59f1a755e7121c8722b
parent25198810c88d474c63ff537e3647f12e7df6297c

update start code to use `@disableInstrumentation`

This prevents it from trying to access thread local storage before it has set up thread local storage, particularly when code coverage instrumentation is enabled.

3 files changed, 67 insertions(+), 14 deletions(-)

lib/std/os/linux/start_pie.zig+1
...@@ -71,6 +71,7 @@ fn getDynamicSymbol() [*]elf.Dyn {...@@ -71,6 +71,7 @@ fn getDynamicSymbol() [*]elf.Dyn {
7171
72pub fn relocate(phdrs: []elf.Phdr) void {72pub fn relocate(phdrs: []elf.Phdr) void {
73 @setRuntimeSafety(false);73 @setRuntimeSafety(false);
74 @disableInstrumentation();
7475
75 const dynv = getDynamicSymbol();76 const dynv = getDynamicSymbol();
76 // Recover the delta applied by the loader by comparing the effective and77 // Recover the delta applied by the loader by comparing the effective and
lib/std/os/linux/tls.zig+60-12
...@@ -110,6 +110,8 @@ const TLSImage = struct {...@@ -110,6 +110,8 @@ const TLSImage = struct {
110pub var tls_image: TLSImage = undefined;110pub var tls_image: TLSImage = undefined;
111111
112pub fn setThreadPointer(addr: usize) void {112pub fn setThreadPointer(addr: usize) void {
113 @setRuntimeSafety(false);
114 @disableInstrumentation();
113 switch (native_arch) {115 switch (native_arch) {
114 .x86 => {116 .x86 => {
115 var user_desc: linux.user_desc = .{117 var user_desc: linux.user_desc = .{
...@@ -125,7 +127,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -125,7 +127,7 @@ pub fn setThreadPointer(addr: usize) void {
125 .useable = 1,127 .useable = 1,
126 },128 },
127 };129 };
128 const rc = linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));130 const rc = @call(.always_inline, linux.syscall1, .{ .set_thread_area, @intFromPtr(&user_desc) });
129 assert(rc == 0);131 assert(rc == 0);
130132
131 const gdt_entry_number = user_desc.entry_number;133 const gdt_entry_number = user_desc.entry_number;
...@@ -138,7 +140,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -138,7 +140,7 @@ pub fn setThreadPointer(addr: usize) void {
138 );140 );
139 },141 },
140 .x86_64 => {142 .x86_64 => {
141 const rc = linux.syscall2(.arch_prctl, linux.ARCH.SET_FS, addr);143 const rc = @call(.always_inline, linux.syscall2, .{ .arch_prctl, linux.ARCH.SET_FS, addr });
142 assert(rc == 0);144 assert(rc == 0);
143 },145 },
144 .aarch64, .aarch64_be => {146 .aarch64, .aarch64_be => {
...@@ -149,7 +151,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -149,7 +151,7 @@ pub fn setThreadPointer(addr: usize) void {
149 );151 );
150 },152 },
151 .arm, .thumb => {153 .arm, .thumb => {
152 const rc = linux.syscall1(.set_tls, addr);154 const rc = @call(.always_inline, linux.syscall1, .{ .set_tls, addr });
153 assert(rc == 0);155 assert(rc == 0);
154 },156 },
155 .riscv64 => {157 .riscv64 => {
...@@ -160,7 +162,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -160,7 +162,7 @@ pub fn setThreadPointer(addr: usize) void {
160 );162 );
161 },163 },
162 .mips, .mipsel, .mips64, .mips64el => {164 .mips, .mipsel, .mips64, .mips64el => {
163 const rc = linux.syscall1(.set_thread_area, addr);165 const rc = @call(.always_inline, linux.syscall1, .{ .set_thread_area, addr });
164 assert(rc == 0);166 assert(rc == 0);
165 },167 },
166 .powerpc, .powerpcle => {168 .powerpc, .powerpcle => {
...@@ -189,6 +191,9 @@ pub fn setThreadPointer(addr: usize) void {...@@ -189,6 +191,9 @@ pub fn setThreadPointer(addr: usize) void {
189}191}
190192
191fn initTLS(phdrs: []elf.Phdr) void {193fn initTLS(phdrs: []elf.Phdr) void {
194 @setRuntimeSafety(false);
195 @disableInstrumentation();
196
192 var tls_phdr: ?*elf.Phdr = null;197 var tls_phdr: ?*elf.Phdr = null;
193 var img_base: usize = 0;198 var img_base: usize = 0;
194199
...@@ -236,7 +241,7 @@ fn initTLS(phdrs: []elf.Phdr) void {...@@ -236,7 +241,7 @@ fn initTLS(phdrs: []elf.Phdr) void {
236 l += tls_align_factor - delta;241 l += tls_align_factor - delta;
237 l += @sizeOf(CustomData);242 l += @sizeOf(CustomData);
238 tcb_offset = l;243 tcb_offset = l;
239 l += mem.alignForward(usize, tls_tcb_size, tls_align_factor);244 l += alignForward(tls_tcb_size, tls_align_factor);
240 data_offset = l;245 data_offset = l;
241 l += tls_data_alloc_size;246 l += tls_data_alloc_size;
242 break :blk l;247 break :blk l;
...@@ -244,14 +249,14 @@ fn initTLS(phdrs: []elf.Phdr) void {...@@ -244,14 +249,14 @@ fn initTLS(phdrs: []elf.Phdr) void {
244 .VariantII => blk: {249 .VariantII => blk: {
245 var l: usize = 0;250 var l: usize = 0;
246 data_offset = l;251 data_offset = l;
247 l += mem.alignForward(usize, tls_data_alloc_size, tls_align_factor);252 l += alignForward(tls_data_alloc_size, tls_align_factor);
248 // The thread pointer is aligned to p_align253 // The thread pointer is aligned to p_align
249 tcb_offset = l;254 tcb_offset = l;
250 l += tls_tcb_size;255 l += tls_tcb_size;
251 // The CustomData structure is right after the TCB with no padding256 // The CustomData structure is right after the TCB with no padding
252 // in between so it can be easily found257 // in between so it can be easily found
253 l += @sizeOf(CustomData);258 l += @sizeOf(CustomData);
254 l = mem.alignForward(usize, l, @alignOf(DTV));259 l = alignForward(l, @alignOf(DTV));
255 dtv_offset = l;260 dtv_offset = l;
256 l += @sizeOf(DTV);261 l += @sizeOf(DTV);
257 break :blk l;262 break :blk l;
...@@ -270,13 +275,28 @@ fn initTLS(phdrs: []elf.Phdr) void {...@@ -270,13 +275,28 @@ fn initTLS(phdrs: []elf.Phdr) void {
270 };275 };
271}276}
272277
278/// Inline because TLS is not set up yet.
279inline fn alignForward(addr: usize, alignment: usize) usize {
280 return alignBackward(addr + (alignment - 1), alignment);
281}
282
283/// Inline because TLS is not set up yet.
284inline fn alignBackward(addr: usize, alignment: usize) usize {
285 return addr & ~(alignment - 1);
286}
287
288/// Inline because TLS is not set up yet.
273inline fn alignPtrCast(comptime T: type, ptr: [*]u8) *T {289inline fn alignPtrCast(comptime T: type, ptr: [*]u8) *T {
274 return @ptrCast(@alignCast(ptr));290 return @ptrCast(@alignCast(ptr));
275}291}
276292
277/// Initializes all the fields of the static TLS area and returns the computed293/// Initializes all the fields of the static TLS area and returns the computed
278/// architecture-specific value of the thread-pointer register294/// architecture-specific value of the thread-pointer register
295///
296/// This function is inline because thread local storage is not set up yet.
279pub fn prepareTLS(area: []u8) usize {297pub fn prepareTLS(area: []u8) usize {
298 @setRuntimeSafety(false);
299 @disableInstrumentation();
280 // Clear the area we're going to use, just to be safe300 // Clear the area we're going to use, just to be safe
281 @memset(area, 0);301 @memset(area, 0);
282 // Prepare the DTV302 // Prepare the DTV
...@@ -310,6 +330,9 @@ pub fn prepareTLS(area: []u8) usize {...@@ -310,6 +330,9 @@ pub fn prepareTLS(area: []u8) usize {
310var main_thread_tls_buffer: [0x2100]u8 align(mem.page_size) = undefined;330var main_thread_tls_buffer: [0x2100]u8 align(mem.page_size) = undefined;
311331
312pub fn initStaticTLS(phdrs: []elf.Phdr) void {332pub fn initStaticTLS(phdrs: []elf.Phdr) void {
333 @setRuntimeSafety(false);
334 @disableInstrumentation();
335
313 initTLS(phdrs);336 initTLS(phdrs);
314337
315 const tls_area = blk: {338 const tls_area = blk: {
...@@ -321,22 +344,47 @@ pub fn initStaticTLS(phdrs: []elf.Phdr) void {...@@ -321,22 +344,47 @@ pub fn initStaticTLS(phdrs: []elf.Phdr) void {
321 break :blk main_thread_tls_buffer[0..tls_image.alloc_size];344 break :blk main_thread_tls_buffer[0..tls_image.alloc_size];
322 }345 }
323346
324 const alloc_tls_area = posix.mmap(347 const begin_addr = mmap(
325 null,348 null,
326 tls_image.alloc_size + tls_image.alloc_align - 1,349 tls_image.alloc_size + tls_image.alloc_align - 1,
327 posix.PROT.READ | posix.PROT.WRITE,350 posix.PROT.READ | posix.PROT.WRITE,
328 .{ .TYPE = .PRIVATE, .ANONYMOUS = true },351 .{ .TYPE = .PRIVATE, .ANONYMOUS = true },
329 -1,352 -1,
330 0,353 0,
331 ) catch posix.abort();354 );
355 if (@as(isize, @bitCast(begin_addr)) < 0) @trap();
356 const alloc_tls_area: [*]align(mem.page_size) u8 = @ptrFromInt(begin_addr);
332357
333 // Make sure the slice is correctly aligned.358 // Make sure the slice is correctly aligned.
334 const begin_addr = @intFromPtr(alloc_tls_area.ptr);359 const begin_aligned_addr = alignForward(begin_addr, tls_image.alloc_align);
335 const begin_aligned_addr = mem.alignForward(usize, begin_addr, tls_image.alloc_align);
336 const start = begin_aligned_addr - begin_addr;360 const start = begin_aligned_addr - begin_addr;
337 break :blk alloc_tls_area[start .. start + tls_image.alloc_size];361 break :blk alloc_tls_area[start..][0..tls_image.alloc_size];
338 };362 };
339363
340 const tp_value = prepareTLS(tls_area);364 const tp_value = prepareTLS(tls_area);
341 setThreadPointer(tp_value);365 setThreadPointer(tp_value);
342}366}
367
368inline fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: linux.MAP, fd: i32, offset: i64) usize {
369 if (@hasField(linux.SYS, "mmap2")) {
370 return @call(.always_inline, linux.syscall6, .{
371 .mmap2,
372 @intFromPtr(address),
373 length,
374 prot,
375 @as(u32, @bitCast(flags)),
376 @as(usize, @bitCast(@as(isize, fd))),
377 @as(usize, @truncate(@as(u64, @bitCast(offset)) / linux.MMAP2_UNIT)),
378 });
379 } else {
380 return @call(.always_inline, linux.syscall6, .{
381 .mmap,
382 @intFromPtr(address),
383 length,
384 prot,
385 @as(u32, @bitCast(flags)),
386 @as(usize, @bitCast(@as(isize, fd))),
387 @as(u64, @bitCast(offset)),
388 });
389 }
390}
lib/std/start.zig+6-2
...@@ -387,6 +387,10 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn {...@@ -387,6 +387,10 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn {
387}387}
388388
389fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {389fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {
390 // We're not ready to panic until thread local storage is initialized.
391 @setRuntimeSafety(false);
392 // Code coverage instrumentation might try to use thread local variables.
393 @disableInstrumentation();
390 const argc = argc_argv_ptr[0];394 const argc = argc_argv_ptr[0];
391 const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));395 const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));
392396
...@@ -429,9 +433,9 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {...@@ -429,9 +433,9 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {
429 if (comptime native_arch.isARM()) {433 if (comptime native_arch.isARM()) {
430 if (at_hwcap & std.os.linux.HWCAP.TLS == 0) {434 if (at_hwcap & std.os.linux.HWCAP.TLS == 0) {
431 // FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls435 // FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls
432 // For the time being use a simple abort instead of a @panic call to436 // For the time being use a simple trap instead of a @panic call to
433 // keep the binary bloat under control.437 // keep the binary bloat under control.
434 std.posix.abort();438 @trap();
435 }439 }
436 }440 }
437441