| ... | @@ -110,6 +110,8 @@ const TLSImage = struct { | ... | @@ -110,6 +110,8 @@ const TLSImage = struct { |
| 110 | pub var tls_image: TLSImage = undefined; | 110 | pub var tls_image: TLSImage = undefined; |
| 111 | | 111 | |
| 112 | pub fn setThreadPointer(addr: usize) void { | 112 | pub 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); |
| 130 | | 132 | |
| 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 | } |
| 190 | | 192 | |
| 191 | fn initTLS(phdrs: []elf.Phdr) void { | 193 | fn 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; |
| 194 | | 199 | |
| ... | @@ -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_align | 253 | // 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 padding | 256 | // The CustomData structure is right after the TCB with no padding |
| 252 | // in between so it can be easily found | 257 | // 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 | } |
| 272 | | 277 | |
| | 278 | /// Inline because TLS is not set up yet. |
| | 279 | inline 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. |
| | 284 | inline fn alignBackward(addr: usize, alignment: usize) usize { |
| | 285 | return addr & ~(alignment - 1); |
| | 286 | } |
| | 287 | |
| | 288 | /// Inline because TLS is not set up yet. |
| 273 | inline fn alignPtrCast(comptime T: type, ptr: [*]u8) *T { | 289 | inline fn alignPtrCast(comptime T: type, ptr: [*]u8) *T { |
| 274 | return @ptrCast(@alignCast(ptr)); | 290 | return @ptrCast(@alignCast(ptr)); |
| 275 | } | 291 | } |
| 276 | | 292 | |
| 277 | /// Initializes all the fields of the static TLS area and returns the computed | 293 | /// Initializes all the fields of the static TLS area and returns the computed |
| 278 | /// architecture-specific value of the thread-pointer register | 294 | /// architecture-specific value of the thread-pointer register |
| | 295 | /// |
| | 296 | /// This function is inline because thread local storage is not set up yet. |
| 279 | pub fn prepareTLS(area: []u8) usize { | 297 | pub fn prepareTLS(area: []u8) usize { |
| | 298 | @setRuntimeSafety(false); |
| | 299 | @disableInstrumentation(); |
| 280 | // Clear the area we're going to use, just to be safe | 300 | // Clear the area we're going to use, just to be safe |
| 281 | @memset(area, 0); | 301 | @memset(area, 0); |
| 282 | // Prepare the DTV | 302 | // Prepare the DTV |
| ... | @@ -310,6 +330,9 @@ pub fn prepareTLS(area: []u8) usize { | ... | @@ -310,6 +330,9 @@ pub fn prepareTLS(area: []u8) usize { |
| 310 | var main_thread_tls_buffer: [0x2100]u8 align(mem.page_size) = undefined; | 330 | var main_thread_tls_buffer: [0x2100]u8 align(mem.page_size) = undefined; |
| 311 | | 331 | |
| 312 | pub fn initStaticTLS(phdrs: []elf.Phdr) void { | 332 | pub fn initStaticTLS(phdrs: []elf.Phdr) void { |
| | 333 | @setRuntimeSafety(false); |
| | 334 | @disableInstrumentation(); |
| | 335 | |
| 313 | initTLS(phdrs); | 336 | initTLS(phdrs); |
| 314 | | 337 | |
| 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 | } |
| 323 | | 346 | |
| 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); |
| 332 | | 357 | |
| 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 | }; |
| 339 | | 363 | |
| 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 | |
| | 368 | inline 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 | } |