diff --git a/std/os/bits/linux/arm-eabi.zig b/std/os/bits/linux/arm-eabi.zig index 5048a2afc7..ca80b67fe1 100644 --- a/std/os/bits/linux/arm-eabi.zig +++ b/std/os/bits/linux/arm-eabi.zig @@ -474,6 +474,30 @@ pub const VDSO_USEFUL = true; pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; pub const VDSO_CGT_VER = "LINUX_2.6"; +pub const HWCAP_SWP = 1 << 0; +pub const HWCAP_HALF = 1 << 1; +pub const HWCAP_THUMB = 1 << 2; +pub const HWCAP_26BIT = 1 << 3; +pub const HWCAP_FAST_MULT = 1 << 4; +pub const HWCAP_FPA = 1 << 5; +pub const HWCAP_VFP = 1 << 6; +pub const HWCAP_EDSP = 1 << 7; +pub const HWCAP_JAVA = 1 << 8; +pub const HWCAP_IWMMXT = 1 << 9; +pub const HWCAP_CRUNCH = 1 << 10; +pub const HWCAP_THUMBEE = 1 << 11; +pub const HWCAP_NEON = 1 << 12; +pub const HWCAP_VFPv3 = 1 << 13; +pub const HWCAP_VFPv3D16 = 1 << 14; +pub const HWCAP_TLS = 1 << 15; +pub const HWCAP_VFPv4 = 1 << 16; +pub const HWCAP_IDIVA = 1 << 17; +pub const HWCAP_IDIVT = 1 << 18; +pub const HWCAP_VFPD32 = 1 << 19; +pub const HWCAP_IDIV = HWCAP_IDIVA | HWCAP_IDIVT; +pub const HWCAP_LPAE = 1 << 20; +pub const HWCAP_EVTSTRM = 1 << 21; + pub const msghdr = extern struct { msg_name: ?*sockaddr, msg_namelen: socklen_t, diff --git a/std/os/linux/arm-eabi.zig b/std/os/linux/arm-eabi.zig index 3b8eb055d5..a8cb52d711 100644 --- a/std/os/linux/arm-eabi.zig +++ b/std/os/linux/arm-eabi.zig @@ -78,3 +78,11 @@ pub fn syscall6( /// This matches the libc clone function. pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; + +// LLVM calls this when the read-tp-hard feature is set to false. Currently, there is no way to pass +// that to llvm via zig. See https://github.com/ziglang/zig/issues/2883 +pub nakedcc fn getThreadPointer() usize { + return asm volatile("mrc p15, 0, %[ret], c13, c0, 3" + : [ret] "=r" (-> usize) + ); +} \ No newline at end of file diff --git a/std/os/linux/tls.zig b/std/os/linux/tls.zig index 63c44d6982..a14b26a5cf 100644 --- a/std/os/linux/tls.zig +++ b/std/os/linux/tls.zig @@ -133,6 +133,7 @@ pub fn initTLS() void { var at_phent: usize = undefined; var at_phnum: usize = undefined; var at_phdr: usize = undefined; + var at_hwcap: usize = undefined; var i: usize = 0; while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { @@ -140,10 +141,21 @@ pub fn initTLS() void { elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, + elf.AT_HWCAP => at_phdr = auxv[i].a_un.a_val, else => continue, } } + // If the cpu is arm-based, check if it supports the TLS register + if (builtin.arch == builtin.Arch.arm and builtin.os == .linux) { + if (at_hwcap & std.os.linux.HWCAP_TLS == 0) { + // If the CPU does not support TLS via a coprocessor register, + // it could be accessed via a kernel helper function + // see musl/src/thread/arm/ for details + @panic("cpu does not support TLS via coprocessor register"); + } + } + // Sanity check assert(at_phent == @sizeOf(elf.Phdr)); diff --git a/std/special/c.zig b/std/special/c.zig index 5ac7457429..669a771c2e 100644 --- a/std/special/c.zig +++ b/std/special/c.zig @@ -25,6 +25,8 @@ comptime { @export("strncmp", strncmp, .Strong); @export("strerror", strerror, .Strong); @export("strlen", strlen, .Strong); + } else if (builtin.arch == builtin.Arch.arm and builtin.os == .linux) { + @export("__aeabi_read_tp", std.os.linux.getThreadPointer, .Strong); } }