summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@uclibc-ng.org>2016-10-04 06:51:35 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2017-02-01 17:48:38 +0100
commitdba942c80dc2cfa5768a856fff98e22a755fdd27 (patch)
tree371e775cb6dfec085945f6834aeb9d3b6de36fbe /libc
parent9b457baf8d46329f7d7ee2aa084022bb0df88551 (diff)
add experimental aarch64 support
Ported over from GNU C Library and runtime tested in Qemu.
Diffstat (limited to 'libc')
-rw-r--r--libc/string/aarch64/Makefile13
-rw-r--r--libc/string/aarch64/memcpy.S230
-rw-r--r--libc/string/aarch64/memset.S189
-rw-r--r--libc/sysdeps/linux/aarch64/Makefile9
-rw-r--r--libc/sysdeps/linux/aarch64/Makefile.arch5
-rw-r--r--libc/sysdeps/linux/aarch64/__longjmp.S107
-rw-r--r--libc/sysdeps/linux/aarch64/__syscall_error.c18
-rw-r--r--libc/sysdeps/linux/aarch64/bits/atomic.h172
-rw-r--r--libc/sysdeps/linux/aarch64/bits/endian.h30
-rw-r--r--libc/sysdeps/linux/aarch64/bits/fcntl.h329
-rw-r--r--libc/sysdeps/linux/aarch64/bits/kernel_types.h42
-rw-r--r--libc/sysdeps/linux/aarch64/bits/setjmp.h33
-rw-r--r--libc/sysdeps/linux/aarch64/bits/stackinfo.h33
-rw-r--r--libc/sysdeps/linux/aarch64/bits/syscalls.h106
-rw-r--r--libc/sysdeps/linux/aarch64/bits/uClibc_arch_features.h38
-rwxr-xr-xlibc/sysdeps/linux/aarch64/bits/uClibc_page.h25
-rw-r--r--libc/sysdeps/linux/aarch64/bits/wordsize.h18
-rw-r--r--libc/sysdeps/linux/aarch64/bsd-_setjmp.S1
-rw-r--r--libc/sysdeps/linux/aarch64/bsd-setjmp.S1
-rw-r--r--libc/sysdeps/linux/aarch64/clone.S85
-rw-r--r--libc/sysdeps/linux/aarch64/crt1.S89
-rw-r--r--libc/sysdeps/linux/aarch64/crti.S59
-rw-r--r--libc/sysdeps/linux/aarch64/crtn.S46
-rw-r--r--libc/sysdeps/linux/aarch64/jmpbuf-offsets.h57
-rw-r--r--libc/sysdeps/linux/aarch64/jmpbuf-unwind.h34
-rw-r--r--libc/sysdeps/linux/aarch64/setjmp.S59
-rw-r--r--libc/sysdeps/linux/aarch64/sys/procfs.h123
-rw-r--r--libc/sysdeps/linux/aarch64/sys/ucontext.h53
-rw-r--r--libc/sysdeps/linux/aarch64/sys/user.h37
-rw-r--r--libc/sysdeps/linux/aarch64/syscall.S42
-rw-r--r--libc/sysdeps/linux/aarch64/sysdep.h150
-rw-r--r--libc/sysdeps/linux/aarch64/vfork.S37
-rw-r--r--libc/sysdeps/linux/common-generic/bits/stat.h49
-rw-r--r--libc/sysdeps/linux/common/fstat.c28
-rw-r--r--libc/sysdeps/linux/common/fstatat.c9
-rw-r--r--libc/sysdeps/linux/common/lstat.c9
-rw-r--r--libc/sysdeps/linux/common/lstat64.c14
-rw-r--r--libc/sysdeps/linux/common/stat.c8
38 files changed, 2312 insertions, 75 deletions
diff --git a/libc/string/aarch64/Makefile b/libc/string/aarch64/Makefile
new file mode 100644
index 000000000..0a95346fd
--- /dev/null
+++ b/libc/string/aarch64/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir:=../../../
+top_builddir:=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include ../Makefile.in
+include $(top_srcdir)Makerules
diff --git a/libc/string/aarch64/memcpy.S b/libc/string/aarch64/memcpy.S
new file mode 100644
index 000000000..87b2552a2
--- /dev/null
+++ b/libc/string/aarch64/memcpy.S
@@ -0,0 +1,230 @@
+/* Copyright (C) 2012-2017 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses.
+ *
+ */
+
+#define dstin x0
+#define src x1
+#define count x2
+#define dst x3
+#define srcend x4
+#define dstend x5
+#define A_l x6
+#define A_lw w6
+#define A_h x7
+#define A_hw w7
+#define B_l x8
+#define B_lw w8
+#define B_h x9
+#define C_l x10
+#define C_h x11
+#define D_l x12
+#define D_h x13
+#define E_l src
+#define E_h count
+#define F_l srcend
+#define F_h dst
+#define G_l count
+#define G_h dst
+#define tmp1 x14
+
+ENTRY (memcpy)
+
+ prfm PLDL1KEEP, [src]
+ add srcend, src, count
+ add dstend, dstin, count
+ cmp count, 16
+ b.ls L(copy16)
+ cmp count, 96
+ b.hi L(copy_long)
+
+ /* Medium copies: 17..96 bytes. */
+ sub tmp1, count, 1
+ ldp A_l, A_h, [src]
+ tbnz tmp1, 6, L(copy96)
+ ldp D_l, D_h, [srcend, -16]
+ tbz tmp1, 5, 1f
+ ldp B_l, B_h, [src, 16]
+ ldp C_l, C_h, [srcend, -32]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstend, -32]
+1:
+ stp A_l, A_h, [dstin]
+ stp D_l, D_h, [dstend, -16]
+ ret
+
+ .p2align 4
+ /* Small copies: 0..16 bytes. */
+L(copy16):
+ cmp count, 8
+ b.lo 1f
+ ldr A_l, [src]
+ ldr A_h, [srcend, -8]
+ str A_l, [dstin]
+ str A_h, [dstend, -8]
+ ret
+ .p2align 4
+1:
+ tbz count, 2, 1f
+ ldr A_lw, [src]
+ ldr A_hw, [srcend, -4]
+ str A_lw, [dstin]
+ str A_hw, [dstend, -4]
+ ret
+
+ /* Copy 0..3 bytes. Use a branchless sequence that copies the same
+ byte 3 times if count==1, or the 2nd byte twice if count==2. */
+1:
+ cbz count, 2f
+ lsr tmp1, count, 1
+ ldrb A_lw, [src]
+ ldrb A_hw, [srcend, -1]
+ ldrb B_lw, [src, tmp1]
+ strb A_lw, [dstin]
+ strb B_lw, [dstin, tmp1]
+ strb A_hw, [dstend, -1]
+2: ret
+
+ .p2align 4
+ /* Copy 64..96 bytes. Copy 64 bytes from the start and
+ 32 bytes from the end. */
+L(copy96):
+ ldp B_l, B_h, [src, 16]
+ ldp C_l, C_h, [src, 32]
+ ldp D_l, D_h, [src, 48]
+ ldp E_l, E_h, [srcend, -32]
+ ldp F_l, F_h, [srcend, -16]
+ stp A_l, A_h, [dstin]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstin, 32]
+ stp D_l, D_h, [dstin, 48]
+ stp E_l, E_h, [dstend, -32]
+ stp F_l, F_h, [dstend, -16]
+ ret
+
+ /* Align DST to 16 byte alignment so that we don't cross cache line
+ boundaries on both loads and stores. There are at least 96 bytes
+ to copy, so copy 16 bytes unaligned and then align. The loop
+ copies 64 bytes per iteration and prefetches one iteration ahead. */
+
+ .p2align 4
+L(copy_long):
+ and tmp1, dstin, 15
+ bic dst, dstin, 15
+ ldp D_l, D_h, [src]
+ sub src, src, tmp1
+ add count, count, tmp1 /* Count is now 16 too large. */
+ ldp A_l, A_h, [src, 16]
+ stp D_l, D_h, [dstin]
+ ldp B_l, B_h, [src, 32]
+ ldp C_l, C_h, [src, 48]
+ ldp D_l, D_h, [src, 64]!
+ subs count, count, 128 + 16 /* Test and readjust count. */
+ b.ls 2f
+1:
+ stp A_l, A_h, [dst, 16]
+ ldp A_l, A_h, [src, 16]
+ stp B_l, B_h, [dst, 32]
+ ldp B_l, B_h, [src, 32]
+ stp C_l, C_h, [dst, 48]
+ ldp C_l, C_h, [src, 48]
+ stp D_l, D_h, [dst, 64]!
+ ldp D_l, D_h, [src, 64]!
+ subs count, count, 64
+ b.hi 1b
+
+ /* Write the last full set of 64 bytes. The remainder is at most 64
+ bytes, so it is safe to always copy 64 bytes from the end even if
+ there is just 1 byte left. */
+2:
+ ldp E_l, E_h, [srcend, -64]
+ stp A_l, A_h, [dst, 16]
+ ldp A_l, A_h, [srcend, -48]
+ stp B_l, B_h, [dst, 32]
+ ldp B_l, B_h, [srcend, -32]
+ stp C_l, C_h, [dst, 48]
+ ldp C_l, C_h, [srcend, -16]
+ stp D_l, D_h, [dst, 64]
+ stp E_l, E_h, [dstend, -64]
+ stp A_l, A_h, [dstend, -48]
+ stp B_l, B_h, [dstend, -32]
+ stp C_l, C_h, [dstend, -16]
+ ret
+
+ .p2align 4
+L(move_long):
+ cbz tmp1, 3f
+
+ add srcend, src, count
+ add dstend, dstin, count
+
+ /* Align dstend to 16 byte alignment so that we don't cross cache line
+ boundaries on both loads and stores. There are at least 96 bytes
+ to copy, so copy 16 bytes unaligned and then align. The loop
+ copies 64 bytes per iteration and prefetches one iteration ahead. */
+
+ and tmp1, dstend, 15
+ ldp D_l, D_h, [srcend, -16]
+ sub srcend, srcend, tmp1
+ sub count, count, tmp1
+ ldp A_l, A_h, [srcend, -16]
+ stp D_l, D_h, [dstend, -16]
+ ldp B_l, B_h, [srcend, -32]
+ ldp C_l, C_h, [srcend, -48]
+ ldp D_l, D_h, [srcend, -64]!
+ sub dstend, dstend, tmp1
+ subs count, count, 128
+ b.ls 2f
+
+ nop
+1:
+ stp A_l, A_h, [dstend, -16]
+ ldp A_l, A_h, [srcend, -16]
+ stp B_l, B_h, [dstend, -32]
+ ldp B_l, B_h, [srcend, -32]
+ stp C_l, C_h, [dstend, -48]
+ ldp C_l, C_h, [srcend, -48]
+ stp D_l, D_h, [dstend, -64]!
+ ldp D_l, D_h, [srcend, -64]!
+ subs count, count, 64
+ b.hi 1b
+
+ /* Write the last full set of 64 bytes. The remainder is at most 64
+ bytes, so it is safe to always copy 64 bytes from the start even if
+ there is just 1 byte left. */
+2:
+ ldp G_l, G_h, [src, 48]
+ stp A_l, A_h, [dstend, -16]
+ ldp A_l, A_h, [src, 32]
+ stp B_l, B_h, [dstend, -32]
+ ldp B_l, B_h, [src, 16]
+ stp C_l, C_h, [dstend, -48]
+ ldp C_l, C_h, [src]
+ stp D_l, D_h, [dstend, -64]
+ stp G_l, G_h, [dstin, 48]
+ stp A_l, A_h, [dstin, 32]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstin]
+3: ret
+
+END (memcpy)
+libc_hidden_def (memcpy)
diff --git a/libc/string/aarch64/memset.S b/libc/string/aarch64/memset.S
new file mode 100644
index 000000000..d6686bedc
--- /dev/null
+++ b/libc/string/aarch64/memset.S
@@ -0,0 +1,189 @@
+/* Copyright (C) 2012-2017 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses
+ *
+ */
+
+#define dstin x0
+#define val x1
+#define valw w1
+#define count x2
+#define dst x3
+#define dstend x4
+#define tmp1 x5
+#define tmp1w w5
+#define tmp2 x6
+#define tmp2w w6
+#define zva_len x7
+#define zva_lenw w7
+
+ENTRY_ALIGN (memset, 6)
+
+ dup v0.16B, valw
+ add dstend, dstin, count
+
+ cmp count, 96
+ b.hi L(set_long)
+ cmp count, 16
+ b.hs L(set_medium)
+ mov val, v0.D[0]
+
+ /* Set 0..15 bytes. */
+ tbz count, 3, 1f
+ str val, [dstin]
+ str val, [dstend, -8]
+ ret
+ nop
+1: tbz count, 2, 2f
+ str valw, [dstin]
+ str valw, [dstend, -4]
+ ret
+2: cbz count, 3f
+ strb valw, [dstin]
+ tbz count, 1, 3f
+ strh valw, [dstend, -2]
+3: ret
+
+ /* Set 17..96 bytes. */
+L(set_medium):
+ str q0, [dstin]
+ tbnz count, 6, L(set96)
+ str q0, [dstend, -16]
+ tbz count, 5, 1f
+ str q0, [dstin, 16]
+ str q0, [dstend, -32]
+1: ret
+
+ .p2align 4
+ /* Set 64..96 bytes. Write 64 bytes from the start and
+ 32 bytes from the end. */
+L(set96):
+ str q0, [dstin, 16]
+ stp q0, q0, [dstin, 32]
+ stp q0, q0, [dstend, -32]
+ ret
+
+ .p2align 3
+ nop
+L(set_long):
+ and valw, valw, 255
+ bic dst, dstin, 15
+ str q0, [dstin]
+ cmp count, 256
+ ccmp valw, 0, 0, cs
+ b.eq L(try_zva)
+L(no_zva):
+ sub count, dstend, dst /* Count is 16 too large. */
+ add dst, dst, 16
+ sub count, count, 64 + 16 /* Adjust count and bias for loop. */
+1: stp q0, q0, [dst], 64
+ stp q0, q0, [dst, -32]
+L(tail64):
+ subs count, count, 64
+ b.hi 1b
+2: stp q0, q0, [dstend, -64]
+ stp q0, q0, [dstend, -32]
+ ret
+
+ .p2align 3
+L(try_zva):
+ mrs tmp1, dczid_el0
+ tbnz tmp1w, 4, L(no_zva)
+ and tmp1w, tmp1w, 15
+ cmp tmp1w, 4 /* ZVA size is 64 bytes. */
+ b.ne L(zva_128)
+
+ /* Write the first and last 64 byte aligned block using stp rather
+ than using DC ZVA. This is faster on some cores.
+ */
+L(zva_64):
+ str q0, [dst, 16]
+ stp q0, q0, [dst, 32]
+ bic dst, dst, 63
+ stp q0, q0, [dst, 64]
+ stp q0, q0, [dst, 96]
+ sub count, dstend, dst /* Count is now 128 too large. */
+ sub count, count, 128+64+64 /* Adjust count and bias for loop. */
+ add dst, dst, 128
+ nop
+1: dc zva, dst
+ add dst, dst, 64
+ subs count, count, 64
+ b.hi 1b
+ stp q0, q0, [dst, 0]
+ stp q0, q0, [dst, 32]
+ stp q0, q0, [dstend, -64]
+ stp q0, q0, [dstend, -32]
+ ret
+
+ .p2align 3
+L(zva_128):
+ cmp tmp1w, 5 /* ZVA size is 128 bytes. */
+ b.ne L(zva_other)
+
+ str q0, [dst, 16]
+ stp q0, q0, [dst, 32]
+ stp q0, q0, [dst, 64]
+ stp q0, q0, [dst, 96]
+ bic dst, dst, 127
+ sub count, dstend, dst /* Count is now 128 too large. */
+ sub count, count, 128+128 /* Adjust count and bias for loop. */
+ add dst, dst, 128
+1: dc zva, dst
+ add dst, dst, 128
+ subs count, count, 128
+ b.hi 1b
+ stp q0, q0, [dstend, -128]
+ stp q0, q0, [dstend, -96]
+ stp q0, q0, [dstend, -64]
+ stp q0, q0, [dstend, -32]
+ ret
+
+L(zva_other):
+ mov tmp2w, 4
+ lsl zva_lenw, tmp2w, tmp1w
+ add tmp1, zva_len, 64 /* Max alignment bytes written. */
+ cmp count, tmp1
+ blo L(no_zva)
+
+ sub tmp2, zva_len, 1
+ add tmp1, dst, zva_len
+ add dst, dst, 16
+ subs count, tmp1, dst /* Actual alignment bytes to write. */
+ bic tmp1, tmp1, tmp2 /* Aligned dc zva start address. */
+ beq 2f
+1: stp q0, q0, [dst], 64
+ stp q0, q0, [dst, -32]
+ subs count, count, 64
+ b.hi 1b
+2: mov dst, tmp1
+ sub count, dstend, tmp1 /* Remaining bytes to write. */
+ subs count, count, zva_len
+ b.lo 4f
+3: dc zva, dst
+ add dst, dst, zva_len
+ subs count, count, zva_len
+ b.hs 3b
+4: add count, count, zva_len
+ b L(tail64)
+
+END (memset)
+libc_hidden_def (memset)
diff --git a/libc/sysdeps/linux/aarch64/Makefile b/libc/sysdeps/linux/aarch64/Makefile
new file mode 100644
index 000000000..86a32a613
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/Makefile
@@ -0,0 +1,9 @@
+# Makefile for uClibc-ng
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+top_srcdir=../../../../
+top_builddir=../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libc/sysdeps/linux/aarch64/Makefile.arch b/libc/sysdeps/linux/aarch64/Makefile.arch
new file mode 100644
index 000000000..b38f760a8
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/Makefile.arch
@@ -0,0 +1,5 @@
+# Makefile for uClibc-ng
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+CSRC-y := __syscall_error.c
+SSRC-y := clone.S setjmp.S syscall.S __longjmp.S bsd-setjmp.S bsd-_setjmp.S vfork.S
diff --git a/libc/sysdeps/linux/aarch64/__longjmp.S b/libc/sysdeps/linux/aarch64/__longjmp.S
new file mode 100644
index 000000000..e4d11b165
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/__longjmp.S
@@ -0,0 +1,107 @@
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+
+/* __longjmp(jmpbuf, val) */
+
+ENTRY (__longjmp)
+ cfi_def_cfa(x0, 0)
+ cfi_offset(x19, JB_X19<<3)
+ cfi_offset(x20, JB_X20<<3)
+ cfi_offset(x21, JB_X21<<3)
+ cfi_offset(x22, JB_X22<<3)
+ cfi_offset(x23, JB_X23<<3)
+ cfi_offset(x24, JB_X24<<3)
+ cfi_offset(x25, JB_X25<<3)
+ cfi_offset(x26, JB_X26<<3)
+ cfi_offset(x27, JB_X27<<3)
+ cfi_offset(x28, JB_X28<<3)
+ cfi_offset(x29, JB_X29<<3)
+ cfi_offset(x30, JB_LR<<3)
+
+ cfi_offset( d8, JB_D8<<3)
+ cfi_offset( d9, JB_D9<<3)
+ cfi_offset(d10, JB_D10<<3)
+ cfi_offset(d11, JB_D11<<3)
+ cfi_offset(d12, JB_D12<<3)
+ cfi_offset(d13, JB_D13<<3)
+ cfi_offset(d14, JB_D14<<3)
+ cfi_offset(d15, JB_D15<<3)
+
+ ldp x19, x20, [x0, #JB_X19<<3]
+ ldp x21, x22, [x0, #JB_X21<<3]
+ ldp x23, x24, [x0, #JB_X23<<3]
+ ldp x25, x26, [x0, #JB_X25<<3]
+ ldp x27, x28, [x0, #JB_X27<<3]
+ ldp x29, x30, [x0, #JB_X29<<3]
+
+ /* longjmp probe takes 3 arguments, address of jump buffer as
+ first argument (8@x0), return value as second argument (-4@x1),
+ and target address (8@x30), respectively. */
+ //LIBC_PROBE (longjmp, 3, 8@x0, -4@x1, 8@x30)
+ ldp d8, d9, [x0, #JB_D8<<3]
+ ldp d10, d11, [x0, #JB_D10<<3]
+ ldp d12, d13, [x0, #JB_D12<<3]
+ ldp d14, d15, [x0, #JB_D14<<3]
+
+ /* Originally this was implemented with a series of
+ .cfi_restore() directives.
+
+ The theory was that cfi_restore should revert to previous
+ frame value is the same as the current value. In practice
+ this doesn't work, even after cfi_restore() gdb continues
+ to try to recover a previous frame value offset from x0,
+ which gets stuffed after a few more instructions. The
+ cfi_same_value() mechanism appears to work fine. */
+
+ cfi_same_value(x19)
+ cfi_same_value(x20)
+ cfi_same_value(x21)
+ cfi_same_value(x22)
+ cfi_same_value(x23)
+ cfi_same_value(x24)
+ cfi_same_value(x25)
+ cfi_same_value(x26)
+ cfi_same_value(x27)
+ cfi_same_value(x28)
+ cfi_same_value(x29)
+ cfi_same_value(x30)
+ cfi_same_value(d8)
+ cfi_same_value(d9)
+ cfi_same_value(d10)
+ cfi_same_value(d11)
+ cfi_same_value(d12)
+ cfi_same_value(d13)
+ cfi_same_value(d14)
+ cfi_same_value(d15)
+ ldr x5, [x0, #JB_SP<<3]
+ mov sp, x5
+
+ /* longjmp_target probe takes 3 arguments, address of jump buffer
+ as first argument (8@x0), return value as second argument (-4@x1),
+ and target address (8@x30), respectively. */
+ //LIBC_PROBE (longjmp_target, 3, 8@x0, -4@x1, 8@x30)
+ cmp x1, #0
+ mov x0, #1
+ csel x0, x1, x0, ne
+ /* Use br instead of ret because ret is guaranteed to mispredict */
+ br x30
+END (__longjmp)
+libc_hidden_def(__longjmp)
diff --git a/libc/sysdeps/linux/aarch64/__syscall_error.c b/libc/sysdeps/linux/aarch64/__syscall_error.c
new file mode 100644
index 000000000..2b642e816
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/__syscall_error.c
@@ -0,0 +1,18 @@
+/* Wrapper for setting errno.
+ *
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <features.h>
+
+/* This routine is jumped to by all the syscall handlers, to stash
+ * an error number into errno. */
+int __syscall_error(int err_no) attribute_hidden;
+int __syscall_error(int err_no)
+{
+ __set_errno(-err_no);
+ return -1;
+}
diff --git a/libc/sysdeps/linux/aarch64/bits/atomic.h b/libc/sysdeps/linux/aarch64/bits/atomic.h
new file mode 100644
index 000000000..66e2f57d6
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/bits/atomic.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 2003-2017 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _AARCH64_ATOMIC_MACHINE_H
+#define _AARCH64_ATOMIC_MACHINE_H 1
+
+#define typeof __typeof__
+
+#include <stdint.h>
+#include <sysdep.h>
+
+typedef int8_t atomic8_t;
+typedef int16_t atomic16_t;
+typedef int32_t atomic32_t;
+typedef int64_t atomic64_t;
+
+typedef uint8_t uatomic8_t;
+typedef uint16_t uatomic16_t;
+typedef uint32_t uatomic32_t;
+typedef uint64_t uatomic64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#define __HAVE_64B_ATOMICS 1
+#define USE_ATOMIC_COMPILER_BUILTINS 1
+
+/* Compare and exchange.
+ For all "bool" routines, we return FALSE if exchange succesful. */
+
+# define __arch_compare_and_exchange_bool_8_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_16_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_32_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_64_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_16_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_32_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_64_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+
+/* Compare and exchange with "acquire" semantics, ie barrier after. */
+
+# define atomic_compare_and_exchange_bool_acq(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, __ATOMIC_ACQUIRE)
+
+# define atomic_compare_and_exchange_val_acq(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, __ATOMIC_ACQUIRE)
+
+/* Compare and exchange with "release" semantics, ie barrier before. */
+
+# define atomic_compare_and_exchange_val_rel(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, __ATOMIC_RELEASE)
+
+
+/* Atomic exchange (without compare). */
+
+# define __arch_exchange_8_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_16_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_32_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_64_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define atomic_exchange_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_RELEASE)
+
+
+/* Atomically add value and return the previous (unincremented) value. */
+
+# define __arch_exchange_and_add_8_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_16_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_32_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_64_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define atomic_exchange_and_add_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
+ __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_and_add_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
+ __ATOMIC_RELEASE)
+
+/* Barrier macro. */
+#define atomic_full_barrier() __sync_synchronize()
+
+#endif
diff --git a/libc/sysdeps/linux/aarch64/bits/endian.h b/libc/sysdeps/linux/aarch64/bits/endian.h
new file mode 100644
index 000000000..a32ebc0d8
--- /dev/null
+++ b/libc/sysdeps/linux/aarch64/bits/endian.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+