summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Ren-Wei Chen <vincentc@andestech.com>2017-01-17 07:31:24 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2017-01-22 10:06:29 +0100
commit6af3332a4cbd1ffbc81f74759ef7c5e1a87d2e10 (patch)
tree4deae5f23fd1e2664f21c09dfb57fda799dffd10
parent82af21a60bc6e53dd92c1c140f20179d2ae4ad40 (diff)
nds32: add NPTL/TLS, *context function, libm changes and code cleanup
This commit includes following features. 1. Support NPTL/TLS 2. Add libm function which is used to handle FP rounding and excpetions (ex: fclrexcpt,fedisblxcpti,feenablxcpt... ) 3. Add *context function for operating user context (ex: setcontext,getcontext,makecontext... ) 4. Change the return flow from signal handler 5. Cleanup of old code The testsuite only has 2 errors, tst-cpuclock1 and tst-cputimer1, which are related to timing accuracy. (math and locale tests are disabled) Signed-off-by: Vincent Ren-Wei Chen <vincentc@andestech.com>
-rw-r--r--extra/Configs/Config.in1
-rw-r--r--extra/Configs/Config.nds321
-rw-r--r--extra/Configs/defconfigs/nds32/defconfig167
-rw-r--r--include/elf.h3
-rw-r--r--ldso/ldso/nds32/dl-startup.h94
-rw-r--r--ldso/ldso/nds32/dl-sysdep.h5
-rw-r--r--ldso/ldso/nds32/dl-tlsdesc.S100
-rw-r--r--ldso/ldso/nds32/elfinterp.c94
-rw-r--r--ldso/ldso/nds32/resolve.S24
-rw-r--r--ldso/libdl/Makefile.in1
-rw-r--r--libc/string/nds32/memcpy.S22
-rw-r--r--libc/string/nds32/memset.S2
-rw-r--r--libc/sysdeps/linux/common/posix_fadvise.c2
-rw-r--r--libc/sysdeps/linux/common/posix_fadvise64.c2
-rw-r--r--libc/sysdeps/linux/common/sync_file_range.c2
-rw-r--r--libc/sysdeps/linux/nds32/Makefile6
-rw-r--r--libc/sysdeps/linux/nds32/Makefile.arch6
-rw-r--r--libc/sysdeps/linux/nds32/__longjmp.S2
-rw-r--r--libc/sysdeps/linux/nds32/bits/atomic.h110
-rw-r--r--libc/sysdeps/linux/nds32/bits/fcntl.h6
-rw-r--r--libc/sysdeps/linux/nds32/bits/fenv.h79
-rw-r--r--libc/sysdeps/linux/nds32/bits/mman.h1
-rw-r--r--libc/sysdeps/linux/nds32/bits/setjmp.h18
-rw-r--r--libc/sysdeps/linux/nds32/bits/sigcontext.h59
-rw-r--r--libc/sysdeps/linux/nds32/bits/sigcontextinfo.h35
-rw-r--r--libc/sysdeps/linux/nds32/bits/syscalls.h354
-rw-r--r--libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h2
-rw-r--r--libc/sysdeps/linux/nds32/bsd-_setjmp.S5
-rw-r--r--libc/sysdeps/linux/nds32/bsd-setjmp.S4
-rw-r--r--libc/sysdeps/linux/nds32/clone.S200
-rw-r--r--libc/sysdeps/linux/nds32/crt1.S7
-rw-r--r--libc/sysdeps/linux/nds32/crti.S24
-rw-r--r--libc/sysdeps/linux/nds32/fpu_control.h77
-rw-r--r--libc/sysdeps/linux/nds32/getcontext.S106
-rw-r--r--libc/sysdeps/linux/nds32/jmpbuf-unwind.h18
-rw-r--r--libc/sysdeps/linux/nds32/makecontext.c77
-rw-r--r--libc/sysdeps/linux/nds32/mmap.S101
-rw-r--r--libc/sysdeps/linux/nds32/mremap.c28
-rw-r--r--libc/sysdeps/linux/nds32/prctl.c23
-rw-r--r--libc/sysdeps/linux/nds32/setcontext.S85
-rw-r--r--libc/sysdeps/linux/nds32/setjmp.S2
-rw-r--r--libc/sysdeps/linux/nds32/sigaction.c40
-rw-r--r--libc/sysdeps/linux/nds32/sigrestorer.S42
-rw-r--r--libc/sysdeps/linux/nds32/swapcontext.c38
-rw-r--r--libc/sysdeps/linux/nds32/sys/ucontext.h117
-rw-r--r--libc/sysdeps/linux/nds32/syscall.S60
-rw-r--r--libc/sysdeps/linux/nds32/syscall.c28
-rw-r--r--libc/sysdeps/linux/nds32/sysdep.S39
-rw-r--r--libc/sysdeps/linux/nds32/sysdep.h321
-rw-r--r--libc/sysdeps/linux/nds32/ucontext_i.sym27
-rw-r--r--libc/sysdeps/linux/nds32/vfork.S114
-rw-r--r--libm/nds32/Makefile.arch16
-rw-r--r--libm/nds32/e_sqrt.c34
-rw-r--r--libm/nds32/fclrexcpt.c52
-rw-r--r--libm/nds32/fedisblxcpt.c49
-rw-r--r--libm/nds32/feenablxcpt.c50
-rw-r--r--libm/nds32/fegetenv.c40
-rw-r--r--libm/nds32/fegetexcept.c41
-rw-r--r--libm/nds32/fegetround.c40
-rw-r--r--libm/nds32/feholdexcpt.c51
-rw-r--r--libm/nds32/fenv_libc.h33
-rw-r--r--libm/nds32/fesetenv.c51
-rw-r--r--libm/nds32/fesetround.c42
-rw-r--r--libm/nds32/feupdateenv.c48
-rw-r--r--libm/nds32/fgetexcptflg.c44
-rw-r--r--libm/nds32/fraiseexcpt.c104
-rw-r--r--libm/nds32/fsetexcptflg.c48
-rw-r--r--libm/nds32/ftestexcept.c40
-rw-r--r--libpthread/linuxthreads/sysdeps/nds32/pspinlock.c2
-rw-r--r--libpthread/linuxthreads/sysdeps/nds32/pt-machine.h2
-rw-r--r--libpthread/nptl/sysdeps/nds32/Makefile.arch16
-rw-r--r--libpthread/nptl/sysdeps/nds32/dl-tls.h59
-rw-r--r--libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S1
-rw-r--r--libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c65
-rw-r--r--libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c26
-rw-r--r--libpthread/nptl/sysdeps/nds32/pthreaddef.h39
-rw-r--r--libpthread/nptl/sysdeps/nds32/tcb-offsets.sym12
-rw-r--r--libpthread/nptl/sysdeps/nds32/tls.h178
-rw-r--r--libpthread/nptl/sysdeps/nds32/tlsdesc.sym17
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile9
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch12
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h177
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h38
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S4
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c22
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c27
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h323
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c18
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c92
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h273
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S43
91 files changed, 4023 insertions, 996 deletions
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index f312e7a13..a9d62f50f 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -521,7 +521,6 @@ config UCLIBC_HAS_THREADS_NATIVE
!TARGET_hppa && \
!TARGET_ia64 && \
!TARGET_m68k && \
- !TARGET_nds32 && \
!TARGET_or1k && \
ARCH_USE_MMU
help
diff --git a/extra/Configs/Config.nds32 b/extra/Configs/Config.nds32
index a74249947..2ed6a32b7 100644
--- a/extra/Configs/Config.nds32
+++ b/extra/Configs/Config.nds32
@@ -13,6 +13,7 @@ config FORCE_OPTIONS_FOR_ARCH
select ARCH_ANY_ENDIAN
select ARCH_HAS_DEPRECATED_SYSCALLS
select ARCH_HAS_MMU
+ select ARCH_HAS_UCONTEXT
choice
prompt "MMU Page Size"
diff --git a/extra/Configs/defconfigs/nds32/defconfig b/extra/Configs/defconfigs/nds32/defconfig
new file mode 100644
index 000000000..d870ad747
--- /dev/null
+++ b/extra/Configs/defconfigs/nds32/defconfig
@@ -0,0 +1,167 @@
+TARGET_nds32=y
+#
+# Using ELF file format
+#
+ARCH_HAS_DEPRECATED_SYSCALLS=y
+ARCH_ANY_ENDIAN=y
+ARCH_LITTLE_ENDIAN=y
+# ARCH_WANTS_BIG_ENDIAN is not set
+ARCH_WANTS_LITTLE_ENDIAN=y
+ARCH_HAS_MMU=y
+ARCH_USE_MMU=y
+UCLIBC_HAS_FLOATS=y
+UCLIBC_HAS_FPU=y
+DO_C99_MATH=y
+DO_XSI_MATH=y
+UCLIBC_HAS_FENV=y
+KERNEL_HEADERS=""
+HAVE_DOT_CONFIG=y
+
+#
+# General Library Settings
+#
+DOPIC=y
+ARCH_HAS_UCONTEXT=y
+HAVE_SHARED=y
+# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
+LDSO_LDD_SUPPORT=y
+LDSO_CACHE_SUPPORT=y
+# LDSO_PRELOAD_ENV_SUPPORT is not set
+# LDSO_PRELOAD_FILE_SUPPORT is not set
+LDSO_BASE_FILENAME="ld.so"
+# LDSO_STANDALONE_SUPPORT is not set
+# LDSO_PRELINK_SUPPORT is not set
+UCLIBC_STATIC_LDCONFIG=y
+LDSO_RUNPATH=y
+LDSO_RUNPATH_OF_EXECUTABLE=y
+LDSO_SAFE_RUNPATH=y
+LDSO_SEARCH_INTERP_PATH=y
+LDSO_LD_LIBRARY_PATH=y
+LDSO_NO_CLEANUP=y
+UCLIBC_CTOR_DTOR=y
+LDSO_GNU_HASH_SUPPORT=y
+# HAS_NO_THREADS is not set
+# UCLIBC_HAS_LINUXTHREADS is not set
+UCLIBC_HAS_THREADS_NATIVE=y
+UCLIBC_HAS_THREADS=y
+UCLIBC_HAS_TLS=y
+PTHREADS_DEBUG_SUPPORT=y
+UCLIBC_HAS_SYSLOG=y
+UCLIBC_HAS_LFS=y
+# MALLOC is not set
+# MALLOC_SIMPLE is not set
+MALLOC_STANDARD=y
+MALLOC_GLIBC_COMPAT=y
+# UCLIBC_HAS_OBSTACK is not set
+UCLIBC_DYNAMIC_ATEXIT=y
+COMPAT_ATEXIT=y
+UCLIBC_HAS_UTMPX=y
+UCLIBC_HAS_UTMP=y
+UCLIBC_SUSV2_LEGACY=y
+UCLIBC_SUSV3_LEGACY=y
+UCLIBC_HAS_CONTEXT_FUNCS=y
+UCLIBC_SUSV3_LEGACY_MACROS=y
+UCLIBC_SUSV4_LEGACY=y
+# UCLIBC_STRICT_HEADERS is not set
+# UCLIBC_HAS_STUBS is not set
+UCLIBC_HAS_SHADOW=y
+UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y
+UCLIBC_HAS___PROGNAME=y
+UCLIBC_HAS_PTY=y
+ASSUME_DEVPTS=y
+UNIX98PTY_ONLY=y
+UCLIBC_HAS_GETPT=y
+UCLIBC_HAS_LIBUTIL=y
+UCLIBC_HAS_TM_EXTENSIONS=y
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+UCLIBC_FALLBACK_TO_ETC_LOCALTIME=y
+
+#
+# Advanced Library Settings
+#
+UCLIBC_PWD_BUFFER_SIZE=256
+UCLIBC_GRP_BUFFER_SIZE=256
+
+#
+# Support various families of functions
+#
+UCLIBC_LINUX_MODULE_26=y
+# UCLIBC_LINUX_MODULE_24 is not set
+UCLIBC_LINUX_SPECIFIC=y
+UCLIBC_HAS_GNU_ERROR=y
+UCLIBC_BSD_SPECIFIC=y
+UCLIBC_HAS_BSD_ERR=y
+UCLIBC_HAS_OBSOLETE_BSD_SIGNAL=y
+# UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL is not set
+# UCLIBC_NTP_LEGACY is not set
+UCLIBC_SV4_DEPRECATED=y
+UCLIBC_HAS_REALTIME=y
+UCLIBC_HAS_ADVANCED_REALTIME=y
+UCLIBC_HAS_EPOLL=y
+UCLIBC_HAS_XATTR=y
+UCLIBC_HAS_PROFILING=y
+UCLIBC_HAS_CRYPT_IMPL=y
+UCLIBC_HAS_SHA256_CRYPT_IMPL=y
+# UCLIBC_HAS_SHA512_CRYPT_IMPL is not set
+UCLIBC_HAS_CRYPT=y
+UCLIBC_HAS_NETWORK_SUPPORT=y
+UCLIBC_HAS_SOCKET=y
+UCLIBC_HAS_IPV4=y
+UCLIBC_HAS_IPV6=y
+UCLIBC_HAS_RPC=y
+UCLIBC_HAS_FULL_RPC=y
+# UCLIBC_HAS_REENTRANT_RPC is not set
+UCLIBC_USE_NETLINK=y
+UCLIBC_SUPPORT_AI_ADDRCONFIG=y
+UCLIBC_HAS_BSD_RES_CLOSE=y
+UCLIBC_HAS_COMPAT_RES_STATE=y
+# UCLIBC_HAS_EXTRA_COMPAT_RES_STATE is not set
+UCLIBC_HAS_RESOLVER_SUPPORT=y
+UCLIBC_HAS_LIBRESOLV_STUB=y
+UCLIBC_HAS_LIBNSL_STUB=y
+
+UCLIBC_HAS_STRING_GENERIC_OPT=y
+UCLIBC_HAS_STRING_ARCH_OPT=y
+UCLIBC_HAS_STDIO_FUTEXES=y
+UCLIBC_HAS_CTYPE_TABLES=y
+UCLIBC_HAS_CTYPE_SIGNED=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_WCHAR=y
+# UCLIBC_HAS_LOCALE is not set
+UCLIBC_HAS_HEXADECIMAL_FLOATS=y
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+UCLIBC_HAS_STDIO_BUFSIZ_4096=y
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
+UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
+UCLIBC_HAS_PRINTF_M_SPEC=y
+UCLIBC_HAS_ERRNO_MESSAGES=y
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+UCLIBC_HAS_GNU_GETOPT=y
+UCLIBC_HAS_GETOPT_LONG=y
+UCLIBC_HAS_GNU_GETSUBOPT=y
+UCLIBC_HAS_ARGP=y
+
+UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_REGEX_OLD is not set
+UCLIBC_HAS_FNMATCH=y
+# UCLIBC_HAS_FNMATCH_OLD is not set
+UCLIBC_HAS_WORDEXP=y
+UCLIBC_HAS_NFTW=y
+UCLIBC_HAS_FTW=y
+UCLIBC_HAS_FTS=y
+UCLIBC_HAS_GLOB=y
+UCLIBC_HAS_GNU_GLOB=y
+
+CROSS_COMPILER_PREFIX=""
+UCLIBC_EXTRA_CFLAGS=""
+# DOSTRIP is not set
diff --git a/include/elf.h b/include/elf.h
index e0937b732..0f188e792 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -2985,6 +2985,9 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_NDS32_PLTREL_LO12 65
#define R_NDS32_PLT_GOTREL_HI20 66
#define R_NDS32_PLT_GOTREL_LO12 67
+#define R_NDS32_TLS_TPOFF 102
+#define R_NDS32_TLS_DESC 119
+
/* Processor specific section indices. These sections do not actually
exist. Symbols with a st_shndx field corresponding to one of these
diff --git a/ldso/ldso/nds32/dl-startup.h b/ldso/ldso/nds32/dl-startup.h
index f700531ca..56892a2ba 100644
--- a/ldso/ldso/nds32/dl-startup.h
+++ b/ldso/ldso/nds32/dl-startup.h
@@ -6,68 +6,7 @@
/* Need bootstrap relocations */
#define ARCH_NEEDS_BOOTSTRAP_RELOCS
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-# define STACK_PUSH
-# define STACK_POP
-#else
-# define STACK_PUSH "addi $sp, $sp, -24"
-# define STACK_POP "addi $sp, $sp, 24"
-#endif
-
-#ifdef __NDS32_N1213_43U1H__
-__asm__("\
- .text\n\
- .globl _start\n\
- .globl _dl_start\n\
- .globl _dl_start_user\n\
- .type _start,#function\n\
- .type _dl_start,#function\n\
- .type _dl_start_user,#function\n\
- .align 4\n\
- .pic\n\
-1:\n\
- ret\n\
-_start:\n\
- ! we are PIC code, so get global offset table\n\
- jal 1b\n\
- sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_)\n\
- ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+4)\n\
- add $gp, $lp, $gp\n\
-\n\
- ! at start time, all the args are on the stack\n\
- addi $r0, $sp, 0\n\
- ! adjust stack\n\
- !addi $sp, $sp, -24\n\
- "STACK_PUSH"\n\
- bal _dl_start@PLT\n\
- ! save user entry point in r6\n\
- addi $r6, $r0, 0\n\
- ! adjust sp and reload registers\n\
- !addi $sp, $sp, 24\n\
- "STACK_POP"\n\
-\n\
-_dl_start_user:\n\
-\n\
- ! See if we were run as a command with the executable file\n\
- ! name as an extra leading argument.\n\
- ! skip these arguments\n\
- l.w $r2, _dl_skip_args@GOTOFF ! args to skip\n\
- lwi $r0, [$sp+0] ! original argc\n\
- slli $r1, $r2, 2 ! offset for new sp\n\
- add $sp, $sp, $r1 ! adjust sp to skip args\n\
- sub $r0, $r0, $r2 ! set new argc\n\
- swi $r0, [$sp+0] ! save new argc\n\
-\n\
- ! load address of _dl_fini finalizer function\n\
- la $r5, _dl_fini@GOTOFF\n\
- ! jump to the user_s entry point\n\
- addi $r15, $r6, 0\n\
- jr $r15\n\
- .size _dl_start_user, . - _dl_start_user\n\
- .previous\n\
-");
-#else
__asm__("\
.text\n\
.globl _start\n\
@@ -89,13 +28,11 @@ _start:\n\
addi $r0, $sp, 0\n\
! adjust stack\n\
!addi $sp, $sp, -24\n\
- "STACK_PUSH"\n\
bal _dl_start@PLT\n\
! save user entry point in r6\n\
addi $r6, $r0, 0\n\
! adjust sp and reload registers\n\
!addi $sp, $sp, 24\n\
- "STACK_POP"\n\
\n\
_dl_start_user:\n\
! See if we were run as a command with the executable file\n\
@@ -115,31 +52,12 @@ _dl_start_user:\n\
.size _dl_start_user, . - _dl_start_user\n\
.previous\n\
");
-#endif
-#define COPY_UNALIGNED_WORD(swp, twp, align) \
- { \
- void *__s = (swp), *__t = (twp); \
- unsigned char *__s1 = __s, *__t1 = __t; \
- unsigned short *__s2 = __s, *__t2 = __t; \
- unsigned long *__s4 = __s, *__t4 = __t; \
- switch ((align)) \
- { \
- case 0: \
- *__t4 = *__s4; \
- break; \
- case 2: \
- *__t2++ = *__s2++; \
- *__t2 = *__s2; \
- break; \
- default: \
- *__t1++ = *__s1++; \
- *__t1++ = *__s1++; \
- *__t1++ = *__s1++; \
- *__t1 = *__s1; \
- break; \
- } \
- }
+#define COPY_UNALIGNED_WORD(swp, twp) \
+{ \
+ __typeof (swp) __tmp = __builtin_nds32_unaligned_load_w ((unsigned int*)&swp); \
+ __builtin_nds32_unaligned_store_w ((unsigned int *)twp, __tmp); \
+}
/* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
@@ -162,7 +80,7 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
break;
case R_NDS32_32_RELA:
value = symbol_addr + rpnt->r_addend;
- COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3);
+ COPY_UNALIGNED_WORD (value, reloc_addr);
break;
#undef COPY_UNALIGNED_WORD
case R_NDS32_RELATIVE:
diff --git a/ldso/ldso/nds32/dl-sysdep.h b/ldso/ldso/nds32/dl-sysdep.h
index c4a32ca71..5ff2aa9ae 100644
--- a/ldso/ldso/nds32/dl-sysdep.h
+++ b/ldso/ldso/nds32/dl-sysdep.h
@@ -57,7 +57,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
of the main executable's symbols, as for a COPY reloc. */
#define elf_machine_type_class(type) \
- ((((type) == R_NDS32_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ ((((type) == R_NDS32_JMP_SLOT || (type) == R_NDS32_TLS_TPOFF \
+ || (type) == R_NDS32_TLS_DESC) * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_NDS32_COPY) * ELF_RTYPE_CLASS_COPY))
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
@@ -81,7 +82,7 @@ elf_machine_load_address (void)
via the GOT to make sure the compiler initialized %ebx in time. */
Elf32_Addr addr;
- __asm__ ("la %0, _dl_start@GOTOFF\n" : "=r" (addr) );
+ __asm__ ("la %0, _DYNAMIC@GOTOFF\n" : "=r" (addr) );
return addr - elf_machine_dynamic();
}
diff --git a/ldso/ldso/nds32/dl-tlsdesc.S b/ldso/ldso/nds32/dl-tlsdesc.S
new file mode 100644
index 000000000..a7ea1f2d1
--- /dev/null
+++ b/ldso/ldso/nds32/dl-tlsdesc.S
@@ -0,0 +1,100 @@
+/* Thread-local storage handling in the ELF dynamic linker. NDS32 version.
+ Copyright (C) 2006-2013 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>
+#if defined __UCLIBC_HAS_TLS__
+#include <tls.h>
+#include "tlsdesc.h"
+
+ .text
+ .hidden _dl_tlsdesc_return
+ .global _dl_tlsdesc_return
+ .type _dl_tlsdesc_return,#function
+ cfi_startproc
+ .align 2
+_dl_tlsdesc_return:
+ lwi $r0, [$r0 + 4]
+ add $r0, $r0, $r25
+ ret
+ cfi_endproc
+ .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
+
+#ifdef SHARED
+ .hidden _dl_tlsdesc_dynamic
+ .global _dl_tlsdesc_dynamic
+ .type _dl_tlsdesc_dynamic,#function
+ cfi_startproc
+ .pic
+/*
+ The assembly code that follows is a rendition of the following
+ C code, hand-optimized a little bit.
+
+ptrdiff_t
+_dl_tlsdesc_dynamic(struct tlsdesc *tdp)
+{
+ struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
+ dtv_t *dtv = (dtv_t *)THREAD_DTV();
+ if (__builtin_expect (td->gen_count <= dtv[0].counter
+ && dtv[td->tlsinfo.ti_module].pointer.val
+ != TLS_DTV_UNALLOCATED,
+ 1))
+ return dtv[td->tlsinfo.ti_module].pointer.val +
+ td->tlsinfo.ti_offset - __builtin_thread_pointer();
+
+ return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
+}
+*/
+ .align 2
+
+_dl_tlsdesc_dynamic:
+ lwi $r0, [$r0 + 4]
+ lwi $r1, [$r0 + #TLSDESC_GEN_COUNT] /* $r0=td $r1=td->gen_count*/
+ lwi $r2, [$r25 + #DTV_OFFSET] /* $r2=&dtv[0]*/
+ lwi $r3, [$r2]
+ sub $r1, $r1, $r3
+ bgtz $r1, 2f
+ lwi $r3, [$r0 + #TLSDESC_MODID] /* r3=module id */
+ slli $r3, $r3, #3 /* r3=module offset=module id*8(byte) */
+ lw $r3, [$r2 + $r3] /* r3=&dtc[module ID]=&dtv[0]+ module offset*/
+ movi $r1, #-1
+ beq $r3, $r1, 2f
+ lwi $r1, [$r0 + #TLSDESC_MODOFF]
+ add $r0, $r3, $r1
+1:
+ ret
+2:
+ smw.adm $sp,[$sp],$sp,#0x6
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(gp, 0)
+ cfi_rel_offset(lp, 4)
+ mfusr $r15, $PC;
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4);
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8);
+ add $gp, $r15, $gp;
+ sethi $r15, hi20(__tls_get_addr@PLT);
+ ori $r15, $r15, lo12(__tls_get_addr@PLT);
+ add $r15, $r15, $gp
+ jral $r15
+ lmw.bim $sp,[$sp],$sp,#0x6
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(gp)
+ cfi_restore(lp)
+ j 1b
+ cfi_endproc
+ .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#endif
+#endif // __UCLIBC_HAS_TLS__
diff --git a/ldso/ldso/nds32/elfinterp.c b/ldso/ldso/nds32/elfinterp.c
index 6a091f80a..9f671419c 100644
--- a/ldso/ldso/nds32/elfinterp.c
+++ b/ldso/ldso/nds32/elfinterp.c
@@ -44,6 +44,11 @@
#include "ldso.h"
+#if defined(USE_TLS) && USE_TLS
+#include "dl-tls.h"
+#include "tlsdeschtab.h"
+#endif
+
extern int _dl_linux_resolve(void);
unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
@@ -95,7 +100,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
{
_dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
if (_dl_debug_detail) _dl_dprintf(_dl_debug_file,
- "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
+ "\tpatch %x ==> %x @ %x", (unsigned int)*got_addr, (unsigned int)new_addr, (unsigned int)got_addr);
}
}
if (!_dl_debug_nofixups) {
@@ -168,6 +173,9 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
int reloc_type;
int symtab_index;
char *symname = NULL;
+#if defined USE_TLS && USE_TLS
+ struct elf_resolve *tls_tpnt = NULL;
+#endif
unsigned long *reloc_addr;
unsigned long symbol_addr;
int goof = 0;
@@ -190,40 +198,40 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
* have been intentional. We should not be linking local symbols
* here, so all bases should be covered.
*/
- if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
+ if (!symbol_addr
+ && (ELF32_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
+ && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
_dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
- _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_progname, symname);
_dl_exit (1);
}
+ if (_dl_trace_prelink) {
+ _dl_debug_lookup(symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
+ }
+#if defined USE_TLS && USE_TLS
+ tls_tpnt = sym_ref.tpnt;
+#endif
}
-#define COPY_UNALIGNED_WORD(swp, twp, align) \
- { \
- void *__s = (swp), *__t = (twp); \
- unsigned char *__s1 = __s, *__t1 = __t; \
- unsigned short *__s2 = __s, *__t2 = __t; \
- unsigned long *__s4 = __s, *__t4 = __t; \
- switch ((align)) \
- { \
- case 0: \
- *__t4 = *__s4; \
- break; \
- case 2: \
- *__t2++ = *__s2++; \
- *__t2 = *__s2; \
- break; \
- default: \
- *__t1++ = *__s1++; \
- *__t1++ = *__s1++; \
- *__t1++ = *__s1++; \
- *__t1 = *__s1; \
- break; \
- } \
- }
+#if defined USE_TLS && USE_TLS
+ /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous'
+ symbol. This is the case for a static tls variable, so the lookup
+ module is just that one is referencing the tls variable. */
+ if (!tls_tpnt)
+ tls_tpnt = tpnt;
+#endif
+#define COPY_UNALIGNED_WORD(swp, twp) \
+{ \
+ __typeof (swp) __tmp = __builtin_nds32_unaligned_load_w ((unsigned int*)&swp); \
+ __builtin_nds32_unaligned_store_w ((unsigned int *)twp, __tmp); \
+}
#if defined (__SUPPORT_LD_DEBUG__)
{
- unsigned long old_val = *reloc_addr;
+ unsigned long old_val = 0;
+ if(reloc_type != R_NDS32_NONE)
+ old_val = *reloc_addr;
#endif
symbol_addr += rpnt->r_addend ;
switch (reloc_type) {
@@ -235,7 +243,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
*reloc_addr = symbol_addr;
break;
case R_NDS32_32_RELA:
- COPY_UNALIGNED_WORD (&symbol_addr, reloc_addr,(int) reloc_addr & 3);
+ COPY_UNALIGNED_WORD (symbol_addr, reloc_addr);
break;
#undef COPY_UNALIGNED_WORD
case R_NDS32_RELATIVE:
@@ -245,12 +253,38 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
_dl_memcpy((void *) reloc_addr,
(void *) symbol_addr, symtab[symtab_index].st_size);
break;
+#if defined USE_TLS && USE_TLS
+ case R_NDS32_TLS_TPOFF:
+ CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+ *reloc_addr = (symbol_addr + tls_tpnt->l_tls_offset);
+ break;
+ case R_NDS32_TLS_DESC:
+ {
+ struct tlsdesc volatile *td =
+ (struct tlsdesc volatile *)reloc_addr;
+#ifndef SHARED
+ CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+#else
+ if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+ {
+ td->argument.pointer = _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, symbol_addr);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+#endif
+ {
+ td->argument.value = symbol_addr + tls_tpnt->l_tls_offset;
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+ break;
+#endif
default:
return -1; /*call _dl_exit(1) */
}
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+ _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr);
}
#endif
@@ -283,7 +317,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
}
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+ _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr);
}
#endif
diff --git a/ldso/ldso/nds32/resolve.S b/ldso/ldso/nds32/resolve.S
index 8c53850d7..e88d9ad60 100644
--- a/ldso/ldso/nds32/resolve.S
+++ b/ldso/ldso/nds32/resolve.S
@@ -3,14 +3,6 @@
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-# define STACK_PUSH
-# define STACK_POP
-#else
-# define STACK_PUSH addi $sp, $sp, -24
-# define STACK_POP addi $sp, $sp, 24
-#endif
-
.text
.align 4 ! 16 byte boundary
.globl _dl_linux_resolve
@@ -28,22 +20,11 @@ _dl_linux_resolve:
smw.adm $r0, [$sp], $r5, 6
! init gp
-#ifdef __NDS32_N1213_43U1H__
- sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4)
- ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8)
- add $gp, $ta, $gp
-#else
mfusr $ta, $PC
sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4)
ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8)
add $gp, $ta, $gp
-#endif
- ! #ifdef __NDS32_ABI_1__
- ! adjust stack
- !addi $sp, $sp, -24
- STACK_PUSH
- ! #endif
! set arguments
addi $r0, $r17, 0
@@ -61,11 +42,6 @@ _dl_linux_resolve:
! save the return
addi $ta, $r0, 0
- ! #ifdef __NDS32_ABI_1__
- ! adjust sp
- !addi $sp, $sp, 24
- STACK_POP
- ! #endif
! reload registers
lmw.bim $r0, [$sp], $r5, 6
diff --git a/ldso/libdl/Makefile.in b/ldso/libdl/Makefile.in
index 24e00faf0..3fd8a6cd1 100644
--- a/ldso/libdl/Makefile.in
+++ b/ldso/libdl/Makefile.in
@@ -33,7 +33,6 @@ libdl_SRC := $(libdl_DIR)/libdl.c
libdl_OBJ := $(patsubst $(libdl_DIR)/%.c,$(libdl_OUT)/%.o,$(libdl_SRC))
resolve := $(top_builddir)ldso/ldso/$(TARGET_ARCH)/resolve.o
-
libdl-a-y := $(libdl_OBJ) $(resolve)
ifeq ($(DOPIC),y)
libdl-a-y := $(libdl-a-y:.o=.os)
diff --git a/libc/string/nds32/memcpy.S b/libc/string/nds32/memcpy.S
index 4f285b5ee..4da2c83ea 100644
--- a/libc/string/nds32/memcpy.S
+++ b/libc/string/nds32/memcpy.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
@@ -54,12 +54,32 @@ ENTRY(memcpy)
srli $r3, $r2, #5
beqz $r3, .Lword_copy_entry
pushm $r6, $r13
+ cfi_adjust_cfa_offset(32)
+ cfi_rel_offset(r6, 0)
+ cfi_rel_offset(r7, 4)
+ cfi_rel_offset(r8, 8)
+ cfi_rel_offset(r9, 12)
+ cfi_rel_offset(r10, 16)
+ cfi_rel_offset(r11, 20)
+ cfi_rel_offset(r12, 24)
+ cfi_rel_offset(r13, 28)
+
.L3:
lmw.bim $r6, [$r1], $r13
addi $r3, $r3, #-1
smw.bim $r6, [$r0], $r13
bnez $r3, .L3
popm $r6, $r13
+ cfi_adjust_cfa_offset(-32)
+ cfi_restore(r6)
+ cfi_restore(r7)
+ cfi_restore(r8)
+ cfi_restore(r9)
+ cfi_restore(r10)
+ cfi_restore(r11)
+ cfi_restore(r12)
+ cfi_restore(r13)
+
.Lword_copy_entry:
andi $r2, $r2, #31
diff --git a/libc/string/nds32/memset.S b/libc/string/nds32/memset.S
index edd15a410..ba208f6cf 100644
--- a/libc/string/nds32/memset.S
+++ b/libc/string/nds32/memset.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
diff --git a/libc/sysdeps/linux/common/posix_fadvise.c b/libc/sysdeps/linux/common/posix_fadvise.c
index c4ebeaa31..82a25d031 100644
--- a/libc/sysdeps/linux/common/posix_fadvise.c
+++ b/libc/sysdeps/linux/common/posix_fadvise.c
@@ -41,7 +41,7 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice)
# if __WORDSIZE == 64
ret = INTERNAL_SYSCALL(fadvise64_64, err, 4, fd, offset, len, advice);
# else
-# if defined (__arm__) || \
+# if defined (__arm__) || defined (__nds32__) || \
(defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && (defined(__powerpc__) || defined(__xtensa__)))
/* arch with 64-bit data in even reg alignment #1: [powerpc/xtensa]
* custom syscall handler (rearranges @advice to avoid register hole punch) */
diff --git a/libc/sysdeps/linux/common/posix_fadvise64.c b/libc/sysdeps/linux/common/posix_fadvise64.c
index eb722ec20..b9a9d93ab 100644
--- a/libc/sysdeps/linux/common/posix_fadvise64.c
+++ b/libc/sysdeps/linux/common/posix_fadvise64.c
@@ -25,7 +25,7 @@ int posix_fadvise64(int fd, off64_t offset, off64_t len, int advice)
int ret;
INTERNAL_SYSCALL_DECL (err);
/* ARM has always been funky. */
-#if defined (__arm__) || \
+#if defined (__arm__) || defined (__nds32__) || \
(defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && (defined(__powerpc__) || defined(__xtensa__)))
/* arch with 64-bit data in even reg alignment #1: [powerpc/xtensa]
* custom syscall handler (rearranges @advice to avoid register hole punch) */
diff --git a/libc/sysdeps/linux/common/sync_file_range.c b/libc/sysdeps/linux/common/sync_file_range.c
index ed03d2f85..faeae3c61 100644
--- a/libc/sysdeps/linux/common/sync_file_range.c
+++ b/libc/sysdeps/linux/common/sync_file_range.c
@@ -28,7 +28,7 @@ static int __NC(sync_file_range)(int fd, off64_t offset, off64_t nbytes, unsigne
return INLINE_SYSCALL(sync_file_range, 6, fd,
OFF64_HI_LO(offset), OFF64_HI_LO(nbytes), flags);
# elif (defined __mips__ && _MIPS_SIM == _ABIO32) || \
- (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && !(defined(__powerpc__) || defined(__xtensa__)))
+ (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && !(defined(__powerpc__) || defined(__xtensa__) || defined(__nds32__)))
/* arch with 64-bit data in even reg alignment #2: [arcv2/others-in-future]
* stock syscall handler in kernel (reg hole punched)
* see libc/sysdeps/linux/common/posix_fadvise.c for more details */
diff --git a/libc/sysdeps/linux/nds32/Makefile b/libc/sysdeps/linux/nds32/Makefile
index 633c91f3e..86a32a613 100644
--- a/libc/sysdeps/linux/nds32/Makefile
+++ b/libc/sysdeps/linux/nds32/Makefile
@@ -1,9 +1,5 @@
-# Makefile for uClibc
-#
-# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
-#
+# Makefile for uClibc-ng
# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
-#
top_srcdir=../../../../
top_builddir=../../../../
diff --git a/libc/sysdeps/linux/nds32/Makefile.arch b/libc/sysdeps/linux/nds32/Makefile.arch
index 8691875ee..d5cdddbfa 100644
--- a/libc/sysdeps/linux/nds32/Makefile.arch
+++ b/libc/sysdeps/linux/nds32/Makefile.arch
@@ -1,5 +1,7 @@
# Copyright (C) 2016 Andes Technology, Inc.
# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
-CSRC-y := brk.c sigaction.c
-SSRC-y := setjmp.S __longjmp.S bsd-setjmp.S bsd-_setjmp.S clone.S mmap.S sigrestorer.S vfork.S sysdep.S syscall.S
+CSRC-y := brk.c prctl.c mremap.c syscall.c
+SSRC-y := setjmp.S __longjmp.S bsd-setjmp.S bsd-_setjmp.S clone.S vfork.S sysdep.S syscall.S
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c swapcontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S
diff --git a/libc/sysdeps/linux/nds32/__longjmp.S b/libc/sysdeps/linux/nds32/__longjmp.S
index fbea6f6f4..16c4dad38 100644
--- a/libc/sysdeps/linux/nds32/__longjmp.S
+++ b/libc/sysdeps/linux/nds32/__longjmp.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
diff --git a/libc/sysdeps/linux/nds32/bits/atomic.h b/libc/sysdeps/linux/nds32/bits/atomic.h
new file mode 100644
index 000000000..f93fa7a43
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/bits/atomic.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _NDS32_BITS_ATOMIC_H
+#define _NDS32_BITS_ATOMIC_H
+
+#include <stdint.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef atomic_full_barrier
+# define atomic_full_barrier() __asm__ ("dsb" ::: "memory")
+#endif
+
+#ifndef atomic_read_barrier
+# define atomic_read_barrier() atomic_full_barrier ()
+#endif
+
+#ifndef atomic_write_barrier
+# define atomic_write_barrier() atomic_full_barrier ()
+#endif
+
+#define atomic_exchange_acq(mem, newval) \
+ ({ unsigned long val, offset, temp; \
+ \
+ __asm__ volatile ( \
+ "move %2, %4\n\t" \
+ "move %1, #0x0\n\t" \
+ "1:\n\t" \
+ "llw %0, [%3 + %1 << 0]\n\t" \
+ "move %2, %4\n\t" \
+ "scw %2, [%3 + %1 << 0]\n\t" \
+ "beqz %2, 1b\n\t" \
+ : "=&r" (val), "=&r" (offset), "=&r" (temp) \
+ : "r" (mem), "r" (newval) \
+ : "memory" ); \
+ val; })
+
+#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+ ({ unsigned long val, offset, temp; \
+ \
+ __asm__ volatile ( \
+ "move %1, #0x0\n\t" \
+ "move %2, %4\n\t" \
+ "1:\n\t" \
+ "llw %0, [%3 + %1 << 0]\n\t" \
+ "bne %0, %5, 2f\n\t" \
+ "move %2, %4\n\t" \
+ "scw %2, [%3 + %1 << 0]\n\t" \
+ "beqz %2, 1b\n\t" \
+ "j 3f\n\t" \
+ "2:\n\t" \
+ "move %2, %0\n\t" \
+ "scw %2, [%3 + %1 << 0]\n\t" \
+ "3:\n\t" \
+ : "=&r" (val), "=&r" (offset), "=&r" (temp) \
+ : "r" (mem), "r" (newval), "r" (oldval) \
+ : "memory" ); \
+ val; })
+
+#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+ ({ unsigned long val, offset, temp; \
+ \
+ __asm__ volatile ( \
+ "move %1, #0x0\n\t" \
+ "move %2, %4\n\t" \
+ "1:\n\t" \
+ "llw %0, [%3 + %1 << 0]\n\t" \
+ "bne %5, %0, 2f\n\t" \
+ "move %2, %4\n\t" \
+ "scw %2, [%3 + %1 << 0]\n\t" \
+ "beqz %2, 1b\n\t" \
+ "addi %0, %1, #0\n\t" \
+ "j 3f\n\t" \
+ "2:\n\t" \
+ "scw %0, [%3 + %1 << 0]\n\t" \
+ "addi %0, %1, #0x1\n\t" \
+ "3:\n\t" \
+ : "=&r" (val), "=&r" (offset), "=&r" (temp) \
+ : "r" (mem), "r" (newval), "r" (oldval) \
+ : "memory" ); \
+ val; })
+
+#endif
diff --git a/libc/sysdeps/linux/nds32/bits/fcntl.h b/libc/sysdeps/linux/nds32/bits/fcntl.h
index d21c4e03c..a936023aa 100644
--- a/libc/sysdeps/linux/nds32/bits/fcntl.h
+++ b/libc/sysdeps/linux/nds32/bits/fcntl.h
@@ -1,7 +1,11 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
/* O_*, F_*, FD_* bit values for Linux.
Copyright (C) 1995, 1996, 1997, 1998, 2000, 2004, 2007
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
diff --git a/libc/sysdeps/linux/nds32/bits/fenv.h b/libc/sysdeps/linux/nds32/bits/fenv.h
new file mode 100644
index 000000000..010d870f5
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/bits/fenv.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 2004-2012 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/>. */
+
+#ifndef _FENV_H
+# error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
+#endif
+
+/* Define bits representing exceptions in the FPCSR status word. */
+enum
+ {
+ FE_INVALID =
+#define FE_INVALID 0x4
+ FE_INVALID,
+ FE_DIVBYZERO =
+#define FE_DIVBYZERO 0x8
+ FE_DIVBYZERO,
+ FE_OVERFLOW =
+#define FE_OVERFLOW 0x10
+ FE_OVERFLOW,
+ FE_UNDERFLOW =
+#define FE_UNDERFLOW 0x20
+ FE_UNDERFLOW,
+ FE_INEXACT =
+#define FE_INEXACT 0x40
+ FE_INEXACT,
+ };
+
+
+/* All supported exceptions. */
+#define FE_ALL_EXCEPT \
+ (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
+
+/* Define bits representing rounding modes in the FPCSR RM field. */
+enum
+ {
+ FE_TONEAREST =
+#define FE_TONEAREST 0x0
+ FE_TONEAREST,
+ FE_UPWARD =
+#define FE_UPWARD 0x1
+ FE_UPWARD,
+ FE_DOWNWARD =
+#define FE_DOWNWARD 0x2
+ FE_DOWNWARD,
+ FE_TOWARDZERO =
+#define FE_TOWARDZERO 0x3
+ FE_TOWARDZERO
+ };
+
+/* Type representing exception flags. */
+typedef unsigned int fexcept_t;
+
+/* Type representing floating-point environment. */
+typedef struct
+ {
+ unsigned int __fpcsr;
+ }
+fenv_t;
+
+/* If the default argument is used we use this value. */
+#define FE_DFL_ENV ((const fenv_t *) -1l)
+
+#ifdef __USE_GNU
+/* Floating-point environment where none of the exceptions are masked. */
+# define FE_NOMASK_ENV ((const fenv_t *) -2)
+#endif
diff --git a/libc/sysdeps/linux/nds32/bits/mman.h b/libc/sysdeps/linux/nds32/bits/mman.h
index 13f3e60b3..ac242e065 100644
--- a/libc/sysdeps/linux/nds32/bits/mman.h
+++ b/libc/sysdeps/linux/nds32/bits/mman.h
@@ -103,4 +103,5 @@
/* Flags for `mremap'. */
#ifdef __USE_GNU
# define MREMAP_MAYMOVE 1
+# define MREMAP_FIXED 2
#endif
diff --git a/libc/sysdeps/linux/nds32/bits/setjmp.h b/libc/sysdeps/linux/nds32/bits/setjmp.h
index 92d89003a..e287c2481 100644
--- a/libc/sysdeps/linux/nds32/bits/setjmp.h
+++ b/libc/sysdeps/linux/nds32/bits/setjmp.h
@@ -24,19 +24,25 @@
#ifndef _BITS_SETJMP_H
#define _BITS_SETJMP_H 1
-#ifndef _SETJMP_H
+#if !defined _SETJMP_H && !defined _PTHREAD_H
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
#ifndef _ASM
typedef struct
{
- /* Callee-saved registers r6 - r14, r16 - r19 and r28 - r31. */
- int __regs[31];
+ /* Callee-saved registers: r6 - r14,
+ * * fp, gp, lp, sp: r28 - r31. */
+ int __regs[13];
+
+ /* Floating-Point Configuration Register. */
+ int __fpcfg;
+
+ /* Callee-saved fp registers pointer. */
+ int __fpregs[32];
+
+ } __jmp_buf[1] __attribute__((__aligned__ (8)));
- /* Program counter. */
- void * __pc;
- } __jmp_buf[1];
#endif
#endif /* bits/setjmp.h */
diff --git a/libc/sysdeps/linux/nds32/bits/sigcontext.h b/libc/sysdeps/linux/nds32/bits/sigcontext.h
deleted file mode 100644
index e91f6a9b0..000000000
--- a/libc/sysdeps/linux/nds32/bits/sigcontext.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-#ifndef _BITS_SIGCONTEXT_H
-#define _BITS_SIGCONTEXT_H 1
-
-#ifndef sigcontext_struct
-#define sigcontext_struct sigcontext
-
-struct sigcontext{
- unsigned long trap_no;
- unsigned long error_code;
- unsigned long oldmask;
- unsigned long nds32_r0;
- unsigned long nds32_r1;
- unsigned long nds32_r2;
- unsigned long nds32_r3;
- unsigned long nds32_r4;
- unsigned long nds32_r5;
- unsigned long nds32_r6;
- unsigned long nds32_r7;
- unsigned long nds32_r8;
- unsigned long nds32_r9;
- unsigned long nds32_r10;
- unsigned long nds32_r11;
- unsigned long nds32_r12;
- unsigned long nds32_r13;
- unsigned long nds32_r14;
- unsigned long nds32_r15;
- unsigned long nds32_r16;
- unsigned long nds32_r17;
- unsigned long nds32_r18;
- unsigned long nds32_r19;
- unsigned long nds32_r20;
- unsigned long nds32_r21;
- unsigned long nds32_r22;
- unsigned long nds32_r23;
- unsigned long nds32_r24;
- unsigned long nds32_r25;
- unsigned long nds32_fp; //r28
- unsigned long nds32_gp; //r29
- unsigned long nds32_lp; //r30
- unsigned long nds32_sp; //r31
- unsigned long nds32_d1lo;
- unsigned long nds32_d1hi;
- unsigned long nds32_d0lo;
- unsigned long nds32_d0hi;
- unsigned long nds32_ipsw;
- unsigned long nds32_ipc;
- unsigned long fault_address;
-};
-
-#define sc_pc nds32_ipc /* For sysdeps/generic/profil-counter.h. */
-
-#endif /* sigcontext_struct */
-
-#endif /* _BITS_SIGCONTEXT_H */
diff --git a/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h b/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h
new file mode 100644
index 000000000..f3237bd57
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
+ Contributed by Philip Blundell <philb@gnu.org>, 1999.
+
+ 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 <sys/ucontext.h>
+
+#define SIGCONTEXT siginfo_t *_si, struct ucontext *
+#define SIGCONTEXT_EXTRA_ARGS _si,
+
+#define GET_PC(ctx) ((void *) (ctx)->uc_mcontext.nds32_ipc)
+#define GET_FRAME(ctx) ADVANCE_STACK_FRAME ((void *) ctx->uc_mcontext.nds32_fp)
+#define GET_STACK(ctx) ((void *) (ctx)->uc_mcontext.nds32_sp)
+
+
+#define CALL_SIGHANDLER(handler, signo, ctx) \
+ (handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx))
+
diff --git a/libc/sysdeps/linux/nds32/bits/syscalls.h b/libc/sysdeps/linux/nds32/bits/syscalls.h
index f69ad4c41..215ce3467 100644
--- a/libc/sysdeps/linux/nds32/bits/syscalls.h
+++ b/libc/sysdeps/linux/nds32/bits/syscalls.h
@@ -3,6 +3,26 @@
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
+/*
+ * For nds32 ISA, the syscall number(SWID) shall be determined at compile time.
+ * (ex: asm("syscall SWID"); )
+ * If the value of syscall number is determined at run time, we shall issue
+ * this syscall through sys_syscall.
+ * (ex:
+ * asm("move $r0, SYSCALL_number"
+ * "syscall 0x5071");
+ * where 0x5071 is syscall number for sys_syscall
+ * )
+ *
+ * The following two macros are implemented according that syscall number
+ * is determined in compiler time or run time,
+ *
+ * 1. INTERNAL_SYSCALL_NCS: the syscall number is determined at run time
+ * 2. INTERNAL_SYSCALL: the syscall number is determined at compile time
+ *
+ */
+
+
#ifndef _BITS_SYSCALLS_H
#define _BITS_SYSCALLS_H
#ifndef _SYSCALL_H
@@ -11,6 +31,14 @@
#ifndef __ASSEMBLER__
#include <errno.h>
+#include <common/sysdep.h>
+
+#define X(x) #x
+#define Y(x) X(x)
+#define LIB_SYSCALL __NR_syscall
+
+#define __issue_syscall(syscall_name) \
+" syscall " Y(syscall_name) "; \n"
#undef INTERNAL_SYSCALL_ERROR_P
#define INTERNAL_SYSCALL_ERROR_P(val, err) ((unsigned int) (val) >= 0xfffff001u)
@@ -18,86 +46,258 @@
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
-#define X(x) #x
-#define Y(x) X(x)
+#undef INLINE_SYSCALL
+#define INLINE_SYSCALL(name, nr, args...) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (err); \
+ long result_var = INTERNAL_SYSCALL (name, err, nr, args); \
+ if (INTERNAL_SYSCALL_ERROR_P (result_var, err)) \
+ { \
+ __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \
+ result_var = -1 ; \
+ } \
+ result_var; \
+ })
+
+
+#undef INTERNAL_SYSCALL_DECL
+#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+
-#define __issue_syscall(syscall_name) \
-" syscall " Y(syscall_name) "; \n"
-
-#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
-(__extension__ \
-({ \
- register long __result __asm__("$r0"); \
- register long _sys_num __asm__("$r8"); \
- \
- LOAD_ARGS_##nr (name, args) \
- _sys_num = (name); \
- \
- __asm__ volatile ( \
- __issue_syscall (name) \
- : "=r" (__result) \
- : "r"(_sys_num) ASM_ARGS_##nr \
- : "$lp", "memory"); \
- __result; \
-}) \
-)
-
-/* Macros for setting up inline __asm__ input regs */
-#define ASM_ARGS_0
-#define ASM_ARGS_1 ASM_ARGS_0, "r" (__result)
-#define ASM_ARGS_2 ASM_ARGS_1, "r" (_arg2)
-#define ASM_ARGS_3 ASM_ARGS_2, "r" (_arg3)
-#define ASM_ARGS_4 ASM_ARGS_3, "r" (_arg4)
-#define ASM_ARGS_5 ASM_ARGS_4, "r" (_arg5)
-#define ASM_ARGS_6 ASM_ARGS_5, "r" (_arg6)
-#define ASM_ARGS_7 ASM_ARGS_6, "r" (_arg7)
-
-/* Macros for converting sys-call wrapper args into sys call args */
-#define LOAD_ARGS_0(name, arg) \
- _sys_num = (long) (name); \
-
-#define LOAD_ARGS_1(name, arg1) \
- __result = (long) (arg1); \
- LOAD_ARGS_0 (name, arg1)
+#undef INTERNAL_SYSCALL
+#define INTERNAL_SYSCALL(name, err, nr, args...) internal_syscall##nr(__NR_##name, err, args)
/*
- * Note that the use of _tmpX might look superflous, however it is needed
- * to ensure that register variables are not clobbered if arg happens to be
- * a function call itself. e.g. sched_setaffinity() calling getpid() for arg2
- *
- * Also this specific order of recursive calling is important to segregate
- * the tmp args evaluation (function call case described above) and assigment
- * of register variables
- */
-#define LOAD_ARGS_2(name, arg1, arg2) \
- long _tmp2 = (long) (arg2); \
- LOAD_ARGS_1 (name, arg1) \
- register long _arg2 __asm__ ("$r1") = _tmp2;
-
-#define LOAD_ARGS_3(name, arg1, arg2, arg3) \
- long _tmp3 = (long) (arg3); \
- LOAD_ARGS_2 (name, arg1, arg2) \
- register long _arg3 __asm__ ("$r2") = _tmp3;
-
-#define LOAD_ARGS_4(name, arg1, arg2, arg3, arg4) \
- long _tmp4 = (long) (arg4); \
- LOAD_ARGS_3 (name, arg1, arg2, arg3) \
- register long _arg4 __asm__ ("$r3") = _tmp4;
-
-#define LOAD_ARGS_5(name, arg1, arg2, arg3, arg4, arg5) \
- long _tmp5 = (long) (arg5); \
- LOAD_ARGS_4 (name, arg1, arg2, arg3, arg4) \
- register long _arg5 __asm__ ("$r4") = _tmp5;
-
-#define LOAD_ARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \
- long _tmp6 = (long) (arg6); \
- LOAD_ARGS_5 (name, arg1, arg2, arg3, arg4, arg5) \
- register long _arg6 __asm__ ("$r5") = _tmp6;
-
-#define LOAD_ARGS_7(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
- long _tmp7 = (long) (arg7); \
- LOAD_ARGS_6 (name, arg1, arg2, arg3, arg4, arg5, arg6) \
- register long _arg7 __asm__ ("$r6") = _tmp7;
+ The _NCS variant allows non-constant syscall numbers but it is not
+ possible to use more than four parameters.
+*/
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) internal_syscall_ncs##nr(name, err, args)
+
+
+#define internal_syscall0(name, err, dummy...) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall1(name, err, arg1) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall2(name, err, arg1, arg2) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall3(name, err, arg1, arg2, arg3) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ register long __arg3 __asm__("$r2") = (long) (arg3); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall4(name, err, arg1, arg2, arg3, arg4) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ register long __arg3 __asm__("$r2") = (long) (arg3); \
+ register long __arg4 __asm__("$r3") = (long) (arg4); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__arg4) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall5(name, err, arg1, arg2, arg3, arg4, arg5) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ register long __arg3 __asm__("$r2") = (long) (arg3); \
+ register long __arg4 __asm__("$r3") = (long) (arg4); \
+ register long __arg5 __asm__("$r4") = (long) (arg5); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__arg4) /* input operands */ \
+ , "r" (__arg5) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall6(name, err, arg1, arg2, arg3, arg4, arg5, arg6) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ register long __arg3 __asm__("$r2") = (long) (arg3); \
+ register long __arg4 __asm__("$r3") = (long) (arg4); \
+ register long __arg5 __asm__("$r4") = (long) (arg5); \
+ register long __arg6 __asm__("$r5") = (long) (arg6); \
+ __asm__ volatile ( \
+ __issue_syscall (name) \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__arg4) /* input operands */ \
+ , "r" (__arg5) /* input operands */ \
+ , "r" (__arg6) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+#define internal_syscall7(name, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
+ ({ \
+ register long ___res __asm__("$r0"); \
+ register long __arg1 __asm__("$r0") = (long) (arg1); \
+ register long __arg2 __asm__("$r1") = (long) (arg2); \
+ register long __arg3 __asm__("$r2") = (long) (arg3); \
+ register long __arg4 __asm__("$r3") = (long) (arg4); \
+ register long __arg5 __asm__("$r4") = (long) (arg5); \
+ register long __arg6 __asm__("$r5") = (long) (arg6); \
+ __asm__ volatile ( \
+ "addi10.sp\t #-4\n\t" \
+ CFI_ADJUST_CFA_OFFSET(4)"\n\t" \
+ "push\t %7\n\t" \
+ CFI_ADJUST_CFA_OFFSET(4)"\n\t" \
+ __issue_syscall (name) \
+ "addi10.sp\t #4\n\t" \
+ CFI_ADJUST_CFA_OFFSET(-4)"\n\t" \
+ "pop\t %7\n\t" \
+ CFI_ADJUST_CFA_OFFSET(-4)"\n\t" \
+ : "=r" (___res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__arg4) /* input operands */ \
+ , "r" (__arg5) /* input operands */ \
+ , "r" (__arg6) /* input operands */ \
+ , "r" (arg7) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ ___res; \
+ })
+
+#define internal_syscall_ncs0(name, err, dummy...) \
+ ({ \
+ register long __res __asm__("$r0"); \
+ register long __no __asm__("$r0") = (long) (name); \
+ __asm__ volatile ( \
+ __issue_syscall (LIB_SYSCALL) \
+ : "=r" (__res) /* output operands */ \
+ : "r" (__no) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ __res; \
+ })
+
+#define internal_syscall_ncs1(name, err, arg1) \
+ ({ \
+ register long __res __asm__("$r0"); \
+ register long __no __asm__("$r0") = (long) (name); \
+ register long __arg1 __asm__("$r1") = (long) (arg1); \
+ __asm__ volatile ( \
+ __issue_syscall (LIB_SYSCALL) \
+ : "=r" (__res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__no) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ __res; \
+ })
+
+#define internal_syscall_ncs2(name, err, arg1, arg2) \
+ ({ \
+ register long __res __asm__("$r0"); \
+ register long __no __asm__("$r0") = (long) (name); \
+ register long __arg1 __asm__("$r1") = (long) (arg1); \
+ register long __arg2 __asm__("$r2") = (long) (arg2); \
+ __asm__ volatile ( \
+ __issue_syscall (LIB_SYSCALL) \
+ : "=r" (__res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__no) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ __res; \
+ })
+
+#define internal_syscall_ncs3(name, err, arg1, arg2, arg3) \
+ ({ \
+ register long __res __asm__("$r0"); \
+ register long __no __asm__("$r0") = (long) (name); \
+ register long __arg1 __asm__("$r1") = (long) (arg1); \
+ register long __arg2 __asm__("$r2") = (long) (arg2); \
+ register long __arg3 __asm__("$r3") = (long) (arg3); \
+ __asm__ volatile ( \
+ __issue_syscall (LIB_SYSCALL) \
+ : "=r" (__res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__no) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ __res; \
+ })
+
+#define internal_syscall_ncs4(name, err, arg1, arg2, arg3, arg4) \
+ ({ \
+ register long __res __asm__("$r0"); \
+ register long __no __asm__("$r0") = (long) (name); \
+ register long __arg1 __asm__("$r1") = (long) (arg1); \
+ register long __arg2 __asm__("$r2") = (long) (arg2); \
+ register long __arg3 __asm__("$r3") = (long) (arg3); \
+ register long __arg4 __asm__("$r4") = (long) (arg4); \
+ __asm__ volatile ( \
+ __issue_syscall (LIB_SYSCALL) \
+ : "=r" (__res) /* output operands */ \
+ : "r" (__arg1) /* input operands */ \
+ , "r" (__arg2) /* input operands */ \
+ , "r" (__arg3) /* input operands */ \
+ , "r" (__arg4) /* input operands */ \
+ , "r" (__no) /* input operands */ \
+ : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \
+ __res; \
+ })
+#define __SYSCALL_CLOBBERS "$lp", "memory"
#endif /* ! __ASSEMBLER__ */
#endif /* _BITS_SYSCALLS_H */
diff --git a/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h b/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h
index 12e4af9cd..5c4f634a0 100644
--- a/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h
+++ b/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h
@@ -11,7 +11,7 @@
#define _BITS_UCLIBC_ARCH_FEATURES_H
/* instruction used when calling abort() to kill yourself */
-#undef __UCLIBC_ABORT_INSTRUCTION__
+#define __UCLIBC_ABORT_INSTRUCTION__ "bal abort"
/* does your target align 64bit values in register pairs ? (32bit arches only) */
#define __UCLIBC_SYSCALL_ALIGN_64BIT__
diff --git a/libc/sysdeps/linux/nds32/bsd-_setjmp.S b/libc/sysdeps/linux/nds32/bsd-_setjmp.S
index a7ab1c731..745f109b4 100644
--- a/libc/sysdeps/linux/nds32/bsd-_setjmp.S
+++ b/libc/sysdeps/linux/nds32/bsd-_setjmp.S
@@ -21,8 +21,8 @@ ENTRY(_setjmp)
add $r2, $r15, $r2
! la $r3, __sigsetjmp@PLT
- sethi $r3, hi20(__sigsetjmp@PLT)
- ori $r3, $r3, lo12(__sigsetjmp@PLT)
+ sethi $r3, hi20(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT)
+ ori $r3, $r3, lo12(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT)
add $r3, $r3, $r2
jr $r3
@@ -32,4 +32,3 @@ ENTRY(_setjmp)
#endif
END(_setjmp)
-libc_hidden_def(_setjmp)
diff --git a/libc/sysdeps/linux/nds32/bsd-setjmp.S b/libc/sysdeps/linux/nds32/bsd-setjmp.S
index b00e62da8..e1f7c83fc 100644
--- a/libc/sysdeps/linux/nds32/bsd-setjmp.S
+++ b/libc/sysdeps/linux/nds32/bsd-setjmp.S
@@ -21,8 +21,8 @@ ENTRY(setjmp)
add $r2, $r15, $r2
! la $r3, __sigsetjmp@PLT
- sethi $r3, hi20(__sigsetjmp@PLT)
- ori $r3, $r3, lo12(__sigsetjmp@PLT)
+ sethi $r3, hi20(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT)
+ ori $r3, $r3, lo12(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT)
add $r3, $r3, $r2
jr $r3
diff --git a/libc/sysdeps/linux/nds32/clone.S b/libc/sysdeps/linux/nds32/clone.S
index 5dba17896..1ed77fb2e 100644
--- a/libc/sysdeps/linux/nds32/clone.S
+++ b/libc/sysdeps/linux/nds32/clone.S
@@ -1,92 +1,180 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
+/* Copyright (C) 2010-2014 Free Software Foundation, Inc.
+ Contributed by Pat Beirne <patb@corelcomputer.com>
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
/* clone() is even more special than fork() as it mucks with stacks
and invokes a function in the right context after its all over. */
#include <sysdep.h>
-#include <sys/syscall.h>
#define _ERRNO_H 1
#include <bits/errno.h>
-/*
- int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
- _syscall2(int, clone, int, flags, void *, child_stack)
-*/
+#ifdef RESET_PID
+#include <tcb-offsets.h>
+#endif
+
+#define CLONE_VM 0x00000100
+#define CLONE_THREAD 0x00010000
+
+/* int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
+ _syscall2(int, clone, int, flags, void *, child_stack) */
ENTRY(__clone)
+#ifdef __NDS32_ABI_2FP_PLUS__
+ lwi $r4, [$sp]
+ lwi $r5, [$sp+4]
+#endif
#ifdef PIC
/* set GP register to parent only, cause child's $SP will be $r1. */
pushm $fp, $gp
-#ifndef __NDS32_N1213_43U1H__
- mfusr $r15, $PC
-#endif
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4)
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8)
- add $gp, $gp, $r15
-#endif
- /* sanity check arguments. */
- beqz $r0, 1f
- bnez $r1, 2f
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(fp, 0)
+ cfi_rel_offset(gp, 4)
+ mfusr $r15, $pc
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4)
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8)
+ add $gp, $gp, $r15
+#endif /* PIC */
+
+ /* sanity check arguments. */
+ beqz $r0, 1f
+ bnez $r1, 2f
1:
- movi $r0, -EINVAL
+ movi $r0, -EINVAL
+
5:
#ifdef PIC
- /* restore GP register, only in parent's stack */
- popm $fp, $gp
- la $r15, C_SYMBOL_NAME(__syscall_error@PLT)
- jr $r15
-#else
- b C_SYMBOL_NAME(__syscall_error)
-#endif
+ /* restore GP register, only in parent's stack */
+ la $r15, C_SYMBOL_NAME(__syscall_error@PLT)
+ push $lp
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset(lp, 0)
+ addi $sp, $sp, -4
+ cfi_adjust_cfa_offset(4)
+ jral $r15
+ addi $sp, $sp, 4
+ cfi_adjust_cfa_offset(-4)
+ pop $lp
+ cfi_adjust_cfa_offset(-4)
+ cfi_restore(lp)
+ popm $fp, $gp
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(fp)
+ cfi_restore(gp)
+ ret
+#else /* ! PIC */
+ la $r15, C_SYMBOL_NAME(__syscall_error)
+ jr $r15
+#endif /* ! PIC */
2:
- /* Child's $SP will be $r1, push to child's stack only. */
+ /* Child's $sp will be $r1, make $sp 8-byte alignment */
+ bitci $r1, $r1, 7
+ /* push to child's stack only. */
addi $r1, $r1, -4
- swi.p $r3, [$r1], -4 ! arg
- swi $r0, [$r1] ! fn
+ swi.p $r3, [$r1], -4 ! arg
+ swi $r0, [$r1] ! fn
+
+ /* do the system call */
+ or $r0, $r2, $r2 ! move $r0, $r2
+
+ move $r3, $r5
+ move $r5, $r2 ! Use $r5 to backup $r2
+ ! The pt_regs is placed in $r5 in kerenl (sys_clone_wrapper)
+ move $r2, $r4
- /* do the system call */
- or $r0, $r2, $r2 ! move r0, r2
- __do_syscall(clone)
- !syscall (__NR_clone)
- beqz $r0, 4f
- bltz $r0, 5b
+#ifdef __NDS32_ABI_2FP_PLUS__
+# ifdef PIC
+ lwi $r4, [$sp+#0x10]
+# else
+ lwi $r4, [$sp+#0x8]
+# endif
+#else
+# ifdef PIC
+ lwi $r4, [$sp+#0x8]
+# else
+ lwi $r4, [$sp]
+# endif
+#endif
+
+ __do_syscall(clone)
+ beqz $r0, 4f
+ bltz $r0, 5b
- ! parent
+
+10:
#ifdef PIC
- /* restore GP register, only in parent's stack */
+ /* restore GP register, only in parent's stack */
popm $fp, $gp
-#endif
- ret
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(gp)
+ cfi_restore(fp)
+#endif /* PIC */
+ ret
+#ifdef RESET_PID
4:
- /* Only in child's stack. */
- pop $r1 ! fn
- pop $r0 ! arg
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
+ cfi_undefined(lp)
+ movi $r0, CLONE_THREAD ! Skip when CLONE_THREAD is set.
+ and $r0, $r5, $r0
+ bnez $r0, 8f
+ movi $r0, CLONE_VM ! Value = -1 when CLONE_VM is set.
+ and $r0, $r5, $r0
+ beqz $r0, 6f
+ movi $r0, -1
+ j 7f
+6:
+ __do_syscall(getpid) ! __do_syscall(gettid) ! __do_syscall(getpid)
+7:
+ swi $r0, [$r25 + PID_OFFSET]
+ swi $r0, [$r25 + TID_OFFSET]
+8:
#else
- addi $sp, $sp, -24
-#endif
- ! use r15 in case _exit is PIC
-#ifdef __NDS32_N1213_43U1H__
- or $r15, $r1, $r1 ! move r15, r2
+4:
#endif
- bral $r1
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-#else
+ /* Only in child's stack. */
+ pop $r1 ! fn
+ pop $r0 ! arg
+
+
+#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__)
+ addi $sp, $sp, -24
+#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */
+
+ ! use $r15 in case _exit is PIC
+ bral $r1
+
+#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__)
addi $sp, $sp, 24
-#endif
- ! use r15 in case _exit is PIC
+#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */
+
+ ! use $r15 in case _exit is PIC
#ifdef PIC
- la $r15, C_SYMBOL_NAME(_exit@PLT)
- jr $r15
-#else
- b C_SYMBOL_NAME(_exit)
-#endif
+ la $r15, C_SYMBOL_NAME(_exit@PLT)
+#else /* ! PIC */
+ la $r15, C_SYMBOL_NAME(_exit)
+#endif /* ! PIC */
+ jr $r15
PSEUDO_END (__clone)
diff --git a/libc/sysdeps/linux/nds32/crt1.S b/libc/sysdeps/linux/nds32/crt1.S
index 54544010f..c30f4334d 100644
--- a/libc/sysdeps/linux/nds32/crt1.S
+++ b/libc/sysdeps/linux/nds32/crt1.S
@@ -45,17 +45,10 @@ _start:
#ifdef SHARED
/* set gp register */
-#ifdef __NDS32_N1213_43U1H__
- jal 1b
- sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_)
- ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 4)
- add $gp, $lp, $gp
-#else
mfusr $r15, $PC
sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4)
ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 8)
add $gp, $r15, $gp
-#endif
la $r3, _init@GOTOFF
la $r4, _fini@GOTOFF
diff --git a/libc/sysdeps/linux/nds32/crti.S b/libc/sysdeps/linux/nds32/crti.S
index 92e5e7175..61d01b63a 100644
--- a/libc/sysdeps/linux/nds32/crti.S
+++ b/libc/sysdeps/linux/nds32/crti.S
@@ -11,8 +11,6 @@
.type _init, @function
_init:
.LFB28:
- ! Generate instructions for ABI: 1
- ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 24
! Generate instructions for ABI: 2
! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 0
! frame pointer: $fp, needed: yes
@@ -22,22 +20,12 @@ _init:
smw.adm $sp,[$sp],$sp,#0x8
smw.adm $sp,[$sp],$sp,#0x6
.restore_16bit
-#ifdef __NDS32_N1213_43U1H__
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+8)
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+12)
-#else
sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
mfusr $ta, $pc
-#endif
add $gp, $ta, $gp
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
addi $sp, $sp, -4
addi $fp, $sp, 8
-#else
- addi $sp, $sp, -28
- addi $fp, $sp, 32
-#endif
! end of prologue
#APP
.align 2
@@ -48,8 +36,6 @@ _init:
.type _fini, @function
_fini:
.LFB29:
- ! Generate instructions for ABI: 1
- ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 24
! Generate instructions for ABI: 2
! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 0
! frame pointer: $fp, needed: yes
@@ -59,22 +45,12 @@ _fini:
smw.adm $sp,[$sp],$sp,#0x8
smw.adm $sp,[$sp],$sp,#0x6
.restore_16bit
-#ifdef __NDS32_N1213_43U1H__
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+8)
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+12)
-#else
sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
mfusr $ta, $pc
-#endif
add $gp, $ta, $gp
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
addi $sp, $sp, -4
addi $fp, $sp, 8
-#else
- addi $sp, $sp, -28
- addi $fp, $sp, 32
-#endif
! end of prologue
#APP
.align 2
diff --git a/libc/sysdeps/linux/nds32/fpu_control.h b/libc/sysdeps/linux/nds32/fpu_control.h
new file mode 100644
index 000000000..8ad43f623
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/fpu_control.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _FPU_CONTROL_H
+
+#ifdef __NDS32_ABI_2FP_PLUS__
+/*
+ * Andes Floating-Point Control Status Register
+ * 31-20 -> Reserved
+ * 19 -> RIT (RO)
+ * 18 -> DNIT(RO)
+ * 17 -> IEXT(RO)
+ * 16 -> UDFT(RO)
+ * 15 -> OVFT(RO)
+ * 14 -> DBZT(RO)
+ * 13 -> IVOT(RO)
+ * 12 -> DNZ(RW),Denormalized flush-to-Zero mode.
+ * 11 -> IEXE(RW),IEEE Ineaxct (IEX) exception trapping enable.
+ * 10 -> UDFE(RW),IEEE Underflow (UDF) exception trapping enable.
+ * 9 -> OVFE(RW),IEEE Overflow (OVF) exception trapping enable.
+ * 8 -> DBZE(RW),IEEE Divide by Zero (DBZ) exception trapping enable.
+ * 7 -> IVOE(RW),IEEE Invalid Operation (IVO) exception trapping enable.
+ * 6 -> IEX(RW),IEEE Inexact (IEX) cumulative exception flag.
+ * 5 -> UDF(RW),IEEE Underflow (UDF) cumulative exception flag.
+ * 4 -> OVF(RW),IEEE Overflow (OVF) cumulative exception flag.
+ * 3 -> DBZ(RW),IEEE Divide by Zero (DBZ) cumulative exception flag.
+ * 2 -> IVO(RW),IEEE Invalid Operation (IVO) cumulative exception flag.
+ * 1-0 -> Rounding modes.
+ *
+ * Rounding modes.
+ * 00 - rounding to nearest (RN)
+ * 01 - rounding (up) toward plus infinity (RP)
+ * 10 - rounding (down)toward minus infinity (RM)
+ * 11 - rounding toward zero (RZ)
+ *
+ */
+
+
+/* masking of interrupts */
+#define _FPU_MASK_IEX 0x0800 /* Invalid operation */
+#define _FPU_MASK_UDF 0x0400 /* Underflow */
+#define _FPU_MASK_OVF 0x0200 /* Overflow */
+#define _FPU_MASK_DBZ 0x0100 /* Division by zero */
+#define _FPU_MASK_IVO 0x0080 /* Invalid operation */
+
+/*Reserved and read-only bits*/
+#define _FPU_RESERVED 0xffffe000
+#define _FPU_DEFAULT 0x00000000
+
+/* Default + exceptions enabled. */
+#define _FPU_IEEE (_FPU_DEFAULT | 0x00000f80)
+
+/* Type of the control word. */
+typedef unsigned int fpu_control_t;
+
+/* Macros for accessing the hardware control word. */
+/* This is fmrx %0, fpscr. */
+#define _FPU_GETCW(cw) \
+ __asm__ __volatile__ ("fmfcsr\t %0\n\t" : "=r" (cw))
+/* This is fmxr fpscr, %0. */
+#define _FPU_SETCW(cw) \
+ __asm__ __volatile__ ("fmtcsr\t %0\n\t": : "r" (cw))
+
+/* Default control word set at startup. */
+extern fpu_control_t __fpu_control;
+#else
+#define _FPU_GETCW(cw) (cw) = 0
+#define _FPU_SETCW(cw) (void) (cw)
+#define _FPU_RESERVED 0xffffffff
+#define _FPU_DEFAULT 0x00000000
+typedef unsigned int fpu_control_t;
+extern fpu_control_t __fpu_control;
+
+#endif //__NDS32_ABI_2FP_PLUS__
+#endif //_FPU_CONTROL_H
diff --git a/libc/sysdeps/linux/nds32/getcontext.S b/libc/sysdeps/linux/nds32/getcontext.S
new file mode 100644
index 000000000..7bc1ca292
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/getcontext.S
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 20[B01-2013 Free Software Foundation, Inc.
+ Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
+
+ 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 "ucontext_i.h"
+
+/* __getcontext (const ucontext_t *ucp)
+
+ Saves the machine context in UCP such that when it is activated,
+ it appears as if __getcontext() returned again.
+
+ This implementation is intended to be used for *synchronous* context
+ switches only. Therefore, it does not have to save anything
+ other than the PRESERVED state. */
+
+ENTRY(__getcontext)
+ swi $lp, [$r0 + UCONTEXT_PC]
+ addi $r15, $r0, UCONTEXT_GREGS
+ xor $r1, $r1, $r1
+ smw.bim $r1, [$r15], $r1
+ smw.bim $r1, [$r15], $r14
+ addi $r15, $r15, 4
+ smw.bim $r16, [$r15], $r25, #0xf
+ move $r4, $r0
+
+ /* sigprocmask (SIG_BLOCK, NULL, &sc->sc_mask). */
+ move $r0, SIG_BLOCK
+ move $r1, 0
+ addi $r2, $r4, UCONTEXT_SIGMASK
+ move $r3, _NSIG8
+ syscall SYS_ify(rt_sigprocmask)
+ bnez $r0, 1f
+
+
+#ifdef __NDS32_ABI_2FP_PLUS__
+ addi $r2, $r4, UCONTEXT_FDREGS
+/* Process for FPU registers. */
+ fmfcfg $r20 /* Keep $fpcfg in $r20. */
+ slli $r20, $r20, #28
+ srli $r20, $r20, #30 /* Set $r20 as $fpcfg.freg. */
+
+ /* Case switch for $r20 as $fpcfg.freg. */
+ beqz $r20, .LCFG0 /* Branch if $fpcfg.freg = 0b00. */
+ xori $r15, $r20, #0b10
+ beqz $r15, .LCFG2 /* Branch if $fpcfg.freg = 0b10. */
+ srli $r20, $r20, #0b01
+ beqz $r20, .LCFG1 /* Branch if $fpcfg.freg = 0b01. */
+ /* Fall-through if $fpcfg.freg = 0b11. */
+.LCFG3:
+ fsdi $fd31, [$r2 + 248]
+ fsdi $fd30, [$r2 + 240]
+ fsdi $fd29, [$r2 + 232]
+ fsdi $fd28, [$r2 + 224]
+ fsdi $fd27, [$r2 + 216]
+ fsdi $fd26, [$r2 + 208]
+ fsdi $fd25, [$r2 + 200]
+ fsdi $fd24, [$r2 + 192]
+.LCFG2:
+ fsdi $fd10, [$r2 + 80]
+ fsdi $fd9, [$r2 + 72]
+ fsdi $fd8, [$r2 + 64]
+.LCFG1:
+ fsdi $fd7, [$r2 + 56]
+ fsdi $fd6, [$r2 + 48]
+ fsdi $fd5, [$r2 + 40]
+ fsdi $fd4, [$r2 + 32]
+.LCFG0:
+ fsdi $fd3, [$r2 + 24]
+ /*save fpcsr*/
+ fmfcsr $r1
+ swi $r1, [$r2 + 0x100]
+#endif /* __NDS32_ABI_2FP_PLUS__ */
+
+ /* Set __getcontext return value to 0. */
+ xor $r0, $r0, $r0
+ /* Return first_return: 1 */
+ addi $r1, $r0, 1
+ ret
+
+1:
+ move $r0, -1
+ ret
+END(__getcontext)
+
+weak_alias (__getcontext, getcontext)
+
diff --git a/libc/sysdeps/linux/nds32/jmpbuf-unwind.h b/libc/sysdeps/linux/nds32/jmpbuf-unwind.h
index 14a302969..8499e99b4 100644
--- a/libc/sysdeps/linux/nds32/jmpbuf-unwind.h
+++ b/libc/sysdeps/linux/nds32/jmpbuf-unwind.h
@@ -5,8 +5,24 @@
#include <setjmp.h>
#include <jmpbuf-offsets.h>
+#include <stdint.h>
+#include <unwind.h>
+#include <sysdep.h>
/* Test if longjmp to JMPBUF would unwind the frame
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
- ((void *) (address) < (void *) &(jmpbuf)[0].__regs[__JMP_BUF_SP])
+ ((void *) (address) < &(jmpbuf)[0].__regs[__JMP_BUF_SP])
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+static inline uintptr_t __attribute__ ((unused))
+_jmpbuf_sp (__jmp_buf regs)
+{
+ uintptr_t sp = &(regs)[0].__regs[__JMP_BUF_SP];
+ return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+ ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
diff --git a/libc/sysdeps/linux/nds32/makecontext.c b/libc/sysdeps/linux/nds32/makecontext.c
new file mode 100644
index 000000000..d8f38aa15
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/makecontext.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 2011-2013 Free Software Foundation, Inc.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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 <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+/* makecontext sets up a stack and the registers for the
+ user context. The stack looks like this:
+
+ +-----------------------+
+ | padding as required |
+ +-----------------------+
+ sp -> | parameter 7-n |
+ +-----------------------+
+
+ The registers are set up like this:
+ $r0 .. $r5: parameter 1 to 6
+ $r6 : uc_link
+ $sp : stack pointer.
+*/
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __startcontext (void);
+ unsigned long int *sp;
+ unsigned long *regptr;
+ va_list ap;
+ int i;
+
+ sp = (unsigned long int *)
+ ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+
+ /* Allocate stack arguments. */
+ sp -= argc < 6 ? 0 : argc - 6;
+
+ /* Keep the stack aligned. */
+ sp = (unsigned long int *) (((uintptr_t) sp) & -8L);
+
+ ucp->uc_mcontext.nds32_r6 = (uintptr_t) ucp->uc_link;
+ ucp->uc_mcontext.nds32_sp = (uintptr_t) sp;
+ ucp->uc_mcontext.nds32_ipc = (uintptr_t) func;
+ ucp->uc_mcontext.nds32_lp = (uintptr_t) &__startcontext;
+
+ va_start (ap, argc);
+ regptr = &ucp->uc_mcontext.nds32_r0;
+ for (i = 0; i < argc; ++i)
+ if (i < 6)
+ *regptr++ = va_arg (ap, unsigned long int);
+ else
+ sp[i - 6] = va_arg (ap, unsigned long int);
+
+ va_end (ap);
+
+}
+weak_alias (__makecontext, makecontext)
diff --git a/libc/sysdeps/linux/nds32/mmap.S b/libc/sysdeps/linux/nds32/mmap.S
deleted file mode 100644
index 351d1c502..000000000
--- a/libc/sysdeps/linux/nds32/mmap.S
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-/* Copyright (C) 1998, 2000, 2003 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, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <sys/syscall.h>
-#include <sysdep.h>
- .text
-
-.globl __mmap
-ENTRY (__mmap)
-
-#ifdef PIC
-.pic
-#endif
-
- // reserve space for r0, r1
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-#else
- addi $sp, $sp, -8
-#endif
- // change to units of the system page size
- srli $r5, $r5, 0xc
-
- syscall SYS_ify(mmap2)
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-#else
- addi $sp, $sp, 8
-#endif
-
- /* r0 is < -4096 if there was an error. */
- bgez $r0, 1f
- sltsi $r1,$r0,-4096
- beqz $r1,2f
-
-1:
- ret
-2:
-#ifdef PIC
-#ifdef __NDS32_N1213_43U1H__
- ! save lp
- addi $r2, $lp, 0
-
- ! set r1 as gp
- jal 1b
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4)
- add $r1, $lp, $r1
-
- ! restore lp
- addi $lp, $r2, 0
-
- ! r15=SYSCALL_ERROR@PLT
- sethi $r15, hi20(SYSCALL_ERROR@PLT)
- ori $r15, $r15, lo12(SYSCALL_ERROR@PLT)
- add $r15, $r15, $r1
-
- ! jump to SYSCALL_ERROR
- jr $r15
-#else
- ! set r1 as gp
- mfusr $r15, $PC
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_+4)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+8)
- add $r1, $r1, $r15
-
- ! r15=SYSCALL_ERROR@PLT
- sethi $r15, hi20(SYSCALL_ERROR@PLT)
- ori $r15, $r15, lo12(SYSCALL_ERROR@PLT)
- add $r15, $r15, $r1
-
- ! jump to SYSCALL_ERROR
- jr $r15
-#endif
-#else
- j SYSCALL_ERROR
-#endif
-
-ret
-
-PSEUDO_END (__mmap)
-
-weak_alias (__mmap, mmap)
-libc_hidden_def(mmap)
diff --git a/libc/sysdeps/linux/nds32/mremap.c b/libc/sysdeps/linux/nds32/mremap.c
new file mode 100644
index 000000000..9b2d83544
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/mremap.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sysdep.h>
+
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_mremap
+void *mremap (void *__addr, size_t __old_len, size_t __new_len,
+ int __flags, ...);
+libc_hidden_proto(mremap)
+
+void *mremap (void *__addr, size_t __old_len, size_t __new_len, int __flags, ...)
+{
+ unsigned long arg1;
+ va_list arg;
+ va_start (arg, __flags);
+ arg1 = va_arg (arg, int);
+ va_end (arg);
+ return (void *)INLINE_SYSCALL(mremap,5,__addr,__old_len,__new_len,__flags,arg1);
+}
+libc_hidden_def (mremap)
+#endif
diff --git a/libc/sysdeps/linux/nds32/prctl.c b/libc/sysdeps/linux/nds32/prctl.c
new file mode 100644
index 000000000..b20f4ca79
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/prctl.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sysdep.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+
+int prctl (int __option, ...)
+{
+ unsigned long arg1,arg2,arg3,arg4;
+ va_list arg;
+ va_start (arg, __option);
+ arg1 = va_arg (arg, unsigned long);
+ arg2 = va_arg (arg, unsigned long);
+ arg3 = va_arg (arg, unsigned long);
+ arg4 = va_arg (arg, unsigned long);
+ va_end (arg);
+ return INLINE_SYSCALL(prctl,5,__option,arg1,arg2,arg3,arg4);
+}
diff --git a/libc/sysdeps/linux/nds32/setcontext.S b/libc/sysdeps/linux/nds32/setcontext.S
new file mode 100644
index 000000000..f9265328f
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/setcontext.S
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ENTRY(__setcontext)
+ move $r4, $r0
+
+#ifdef __NDS32_ABI_2FP_PLUS__
+ addi $r0, $r4, UCONTEXT_FDREGS
+
+ /* Case switch for $r20 as $fpcfg.freg. */
+ beqz $r20, .LCFG0 /* Branch if $fpcfg.freg = 0b00. */
+ xori $r15, $r20, #0b10
+ beqz $r15, .LCFG2 /* Branch if $fpcfg.freg = 0b10. */
+ srli $r20, $r20, #0b01
+ beqz $r20, .LCFG1 /* Branch if $fpcfg.freg = 0b01. */
+ /* Fall-through if $fpcfg.freg = 0b11. */
+.LCFG3:
+ fldi $fd31, [$r0 + 248]
+ fldi $fd30, [$r0 + 240]
+ fldi $fd29, [$r0 + 232]
+ fldi $fd28, [$r0 + 224]
+ fldi $fd27, [$r0 + 216]
+ fldi $fd26, [$r0 + 208]
+ fldi $fd25, [$r0 + 200]
+ fldi $fd24, [$r0 + 192]
+.LCFG2:
+ fldi $fd10, [$r0 + 80]
+ fldi $fd9, [$r0 + 72]
+ fldi $fd8, [$r0 + 64]
+.LCFG1:
+ fldi $fd7, [$r0 + 56]
+ fldi $fd6, [$r0 + 48]
+ fldi $fd5, [$r0 + 40]
+ fldi $fd4, [$r0 + 32]
+.LCFG0:
+ fldi $fd3, [$r0 + 24]
+ /*save fpcsr*/
+ lwi $r1, [$r0 + 0x100]
+ fmtcsr $r1
+#endif /* __NDS32_ABI_2FP_PLUS__ */
+
+ /* sigprocmask (SIG_BLOCK, &sc->sc_mask, NULL). */
+ move $r0, SIG_SETMASK
+ addi $r1, $r4, UCONTEXT_SIGMASK
+ move $r2, 0
+ move $r3, _NSIG8
+ syscall SYS_ify(rt_sigprocmask)
+ bnez $r0, 1f
+
+ move $r0, $r4
+ addi $r15, $r4, UCONTEXT_GREGS + 4
+ lmw.bim $r1, [$r15], $r14
+ addi $r15, $r15, 4
+ lmw.bim $r16, [$r15], $r25, #0xf
+ lwi $r15, [$r0 + UCONTEXT_PC]
+ push $r1
+ cfi_adjust_cfa_offset (4)
+ move $r1, $r0
+ lwi $r0, [$r1 + UCONTEXT_GREGS]
+ pop $r1
+ cfi_adjust_cfa_offset (-4)
+ jr $r15
+1:
+ move $r0, -1
+ ret
+END(__setcontext)
+
+weak_alias (__setcontext, setcontext)
+libc_hidden_def(__setcontext)
+
+ENTRY (__startcontext)
+ move $r0, $r6
+ beqz $r0, 1f
+ jal HIDDEN_JUMPTARGET(__setcontext)
+1:
+ move $r0, 0
+ j HIDDEN_JUMPTARGET(exit)
+END (__startcontext)
+
diff --git a/libc/sysdeps/linux/nds32/setjmp.S b/libc/sysdeps/linux/nds32/setjmp.S
index 8cb9adbeb..262d74925 100644
--- a/libc/sysdeps/linux/nds32/setjmp.S
+++ b/libc/sysdeps/linux/nds32/setjmp.S
@@ -106,4 +106,4 @@ ENTRY(__sigsetjmp)
#endif
END(__sigsetjmp)
-hidden_def(__sigsetjmp)
+libc_hidden_def(__sigsetjmp)
diff --git a/libc/sysdeps/linux/nds32/sigaction.c b/libc/sysdeps/linux/nds32/sigaction.c
deleted file mode 100644
index 1a24c49b4..000000000
--- a/libc/sysdeps/linux/nds32/sigaction.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/syscall.h>
-#include <string.h>
-#include <bits/kernel_sigaction.h>
-
-#define SA_RESTORER 0x04000000
-
-extern void __default_sa_restorer(void);
-
-int __libc_sigaction(int sig, const struct sigaction *act,
- struct sigaction *oact)
-{
- struct sigaction kact;
-
- if (act && !(act->sa_flags & SA_RESTORER)) {
- memcpy(&kact, act, sizeof(kact));
- kact.sa_restorer = __default_sa_restorer;
- kact.sa_flags |= SA_RESTORER;
- act = &kact;
- }
- /* NB: kernel (as of 2.6.25) will return EINVAL
- * if sizeof(act->sa_mask) does not match kernel's sizeof(sigset_t) */
- return __syscall_rt_sigaction(sig, act, oact, sizeof(act->sa_mask));
-}
-
-#ifndef LIBC_SIGACTION
-# ifndef __UCLIBC_HAS_THREADS__
-strong_alias(__libc_sigaction,sigaction)
-libc_hidden_def(sigaction)
-# else
-weak_alias(__libc_sigaction,sigaction)
-libc_hidden_weak(sigaction)
-# endif
-#endif
diff --git a/libc/sysdeps/linux/nds32/sigrestorer.S b/libc/sysdeps/linux/nds32/sigrestorer.S
deleted file mode 100644
index bf6188656..000000000
--- a/libc/sysdeps/linux/nds32/sigrestorer.S
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-/* Copyright (C) 1999 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, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-/* If no SA_RESTORER function was specified by the application we use
- one of these. This avoids the need for the kernel to synthesise a return
- instruction on the stack, which would involve expensive cache flushes. */
-
-ENTRY(__default_sa_restorer)
- /* DO NOT SAVE r7 INTO STACK, THIS SYSCALL NEVER RETURN */
- syscall SYS_ify(sigreturn)
-END(__default_sa_restorer)
-
-#ifdef __NR_rt_sigreturn
-
-ENTRY(__default_rt_sa_restorer)
- /* DO NOT SAVE r7 INTO STACK, THIS SYSCALL NEVER RETURN */
- syscall SYS_ify(rt_sigreturn)
-END(__default_rt_sa_restorer)
-
-#endif
diff --git a/libc/sysdeps/linux/nds32/swapcontext.c b/libc/sysdeps/linux/nds32/swapcontext.c
new file mode 100644
index 000000000..310923f0d
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/swapcontext.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2001-2013 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ 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 <ucontext.h>
+
+struct rv
+ {
+ long retval;
+ long first_return;
+ };
+
+extern struct rv __getcontext (ucontext_t *__ucp);
+extern int __setcontext (const ucontext_t *__ucp);
+
+int
+__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
+{
+ struct rv rv = __getcontext (oucp);
+ if (rv.first_return)
+ __setcontext (ucp);
+ return 0;
+}
+
+weak_alias (__swapcontext, swapcontext)
diff --git a/libc/sysdeps/linux/nds32/sys/ucontext.h b/libc/sysdeps/linux/nds32/sys/ucontext.h
index 4dca27fd5..0d7422aab 100644
--- a/libc/sysdeps/linux/nds32/sys/ucontext.h
+++ b/libc/sysdeps/linux/nds32/sys/ucontext.h
@@ -1,7 +1,20 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
+/* Copyright (C) 1998, 1999, 2001, 2006 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 _SYS_UCONTEXT_H
#define _SYS_UCONTEXT_H 1
@@ -10,103 +23,25 @@
#include <signal.h>
#include <sys/procfs.h>
-typedef int greg_t;
-
-/* Number of general registers. */
-#define NGREG 32
-
-/* Container for all general registers. */
-typedef elf_gregset_t gregset_t;
+/* We need the signal context definitions even if they are not used
+ * included in <signal.h>. */
+#include <bits/sigcontext.h>
-/* Number of each register is the `gregset_t' array. */
-enum
-{
- R0 = 0,
-#define R0 R0
- R1 = 1,
-#define R1 R1
- R2 = 2,
-#define R2 R2
- R3 = 3,
-#define R3 R3
- R4 = 4,
-#define R4 R4
- R5 = 5,
-#define R5 R5
- R6 = 6,
-#define R6 R6
- R7 = 7,
-#define R7 R7
- R8 = 8,
-#define R8 R8
- R9 = 9,
-#define R9 R9
- R10 = 10,
-#define R10 R10
- R11 = 11,
-#define R11 R11
- R12 = 12,
-#define R12 R12
- R13 = 13,
-#define R13 R13
- R14 = 14,
-#define R14 R14
- R15 = 15,
-#define R15 R15
- R16 = 16,
-#define R16 R16
- R17 = 17,
-#define R17 R17
- R18 = 18,
-#define R18 R18
- R19 = 19,
-#define R19 R19
- R20 = 20,
-#define R20 R20
- R21 = 21,
-#define R21 R21
- R22 = 22,
-#define R22 R22
- R23 = 23,
-#define R23 R23
- R24 = 24,
-#define R24 R24
- R25 = 25,
-#define R25 R25
- R26 = 26,
-#define R26 R26
- R27 = 27,
-#define R27 R27
- R28 = 28,
-#define R28 R28
- R29 = 29,
-#define R29 R29
- R30 = 30,
-#define R30 R30
- R31 = 31
-#define R31 R31
-};
+/* Context to describe whole processor state. This only describes
+ the core registers; coprocessor registers get saved elsewhere
+ (e.g. in uc_regspace, or somewhere unspecified on the stack
+ during non-RT signal handlers). */
+typedef struct sigcontext mcontext_t;
-/* Structure to describe FPU registers. */
-typedef elf_fpregset_t fpregset_t;
-
-/* Context to describe whole processor state. */
-typedef struct
- {
- gregset_t gregs;
- fpregset_t fpregs;
- } mcontext_t;
/* Userlevel context. */
typedef struct ucontext
{
unsigned long int uc_flags;
struct ucontext *uc_link;
- __sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
- long int uc_filler[5];
+ __sigset_t uc_sigmask;
} ucontext_t;
-
#endif /* sys/ucontext.h */
diff --git a/libc/sysdeps/linux/nds32/syscall.S b/libc/sysdeps/linux/nds32/syscall.S
deleted file mode 100644
index 032c643fd..000000000
--- a/libc/sysdeps/linux/nds32/syscall.S
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 Andes Technology, Inc.
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-#include <sys/syscall.h>
-#include <sysdep.h>
-
- .text
-#ifdef PIC
- .pic
-#endif
- .align 2
-
-
-#ifdef PIC
-#ifdef __NDS32_N1213_43U1H__
-1:
- ret
-99:
- addi $r2, $lp, 0
- jal 1b
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4)
- add $r1, $lp, $r1
- addi $lp, $r2, 0
-#else /* !__NDS32_N1213_43U1H__ */
-99:
- mfusr $r15, $PC
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_ + 8)
- add $r1, $r15, $r1
-#endif /* end of __NDS32_N1213_43U1H__ */
- sethi $r15, hi20(__syscall_error@PLT)
- ori $r15, $r15, lo12(__syscall_error@PLT)
- add $r15, $r15, $r1
- jr $r15
-#else /* !PIC */
-99:
- j __syscall_error
-#endif /* end of PIC */
-
-#ifdef PIC
- .pic
-#endif
-
- .align 2
- .globl syscall
- .func syscall
- .type syscall, @function
-
-syscall:
- syscall __NR_syscall
- bgez $r0, 2f
- sltsi $r1, $r0, -4096;
- beqz $r1, 99b;
-2:
- ret
- .endfunc
- .size syscall, .-syscall
diff --git a/libc/sysdeps/linux/nds32/syscall.c b/libc/sysdeps/linux/nds32/syscall.c
new file mode 100644
index 000000000..2c949ef3a
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/syscall.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/syscall.h>
+#include <sysdep.h>
+#include <unistd.h>
+long int syscall (long int __sysno, ...)
+{
+
+ int result;
+ unsigned long arg1,arg2,arg3,arg4,arg5,arg6;
+ va_list arg;
+ va_start (arg, __sysno);
+ arg1 = va_arg (arg, unsigned long);
+ arg2 = va_arg (arg, unsigned long);
+ arg3 = va_arg (arg, unsigned long);
+ arg4 = va_arg (arg, unsigned long);
+ arg5 = va_arg (arg, unsigned long);
+ arg6 = va_arg (arg, unsigned long);
+ va_end (arg);
+ __asm__ volatile ( "" ::: "memory" );
+ result = INLINE_SYSCALL(syscall,7,__sysno,arg1,arg2,arg3,arg4,arg5,arg6);
+ return result;
+}
diff --git a/libc/sysdeps/linux/nds32/sysdep.S b/libc/sysdeps/linux/nds32/sysdep.S
index 4e86a26e0..0ab325f26 100644
--- a/libc/sysdeps/linux/nds32/sysdep.S
+++ b/libc/sysdeps/linux/nds32/sysdep.S
@@ -26,15 +26,10 @@
.text
-.globl C_SYMBOL_NAME(errno)
.globl __syscall_error
ENTRY (__syscall_error)
-#ifdef OLD_ABI
- subri $r5, $r5, #0
-#else
subri $r0, $r0, #0
-#endif
#define __syscall_error __syscall_error_1
@@ -48,56 +43,57 @@ syscall_error:
#ifdef PIC
/* set GP register */
pushm $gp, $lp
-#ifdef __NDS32_N1213_43U1H__
- jal 2f
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_)
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4)
- add $gp, $gp, $lp
-#else
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(gp, 0)
+ cfi_rel_offset(lp, 4)
mfusr $r15, $PC
sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4)
ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8)
add $gp, $gp, $r15
#endif
-#endif
#if defined (EWOULDBLOCK_sys) && EWOULDBLOCK_sys != EAGAIN
/* We translate the system's EWOULDBLOCK error into EAGAIN.
The GNU C library always defines EWOULDBLOCK==EAGAIN.
EWOULDBLOCK_sys is the original number. */
push $t0
+ cfi_adjust_cfa_offset(4)
li $t0, EWOULDBLOCK_sys
bne $r0, $t0, 1f
pop $t0
+ cfi_adjust_cfa_offset(-4)
li $r0, EAGAIN
1:
#endif
#ifdef _LIBC_REENTRANT
push $lp
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset(lp, 0)
push $r0
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-#else
- addi $sp, $sp, -24
-#endif
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset(r0, 0)
#ifdef PIC
bal C_SYMBOL_NAME(__errno_location@PLT)
#else
bal C_SYMBOL_NAME(__errno_location)
#endif
-#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP)
-#else
- addi $sp, $sp, 24
-#endif
pop $r1
+ cfi_adjust_cfa_offset(-4)
+ cfi_restore(r1)
swi $r1, [$r0]
li $r0, -1
pop $lp
+ cfi_adjust_cfa_offset(-4)
+ cfi_restore(lp)
#ifdef PIC
/* restore GP register */
popm $gp, $lp
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(lp)
+ cfi_restore(gp)
#endif
2:
ret
@@ -115,6 +111,9 @@ syscall_error:
/* restore GP register */
popm $gp, $lp
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(lp)
+ cfi_restore(gp)
2:
ret
diff --git a/libc/sysdeps/linux/nds32/sysdep.h b/libc/sysdeps/linux/nds32/sysdep.h
index 7472a99d4..340797858 100644
--- a/libc/sysdeps/linux/nds32/sysdep.h
+++ b/libc/sysdeps/linux/nds32/sysdep.h
@@ -1,148 +1,96 @@
-//#include <sysdeps/generic/sysdep.h>
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _LINUX_NDS32_SYSDEP_H
+#define _LINUX_NDS32_SYSDEP_H 1
+
+#include <common/sysdep.h>
+
#ifdef __ASSEMBLER__
/* Define an entry point visible from C. */
-#ifdef PIC
-#define ENTRY(name) \
+# ifdef PIC
+# define ENTRY(name) \
.pic \
.align 2; \
.globl C_SYMBOL_NAME(name); \
.func C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name), @function; \
-C_SYMBOL_NAME(name):
-#else
-#define ENTRY(name) \
+C_SYMBOL_NAME(name): \
+ cfi_startproc;
+
+# else
+# define ENTRY(name) \
.align 2; \
.globl C_SYMBOL_NAME(name); \
.func C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name), @function; \
-C_SYMBOL_NAME(name):
-#endif
+C_SYMBOL_NAME(name): \
+ cfi_startproc;
+# endif
#undef END
#define END(name) \
+ cfi_endproc; \
.endfunc; \
.size C_SYMBOL_NAME(name), .-C_SYMBOL_NAME(name)
/* If compiled for profiling, call `mcount' at the start of each function. */
-#ifdef HAVE_ELF
+# ifdef HAVE_ELF
#undef NO_UNDERSCORES
#define NO_UNDERSCORES
-#endif
+# endif
-#ifdef NO_UNDERSCORES
+# ifdef NO_UNDERSCORES
#define syscall_error __syscall_error
-#endif
+# endif
#define SYS_ify(syscall_name) (__NR_##syscall_name)
#define __do_syscall(syscall_name) \
syscall SYS_ify(syscall_name);
-#define SYSCALL_ERROR_HANDLER
-#define SYSCALL_ERROR __syscall_error
-
-
-#ifdef PIC
-#ifdef __NDS32_N1213_43U1H__
-#ifdef NDS_ABI_V0
-#define PSEUDO(name, syscall_name, args) \
- .pic; \
- .align 2; \
- 1: ret; \
- 99: addi $r0, $lp, 0; \
- jal 1b; \
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_); \
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4); \
- add $r1, $lp, $r1; \
- addi $lp, $r0, 0; \
- sethi $r15, hi20(SYSCALL_ERROR@PLT); \
- ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
- add $r15, $r15, $r1; \
- jr $r15; \
- nop; \
- ENTRY(name); \
- __do_syscall(syscall_name); \
- bgez $r5, 2f; \
- sltsi $r0, $r5, -4096; \
- beqz $r0, 99b; \
- 2:
-#else
-#define PSEUDO(name, syscall_name, args) \
- .pic; \
- .align 2; \
- 1: ret; \
- 99: addi $r2, $lp, 0; \
- jal 1b; \
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_); \
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4); \
- add $r1, $lp, $r1; \
- addi $lp, $r2, 0; \
- sethi $r15, hi20(SYSCALL_ERROR@PLT); \
- ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
- add $r15, $r15, $r1; \
- jr $r15; \
- nop; \
- ENTRY(name); \
- __do_syscall(syscall_name); \
- bgez $r0, 2f; \
- sltsi $r1, $r0, -4096; \
- beqz $r1, 99b; \
- 2:
-#endif
-#else
-#define PSEUDO(name, syscall_name, args) \
- .pic; \
- .align 2; \
- 99: mfusr $r15, $PC; \
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
+# ifdef PIC
+# define PSEUDO(name, syscall_name, args) \
+ .pic; \
+ .align 2; \
+ 99: mfusr $r15, $PC; \
+ sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
- add $r1, $r15, $r1; \
- sethi $r15, hi20(SYSCALL_ERROR@PLT); \
- ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
- add $r15, $r15, $r1; \
- jr $r15; \
- nop; \
- ENTRY(name); \
- __do_syscall(syscall_name); \
- bgez $r0, 2f; \
- sltsi $r1, $r0, -4096; \
- beqz $r1, 99b; \
+ add $r1, $r15, $r1; \
+ sethi $r15, hi20(SYSCALL_ERROR@PLT); \
+ ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
+ add $r15, $r15, $r1; \
+ jr $r15; \
+ nop; \
+ ENTRY(name); \
+ __do_syscall(syscall_name); \
+ bgez $r0, 2f; \
+ sltsi $r1, $r0, -4096; \
+ beqz $r1, 99b; \
2:
-#endif
-#else
-#ifdef OLD2_ABI
-#define PSEUDO(name, syscall_name, args) \
- .align 2; \
- 99: j SYSCALL_ERROR; \
- nop; \
- ENTRY(name); \
- __do_syscall(syscall_name); \
- bgez $r5, 2f; \
- sltsi $r0, $r5, -4096; \
- beqz $r0, 99b; \
+# else
+# define PSEUDO(name, syscall_name, args) \
+ .align 2; \
+ 99: j SYSCALL_ERROR; \
+ nop; \
+ ENTRY(name); \
+ __do_syscall(syscall_name); \
+ bgez $r0, 2f; \
+ sltsi $r1, $r0, -4096; \
+ beqz $r1, 99b; \
2:
-#else
-#define PSEUDO(name, syscall_name, args) \
- .align 2; \
- 99: j SYSCALL_ERROR; \
- nop; \
- ENTRY(name); \
- __do_syscall(syscall_name); \
- bgez $r0, 2f; \
- sltsi $r1, $r0, -4096; \
- beqz $r1, 99b; \
- 2:
-#endif
-#endif
+# endif
-#define PSEUDO_NOERRNO(name, syscall_name, args) \
- ENTRY(name); \
+#define PSEUDO_NOERRNO(name, syscall_name, args) \
+ ENTRY(name); \
__do_syscall(syscall_name);
#undef PSEUDO_END
-#define PSEUDO_END(sym) \
- SYSCALL_ERROR_HANDLER \
+#define PSEUDO_END(sym) \
+ SYSCALL_ERROR_HANDLER \
END(sym)
#undef PSEUDO_END_ERRVAL
@@ -152,120 +100,65 @@ C_SYMBOL_NAME(name):
#define ret_ERRVAL ret
-#define ret_NOERRNO ret
+#define ret_NOERRNO ret
#if defined NOT_IN_libc
#define SYSCALL_ERROR __local_syscall_error
#ifdef PIC
- #ifdef __NDS32_N1213_43U1H__
- #ifdef NDS_ABI_V0
- #define SYSCALL_ERROR_HANDLER \
- __local_syscall_error: pushm $gp, $lp, $sp; \
- jal 1f; \
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_); \
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4); \
- add $gp, $gp, $lp; \
- neg $r5, $r5; \
- push $r5; \
- addi $sp, $sp, -28; \
- bal C_SYMBOL_NAME(__errno_location@PLT); \
- addi $sp, $sp, 28; \
- pop $r1; \
- swi $r1, [$r5]; \
- li $r5, -1; \
- popm $gp, $lp, $sp; \
- 1: ret;
- #else
- #define SYSCALL_ERROR_HANDLER \
- __local_syscall_error: pushm $gp, $lp, $sp; \
- jal 1f; \
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_); \
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4); \
- add $gp, $gp, $lp; \
- neg $r0, $r0; \
- push $r0; \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, -4; \
- #else \
- addi $sp, $sp, -28; \
- #endif \
- bal C_SYMBOL_NAME(__errno_location@PLT); \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, 4; \
- #else \
- addi $sp, $sp, 28; \
- #endif \
- pop $r1; \
- swi $r1, [$r0]; \
- li $r0, -1; \
- popm $gp, $lp, $sp; \
- 1: ret;
- #endif
- #else
- #define SYSCALL_ERROR_HANDLER \
- __local_syscall_error: pushm $gp, $lp, $sp; \
- mfusr $r15, $PC; \
- sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4); \
- ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8); \
- add $gp, $gp, $r15; \
- neg $r0, $r0; \
- push $r0; \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, -4; \
- #else \
- addi $sp, $sp, -28; \
- #endif \
- bal C_SYMBOL_NAME(__errno_location@PLT); \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, 4; \
- #else \
- addi $sp, $sp, 28; \
- #endif \
- pop $r1; \
- swi $r1, [$r0]; \
- li $r0, -1; \
- popm $gp, $lp, $sp; \
- 1: ret;
- #endif
+ #define SYSCALL_ERROR_HANDLER \
+ __local_syscall_error: \
+ pushm $gp, $lp; \
+ cfi_adjust_cfa_offset(8) \
+ cfi_rel_offset(gp, 0) \
+ cfi_rel_offset(lp, 4) \
+ mfusr $r15, $PC; \
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4); \
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8); \
+ add $gp, $gp, $r15; \
+ neg $r0, $r0; \
+ push $r0; \
+ cfi_adjust_cfa_offset(4) \
+ cfi_rel_offset(r0, 0) \
+ addi $sp, $sp, -4; \
+ bal C_SYMBOL_NAME(__errno_location@PLT); \
+ addi $sp, $sp, 4; \
+ pop $r1; \
+ cfi_adjust_cfa_offset(-4); \
+ cfi_restore(r1); \
+ swi $r1, [$r0]; \
+ li $r0, -1; \
+ popm $gp, $lp; \
+ cfi_adjust_cfa_offset(-8); \
+ cfi_restore(lp); \
+ cfi_restore(gp); \
+ 1: ret;
#else
- #ifdef NDS_ABI_V0
- #define SYSCALL_ERROR_HANDLER \
- __local_syscall_error: push $lp; \
- neg $r5, $r5; \
- push $r5; \
- addi $sp, $sp, -28; \
- bal C_SYMBOL_NAME(__errno_location); \
- addi $sp, $sp, 28; \
- pop $r1; \
- swi $r1, [$r5]; \
- li $r5, -1; \
- pop $lp; \
+ #define SYSCALL_ERROR_HANDLER \
+ __local_syscall_error: \
+ push $lp; \
+ cfi_adjust_cfa_offset(4) \
+ cfi_rel_offset(lp, 0) \
+ neg $r0, $r0; \
+ push $r0; \
+ cfi_adjust_cfa_offset(4) \
+ cfi_rel_offset(r0, 0) \
+ addi $sp, $sp, -4; \
+ bal C_SYMBOL_NAME(__errno_location); \
+ addi $sp, $sp, 4; \
+ pop $r1; \
+ cfi_adjust_cfa_offset(-4); \
+ cfi_restore(r1); \
+ swi $r1, [$r0]; \
+ li $r0, -1; \
+ pop $lp; \
+ cfi_adjust_cfa_offset(-4); \
+ cfi_restore(lp); \
ret;
- #else
- #define SYSCALL_ERROR_HANDLER \
- __local_syscall_error: push $lp; \
- neg $r0, $r0; \
- push $r0; \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, -4; \
- #else \
- addi $sp, $sp, -28; \
- #endif \
- bal C_SYMBOL_NAME(__errno_location); \
- #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \
- addi $sp, $sp, 4; \
- #else \
- addi $sp, $sp, 28; \
- #endif \
- pop $r1; \
- swi $r1, [$r0]; \
- li $r0, -1; \
- pop $lp; \
- ret;
- #endif
#endif
#else
#define SYSCALL_ERROR_HANDLER
#define SYSCALL_ERROR __syscall_error
#endif
+
#endif /* __ASSEMBLER__ */
+#endif //_LINUX_NDS32_SYSDEP_H
diff --git a/libc/sysdeps/linux/nds32/ucontext_i.sym b/libc/sysdeps/linux/nds32/ucontext_i.sym
new file mode 100644
index 000000000..1a5f2e5f3
--- /dev/null
+++ b/libc/sysdeps/linux/nds32/ucontext_i.sym
@@ -0,0 +1,27 @@
+#include <stddef.h>
+#include <signal.h>
+#include <sys/ucontext.h>
+
+--
+
+SIG_BLOCK
+SIG_SETMASK
+_NSIG8 (_NSIG / 8)
+
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+#define mreg(reg) mcontext (nds32_##reg)
+
+
+UCONTEXT_GREGS mcontext (nds32_r0)
+#ifdef __NDS32_ABI_2FP_PLUS__
+UCONTEXT_FDREGS mcontext (fpu.fd_regs)
+#endif
+UCONTEXT_PC mcontext (nds32_ipc)
+
+
+UCONTEXT_FLAGS ucontext (uc_flags)
+UCONTEXT_LINK ucontext (uc_link)
+UCONTEXT_STACK ucontext (uc_stack)
+UCONTEXT_MCONTEXT ucontext (uc_mcontext)
+UCONTEXT_SIGMASK ucontext (uc_sigmask)
diff --git a/libc/sysdeps/linux/nds32/vfork.S b/libc/sysdeps/linux/nds32/vfork.S
index c955359fb..ac3fa30fd 100644
--- a/libc/sysdeps/linux/nds32/vfork.S
+++ b/libc/sysdeps/linux/nds32/vfork.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
@@ -21,24 +21,36 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <sys/syscall.h>
#include <sysdep.h>
-
#define _ERRNO_H 1
+#include <bits/errno.h>
+
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
+
ENTRY (__vfork)
#ifdef PIC
.pic
#endif
#ifdef __NR_vfork
-
+# ifdef SAVE_PID
+ SAVE_PID
+# endif
syscall __NR_vfork
+# ifdef RESTORE_PID
+ RESTORE_PID
+# endif
bltz $r0, 2f
1:
ret
@@ -46,42 +58,86 @@ ENTRY (__vfork)
sltsi $r1, $r0, -4096
bnez $r1, 1b;
+# ifdef __ASSUME_VFORK_SYSCALL
# ifdef PIC
- #ifdef __NDS32_N1213_43U1H__
- ! save lp
- addi $r2, $lp, 0
-
- ! set r1 as gp
- jal 1b
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4)
- add $r1, $lp, $r1
-
- ! restore lp
- addi $lp, $r2, 0
- #else
- ! set r1 as gp
- mfusr $r15, $PC
- sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_+4)
- ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+8)
- add $r1, $r1, $r15
- #endif
+ pushm $gp, $lp
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(gp, 0)
+ cfi_rel_offset(lp, 4)
+ mfusr $r15, $PC
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4)
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8)
+ add $gp, $gp, $r15
! r15=C_SYMBOL_NAME(__syscall_error)@PLT
- sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT)
+ sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT)
ori $r15, $r15, lo12(C_SYMBOL_NAME(__syscall_error)@PLT)
- add $r15, $r15, $r1
+ add $r15, $r15, $gp
! jump to SYSCALL_ERROR
- jr $r15
+ jral $r15
+ popm $gp, $lp
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(lp)
+ cfi_restore(gp)
+ ret
# else
j C_SYMBOL_NAME(__syscall_error)
# endif
+# else
+ /* Check if vfork syscall is known at all. */
+ li $r1, -ENOSYS
+ beq $r0, $r1, 1f
+
+# ifdef PIC
+3:
+ pushm $gp, $lp
+ cfi_adjust_cfa_offset(8)
+ cfi_rel_offset(gp, 0)
+ cfi_rel_offset(lp, 4)
+ mfusr $r15, $PC
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4)
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8)
+ add $gp, $gp, $r15
+
+ ! r15=C_SYMBOL_NAME(__syscall_error)@PLT
+ sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT)
+ ori $r15, $r15, lo12(C_SYMBOL_NAME(__syscall_error)@PLT)
+ add $r15, $r15, $gp
+
+ ! jump to SYSCALL_ERROR
+ jral $r15
+ popm $gp, $lp
+ cfi_adjust_cfa_offset(-8)
+ cfi_restore(lp)
+ cfi_restore(gp)
+ ret
+# else
+ j C_SYMBOL_NAME(__syscall_error)
+# endif
+1:
+# endif
+#endif
+
+#ifndef __ASSUME_VFORK_SYSCALL
+ /* If we don't have vfork, fork is close enough. */
+ syscall __NR_fork
+ bgez $r0, 1f
+ sltsi $r1, $r0, -4096
+ bnez $r1, 1f
+
+# ifdef PIC
+ b 3b
+# else
+ j C_SYMBOL_NAME(__syscall_error)
+# endif
+1:
+ ret
-#else
-# error "__NR_vfork not available"
+#elif !defined __NR_vfork
+# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined"
#endif
PSEUDO_END (__vfork)
weak_alias (__vfork, vfork)
-libc_hidden_def(vfork)
+libc_hidden_def (vfork)
diff --git a/libm/nds32/Makefile.arch b/libm/nds32/Makefile.arch
new file mode 100644
index 000000000..bd38690be
--- /dev/null
+++ b/libm/nds32/Makefile.arch
@@ -0,0 +1,16 @@
+# Makefile for uClibc-ng
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+ifeq ($(UCLIBC_HAS_FENV),y)
+libm_ARCH_SRC:=$(wildcard $(libm_ARCH_DIR)/*.c)
+libm_ARCH_OBJ:=$(patsubst $(libm_ARCH_DIR)/%.c,$(libm_ARCH_OUT)/%.o,$(libm_ARCH_SRC))
+endif
+
+libm_ARCH_OBJS:=$(libm_ARCH_OBJ)
+
+ifeq ($(DOPIC),y)
+libm-a-y+=$(libm_ARCH_OBJS:.o=.os)
+else
+libm-a-y+=$(libm_ARCH_OBJS)
+endif
+libm-so-y+=$(libm_ARCH_OBJS:.o=.os)
diff --git a/libm/nds32/e_sqrt.c b/libm/nds32/e_sqrt.c
new file mode 100644
index 000000000..c737e10c6
--- /dev/null
+++ b/libm/nds32/e_sqrt.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 2002-2013 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/>. */
+
+#if defined(__NDS32_ABI_2FP_PLUS__) && defined(__NDS32_EXT_FPU_DP__)
+
+double __ieee754_sqrt (double x)
+{
+ double z;
+ __asm__ ("fsqrtd %0,%1" : "=f" (z) : "f" (x));
+ return z;
+}
+strong_alias(__ieee754_sqrt, sqrt)
+libm_hidden_def(sqrt)
+#else
+#include <libm/e_sqrt.c>
+#endif
diff --git a/libm/nds32/fclrexcpt.c b/libm/nds32/fclrexcpt.c
new file mode 100644
index 000000000..938f15a25
--- /dev/null
+++ b/libm/nds32/fclrexcpt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Clear given exceptions in current floating-point environment.
+ Copyright (C) 1997-2013 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 <fenv.h>
+#include "fenv_libc.h"
+#include <fpu_control.h>
+
+
+int
+feclearexcept (int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long int temp;
+
+ /* Mask out unsupported bits/exceptions. */
+ excepts &= FE_ALL_EXCEPT;
+
+ /* Get the current floating point status. */
+ _FPU_GETCW (temp);
+
+ /* Clear the relevant bits. */
+ temp &= ~excepts;
+
+ /* Put the new data in effect. */
+ _FPU_SETCW (temp);
+
+ /* Success. */
+ return 0;
+#else
+ /* Unsupported, so fail unless nothing needs to be done. */
+ return (excepts != 0);
+#endif
+}
diff --git a/libm/nds32/fedisblxcpt.c b/libm/nds32/fedisblxcpt.c
new file mode 100644
index 000000000..bbb6d54e4
--- /dev/null
+++ b/libm/nds32/fedisblxcpt.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Disable floating-point exceptions.
+ Copyright (C) 2001-2013 Free Software Foundation, Inc.
+ Contributed by Philip Blundell <philb@gnu.org>, 2001.
+
+ 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 <fenv.h>
+#include "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+fedisableexcept (int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long int new_exc, old_exc;
+
+ _FPU_GETCW(new_exc);
+
+ old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT;
+
+ excepts &= FE_ALL_EXCEPT;
+
+ new_exc &= ~(excepts << ENABLE_SHIFT);
+ new_exc &= ~_FPU_RESERVED;
+ _FPU_SETCW (new_exc);
+
+ return old_exc;
+#else
+ /* Unsupported, so return -1 for failure. */
+ return -1;
+#endif
+}
diff --git a/libm/nds32/feenablxcpt.c b/libm/nds32/feenablxcpt.c
new file mode 100644
index 000000000..14aef9850
--- /dev/null
+++ b/libm/nds32/feenablxcpt.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Enable floating-point exceptions.
+ Copyright (C) 2001-2013 Free Software Foundation, Inc.
+ Contributed by Philip Blundell <philb@gnu.org>, 2001.
+
+ 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 <fenv.h>
+#include "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+feenableexcept (int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long int new_exc, old_exc;
+
+ _FPU_GETCW(new_exc);
+
+ old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT;
+
+ excepts &= FE_ALL_EXCEPT;
+
+ new_exc |= (excepts << ENABLE_SHIFT);
+ new_exc &= ~_FPU_RESERVED;
+
+ _FPU_SETCW(new_exc);
+
+ return old_exc;
+#else
+ /* Unsupported, so return -1 for failure. */
+ return -1;
+#endif
+}
diff --git a/libm/nds32/fegetenv.c b/libm/nds32/fegetenv.c
new file mode 100644
index 000000000..782cf793e
--- /dev/null
+++ b/libm/nds32/fegetenv.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Store current floating-point environment.
+ Copyright (C) 1997-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fegetenv (fenv_t *envp)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long int temp;
+ _FPU_GETCW (temp);
+ envp->__fpcsr = temp;
+
+ /* Success. */
+ return 0;
+#else
+ /* Unsupported, so fail. */
+ return 1;
+#endif
+}
diff --git a/libm/nds32/fegetexcept.c b/libm/nds32/fegetexcept.c
new file mode 100644
index 000000000..1ffe361cc
--- /dev/null
+++ b/libm/nds32/fegetexcept.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Get floating-point exceptions.
+ Copyright (C) 2001-2013 Free Software Foundation, Inc.
+ Contributed by Philip Blundell <philb@gnu.org>, 2001
+
+ 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 <fenv.h>
+#include "fenv_libc.h"
+#include <fpu_control.h>
+
+int
+fegetexcept (void)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long temp;
+
+ _FPU_GETCW (temp);
+
+ return (temp & ENABLE_MASK) >> ENABLE_SHIFT;
+#else
+ /* Unsupported. Return all exceptions disabled. */
+ return 0;
+#endif
+}
diff --git a/libm/nds32/fegetround.c b/libm/nds32/fegetround.c
new file mode 100644
index 000000000..e4e70eaad
--- /dev/null
+++ b/libm/nds32/fegetround.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Return current rounding direction.
+ Copyright (C) 2004-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fegetround (void)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned int temp;
+
+ /* Get the current environment. */
+ _FPU_GETCW (temp);
+
+ return temp & 0x3;
+#else
+ /* The current soft-float implementation only handles TONEAREST. */
+ return FE_TONEAREST;
+#endif
+}
diff --git a/libm/nds32/feholdexcpt.c b/libm/nds32/feholdexcpt.c
new file mode 100644
index 000000000..4ea3679f5
--- /dev/null
+++ b/libm/nds32/feholdexcpt.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Store current floating-point environment and clear exceptions.
+ Copyright (C) 1997-2013 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 <fenv.h>
+#include <fpu_control.h>
+#include "fenv_libc.h"
+
+int
+feholdexcept (fenv_t *envp)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned long int temp;
+
+ /* Store the environment. */
+ _FPU_GETCW(temp);
+ envp->__fpcsr = temp;
+
+ /* Now set all exceptions to non-stop. */
+ temp &= ~(FE_ALL_EXCEPT << ENABLE_SHIFT);
+
+ /* And clear all exception flags. */
+ temp &= ~FE_ALL_EXCEPT;
+
+ _FPU_SETCW(temp);
+
+ return 0;
+#else
+ /* Unsupported, so fail. */
+ return 1;
+#endif
+}
+
diff --git a/libm/nds32/fenv_libc.h b/libm/nds32/fenv_libc.h
new file mode 100644
index 000000000..a76f131e4
--- /dev/null
+++ b/libm/nds32/fenv_libc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 2000-2013 Free Software Foundation, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+ based on the corresponding file in the mips port.
+
+ 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 _FENV_LIBC_H
+#define _FENV_LIBC_H
+
+/* Mask for enabling exceptions and for the CAUSE bits. */
+#define ENABLE_MASK 0x00F80U
+
+/* Shift for FE_* flags to get up to the ENABLE bits. */
+#define ENABLE_SHIFT 5
+
+#endif /* _FENV_LIBC_H */
diff --git a/libm/nds32/fesetenv.c b/libm/nds32/fesetenv.c
new file mode 100644
index 000000000..4682d3c8e
--- /dev/null
+++ b/libm/nds32/fesetenv.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Install given floating-point environment.
+ Copyright (C) 2004-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetenv (const fenv_t *envp)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned int temp;
+
+ _FPU_GETCW (temp);
+ temp &= _FPU_RESERVED;
+
+ if (envp == FE_DFL_ENV)
+ temp |= _FPU_DEFAULT;
+ else if (envp == FE_NOMASK_ENV)
+ temp |= _FPU_IEEE;
+ else
+ temp |= envp->__fpcsr & ~_FPU_RESERVED;
+
+ _FPU_SETCW (temp);
+
+ /* Success. */
+ return 0;
+#else
+
+ /* Unsupported, so fail. */
+ return 1;
+#endif
+}
diff --git a/libm/nds32/fesetround.c b/libm/nds32/fesetround.c
new file mode 100644
index 000000000..012a5bfff
--- /dev/null
+++ b/libm/nds32/fesetround.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Set current rounding direction.
+ Copyright (C) 2004-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetround (int round)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ fpu_control_t temp;
+ if ((round & ~0x3) != 0)
+ /* ROUND is no valid rounding mode. */
+ return 1;
+
+ _FPU_GETCW (temp);
+ temp = (temp & ~0x3) | round;
+ _FPU_SETCW (temp);
+ return 0;
+#else
+ return (round != FE_TONEAREST);
+#endif
+}
diff --git a/libm/nds32/feupdateenv.c b/libm/nds32/feupdateenv.c
new file mode 100644
index 000000000..d58c9004b
--- /dev/null
+++ b/libm/nds32/feupdateenv.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Install given floating-point environment and raise exceptions.
+ Copyright (C) 1997-2013 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+feupdateenv (const fenv_t *envp)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ unsigned int temp;
+
+ /* Get the current exception state. */
+ _FPU_GETCW (temp);
+
+ /* Install new environment. */
+ fesetenv (envp);
+
+ /* Raise the saved exceptions. */
+ feraiseexcept (temp & FE_ALL_EXCEPT);
+
+ /* Success. */
+ return 0;
+#else
+ /* Unsupported, so fail. */
+ return 1;
+#endif
+}
diff --git a/libm/nds32/fgetexcptflg.c b/libm/nds32/fgetexcptflg.c
new file mode 100644
index 000000000..e446c429c
--- /dev/null
+++ b/libm/nds32/fgetexcptflg.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Store current representation for exceptions.
+ Copyright (C) 1997-2013 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fegetexceptflag (fexcept_t *flagp, int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ fpu_control_t temp;
+
+ /* Get the current exceptions. */
+ _FPU_GETCW (temp);
+
+ *flagp = temp & excepts & FE_ALL_EXCEPT;
+
+ /* Success. */
+ return 0;
+#else
+ /* Unsupported, so fail. */
+ return 1;
+#endif
+}
diff --git a/libm/nds32/fraiseexcpt.c b/libm/nds32/fraiseexcpt.c
new file mode 100644
index 000000000..d1942110c
--- /dev/null
+++ b/libm/nds32/fraiseexcpt.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Raise given exceptions.
+ Copyright (C) 2004-2013 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 <fpu_control.h>
+#include <fenv.h>
+#include <float.h>
+#include "fenv_libc.h"
+
+int
+feraiseexcept (int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ float temp1 = 0.0, temp2 = 1.0;
+ if (FE_INVALID & excepts)
+ {
+ __asm__ volatile(
+ "fmtsr\t %0, $fs0\n\t"
+ "fdivs\t $fs0, $fs0, $fs0\n\t"
+ :
+ :"r"(temp1)
+ :"$fs0"
+ );
+ }
+ if (FE_DIVBYZERO & excepts)
+ {
+ __asm__ volatile(
+ "fmtsr\t %0, $fs0\n\t"
+ "fmtsr\t %1, $fs1\n\t"
+ "fdivs\t $fs0, $fs1, $fs0\n\t"
+ :
+ :"r"(temp1),"r"(temp2)
+ :"$fs0"
+ );
+ }
+ if (FE_OVERFLOW & excepts)
+ {
+ /* There's no way to raise overflow without also raising inexact.
+ */
+ unsigned int fpcsr;
+ temp1 = FLT_MAX;
+ __asm__ volatile(
+ "fmfcsr\t %0\n\t"
+ "fmtsr\t %1, $fs0\n\t"
+ "fadds\t $fs0, $fs0, $fs0\n\t"
+ "ori\t %0,%0,0x10\n\t"
+ "fmtcsr\t %0\n\t"
+ :"=&r"(fpcsr)
+ :"r"(temp1)
+ :"$fs0"
+ );
+ }
+ if (FE_UNDERFLOW & excepts)
+ {
+ /* There's no way to raise overflow without also raising inexact.
+ */
+ temp1 = FLT_MIN;
+ temp2 = 2.0;
+ __asm__ volatile(
+ "fmtsr\t %0, $fs0\n\t"
+ "fmtsr\t %1, $fs1\n\t"
+ "fdivs\t $fs1, $fs0, $fs1\n\t"
+ :
+ :"r"(temp1),"r"(temp2)
+ :"$fs0","$fs1"
+ );
+ }
+ if (FE_INEXACT & excepts)
+ {
+ temp1 = 3.0;
+ __asm__ volatile(
+ "fmtsr\t %0, $fs1\n\t"
+ "fmtsr\t %1, $fs0\n\t"
+ "fdivs\t $fs1, $fs0, $fs1\n\t"
+ :
+ :"r"(temp1),"r"(temp2)
+ :"$fs0","$fs1"
+ );
+ }
+
+ return 0;
+
+#endif
+ /* Unsupported, so fail unless nothing needs to be done. */
+ return (excepts != 0);
+}
diff --git a/libm/nds32/fsetexcptflg.c b/libm/nds32/fsetexcptflg.c
new file mode 100644
index 000000000..7da943b9d
--- /dev/null
+++ b/libm/nds32/fsetexcptflg.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Set floating-point environment exception handling.
+ Copyright (C) 1997-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fesetexceptflag (const fexcept_t *flagp, int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ fexcept_t temp;
+
+ /* Get the current environment. */
+ _FPU_GETCW (temp);
+
+ /* Set the desired exception mask. */
+ temp &= ~(excepts & FE_ALL_EXCEPT);
+ temp |= (*flagp & excepts & FE_ALL_EXCEPT);
+
+ /* Save state back to the FPU. */
+ _FPU_SETCW (temp);
+
+ /* Success. */
+ return 0;
+#else
+ /* Unsupported, so fail unless nothing needs to be done. */
+ return (excepts != 0);
+#endif
+}
diff --git a/libm/nds32/ftestexcept.c b/libm/nds32/ftestexcept.c
new file mode 100644
index 000000000..8257b6f45
--- /dev/null
+++ b/libm/nds32/ftestexcept.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Test exception in current environment.
+ Copyright (C) 1997-2013 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 <fenv.h>
+#include <fpu_control.h>
+
+int
+fetestexcept (int excepts)
+{
+#ifdef __NDS32_ABI_2FP_PLUS__
+ fexcept_t temp;
+
+ /* Get current exceptions. */
+ _FPU_GETCW(temp);
+
+ return temp & excepts & FE_ALL_EXCEPT;
+#else
+ /* Unsupported, return 0. */
+ return 0;
+#endif
+}
diff --git a/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c b/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c
index f8adf07be..770a55ab3 100644
--- a/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c
+++ b/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
diff --git a/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h b/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h
index 5bbb9e850..631c28491 100644
--- a/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Andes Technology, Inc.
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
diff --git a/libpthread/nptl/sysdeps/nds32/Makefile.arch b/libpthread/nptl/sysdeps/nds32/Makefile.arch
new file mode 100644
index 000000000..7eb852af1
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/Makefile.arch
@@ -0,0 +1,16 @@
+# Makefile for uClibc-ng NPTL
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+ASFLAGS-dl-tlsdesc.S = -DNOT_IN_libc=1
+libc_arch_a_SSRC = libc-dl-tlsdesc.S
+
+CFLAGS-gen_tlsdesc.c = -S
+$(libpthread_arch_OUT)/gen_tlsdesc.c: $(libpthread_arch_DIR)/tlsdesc.sym | $(libpthread_arch_OUT)
+ $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+$(libpthread_arch_OUT)/gen_tlsdesc.s: $(libpthread_arch_OUT)/gen_tlsdesc.c | headers
+ $(compile.c)
+libpthread-generated-y += $(libpthread_arch_OUT)/gen_tlsdesc.s
+$(libpthread_arch_OUT)/tlsdesc.h: $(libpthread_arch_OUT)/gen_tlsdesc.s
+ $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@
+ @if test ! -s $@ ; then rm -f $@ ; false ; fi
+pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(libpthread_arch_OUT)/tlsdesc.h
diff --git a/libpthread/nptl/sysdeps/nds32/dl-tls.h b/libpthread/nptl/sysdeps/nds32/dl-tls.h
new file mode 100644
index 000000000..3b11e7f42
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/dl-tls.h
@@ -0,0 +1,59 @@
+/* Thread-local storage handling in the ELF dynamic linker. NDS32 version.
+ Copyright (C) 2013 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/>. */
+
+#ifndef _NDS32_DL_TLS_H
+#define _NDS32_DL_TLS_H 1
+
+
+/* Type used to represent a TLS descriptor. */
+struct tlsdesc
+{
+ ptrdiff_t (*entry)(struct tlsdesc *);
+ union
+ {
+ void *pointer;
+ long value;
+ } argument;
+};
+
+/* Type used for the representation of TLS information in the GOT. */
+typedef struct
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+
+/* Type used as the argument in a TLS descriptor for a symbol that
+ * needs dynamic TLS offsets. */
+struct tlsdesc_dynamic_arg
+{
+ tls_index tlsinfo;
+ size_t gen_count;
+};
+
+
+extern void *__tls_get_addr (tls_index *ti);
+
+extern ptrdiff_t attribute_hidden
+ _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *);
+
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
+extern ptrdiff_t attribute_hidden
+ _dl_tlsdesc_dynamic(struct tlsdesc *);
+
+#endif //_NDS32_DL_TLS_H
diff --git a/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S b/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S
new file mode 100644
index 000000000..5892a8b28
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S
@@ -0,0 +1 @@
+#include <ldso/ldso/nds32/dl-tlsdesc.S>
diff --git a/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c
new file mode 100644
index 000000000..cec3acbc6
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c
@@ -0,0 +1,65 @@
+/* pthread_spin_lock -- lock a spin lock. Generic version.
+ Copyright (C) 2012-2016 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 <atomic.h>
+#include "pthreadP.h"
+
+/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG
+ to the number of plain reads that it's optimal to spin on between uses
+ of atomic_compare_and_exchange_val_acq. If spinning forever is optimal
+ then use -1. If no plain reads here would ever be optimal, use 0. */
+#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ /* atomic_exchange usually takes less instructions than
+ atomic_compare_and_exchange. On the other hand,
+ atomic_compare_and_exchange potentially generates less bus traffic
+ when the lock is locked.
+ We assume that the first try mostly will be successful, and we use
+ atomic_exchange. For the subsequent tries we use
+ atomic_compare_and_exchange. */
+ if (atomic_exchange_acq (lock, 1) == 0)
+ return 0;
+
+ do
+ {
+ /* The lock is contended and we need to wait. Going straight back
+ to cmpxchg is not a good idea on many targets as that will force
+ expensive memory synchronizations among processors and penalize other
+ running threads.
+ On the other hand, we do want to update memory state on the local core
+ once in a while to avoid spinning indefinitely until some event that
+ will happen to update local memory as a side-effect. */
+ if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0)
+ {
+ int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG;
+
+ while (*lock != 0 && wait > 0)
+ --wait;
+ }
+ else
+ {
+ while (*lock != 0)
+ ;
+ }
+ }
+ while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0);
+
+ return 0;
+}
diff --git a/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c
new file mode 100644
index 000000000..4e9aa64d3
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c
@@ -0,0 +1,26 @@
+/* pthread_spin_trylock -- trylock a spin lock. Generic version.
+ Copyright (C) 2012-2016 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 <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ return atomic_exchange_acq (lock, 1) ? EBUSY : 0;
+}
diff --git a/libpthread/nptl/sysdeps/nds32/pthreaddef.h b/libpthread/nptl/sysdeps/nds32/pthreaddef.h
new file mode 100644
index 000000000..c9d3f7781
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/pthreaddef.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002, 2003 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/>. */
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. SSE requires 16
+ bytes. */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here. */
+#define __exit_thread_inline(val) \
+ INLINE_SYSCALL (exit, 1, (val))
+
+
diff --git a/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym b/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym
new file mode 100644
index 000000000..3b9e10186
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym
@@ -0,0 +1,12 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads)
+PID_OFFSET thread_offsetof (pid)
+TID_OFFSET thread_offsetof (tid)
+
diff --git a/libpthread/nptl/sysdeps/nds32/tls.h b/libpthread/nptl/sysdeps/nds32/tls.h
new file mode 100644
index 000000000..e2a38626d
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/tls.h
@@ -0,0 +1,178 @@
+/* Definition for thread-local data handling. NPTL/NDS32 version.
+ Copyright (C) 2005, 2007 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/>. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools. */
+#define HAVE_TLS_SUPPORT 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+#define HAVE___THREAD 1
+
+/* Signal that TLS support is available. */
+#define USE_TLS 1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks. */
+# define TLS_DTV_AT_TP 1
+
+/* We use the multiple_threads field in the pthread struct */
+#define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+/* Get the thread descriptor definition. */
+# include <../../descr.h>
+
+/* The stack_guard is accessed directly by GCC -fstack-protector code,
+ so it is a part of public ABI. The dtv and pointer_guard fields
+ are private. */
+typedef struct
+{
+ dtv_t *dtv;
+ void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB. */
+# define TLS_INIT_TCB_SIZE 0
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size of the TCB. */
+# define TLS_TCB_SIZE 0
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+
+
+/* This is the size we need before TCB - actually, it includes the TCB. */
+# define TLS_PRE_TCB_SIZE \
+ (sizeof (struct pthread) \
+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* Return the thread descriptor (tp) for the current thread. */
+register void *__thread_pointer __asm__ ("$r25");
+
+
+/* The thread pointer (in hardware register tp) points to the end of
+ the TCB. The pthread_descr structure is immediately in front of the TCB. */
+#ifndef TLS_TCB_OFFSET
+# define TLS_TCB_OFFSET 0
+#endif
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(tcbp, dtvp) \
+ (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer (tp). */
+# define TLS_INIT_TP(tcbp, secondcall) \
+ (__thread_pointer = (char *)(tcbp) + TLS_TCB_OFFSET, NULL)
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ (((tcbhead_t *) (__thread_pointer - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread. */
+# define THREAD_SELF \
+ ((struct pthread *) (__thread_pointer \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+# define DB_THREAD_SELF \
+ REGISTER (32, 32, 152, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) (descr->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ (descr->member[idx])
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM(descr, member, value) \
+ (descr->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ (descr->member[idx] = (value))
+
+
+/* l_tls_offset == 0 is perfectly valid on Tile, so we have to use some
+ different value to mean unset l_tls_offset. */
+# define NO_TLS_OFFSET -1
+
+/* Get and set the global scope generation counter in struct pthread. */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED 1
+#define THREAD_GSCOPE_FLAG_WAIT 2
+#define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res \
+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
+ THREAD_GSCOPE_FLAG_UNUSED); \
+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+ do \
+ { \
+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
+ atomic_write_barrier (); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
+
+
diff --git a/libpthread/nptl/sysdeps/nds32/tlsdesc.sym b/libpthread/nptl/sysdeps/nds32/tlsdesc.sym
new file mode 100644
index 000000000..4fa3adacf
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nds32/tlsdesc.sym
@@ -0,0 +1,17 @@
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#define dtv_offsetof(dtv) (long)(offsetof(tcbhead_t, dtv) - sizeof (tcbhead_t))
+DTV_OFFSET dtv_offsetof(dtv)
+
+TLSDESC_ARG offsetof(struct tlsdesc, argument.pointer)
+
+TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
+TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
+TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile
new file mode 100644
index 000000000..2caba11b7
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile
@@ -0,0 +1,9 @@
+# Makefile for uClibc-ng NPTL
+# Licensed under the LGPL v2.1 or later, 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/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch
new file mode 100644
index 000000000..3b8935ce5
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch
@@ -0,0 +1,12 @@
+# Makefile for uClibc-ng NPTL
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+libpthread_linux_arch_SSRC =
+libpthread_linux_arch_CSRC = pthread_once.c
+
+libc_linux_arch_CSRC = fork.c
+libc_linux_arch_SSRC = clone.S vfork.S
+libc_linux_arch_SSRC-OMIT = waitpid.S
+
+CFLAGS += $(SSP_ALL_CFLAGS)
+
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h
new file mode 100644
index 000000000..695a61fdd
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h
@@ -0,0 +1,177 @@
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned long int pthread_t;
+
+union pthread_attr_t
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+};
+#ifndef __have_pthread_attr_t
+typedef union pthread_attr_t pthread_attr_t;
+# define __have_pthread_attr_t 1
+#endif
+
+
+typedef struct __pthread_internal_slist
+{
+ struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ struct __pthread_mutex_s
+ {
+ int __lock;
+ unsigned int __count;
+ int __owner;
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+ unsigned int __nusers;
+ __extension__ union
+ {
+ int __spins;
+ __pthread_slist_t __list;
+ };
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __futex;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
+ void *__mutex;
+ unsigned int __nwaiters;
+ unsigned int __broadcast_seq;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned char __flags;
+ unsigned char __shared;
+ unsigned char __pad1;
+ unsigned char __pad2;
+ int __writer;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+ long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+#endif
+/* Extra attributes for the cleanup functions. */
+/*
+ FIXME, check this after gcc uprgrade.
+ #define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+ warning: '__regparm__' attribute directive ignored
+*/
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h
new file mode 100644
index 000000000..8ee77429a
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) 0)
+
+/* Maximum value the semaphore can have. */
+#define SEM_VALUE_MAX (2147483647)
+
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S
new file mode 100644
index 000000000..94b39fcf9
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S
@@ -0,0 +1,4 @@
+/* We want an #include_next, but we are the main source file.
+ So, #include ourselves and in that incarnation we can use #include_next. */
+# define RESET_PID
+# include <libc/sysdeps/linux/nds32/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c
new file mode 100644
index 000000000..486bc24f5
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 2005-2013 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/>. */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE ((void *) (pd) \
+ + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation. */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c
new file mode 100644
index 000000000..beb6cb0f7
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Phil Blundell <pb@nexus.co.uk>, 2005
+
+ 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 <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 5, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \
+ NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h
new file mode 100644
index 000000000..32b004486
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h
@@ -0,0 +1,323 @@
+/* Copyright (C) 2005-2013 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/>. */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_REQUEUE 3
+#define FUTEX_CMP_REQUEUE 4
+#define FUTEX_WAKE_OP 5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
+#define FUTEX_LOCK_PI 6
+#define FUTEX_UNLOCK_PI 7
+#define FUTEX_TRYLOCK_PI 8
+#define FUTEX_WAIT_BITSET 9
+#define FUTEX_WAKE_BITSET 10
+#define FUTEX_WAIT_REQUEUE_PI 11
+#define FUTEX_CMP_REQUEUE_PI 12
+#define FUTEX_PRIVATE_FLAG 128
+#define FUTEX_CLOCK_REALTIME 256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros. Yes, the
+ definition seems to be backwards. But it is not. The bit will be
+ reversed before passing to the system call. */
+#define LLL_PRIVATE 0
+#define LLL_SHARED FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private. */
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+# define __lll_private_flag(fl, private) \
+ ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+# define __lll_private_flag(fl, private) \
+ (__builtin_constant_p (private) \
+ ? ((private) == 0 \
+ ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
+ : (fl)) \
+ : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
+ & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+ lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAIT, private), \
+ (val), (timespec)); \
+ __ret; \
+ })
+
+#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ int __op = FUTEX_WAIT_BITSET | clockbit; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (__op, private), \
+ (val), (timespec), NULL /* Unused. */, \
+ FUTEX_BITSET_MATCH_ANY); \
+ __ret; \
+ })
+
+#define lll_futex_wake(futexp, nr, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAKE, private), \
+ (nr), 0); \
+ __ret; \
+ })
+
+#define lll_robust_dead(futexv, private) \
+ do \
+ { \
+ int *__futexp = &(futexv); \
+ atomic_or (__futexp, FUTEX_OWNER_DIED); \
+ lll_futex_wake (__futexp, 1, private); \
+ } \
+ while (0)
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+ (nr_wake), (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_WAKE_OP, private), \
+ (nr_wake), (nr_wake2), (futexp2), \
+ FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+/* Priority Inheritance support. */
+#define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \
+ lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private)
+
+#define lll_futex_timed_wait_requeue_pi(futexp, val, timespec, clockbit, \
+ mutex, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ int __op = FUTEX_WAIT_REQUEUE_PI | clockbit; \
+ \
+ INTERNAL_SYSCALL (futex, __err, 5, (futexp), \
+ __lll_private_flag (__op, private), \
+ (val), (timespec), mutex); \
+ })
+
+#define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\
+ (nr_wake), (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+
+#define lll_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
+
+#define lll_cond_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
+
+#define __lll_robust_trylock(futex, id) \
+ (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
+#define lll_robust_trylock(lock, id) \
+ __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, \
+ 1, 0), 0)) \
+ { \
+ if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
+ __lll_lock_wait_private (__futex); \
+ else \
+ __lll_lock_wait (__futex, private); \
+ } \
+ }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
+ 0), 0)) \
+ __val = __lll_robust_lock_wait (__futex, private); \
+ __val; \
+ })
+#define lll_robust_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), id, private)
+
+
+#define __lll_cond_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0)) \
+ __lll_lock_wait (__futex, private); \
+ }))
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+
+#define __lll_timedlock(futex, abstime, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0)) \
+ __val = __lll_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_timedlock(futex, abstime, private) \
+ __lll_timedlock (&(futex), abstime, private)
+
+
+#define __lll_robust_timedlock(futex, abstime, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
+ 0), 0)) \
+ __val = __lll_robust_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_robust_timedlock(futex, abstime, id, private) \
+ __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (__oldval > 1, 0)) \
+ lll_futex_wake (__futex, 1, private); \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (__oldval & FUTEX_WAITERS, 0)) \
+ lll_futex_wake (__futex, 1, private); \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_robust_unlock(futex, private) \
+ __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+ (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+ mutex implementation. */
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (0)
+#define LLL_LOCK_INITIALIZER_LOCKED (1)
+
+/* The states of a lock are:
+ 0 - untaken
+ 1 - taken by one user
+ >1 - taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
+ wakeup when the clone terminates. The memory location contains the
+ thread ID while the clone is running and is reset to zero
+ afterwards. */
+#define lll_wait_tid(tid) \
+ do { \
+ __typeof (tid) __tid; \
+ while ((__tid = (tid)) != 0) \
+ lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+ } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+ attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+ ({ \
+ int __res = 0; \
+ if ((tid) != 0) \
+ __res = __lll_timedwait_tid (&(tid), (abstime)); \
+ __res; \
+ })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c
new file mode 100644
index 000000000..6c0d4b5d3
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c
@@ -0,0 +1,18 @@
+/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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 <nptl/sysdeps/unix/sysv/linux/raise.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c
new file mode 100644
index 000000000..ce68ce68c
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2003-2013 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ 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 "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+ pthread_once_t *once_control = (pthread_once_t *) arg;
+
+ *once_control = 0;
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ while (1)
+ {
+ int oldval, val, newval;
+
+ val = *once_control;
+ do
+ {
+ /* Check if the initialized has already been done. */
+ if ((val & 2) != 0)
+ return 0;
+
+ oldval = val;
+ newval = (oldval & 3) | __fork_generation | 1;
+ val = atomic_compare_and_exchange_val_acq (once_control, newval,
+ oldval);
+ }
+ while (__builtin_expect (val != oldval, 0));
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) != 0)
+ {
+ /* Check whether the initializer execution was interrupted
+ by a fork. */
+ if (((oldval ^ newval) & -4) == 0)
+ {
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, newval, LLL_PRIVATE);
+ continue;
+ }
+ }
+
+ /* This thread is the first here. Do the initialization.
+ Register a cleanup handler so that in case the thread gets
+ interrupted the initialization can be restarted. */
+ pthread_cleanup_push (clear_once_control, once_control);
+
+ init_routine ();
+
+ pthread_cleanup_pop (0);
+
+
+ /* Add one to *once_control. */
+ atomic_increment (once_control);
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+ break;
+ }
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h
new file mode 100644
index 000000000..a0f4de5c8
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 2003-2013 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>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+
+
+#define PUSHARGS_0
+#define PUSHARGS_1 smw.adm $r0, [$sp], $r0, #0; \
+ cfi_adjust_cfa_offset(4); \
+ cfi_rel_offset(r0,0); \
+ addi $sp, $sp, -4; \
+ cfi_adjust_cfa_offset(4);
+#define PUSHARGS_2 smw.adm $r0, [$sp], $r1, #0; \
+ cfi_adjust_cfa_offset(8); \
+ cfi_rel_offset(r1, 4); \
+ cfi_rel_offset(r0, 0);
+#define PUSHARGS_3 smw.adm $r0, [$sp], $r2, #0; \
+ cfi_adjust_cfa_offset(12); \
+ cfi_rel_offset(r2, 8); \
+ cfi_rel_offset(r1, 4); \
+ cfi_rel_offset(r0, 0); \
+ addi $sp, $sp, -4; \
+ cfi_adjust_cfa_offset(4);
+#define PUSHARGS_4 smw.adm $r0, [$sp], $r3, #0; \
+ cfi_adjust_cfa_offset(16); \
+ cfi_rel_offset(r3, 12); \
+ cfi_rel_offset(r2, 8); \
+ cfi_rel_offset(r1, 4); \
+ cfi_rel_offset(r0, 0);
+#define PUSHARGS_5 smw.adm $r0, [$sp], $r4, #0; \
+ cfi_adjust_cfa_offset(20); \
+ cfi_rel_offset(r4, 16); \
+ cfi_rel_offset(r3, 12); \
+ cfi_rel_offset(r2, 8); \
+ cfi_rel_offset(r1, 4); \
+ cfi_rel_offset(r0, 0); \
+ addi $sp, $sp, -4; \
+ cfi_adjust_cfa_offset(4);
+#define PUSHARGS_6 smw.adm $r0, [$sp], $r5, #0; \
+ cfi_adjust_cfa_offset(24); \
+ cfi_rel_offset(r5, 20); \
+ cfi_rel_offset(r4, 16); \
+ cfi_rel_offset(r3, 12); \
+ cfi_rel_offset(r2, 8); \
+ cfi_rel_offset(r1, 4); \
+ cfi_rel_offset(r0, 0);
+
+#define POPARGS2_0
+#define POPARGS2_1 addi $sp, $sp, 4; \
+ cfi_adjust_cfa_offset(-4); \
+ lmw.bim $r0, [$sp], $r0, #0; \
+ cfi_adjust_cfa_offset(-4); \
+ cfi_restore(r0);
+#define POPARGS2_2 lmw.bim $r0, [$sp], $r1, #0; \
+ cfi_adjust_cfa_offset(-8); \
+ cfi_restore(r0); \
+ cfi_restore(r1);
+#define POPARGS2_3 addi $sp, $sp, 4; \
+ cfi_adjust_cfa_offset(-4); \
+ lmw.bim $r0, [$sp], $r2, #0; \
+ cfi_adjust_cfa_offset(-12); \
+ cfi_restore(r0); \
+ cfi_restore(r1); \
+ cfi_restore(r2);
+#define POPARGS2_4 lmw.bim $r0, [$sp], $r3, #0; \
+ cfi_adjust_cfa_offset(-16); \
+ cfi_restore(r0); \
+ cfi_restore(r1); \
+ cfi_restore(r2); \
+ cfi_restore(r3);
+#define POPARGS2_5 addi $sp, $sp, 4; \
+ cfi_adjust_cfa_offset(-4); \
+ lmw.bim $r0, [$sp], $r4, #0; \
+ cfi_adjust_cfa_offset(-20); \
+ cfi_restore(r0); \
+ cfi_restore(r1); \
+ cfi_restore(r2); \
+ cfi_restore(r3); \
+ cfi_restore(r4);
+#define POPARGS2_6 lmw.bim $r0, [$sp], $r5, #0; \
+ cfi_adjust_cfa_offset(-24); \
+ cfi_restore(r0); \
+ cfi_restore(r1); \
+ cfi_restore(r2); \
+ cfi_restore(r3); \
+ cfi_restore(r4); \
+ cfi_restore(r5);
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+/* NOTE: We do mark syscalls with unwind annotations, for the benefit of
+ cancellation; but they're really only accurate at the point of the
+ syscall. The ARM unwind directives are not rich enough without adding
+ a custom personality function. */
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+ .align 2; \
+ ENTRY (__##syscall_name##_nocancel); \
+ __do_syscall(syscall_name); \
+ PSEUDO_RET; \
+ ret; \
+ END (__##syscall_name##_nocancel); \
+ ENTRY (name); \
+ smw.adm $r6,[$sp],$r6,0x2; \
+ cfi_adjust_cfa_offset(8); \
+ cfi_offset(r6,-8); \
+ cfi_offset(lp,-4); \
+ SINGLE_THREAD_P ($r15); \
+ bgtz $r15, .Lpseudo_cancel; \
+ __do_syscall(syscall_name); \
+ j 50f; \
+ .Lpseudo_cancel: \
+ PUSHARGS_##args; /* save syscall args etc. around CENABLE. */ \
+ CENABLE ($r5); \
+ mov55 $r6, $r0; /* put mask in safe place. */ \
+ POPARGS2_##args; \
+ __do_syscall(syscall_name); /* do the call. */ \
+ push $r0; \
+ cfi_adjust_cfa_offset(4); \
+ cfi_rel_offset(r0, 0); \
+ addi $sp, $sp, -4; \
+ cfi_adjust_cfa_offset(4); \
+ mov55 $r0, $r6; /* save syscall return value. */\
+ CDISABLE($r5); \
+ addi $sp, $sp, 4; \
+ cfi_adjust_cfa_offset(-4); \
+ pop $r0; /* retrieve return value. */ \
+ cfi_adjust_cfa_offset(-4); \
+ cfi_restore(r0); \
+50: \
+ lmw.bim $r6,[$sp],$r6, 0x2; \
+ cfi_adjust_cfa_offset(-8); \
+ cfi_restore(lp); \
+ cfi_restore(r6); \
+ PSEUDO_RET;
+# ifndef __ASSEMBLER__
+//# if defined IS_IN_libpthread || !defined NOT_IN_libc
+//extern int __local_multiple_threads attribute_hidden;
+//# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
+//# else
+/* There is no __local_multiple_threads for librt */
+# define SINGLE_THREAD_P __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+//# endif
+# else
+# define SINGLE_THREAD_P(reg) \
+ addi reg, $r25, MULTIPLE_THREADS_OFFSET; \
+ lw reg, [reg];
+# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P(x)
+# endif
+
+
+# ifdef IS_IN_libpthread
+# define CENABLE(reg) jmp(reg, __pthread_enable_asynccancel)
+# define CDISABLE(reg) jmp(reg, __pthread_disable_asynccancel)
+# define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+# define CENABLE(reg) jmp(reg, __libc_enable_asynccancel)
+# define CDISABLE(reg) jmp(reg, __libc_disable_asynccancel)
+# define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+# define CENABLE(reg) jmp(reg, __librt_enable_asynccancel)
+# define CDISABLE(reg) jmp(reg, __librt_disable_asynccancel)
+# else
+# error Unsupported library
+# endif
+
+#elif !defined __ASSEMBLER__
+
+/* For rtld, et cetera. */
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+
+
+
+
+
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+#endif
+
+
+
+#ifdef PIC
+#define PSEUDO_RET \
+ .pic \
+ .align 2; \
+ bgez $r0, 1f; \
+ sltsi $r1, $r0, -4096; \
+ bgtz $r1, 1f; \
+ PIC_jmp_err \
+ nop; \
+ 1:
+#else /* PIC*/
+#define PSEUDO_RET \
+ .align 2; \
+ bgez $r0, 1f; \
+ sltsi $r1, $r0, -4096; \
+ bgtz $r1, 1f; \
+ j SYSCALL_ERROR; \
+ 1:
+#endif
+
+#ifdef PIC
+#define jmp(reg, symble) PIC_jmpr(reg, symble)
+/* reg: available register */
+#define PIC_jmp_err \
+ smw.adm $sp,[$sp],$sp,#0x6; \
+ mfusr $r15, $PC; \
+ sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
+ ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
+ add $gp, $r15, $gp; \
+ sethi $r15, hi20(SYSCALL_ERROR@PLT); \
+ ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \
+ add $r15, $r15, $gp; \
+ jral $r15; \
+ lmw.bim $sp,[$sp],$sp,#0x6; \
+ ret;
+
+#define PIC_jmp(reg, symble) \
+ mfusr $r15, $PC; \
+ sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
+ ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
+ add reg, $r15, reg; \
+ sethi $r15, hi20(symble@PLT); \
+ ori $r15, $r15, lo12(symble@PLT); \
+ add $r15, $r15, reg; \
+ jr $r15;
+
+
+#define PIC_jmpr(reg, symble) \
+ mfusr $r15, $PC; \
+ sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \
+ ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \
+ add reg, $r15, reg; \
+ sethi $r15, hi20(symble@PLT); \
+ ori $r15, $r15, lo12(symble@PLT); \
+ add $r15, $r15, reg; \
+ jral $r15;
+
+#else
+#define jmp(reg, symble) jal symble
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S
new file mode 100644
index 000000000..f11f76ae1
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016-2017 Andes Technology, Inc.
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* Copyright (C) 2013 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 <tls.h>
+
+/* Save the PID value. */
+#define SAVE_PID \
+ lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \
+ subri $r1, $r1, 0x0; /* Negate it. */ \
+ bnez $r1, 1f; /* If it was zero... */ \
+ sethi $r1, 0x80000; /* use 0x80000000 instead. */ \
+1: swi $r1, [$r25 + PID_OFFSET];/* Store the temporary PID. */
+
+/* Restore the old PID value in the parent. */
+#define RESTORE_PID \
+ beqz $r0, 1f; /* If we are the parent... */ \
+ lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \
+ subri $r1, $r1, 0x0; /* Re-negate it. */ \
+ sethi $r2, 0x80000; /* Load 0x80000000... */ \
+ bne $r1, $r2, 2f; /* ... compare against it... */ \
+ movi $r1, 0; /* ... use 0 instead. */ \
+2: swi $r1, [$r25 + PID_OFFSET];/* Restore the PID. */ \
+1:
+
+#include <../../../../../../../libc/sysdeps/linux/nds32/vfork.S>