about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--INSTALL7
-rw-r--r--VERSION2
-rw-r--r--WHATSNEW111
-rw-r--r--arch/aarch64/bits/syscall.h.in5
-rw-r--r--arch/arm/bits/syscall.h.in5
-rw-r--r--arch/arm/reloc.h2
-rw-r--r--arch/arm/syscall_arch.h7
-rw-r--r--arch/i386/bits/syscall.h.in6
-rw-r--r--arch/loongarch64/atomic_arch.h53
-rw-r--r--arch/loongarch64/bits/alltypes.h.in18
-rw-r--r--arch/loongarch64/bits/fenv.h20
-rw-r--r--arch/loongarch64/bits/float.h16
-rw-r--r--arch/loongarch64/bits/posix.h2
-rw-r--r--arch/loongarch64/bits/reg.h2
-rw-r--r--arch/loongarch64/bits/setjmp.h1
-rw-r--r--arch/loongarch64/bits/signal.h101
-rw-r--r--arch/loongarch64/bits/stat.h18
-rw-r--r--arch/loongarch64/bits/stdint.h20
-rw-r--r--arch/loongarch64/bits/syscall.h.in316
-rw-r--r--arch/loongarch64/bits/user.h24
-rw-r--r--arch/loongarch64/crt_arch.h13
-rw-r--r--arch/loongarch64/pthread_arch.h11
-rw-r--r--arch/loongarch64/reloc.h29
-rw-r--r--arch/loongarch64/syscall_arch.h137
-rw-r--r--arch/m68k/bits/syscall.h.in5
-rw-r--r--arch/microblaze/bits/signal.h1
-rw-r--r--arch/microblaze/bits/syscall.h.in5
-rw-r--r--arch/mips/bits/signal.h1
-rw-r--r--arch/mips/bits/syscall.h.in5
-rw-r--r--arch/mips/ksigaction.h5
-rw-r--r--arch/mips/reloc.h1
-rw-r--r--arch/mips64/bits/signal.h1
-rw-r--r--arch/mips64/bits/syscall.h.in5
-rw-r--r--arch/mips64/ksigaction.h2
-rw-r--r--arch/mips64/reloc.h1
-rw-r--r--arch/mipsn32/bits/signal.h1
-rw-r--r--arch/mipsn32/bits/syscall.h.in5
-rw-r--r--arch/mipsn32/ksigaction.h2
-rw-r--r--arch/mipsn32/reloc.h1
-rw-r--r--arch/or1k/bits/signal.h1
-rw-r--r--arch/or1k/bits/syscall.h.in5
-rw-r--r--arch/powerpc/bits/syscall.h.in5
-rw-r--r--arch/powerpc64/bits/syscall.h.in5
-rw-r--r--arch/riscv32/atomic_arch.h21
-rw-r--r--arch/riscv32/bits/alltypes.h.in18
-rw-r--r--arch/riscv32/bits/fenv.h17
-rw-r--r--arch/riscv32/bits/float.h16
-rw-r--r--arch/riscv32/bits/ipcstat.h1
-rw-r--r--arch/riscv32/bits/msg.h18
-rw-r--r--arch/riscv32/bits/posix.h2
-rw-r--r--arch/riscv32/bits/reg.h2
-rw-r--r--arch/riscv32/bits/sem.h18
-rw-r--r--arch/riscv32/bits/setjmp.h1
-rw-r--r--arch/riscv32/bits/shm.h31
-rw-r--r--arch/riscv32/bits/signal.h120
-rw-r--r--arch/riscv32/bits/stat.h18
-rw-r--r--arch/riscv32/bits/stdint.h20
-rw-r--r--arch/riscv32/bits/syscall.h.in300
-rw-r--r--arch/riscv32/bits/user.h6
-rw-r--r--arch/riscv32/crt_arch.h19
-rw-r--r--arch/riscv32/kstat.h0
-rw-r--r--arch/riscv32/pthread_arch.h13
-rw-r--r--arch/riscv32/reloc.h22
-rw-r--r--arch/riscv32/syscall_arch.h80
-rw-r--r--arch/riscv64/bits/signal.h3
-rw-r--r--arch/riscv64/bits/syscall.h.in5
-rw-r--r--arch/riscv64/reloc.h1
-rw-r--r--arch/s390x/bits/syscall.h.in6
-rw-r--r--arch/sh/bits/syscall.h.in5
-rw-r--r--arch/x32/bits/syscall.h.in6
-rw-r--r--arch/x86_64/bits/syscall.h.in6
-rw-r--r--compat/time32/__xstat.c8
-rw-r--r--compat/time32/aio_suspend_time32.c2
-rw-r--r--compat/time32/fstat_time32.c2
-rw-r--r--compat/time32/fstatat_time32.c2
-rw-r--r--compat/time32/lstat_time32.c2
-rw-r--r--compat/time32/stat_time32.c2
-rwxr-xr-xconfigure40
-rw-r--r--include/aio.h2
-rw-r--r--include/arpa/nameser.h71
-rw-r--r--include/dirent.h2
-rw-r--r--include/elf.h136
-rw-r--r--include/fcntl.h6
-rw-r--r--include/ftw.h2
-rw-r--r--include/glob.h2
-rw-r--r--include/netdb.h1
-rw-r--r--include/poll.h4
-rw-r--r--include/sched.h2
-rw-r--r--include/stdc-predef.h5
-rw-r--r--include/stdio.h2
-rw-r--r--include/stdlib.h4
-rw-r--r--include/string.h5
-rw-r--r--include/strings.h1
-rw-r--r--include/sys/mman.h2
-rw-r--r--include/sys/resource.h2
-rw-r--r--include/sys/sendfile.h2
-rw-r--r--include/sys/stat.h57
-rw-r--r--include/sys/statfs.h2
-rw-r--r--include/sys/statvfs.h5
-rw-r--r--include/sys/types.h2
-rw-r--r--include/sys/uio.h9
-rw-r--r--include/sys/wait.h2
-rw-r--r--include/unistd.h4
-rw-r--r--ldso/dlstart.c15
-rw-r--r--ldso/dynlink.c118
-rw-r--r--src/aio/aio.c32
-rw-r--r--src/aio/aio_suspend.c6
-rw-r--r--src/aio/lio_listio.c2
-rw-r--r--src/conf/sysconf.c13
-rw-r--r--src/dirent/alphasort.c2
-rw-r--r--src/dirent/readdir.c2
-rw-r--r--src/dirent/readdir_r.c2
-rw-r--r--src/dirent/scandir.c2
-rw-r--r--src/dirent/versionsort.c3
-rw-r--r--src/fcntl/creat.c2
-rw-r--r--src/fcntl/open.c2
-rw-r--r--src/fcntl/openat.c2
-rw-r--r--src/fcntl/posix_fadvise.c2
-rw-r--r--src/fcntl/posix_fallocate.c2
-rw-r--r--src/fenv/loongarch64/fenv.S78
-rw-r--r--src/fenv/riscv32/fenv-sf.c3
-rw-r--r--src/fenv/riscv32/fenv.S56
-rw-r--r--src/internal/atomic.h2
-rw-r--r--src/internal/dynlink.h10
-rw-r--r--src/internal/emulate_wait4.c55
-rw-r--r--src/internal/fork_impl.h4
-rw-r--r--src/internal/ksigaction.h5
-rw-r--r--src/internal/syscall.h18
-rw-r--r--src/ipc/semtimedop.c3
-rw-r--r--src/ldso/dlerror.c34
-rw-r--r--src/ldso/loongarch64/dlsym.s7
-rw-r--r--src/ldso/riscv32/dlsym.s6
-rw-r--r--src/ldso/riscv64/tlsdesc.s32
-rw-r--r--src/ldso/sh/dlsym.s2
-rw-r--r--src/legacy/ftw.c2
-rw-r--r--src/linux/cache.c3
-rw-r--r--src/linux/clone.c56
-rw-r--r--src/linux/epoll.c1
-rw-r--r--src/linux/fallocate.c3
-rw-r--r--src/linux/getdents.c2
-rw-r--r--src/linux/membarrier.c2
-rw-r--r--src/linux/preadv2.c17
-rw-r--r--src/linux/prlimit.c3
-rw-r--r--src/linux/pwritev2.c17
-rw-r--r--src/linux/sendfile.c2
-rw-r--r--src/linux/statx.c42
-rw-r--r--src/linux/wait4.c4
-rw-r--r--src/locale/iconv.c9
-rw-r--r--src/malloc/mallocng/free.c2
-rw-r--r--src/malloc/mallocng/glue.h2
-rw-r--r--src/math/acoshl.c10
-rw-r--r--src/math/logf.c2
-rw-r--r--src/math/powl.c34
-rw-r--r--src/math/riscv32/copysign.c15
-rw-r--r--src/math/riscv32/copysignf.c15
-rw-r--r--src/math/riscv32/fabs.c15
-rw-r--r--src/math/riscv32/fabsf.c15
-rw-r--r--src/math/riscv32/fma.c15
-rw-r--r--src/math/riscv32/fmaf.c15
-rw-r--r--src/math/riscv32/fmax.c15
-rw-r--r--src/math/riscv32/fmaxf.c15
-rw-r--r--src/math/riscv32/fmin.c15
-rw-r--r--src/math/riscv32/fminf.c15
-rw-r--r--src/math/riscv32/sqrt.c15
-rw-r--r--src/math/riscv32/sqrtf.c15
-rw-r--r--src/math/sqrtl.c4
-rw-r--r--src/misc/getopt.c3
-rw-r--r--src/misc/getrlimit.c2
-rw-r--r--src/misc/lockf.c2
-rw-r--r--src/misc/mntent.c46
-rw-r--r--src/misc/nftw.c6
-rw-r--r--src/misc/setrlimit.c2
-rw-r--r--src/misc/syslog.c3
-rw-r--r--src/mman/mmap.c2
-rw-r--r--src/mq/mq_notify.c47
-rw-r--r--src/multibyte/mbrtowc.c2
-rw-r--r--src/network/accept4.c4
-rw-r--r--src/network/dns_parse.c11
-rw-r--r--src/network/gai_strerror.c2
-rw-r--r--src/network/getaddrinfo.c7
-rw-r--r--src/network/gethostbyaddr.c2
-rw-r--r--src/network/gethostbyaddr_r.c5
-rw-r--r--src/network/gethostbyname2.c2
-rw-r--r--src/network/gethostbyname2_r.c6
-rw-r--r--src/network/getifaddrs.c14
-rw-r--r--src/network/getnameinfo.c9
-rw-r--r--src/network/getservbyport_r.c4
-rw-r--r--src/network/inet_pton.c1
-rw-r--r--src/network/lookup.h2
-rw-r--r--src/network/lookup_ipliteral.c4
-rw-r--r--src/network/lookup_name.c47
-rw-r--r--src/network/res_mkquery.c1
-rw-r--r--src/network/res_msend.c183
-rw-r--r--src/network/res_send.c10
-rw-r--r--src/network/sendmsg.c7
-rw-r--r--src/process/_Fork.c31
-rw-r--r--src/process/aarch64/vfork.s9
-rw-r--r--src/process/fork.c8
-rw-r--r--src/process/posix_spawn.c7
-rw-r--r--src/process/riscv64/vfork.s12
-rw-r--r--src/process/waitpid.c2
-rw-r--r--src/regex/glob.c5
-rw-r--r--src/search/hsearch.c4
-rw-r--r--src/select/poll.c9
-rw-r--r--src/select/ppoll.c (renamed from src/linux/ppoll.c)2
-rw-r--r--src/select/select.c1
-rw-r--r--src/setjmp/loongarch64/longjmp.S32
-rw-r--r--src/setjmp/loongarch64/setjmp.S34
-rw-r--r--src/setjmp/powerpc/longjmp.S8
-rw-r--r--src/setjmp/riscv32/longjmp.S42
-rw-r--r--src/setjmp/riscv32/setjmp.S41
-rw-r--r--src/signal/loongarch64/restore.s (renamed from src/signal/mips/restore.s)15
-rw-r--r--src/signal/loongarch64/sigsetjmp.s25
-rw-r--r--src/signal/mips64/restore.s11
-rw-r--r--src/signal/mipsn32/restore.s11
-rw-r--r--src/signal/riscv32/restore.s8
-rw-r--r--src/signal/riscv32/sigsetjmp.s23
-rw-r--r--src/signal/sh/sigsetjmp.s2
-rw-r--r--src/signal/sigaction.c5
-rw-r--r--src/stat/__xstat.c5
-rw-r--r--src/stat/fchmodat.c7
-rw-r--r--src/stat/fstat.c4
-rw-r--r--src/stat/fstatat.c5
-rw-r--r--src/stat/lstat.c4
-rw-r--r--src/stat/stat.c4
-rw-r--r--src/stat/statvfs.c6
-rw-r--r--src/stdio/fgetpos.c2
-rw-r--r--src/stdio/fgets.c5
-rw-r--r--src/stdio/fopen.c2
-rw-r--r--src/stdio/freopen.c4
-rw-r--r--src/stdio/fseek.c2
-rw-r--r--src/stdio/fsetpos.c2
-rw-r--r--src/stdio/ftell.c2
-rw-r--r--src/stdio/open_wmemstream.c6
-rw-r--r--src/stdio/pclose.c2
-rw-r--r--src/stdio/tmpfile.c2
-rw-r--r--src/stdio/vfprintf.c31
-rw-r--r--src/stdio/vfwprintf.c43
-rw-r--r--src/stdio/vsnprintf.c5
-rw-r--r--src/stdio/vswprintf.c4
-rw-r--r--src/string/strverscmp.c6
-rw-r--r--src/string/wcscmp.c2
-rw-r--r--src/string/wcsncmp.c2
-rw-r--r--src/string/wmemcmp.c2
-rw-r--r--src/temp/__randname.c3
-rw-r--r--src/temp/mkostemp.c2
-rw-r--r--src/temp/mkostemps.c1
-rw-r--r--src/temp/mkstemp.c2
-rw-r--r--src/temp/mkstemps.c2
-rw-r--r--src/thread/loongarch64/__set_thread_area.s7
-rw-r--r--src/thread/loongarch64/__unmapself.s7
-rw-r--r--src/thread/loongarch64/clone.s29
-rw-r--r--src/thread/loongarch64/syscall_cp.s29
-rw-r--r--src/thread/pthread_atfork.c8
-rw-r--r--src/thread/pthread_cancel.c9
-rw-r--r--src/thread/pthread_create.c16
-rw-r--r--src/thread/pthread_detach.c8
-rw-r--r--src/thread/pthread_key_create.c8
-rw-r--r--src/thread/riscv32/__set_thread_area.s6
-rw-r--r--src/thread/riscv32/__unmapself.s7
-rw-r--r--src/thread/riscv32/clone.s34
-rw-r--r--src/thread/riscv32/syscall_cp.s29
-rw-r--r--src/thread/sem_getvalue.c3
-rw-r--r--src/thread/sem_post.c12
-rw-r--r--src/thread/sem_timedwait.c10
-rw-r--r--src/thread/sem_trywait.c6
-rw-r--r--src/thread/synccall.c10
-rw-r--r--src/time/__year_to_secs.c4
-rw-r--r--src/time/clock_getcpuclockid.c1
-rw-r--r--src/time/clock_gettime.c3
-rw-r--r--src/time/strftime.c8
-rw-r--r--src/time/timer_create.c8
-rw-r--r--src/unistd/dup3.c6
-rw-r--r--src/unistd/faccessat.c2
-rw-r--r--src/unistd/ftruncate.c2
-rw-r--r--src/unistd/lseek.c1
-rw-r--r--src/unistd/mipsn32/lseek.c1
-rw-r--r--src/unistd/pipe2.c1
-rw-r--r--src/unistd/pread.c2
-rw-r--r--src/unistd/preadv.c2
-rw-r--r--src/unistd/pwrite.c2
-rw-r--r--src/unistd/pwritev.c2
-rw-r--r--src/unistd/setxid.c2
-rw-r--r--src/unistd/truncate.c2
-rw-r--r--src/unistd/x32/lseek.c1
-rwxr-xr-xtools/install.sh2
286 files changed, 3799 insertions, 510 deletions
diff --git a/INSTALL b/INSTALL
index c583691d..ddbbbb2f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -97,11 +97,16 @@ and ABI combinations:
 
 * OpenRISC 1000 (or1k)
 
-* RISC-V 64
+* RISC-V
+    * 32-bit and 64-bit
     * Little endian
     * Hard, soft, and hard-single/soft-double floating point ABIs
     * Standard ELF; no shared-text NOMMU support
 
+* LoongArch
+    * 64-bit ISA
+    * Hard, soft, and hard-single/soft-double floating point ABIs
+
 
 
 Build and Installation Procedure
diff --git a/VERSION b/VERSION
index 0495c4a8..c813fe11 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.3
+1.2.5
diff --git a/WHATSNEW b/WHATSNEW
index f9bb2482..7bd90728 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -2327,3 +2327,114 @@ bugs fixed:
 arch-specific bugs fixed:
 - powerpc (32-bit) struct shmid_ds layout was wrong for some fields
 - time64 struct layout was wrong in sound ioctl fallback (32-bit archs)
+
+
+
+1.2.4 release notes
+
+new features:
+- large dns record lookups via tcp fallback
+- new getaddrinfo EAI_NODATA result to distinguish NODATA/NxDomain
+- support for new RELR compressed format for relative relocations
+- sysconf keys for querying signal stack size requirements
+- real vfork on riscv64
+
+performance:
+- mallocng no longer uses MADV_FREE (high performance cost, little gain)
+- vdso clock_gettime is supported once again on 32-bit arm
+
+compatibility:
+- gethostbyname family now distinguishes NO_DATA from HOST_NOT_FOUND
+- res_send now works with caller-provided edns0 queries
+- arpa/nameser.h RR types list is now up-to-date
+- previously-missing POSIX confstr keys have been added
+- mntent interfaces now accept missing fields
+- alt signal stack, if any, is now used for internal signals
+- the LFS64 macros are no longer exposed without _LARGEFILE64_SOURCE
+- memmem (POSIX-future) is now exposed in default feature profile
+- pthread_atfork now admits calls from an application-provided malloc
+- debugger tracking of shared libraries now works on MIPS PIE binaries
+- sendmsg now supports up to SCM_MAX_FD fds in SCM_RIGHTS messages
+
+bugs fixed:
+- gethostbyname[2]_r wrongly returned nonzero (error) on negative result
+- parallel v4/v6 address queries could fail on query id collisions
+- spurious getaddrinfo/AI_ADDRCONFIG failures due to errno clobbering
+- dns search domains ending in dot (including lone dot) broke lookups
+- ipv6 servers in resolv.conf broke lookups on systems with v6 disabled
+- systems with bindv6only failed to query both v4 and v6 nameservers
+- res_mkquery mishandled consecutive final dots in name
+- res_send could malfunction for very small answer buffer sizes
+- resolver dns backend accepted answers with wrong (A vs AAAA) RR type
+- getservbyport_r returned junk or ENOENT (vs ERANGE) on buffer size errors
+- dns result parsing of malformed responses could process uninitialized data
+- freopen didn't reset stream orientation (byte/wide) & encoding rule
+- fwprintf didn't print most fields on open_wmemstream FILEs
+- wide printf %lc ignored field width
+- wide printf erroneously processed %n after encoding errors
+- use of wide printf %9$ argument slot overflowed undersized buffer
+- swprintf malfunctioned on nul character in output
+- strverscmp ordered digit sequences vs nondigits incorrectly
+- timer_create/SIGEV_THREAD failure leaked the thread
+- semaphores were subject to missed-wake under certain usage patterns
+- several possible rare deadlocks with lock handling at thread exit
+- several possible rare deadlocks with aio and multithreaded fork
+- dynamic linker relro processing was broken on archs w/variable pagesize
+- async cancellation could run cancellation handlers in invalid context
+- pthread_detach was wrongly a cancellation point in rare race code path
+- use-after-close/double-close errors in mq_notify error paths
+- mq_notify event thread wrongly ran with signals unmasked
+- wcs{,n}cmp, wmemcmp returned wrong results when difference overflowed
+- accept4, pipe2, and dup3 handled unknown flags wrong in fallback cases
+- CPU_SETSIZE macro had wrong unit
+- select fallback for pre-time64 kernels truncated timeout (vs clamping)
+
+arch-specific bugs fixed:
+- x32 new socketcalls took fallback path due to pointer sign extension
+- x32 wait4 didn't fill rusage structure (time64 regression)
+- x32 semtimedop mismatched timespec ABI with kernel (time64 regression)
+- sigaction signal mask was bogus on or1k, microblaze, mips, and riscv
+- powerpc-sf longjmp asm clobbered value argument
+- or1k poll function passed timeout to syscall in wrong form
+
+
+
+1.2.5 release notes
+
+new features:
+- statx function (linux extension; via syscall and fallback using fstatat)
+- clone function is now usable and gives _Fork-like consistency in child
+- statvfs now provides f_type result
+- preadv2 and pwritev2 (linux extension) syscall wrappers
+- riscv64 TLSDESC support
+
+new ports:
+- loongarch64
+- riscv32
+
+compatibility:
+- DNS resolver can now handle answers with long CNAME chains
+- string.h no longer provides (C23-incompat) non-prototype decl of basename
+- fstatat statx backend now matches stat syscall non-automounting behavior
+- mntent interfaces now handle escaped whitespace in paths/options
+
+standards updates:
+- printf %lc of nul wchar now produces output
+- snprintf and swprintf no longer fail on n > INT_MAX
+- ppoll is now exposed in default feature profile
+
+bugs fixed:
+- some long DNS answers were wrongly rejected despite new TCP support
+- glob could wrongly return GLOB_NOMATCH if aborted before any matches
+- multithreaded set*id could malfunction from thread sequencing logic bug
+- certain use of threads after fork could deadlock thread-list lock
+- posix_spawn child could deadlock in race with async parent death
+- mbrtowc return value was wrong if argument n exceeded UINT_MAX
+- 80-bit extended acoshl and powl got some corner cases wrong
+- syslog incorrectly generated localized timestamps
+
+arch-specific bugs fixed:
+- arm (32-bit) TLSDESC malfunctioned due to addends being processed wrong
+- riscv64 icache flush operation was non-functional
+- sh sigsetjmp failed to properly restore call-saved register r8 on return
+- sh dlsym RTLD_NEXT did not identify calling module correctly
diff --git a/arch/aarch64/bits/syscall.h.in b/arch/aarch64/bits/syscall.h.in
index 5f420e61..ea5a152a 100644
--- a/arch/aarch64/bits/syscall.h.in
+++ b/arch/aarch64/bits/syscall.h.in
@@ -299,4 +299,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/arm/bits/syscall.h.in b/arch/arm/bits/syscall.h.in
index 048fdea7..157b304d 100644
--- a/arch/arm/bits/syscall.h.in
+++ b/arch/arm/bits/syscall.h.in
@@ -399,6 +399,11 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
 #define __ARM_NR_breakpoint	0x0f0001
 #define __ARM_NR_cacheflush	0x0f0002
diff --git a/arch/arm/reloc.h b/arch/arm/reloc.h
index d091d2ad..d98eb8af 100644
--- a/arch/arm/reloc.h
+++ b/arch/arm/reloc.h
@@ -26,7 +26,7 @@
 #define REL_TPOFF       R_ARM_TLS_TPOFF32
 #define REL_TLSDESC     R_ARM_TLS_DESC
 
-#define TLSDESC_BACKWARDS
+#define TLSDESC_BACKWARDS 1
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
 	"mov sp,%1 ; bx %0" : : "r"(pc), "r"(sp) : "memory" )
diff --git a/arch/arm/syscall_arch.h b/arch/arm/syscall_arch.h
index a877b2cf..624e992e 100644
--- a/arch/arm/syscall_arch.h
+++ b/arch/arm/syscall_arch.h
@@ -101,3 +101,10 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
 #define SYSCALL_FADVISE_6_ARG
 
 #define SYSCALL_IPC_BROKEN_MODE
+
+#define VDSO_USEFUL
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
+#define VDSO_CGT_VER "LINUX_2.6"
+#define VDSO_CGT_WORKAROUND 1
diff --git a/arch/i386/bits/syscall.h.in b/arch/i386/bits/syscall.h.in
index 46ffe1d9..55e91cc4 100644
--- a/arch/i386/bits/syscall.h.in
+++ b/arch/i386/bits/syscall.h.in
@@ -436,4 +436,10 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_memfd_secret	447
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/loongarch64/atomic_arch.h b/arch/loongarch64/atomic_arch.h
new file mode 100644
index 00000000..2225d027
--- /dev/null
+++ b/arch/loongarch64/atomic_arch.h
@@ -0,0 +1,53 @@
+#define a_ll a_ll
+static inline int a_ll(volatile int *p)
+{
+	int v;
+	__asm__ __volatile__ (
+		"ll.w %0, %1"
+		: "=r"(v)
+		: "ZC"(*p));
+	return v;
+}
+
+#define a_sc a_sc
+static inline int a_sc(volatile int *p, int v)
+{
+	int r;
+	__asm__ __volatile__ (
+		"sc.w %0, %1"
+		: "=r"(r), "=ZC"(*p)
+		: "0"(v) : "memory");
+	return r;
+}
+
+#define a_ll_p a_ll_p
+static inline void *a_ll_p(volatile void *p)
+{
+	void *v;
+	__asm__ __volatile__ (
+		"ll.d %0, %1"
+		: "=r"(v)
+		: "ZC"(*(void *volatile *)p));
+	return v;
+}
+
+#define a_sc_p a_sc_p
+static inline int a_sc_p(volatile void *p, void *v)
+{
+	long r;
+	__asm__ __volatile__ (
+		"sc.d %0, %1"
+		: "=r"(r), "=ZC"(*(void *volatile *)p)
+		: "0"(v)
+		: "memory");
+	return r;
+}
+
+#define a_barrier a_barrier
+static inline void a_barrier()
+{
+	__asm__ __volatile__ ("dbar 0" : : : "memory");
+}
+
+#define a_pre_llsc  a_barrier
+#define a_post_llsc a_barrier
diff --git a/arch/loongarch64/bits/alltypes.h.in b/arch/loongarch64/bits/alltypes.h.in
new file mode 100644
index 00000000..d1807aca
--- /dev/null
+++ b/arch/loongarch64/bits/alltypes.h.in
@@ -0,0 +1,18 @@
+#define _Addr long
+#define _Int64 long
+#define _Reg long
+
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffffffffffL
+
+#ifndef __cplusplus
+TYPEDEF int wchar_t;
+#endif
+
+TYPEDEF float float_t;
+TYPEDEF double double_t;
+
+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
+
+TYPEDEF unsigned nlink_t;
+TYPEDEF int blksize_t;
diff --git a/arch/loongarch64/bits/fenv.h b/arch/loongarch64/bits/fenv.h
new file mode 100644
index 00000000..264cafb5
--- /dev/null
+++ b/arch/loongarch64/bits/fenv.h
@@ -0,0 +1,20 @@
+#define FE_INEXACT    0x010000
+#define FE_UNDERFLOW  0x020000
+#define FE_OVERFLOW   0x040000
+#define FE_DIVBYZERO  0x080000
+#define FE_INVALID    0x100000
+
+#define FE_ALL_EXCEPT 0x1F0000
+
+#define FE_TONEAREST  0x000
+#define FE_TOWARDZERO 0x100
+#define FE_UPWARD     0x200
+#define FE_DOWNWARD   0x300
+
+typedef unsigned fexcept_t;
+
+typedef struct {
+	unsigned __cw;
+} fenv_t;
+
+#define FE_DFL_ENV ((const fenv_t *) -1)
diff --git a/arch/loongarch64/bits/float.h b/arch/loongarch64/bits/float.h
new file mode 100644
index 00000000..719c7908
--- /dev/null
+++ b/arch/loongarch64/bits/float.h
@@ -0,0 +1,16 @@
+#define FLT_EVAL_METHOD 0
+
+#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L
+#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
+#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L
+#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L
+
+#define LDBL_MANT_DIG 113
+#define LDBL_MIN_EXP (-16381)
+#define LDBL_MAX_EXP 16384
+
+#define LDBL_DIG 33
+#define LDBL_MIN_10_EXP (-4931)
+#define LDBL_MAX_10_EXP 4932
+
+#define DECIMAL_DIG 36
diff --git a/arch/loongarch64/bits/posix.h b/arch/loongarch64/bits/posix.h
new file mode 100644
index 00000000..8068ce98
--- /dev/null
+++ b/arch/loongarch64/bits/posix.h
@@ -0,0 +1,2 @@
+#define _POSIX_V6_LP64_OFF64 1
+#define _POSIX_V7_LP64_OFF64 1
diff --git a/arch/loongarch64/bits/reg.h b/arch/loongarch64/bits/reg.h
new file mode 100644
index 00000000..2633f39d
--- /dev/null
+++ b/arch/loongarch64/bits/reg.h
@@ -0,0 +1,2 @@
+#undef __WORDSIZE
+#define __WORDSIZE 64
diff --git a/arch/loongarch64/bits/setjmp.h b/arch/loongarch64/bits/setjmp.h
new file mode 100644
index 00000000..3b15e87b
--- /dev/null
+++ b/arch/loongarch64/bits/setjmp.h
@@ -0,0 +1 @@
+typedef unsigned long __jmp_buf[23];
diff --git a/arch/loongarch64/bits/signal.h b/arch/loongarch64/bits/signal.h
new file mode 100644
index 00000000..5a9ed8c9
--- /dev/null
+++ b/arch/loongarch64/bits/signal.h
@@ -0,0 +1,101 @@
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+#define MINSIGSTKSZ 4096
+#define SIGSTKSZ 16384
+#endif
+
+#if defined(_GNU_SOURCE)
+#define LARCH_NGREG 32
+#define LARCH_REG_RA 1
+#define LARCH_REG_SP 3
+#define LARCH_REG_S0 23
+#define LARCH_REG_S1 24
+#define LARCH_REG_A0 4
+#define LARCH_REG_S2 25
+#define LARCH_REG_NARGS 8
+#endif
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+typedef unsigned long greg_t, gregset_t[32];
+
+struct sigcontext {
+	unsigned long sc_pc;
+	unsigned long sc_regs[32];
+	unsigned sc_flags;
+	unsigned long sc_extcontext[] __attribute__((__aligned__(16)));
+};
+#endif
+
+typedef struct {
+	unsigned long __pc;
+	unsigned long __gregs[32];
+	unsigned __flags;
+	unsigned long __extcontext[] __attribute__((__aligned__(16)));
+} mcontext_t;
+
+struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+};
+
+typedef struct __ucontext
+{
+	unsigned long uc_flags;
+	struct __ucontext *uc_link;
+	stack_t uc_stack;
+	sigset_t uc_sigmask;
+	long __uc_pad;
+	mcontext_t uc_mcontext;
+} ucontext_t;
+
+#define __uc_flags uc_flags
+
+#define SA_NOCLDSTOP 1
+#define SA_NOCLDWAIT 2
+#define SA_SIGINFO   4
+#define SA_ONSTACK   0x08000000
+#define SA_RESTART   0x10000000
+#define SA_NODEFER   0x40000000
+#define SA_RESETHAND 0x80000000
+
+#endif
+
+#define SIGHUP     1
+#define SIGINT     2
+#define SIGQUIT    3
+#define SIGILL     4
+#define SIGTRAP    5
+#define SIGABRT    6
+#define SIGIOT     SIGABRT
+#define SIGBUS     7
+#define SIGFPE     8
+#define SIGKILL    9
+#define SIGUSR1   10
+#define SIGSEGV   11
+#define SIGUSR2   12
+#define SIGPIPE   13
+#define SIGALRM   14
+#define SIGTERM   15
+#define SIGSTKFLT 16
+#define SIGCHLD   17
+#define SIGCONT   18
+#define SIGSTOP   19
+#define SIGTSTP   20
+#define SIGTTIN   21
+#define SIGTTOU   22
+#define SIGURG    23
+#define SIGXCPU   24
+#define SIGXFSZ   25
+#define SIGVTALRM 26
+#define SIGPROF   27
+#define SIGWINCH  28
+#define SIGIO     29
+#define SIGPOLL   SIGIO
+#define SIGPWR    30
+#define SIGSYS    31
+#define SIGUNUSED SIGSYS
+
+#define _NSIG 65
diff --git a/arch/loongarch64/bits/stat.h b/arch/loongarch64/bits/stat.h
new file mode 100644
index 00000000..b7f4221b
--- /dev/null
+++ b/arch/loongarch64/bits/stat.h
@@ -0,0 +1,18 @@
+struct stat {
+	dev_t st_dev;
+	ino_t st_ino;
+	mode_t st_mode;
+	nlink_t st_nlink;
+	uid_t st_uid;
+	gid_t st_gid;
+	dev_t st_rdev;
+	unsigned long __pad;
+	off_t st_size;
+	blksize_t st_blksize;
+	int __pad2;
+	blkcnt_t st_blocks;
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	unsigned __unused[2];
+};
diff --git a/arch/loongarch64/bits/stdint.h b/arch/loongarch64/bits/stdint.h
new file mode 100644
index 00000000..1bb147f2
--- /dev/null
+++ b/arch/loongarch64/bits/stdint.h
@@ -0,0 +1,20 @@
+typedef int32_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef uint32_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+
+#define INT_FAST16_MIN  INT32_MIN
+#define INT_FAST32_MIN  INT32_MIN
+
+#define INT_FAST16_MAX  INT32_MAX
+#define INT_FAST32_MAX  INT32_MAX
+
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN      INT64_MIN
+#define INTPTR_MAX      INT64_MAX
+#define UINTPTR_MAX     UINT64_MAX
+#define PTRDIFF_MIN     INT64_MIN
+#define PTRDIFF_MAX     INT64_MAX
+#define SIZE_MAX        UINT64_MAX
diff --git a/arch/loongarch64/bits/syscall.h.in b/arch/loongarch64/bits/syscall.h.in
new file mode 100644
index 00000000..2afb4ea1
--- /dev/null
+++ b/arch/loongarch64/bits/syscall.h.in
@@ -0,0 +1,316 @@
+#define __NR_io_setup                   0
+#define __NR_io_destroy                 1
+#define __NR_io_submit                  2
+#define __NR_io_cancel                  3
+#define __NR_io_getevents               4
+#define __NR_setxattr                   5
+#define __NR_lsetxattr                  6
+#define __NR_fsetxattr                  7
+#define __NR_getxattr                   8
+#define __NR_lgetxattr                  9
+#define __NR_fgetxattr                  10
+#define __NR_listxattr                  11
+#define __NR_llistxattr                 12
+#define __NR_flistxattr                 13
+#define __NR_removexattr                14
+#define __NR_lremovexattr               15
+#define __NR_fremovexattr               16
+#define __NR_getcwd                     17
+#define __NR_lookup_dcookie             18
+#define __NR_eventfd2                   19
+#define __NR_epoll_create1              20
+#define __NR_epoll_ctl                  21
+#define __NR_epoll_pwait                22
+#define __NR_dup                        23
+#define __NR_dup3                       24
+#define __NR3264_fcntl                  25
+#define __NR_inotify_init1              26
+#define __NR_inotify_add_watch          27
+#define __NR_inotify_rm_watch           28
+#define __NR_ioctl                      29
+#define __NR_ioprio_set                 30
+#define __NR_ioprio_get                 31
+#define __NR_flock                      32
+#define __NR_mknodat                    33
+#define __NR_mkdirat                    34
+#define __NR_unlinkat                   35
+#define __NR_symlinkat                  36
+#define __NR_linkat                     37
+#define __NR_umount2                    39
+#define __NR_mount                      40
+#define __NR_pivot_root                 41
+#define __NR_nfsservctl                 42
+#define __NR3264_statfs                 43
+#define __NR3264_fstatfs                44
+#define __NR3264_truncate               45
+#define __NR3264_ftruncate              46
+#define __NR_fallocate                  47
+#define __NR_faccessat                  48
+#define __NR_chdir                      49
+#define __NR_fchdir                     50
+#define __NR_chroot                     51
+#define __NR_fchmod                     52
+#define __NR_fchmodat                   53
+#define __NR_fchownat                   54
+#define __NR_fchown                     55
+#define __NR_openat                     56
+#define __NR_close                      57
+#define __NR_vhangup                    58
+#define __NR_pipe2                      59
+#define __NR_quotactl                   60
+#define __NR_getdents64                 61
+#define __NR3264_lseek                  62
+#define __NR_read                       63
+#define __NR_write                      64
+#define __NR_readv                      65
+#define __NR_writev                     66
+#define __NR_pread64                    67
+#define __NR_pwrite64                   68
+#define __NR_preadv                     69
+#define __NR_pwritev                    70
+#define __NR3264_sendfile               71
+#define __NR_pselect6                   72
+#define __NR_ppoll                      73
+#define __NR_signalfd4                  74
+#define __NR_vmsplice                   75
+#define __NR_splice                     76
+#define __NR_tee                        77
+#define __NR_readlinkat                 78
+#define __NR_sync                       81
+#define __NR_fsync                      82
+#define __NR_fdatasync                  83
+#define __NR_sync_file_range            84
+#define __NR_timerfd_create             85
+#define __NR_timerfd_settime            86
+#define __NR_timerfd_gettime            87
+#define __NR_utimensat                  88
+#define __NR_acct                       89
+#define __NR_capget                     90
+#define __NR_capset                     91
+#define __NR_personality                92
+#define __NR_exit                       93
+#define __NR_exit_group                 94
+#define __NR_waitid                     95
+#define __NR_set_tid_address            96
+#define __NR_unshare                    97
+#define __NR_futex                      98
+#define __NR_set_robust_list            99
+#define __NR_get_robust_list            100
+#define __NR_nanosleep                  101
+#define __NR_getitimer                  102
+#define __NR_setitimer                  103
+#define __NR_kexec_load                 104
+#define __NR_init_module                105
+#define __NR_delete_module              106
+#define __NR_timer_create               107
+#define __NR_timer_gettime              108
+#define __NR_timer_getoverrun           109
+#define __NR_timer_settime              110
+#define __NR_timer_delete               111
+#define __NR_clock_settime              112
+#define __NR_clock_gettime              113
+#define __NR_clock_getres               114
+#define __NR_clock_nanosleep            115
+#define __NR_syslog                     116
+#define __NR_ptrace                     117
+#define __NR_sched_setparam             118
+#define __NR_sched_setscheduler         119
+#define __NR_sched_getscheduler         120
+#define __NR_sched_getparam             121
+#define __NR_sched_setaffinity          122
+#define __NR_sched_getaffinity          123
+#define __NR_sched_yield                124
+#define __NR_sched_get_priority_max     125
+#define __NR_sched_get_priority_min     126
+#define __NR_sched_rr_get_interval      127
+#define __NR_restart_syscall            128
+#define __NR_kill                       129
+#define __NR_tkill                      130
+#define __NR_tgkill                     131
+#define __NR_sigaltstack                132
+#define __NR_rt_sigsuspend              133
+#define __NR_rt_sigaction               134
+#define __NR_rt_sigprocmask             135
+#define __NR_rt_sigpending              136
+#define __NR_rt_sigtimedwait            137
+#define __NR_rt_sigqueueinfo            138
+#define __NR_rt_sigreturn               139
+#define __NR_setpriority                140
+#define __NR_getpriority                141
+#define __NR_reboot                     142
+#define __NR_setregid                   143
+#define __NR_setgid                     144
+#define __NR_setreuid                   145
+#define __NR_setuid                     146
+#define __NR_setresuid                  147
+#define __NR_getresuid                  148
+#define __NR_setresgid                  149
+#define __NR_getresgid                  150
+#define __NR_setfsuid                   151
+#define __NR_setfsgid                   152
+#define __NR_times                      153
+#define __NR_setpgid                    154
+#define __NR_getpgid                    155
+#define __NR_getsid                     156
+#define __NR_setsid                     157
+#define __NR_getgroups                  158
+#define __NR_setgroups                  159
+#define __NR_uname                      160
+#define __NR_sethostname                161
+#define __NR_setdomainname              162
+#define __NR_getrusage                  165
+#define __NR_umask                      166
+#define __NR_prctl                      167
+#define __NR_getcpu                     168
+#define __NR_gettimeofday               169
+#define __NR_settimeofday               170
+#define __NR_adjtimex                   171
+#define __NR_getpid                     172
+#define __NR_getppid                    173
+#define __NR_getuid                     174
+#define __NR_geteuid                    175
+#define __NR_getgid                     176
+#define __NR_getegid                    177
+#define __NR_gettid                     178
+#define __NR_sysinfo                    179
+#define __NR_mq_open                    180
+#define __NR_mq_unlink                  181
+#define __NR_mq_timedsend               182
+#define __NR_mq_timedreceive            183
+#define __NR_mq_notify                  184
+#define __NR_mq_getsetattr              185
+#define __NR_msgget                     186
+#define __NR_msgctl                     187
+#define __NR_msgrcv                     188
+#define __NR_msgsnd                     189
+#define __NR_semget                     190
+#define __NR_semctl                     191
+#define __NR_semtimedop                 192
+#define __NR_semop                      193
+#define __NR_shmget                     194
+#define __NR_shmctl                     195
+#define __NR_shmat                      196
+#define __NR_shmdt                      197
+#define __NR_socket                     198
+#define __NR_socketpair                 199
+#define __NR_bind                       200
+#define __NR_listen                     201
+#define __NR_accept                     202
+#define __NR_connect                    203
+#define __NR_getsockname                204
+#define __NR_getpeername                205
+#define __NR_sendto                     206
+#define __NR_recvfrom                   207
+#define __NR_setsockopt                 208
+#define __NR_getsockopt                 209
+#define __NR_shutdown                   210
+#define __NR_sendmsg                    211
+#define __NR_recvmsg                    212
+#define __NR_readahead                  213
+#define __NR_brk                        214
+#define __NR_munmap                     215
+#define __NR_mremap                     216
+#define __NR_add_key                    217
+#define __NR_request_key                218
+#define __NR_keyctl                     219
+#define __NR_clone                      220
+#define __NR_execve                     221
+#define __NR3264_mmap                   222
+#define __NR3264_fadvise64              223
+#define __NR_swapon                     224
+#define __NR_swapoff                    225
+#define __NR_mprotect                   226
+#define __NR_msync                      227
+#define __NR_mlock                      228
+#define __NR_munlock                    229
+#define __NR_mlockall                   230
+#define __NR_munlockall                 231
+#define __NR_mincore                    232
+#define __NR_madvise                    233
+#define __NR_remap_file_pages           234
+#define __NR_mbind                      235
+#define __NR_get_mempolicy              236
+#define __NR_set_mempolicy              237
+#define __NR_migrate_pages              238
+#define __NR_move_pages                 239
+#define __NR_rt_tgsigqueueinfo          240
+#define __NR_perf_event_open            241
+#define __NR_accept4                    242
+#define __NR_recvmmsg                   243
+#define __NR_arch_specific_syscall      244
+#define __NR_wait4                      260
+#define __NR_prlimit64                  261
+#define __NR_fanotify_init              262
+#define __NR_fanotify_mark              263
+#define __NR_name_to_handle_at          264
+#define __NR_open_by_handle_at          265
+#define __NR_clock_adjtime              266
+#define __NR_syncfs                     267
+#define __NR_setns                      268
+#define __NR_sendmmsg                   269
+#define __NR_process_vm_readv           270
+#define __NR_process_vm_writev          271
+#define __NR_kcmp                       272
+#define __NR_finit_module               273
+#define __NR_sched_setattr              274
+#define __NR_sched_getattr              275
+#define __NR_renameat2                  276
+#define __NR_seccomp                    277
+#define __NR_getrandom                  278
+#define __NR_memfd_create               279
+#define __NR_bpf                        280
+#define __NR_execveat                   281
+#define __NR_userfaultfd                282
+#define __NR_membarrier                 283
+#define __NR_mlock2                     284
+#define __NR_copy_file_range            285
+#define __NR_preadv2                    286
+#define __NR_pwritev2                   287
+#define __NR_pkey_mprotect              288
+#define __NR_pkey_alloc                 289
+#define __NR_pkey_free                  290
+#define __NR_statx                      291
+#define __NR_io_pgetevents              292
+#define __NR_rseq                       293
+#define __NR_kexec_file_load            294
+#define __NR_pidfd_send_signal          424
+#define __NR_io_uring_setup             425
+#define __NR_io_uring_enter             426
+#define __NR_io_uring_register          427
+#define __NR_open_tree                  428
+#define __NR_move_mount                 429
+#define __NR_fsopen                     430
+#define __NR_fsconfig                   431
+#define __NR_fsmount                    432
+#define __NR_fspick                     433
+#define __NR_pidfd_open                 434
+#define __NR_clone3                     435
+#define __NR_close_range                436
+#define __NR_openat2                    437
+#define __NR_pidfd_getfd                438
+#define __NR_faccessat2                 439
+#define __NR_process_madvise            440
+#define __NR_epoll_pwait2               441
+#define __NR_mount_setattr              442
+#define __NR_quotactl_fd                443
+#define __NR_landlock_create_ruleset    444
+#define __NR_landlock_add_rule          445
+#define __NR_landlock_restrict_self     446
+#define __NR_process_mrelease           448
+#define __NR_futex_waitv                449
+#define __NR_set_mempolicy_home_node    450
+#define __NR_cachestat                  451
+#define __NR_fchmodat2                  452
+#define __NR_map_shadow_stack           453
+#define __NR_futex_wake                 454
+#define __NR_futex_wait                 455
+#define __NR_futex_requeue              456
+#define __NR_fcntl                      __NR3264_fcntl
+#define __NR_statfs                     __NR3264_statfs
+#define __NR_fstatfs                    __NR3264_fstatfs
+#define __NR_truncate                   __NR3264_truncate
+#define __NR_ftruncate                  __NR3264_ftruncate
+#define __NR_lseek                      __NR3264_lseek
+#define __NR_sendfile                   __NR3264_sendfile
+#define __NR_mmap                       __NR3264_mmap
+#define __NR_fadvise64                  __NR3264_fadvise64
diff --git a/arch/loongarch64/bits/user.h b/arch/loongarch64/bits/user.h
new file mode 100644
index 00000000..fd9b7b22
--- /dev/null
+++ b/arch/loongarch64/bits/user.h
@@ -0,0 +1,24 @@
+#define ELF_NGREG    45
+#define ELF_NFPREG   34
+
+struct user_regs_struct {
+	unsigned long regs[32];
+	unsigned long orig_a0;
+	unsigned long csr_era;
+	unsigned long csr_badv;
+	unsigned long reserved[10];
+};
+
+struct user_fp_struct {
+	unsigned long fpr[32];
+	unsigned long fcc;
+	unsigned int fcsr;
+};
+
+typedef unsigned long elf_greg_t, elf_gregset_t[ELF_NGREG];
+
+typedef union {
+	double d;
+	float f;
+} elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
diff --git a/arch/loongarch64/crt_arch.h b/arch/loongarch64/crt_arch.h
new file mode 100644
index 00000000..e0760d9e
--- /dev/null
+++ b/arch/loongarch64/crt_arch.h
@@ -0,0 +1,13 @@
+__asm__(
+".text \n"
+".global " START "\n"
+".type   " START ", @function\n"
+START ":\n"
+"	move $fp, $zero\n"
+"	move $a0, $sp\n"
+".weak _DYNAMIC\n"
+".hidden _DYNAMIC\n"
+"	la.local $a1, _DYNAMIC\n"
+"	bstrins.d $sp, $zero, 3, 0\n"
+"	b " START "_c\n"
+);
diff --git a/arch/loongarch64/pthread_arch.h b/arch/loongarch64/pthread_arch.h
new file mode 100644
index 00000000..365f6ca8
--- /dev/null
+++ b/arch/loongarch64/pthread_arch.h
@@ -0,0 +1,11 @@
+static inline uintptr_t __get_tp()
+{
+	register uintptr_t tp __asm__("tp");
+	__asm__ ("" : "=r" (tp) );
+	return tp;
+}
+
+#define TLS_ABOVE_TP
+#define GAP_ABOVE_TP   0
+#define DTP_OFFSET     0
+#define MC_PC          __pc
diff --git a/arch/loongarch64/reloc.h b/arch/loongarch64/reloc.h
new file mode 100644
index 00000000..61eaca9e
--- /dev/null
+++ b/arch/loongarch64/reloc.h
@@ -0,0 +1,29 @@
+#ifdef __loongarch_soft_float
+#define FP_SUFFIX "-sf"
+#elif defined __loongarch_single_float
+#define FP_SUFFIX "-sp"
+#else
+#define FP_SUFFIX ""
+#endif
+
+#define LDSO_ARCH "loongarch64" FP_SUFFIX
+
+#define TPOFF_K         0
+
+#define REL_PLT         R_LARCH_JUMP_SLOT
+#define REL_COPY        R_LARCH_COPY
+#define REL_DTPMOD      R_LARCH_TLS_DTPMOD64
+#define REL_DTPOFF      R_LARCH_TLS_DTPREL64
+#define REL_TPOFF       R_LARCH_TLS_TPREL64
+#define REL_RELATIVE    R_LARCH_RELATIVE
+#define REL_SYMBOLIC    R_LARCH_64
+
+#define CRTJMP(pc,sp) __asm__ __volatile__( \
+	"move $sp, %1 ; jr %0" : : "r"(pc), "r"(sp) : "memory" )
+
+#define GETFUNCSYM(fp, sym, got) __asm__ ( \
+	".hidden " #sym "\n" \
+	".align 8 \n" \
+	"	la.local $t1, "#sym" \n" \
+	"	move %0, $t1 \n" \
+	: "=r"(*(fp)) : : "memory" )
diff --git a/arch/loongarch64/syscall_arch.h b/arch/loongarch64/syscall_arch.h
new file mode 100644
index 00000000..4d5e1885
--- /dev/null
+++ b/arch/loongarch64/syscall_arch.h
@@ -0,0 +1,137 @@
+#define __SYSCALL_LL_E(x) (x)
+#define __SYSCALL_LL_O(x) (x)
+
+#define SYSCALL_CLOBBERLIST \
+	"$t0", "$t1", "$t2", "$t3", \
+	"$t4", "$t5", "$t6", "$t7", "$t8", "memory"
+
+static inline long __syscall0(long n)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0");
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "=r"(a0)
+		: "r"(a7)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall1(long n, long a)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+		: "r"(a7)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall2(long n, long a, long b)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall3(long n, long a, long b, long c)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+	register long a2 __asm__("$a2") = c;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1), "r"(a2)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall4(long n, long a, long b, long c, long d)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+	register long a2 __asm__("$a2") = c;
+	register long a3 __asm__("$a3") = d;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1), "r"(a2), "r"(a3)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall5(long n, long a, long b, long c, long d, long e)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+	register long a2 __asm__("$a2") = c;
+	register long a3 __asm__("$a3") = d;
+	register long a4 __asm__("$a4") = e;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+	register long a2 __asm__("$a2") = c;
+	register long a3 __asm__("$a3") = d;
+	register long a4 __asm__("$a4") = e;
+	register long a5 __asm__("$a5") = f;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+static inline long __syscall7(long n, long a, long b, long c, long d, long e, long f, long g)
+{
+	register long a7 __asm__("$a7") = n;
+	register long a0 __asm__("$a0") = a;
+	register long a1 __asm__("$a1") = b;
+	register long a2 __asm__("$a2") = c;
+	register long a3 __asm__("$a3") = d;
+	register long a4 __asm__("$a4") = e;
+	register long a5 __asm__("$a5") = f;
+	register long a6 __asm__("$a6") = g;
+
+	__asm__ __volatile__ (
+		"syscall 0"
+		: "+r"(a0)
+	        : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6)
+		: SYSCALL_CLOBBERLIST);
+	return a0;
+}
+
+#define VDSO_USEFUL
+#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT_VER "LINUX_5.10"
+
+#define IPC_64  0
diff --git a/arch/m68k/bits/syscall.h.in b/arch/m68k/bits/syscall.h.in
index a0c63323..5cd84602 100644
--- a/arch/m68k/bits/syscall.h.in
+++ b/arch/m68k/bits/syscall.h.in
@@ -416,3 +416,8 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
diff --git a/arch/microblaze/bits/signal.h b/arch/microblaze/bits/signal.h
index 490f83bf..f25b7c6a 100644
--- a/arch/microblaze/bits/signal.h
+++ b/arch/microblaze/bits/signal.h
@@ -46,7 +46,6 @@ typedef struct __ucontext {
 #define SA_RESTART    0x10000000
 #define SA_NODEFER    0x40000000
 #define SA_RESETHAND  0x80000000
-#define SA_RESTORER   0x04000000
 
 #endif
 
diff --git a/arch/microblaze/bits/syscall.h.in b/arch/microblaze/bits/syscall.h.in
index 931d7919..40860e6d 100644
--- a/arch/microblaze/bits/syscall.h.in
+++ b/arch/microblaze/bits/syscall.h.in
@@ -437,4 +437,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/mips/bits/signal.h b/arch/mips/bits/signal.h
index 1b69e762..a3b3857a 100644
--- a/arch/mips/bits/signal.h
+++ b/arch/mips/bits/signal.h
@@ -66,7 +66,6 @@ typedef struct __ucontext {
 #define SA_RESTART    0x10000000
 #define SA_NODEFER    0x40000000
 #define SA_RESETHAND  0x80000000
-#define SA_RESTORER   0x04000000
 
 #undef SIG_BLOCK
 #undef SIG_UNBLOCK
diff --git a/arch/mips/bits/syscall.h.in b/arch/mips/bits/syscall.h.in
index 63e3503a..55e35742 100644
--- a/arch/mips/bits/syscall.h.in
+++ b/arch/mips/bits/syscall.h.in
@@ -418,4 +418,9 @@
 #define __NR_landlock_create_ruleset	4444
 #define __NR_landlock_add_rule	4445
 #define __NR_landlock_restrict_self	4446
+#define __NR_process_mrelease	4448
+#define __NR_futex_waitv	4449
+#define __NR_set_mempolicy_home_node	4450
+#define __NR_cachestat		4451
+#define __NR_fchmodat2		4452
 
diff --git a/arch/mips/ksigaction.h b/arch/mips/ksigaction.h
index 63fdfab0..485abf75 100644
--- a/arch/mips/ksigaction.h
+++ b/arch/mips/ksigaction.h
@@ -4,10 +4,7 @@ struct k_sigaction {
 	unsigned flags;
 	void (*handler)(int);
 	unsigned long mask[4];
-	/* The following field is past the end of the structure the
-	 * kernel will read or write, and exists only to avoid having
-	 * mips-specific preprocessor conditionals in sigaction.c. */
-	void (*restorer)();
+	void *unused;
 };
 
 hidden void __restore(), __restore_rt();
diff --git a/arch/mips/reloc.h b/arch/mips/reloc.h
index 88d23639..f4023b16 100644
--- a/arch/mips/reloc.h
+++ b/arch/mips/reloc.h
@@ -29,6 +29,7 @@
 
 #define NEED_MIPS_GOT_RELOCS 1
 #define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
 #define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/mips64/bits/signal.h b/arch/mips64/bits/signal.h
index 4f91c9fc..ffec7fd0 100644
--- a/arch/mips64/bits/signal.h
+++ b/arch/mips64/bits/signal.h
@@ -85,7 +85,6 @@ typedef struct __ucontext {
 #define SA_RESTART    0x10000000
 #define SA_NODEFER    0x40000000
 #define SA_RESETHAND  0x80000000
-#define SA_RESTORER   0x04000000
 
 #undef SIG_BLOCK
 #undef SIG_UNBLOCK
diff --git a/arch/mips64/bits/syscall.h.in b/arch/mips64/bits/syscall.h.in
index b89965d1..50cec45a 100644
--- a/arch/mips64/bits/syscall.h.in
+++ b/arch/mips64/bits/syscall.h.in
@@ -348,4 +348,9 @@
 #define __NR_landlock_create_ruleset	5444
 #define __NR_landlock_add_rule	5445
 #define __NR_landlock_restrict_self	5446
+#define __NR_process_mrelease	5448
+#define __NR_futex_waitv	5449
+#define __NR_set_mempolicy_home_node	5450
+#define __NR_cachestat		5451
+#define __NR_fchmodat2		5452
 
diff --git a/arch/mips64/ksigaction.h b/arch/mips64/ksigaction.h
index c16e4731..b4d0fa5f 100644
--- a/arch/mips64/ksigaction.h
+++ b/arch/mips64/ksigaction.h
@@ -4,7 +4,7 @@ struct k_sigaction {
 	unsigned flags;
 	void (*handler)(int);
 	unsigned long mask[2];
-	void (*restorer)();
+	void *unused;
 };
 
 hidden void __restore(), __restore_rt();
diff --git a/arch/mips64/reloc.h b/arch/mips64/reloc.h
index fdb5edc9..145d8b0b 100644
--- a/arch/mips64/reloc.h
+++ b/arch/mips64/reloc.h
@@ -38,6 +38,7 @@
 
 #define NEED_MIPS_GOT_RELOCS 1
 #define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
 #define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/mipsn32/bits/signal.h b/arch/mipsn32/bits/signal.h
index 4f91c9fc..ffec7fd0 100644
--- a/arch/mipsn32/bits/signal.h
+++ b/arch/mipsn32/bits/signal.h
@@ -85,7 +85,6 @@ typedef struct __ucontext {
 #define SA_RESTART    0x10000000
 #define SA_NODEFER    0x40000000
 #define SA_RESETHAND  0x80000000
-#define SA_RESTORER   0x04000000
 
 #undef SIG_BLOCK
 #undef SIG_UNBLOCK
diff --git a/arch/mipsn32/bits/syscall.h.in b/arch/mipsn32/bits/syscall.h.in
index bb2d04a8..9a4bd301 100644
--- a/arch/mipsn32/bits/syscall.h.in
+++ b/arch/mipsn32/bits/syscall.h.in
@@ -372,4 +372,9 @@
 #define __NR_landlock_create_ruleset	6444
 #define __NR_landlock_add_rule	6445
 #define __NR_landlock_restrict_self	6446
+#define __NR_process_mrelease	6448
+#define __NR_futex_waitv	6449
+#define __NR_set_mempolicy_home_node	6450
+#define __NR_cachestat		6451
+#define __NR_fchmodat2		6452
 
diff --git a/arch/mipsn32/ksigaction.h b/arch/mipsn32/ksigaction.h
index b565f1fc..485abf75 100644
--- a/arch/mipsn32/ksigaction.h
+++ b/arch/mipsn32/ksigaction.h
@@ -4,7 +4,7 @@ struct k_sigaction {
 	unsigned flags;
 	void (*handler)(int);
 	unsigned long mask[4];
-	void (*restorer)();
+	void *unused;
 };
 
 hidden void __restore(), __restore_rt();
diff --git a/arch/mipsn32/reloc.h b/arch/mipsn32/reloc.h
index 47c6e591..bf00bd6a 100644
--- a/arch/mipsn32/reloc.h
+++ b/arch/mipsn32/reloc.h
@@ -29,6 +29,7 @@
 
 #define NEED_MIPS_GOT_RELOCS 1
 #define DT_DEBUG_INDIRECT DT_MIPS_RLD_MAP
+#define DT_DEBUG_INDIRECT_REL DT_MIPS_RLD_MAP_REL
 #define ARCH_SYM_REJECT_UND(s) (!((s)->st_other & STO_MIPS_PLT))
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
diff --git a/arch/or1k/bits/signal.h b/arch/or1k/bits/signal.h
index be576d1d..c45be676 100644
--- a/arch/or1k/bits/signal.h
+++ b/arch/or1k/bits/signal.h
@@ -43,7 +43,6 @@ typedef struct __ucontext {
 #define SA_RESTART    0x10000000
 #define SA_NODEFER    0x40000000
 #define SA_RESETHAND  0x80000000
-#define SA_RESTORER   0x04000000
 
 #endif
 
diff --git a/arch/or1k/bits/syscall.h.in b/arch/or1k/bits/syscall.h.in
index 2b5f2052..00812bf8 100644
--- a/arch/or1k/bits/syscall.h.in
+++ b/arch/or1k/bits/syscall.h.in
@@ -321,4 +321,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/powerpc/bits/syscall.h.in b/arch/powerpc/bits/syscall.h.in
index b1605a58..ea95f3ed 100644
--- a/arch/powerpc/bits/syscall.h.in
+++ b/arch/powerpc/bits/syscall.h.in
@@ -425,4 +425,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/powerpc64/bits/syscall.h.in b/arch/powerpc64/bits/syscall.h.in
index b3a8fba0..43551079 100644
--- a/arch/powerpc64/bits/syscall.h.in
+++ b/arch/powerpc64/bits/syscall.h.in
@@ -397,4 +397,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/riscv32/atomic_arch.h b/arch/riscv32/atomic_arch.h
new file mode 100644
index 00000000..4d418f63
--- /dev/null
+++ b/arch/riscv32/atomic_arch.h
@@ -0,0 +1,21 @@
+#define a_barrier a_barrier
+static inline void a_barrier()
+{
+	__asm__ __volatile__ ("fence rw,rw" : : : "memory");
+}
+
+#define a_cas a_cas
+static inline int a_cas(volatile int *p, int t, int s)
+{
+	int old, tmp;
+	__asm__ __volatile__ (
+		"\n1:	lr.w.aqrl %0, (%2)\n"
+		"	bne %0, %3, 1f\n"
+		"	sc.w.aqrl %1, %4, (%2)\n"
+		"	bnez %1, 1b\n"
+		"1:"
+		: "=&r"(old), "=&r"(tmp)
+		: "r"(p), "r"((long)t), "r"((long)s)
+		: "memory");
+	return old;
+}
diff --git a/arch/riscv32/bits/alltypes.h.in b/arch/riscv32/bits/alltypes.h.in
new file mode 100644
index 00000000..e2b6129e
--- /dev/null
+++ b/arch/riscv32/bits/alltypes.h.in
@@ -0,0 +1,18 @@
+#define _Addr int
+#define _Int64 long long
+#define _Reg int
+
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffL
+
+#ifndef __cplusplus
+TYPEDEF int wchar_t;
+#endif
+
+TYPEDEF int blksize_t;
+TYPEDEF unsigned int nlink_t;
+
+TYPEDEF float float_t;
+TYPEDEF double double_t;
+
+TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
diff --git a/arch/riscv32/bits/fenv.h b/arch/riscv32/bits/fenv.h
new file mode 100644
index 00000000..806ec40f
--- /dev/null
+++ b/arch/riscv32/bits/fenv.h
@@ -0,0 +1,17 @@
+#define FE_INVALID      16
+#define FE_DIVBYZERO    8
+#define FE_OVERFLOW     4
+#define FE_UNDERFLOW    2
+#define FE_INEXACT      1
+
+#define FE_ALL_EXCEPT   31
+
+#define FE_TONEAREST    0
+#define FE_DOWNWARD     2
+#define FE_UPWARD       3
+#define FE_TOWARDZERO   1
+
+typedef unsigned int fexcept_t;
+typedef unsigned int fenv_t;
+
+#define FE_DFL_ENV      ((const fenv_t *) -1)
diff --git a/arch/riscv32/bits/float.h b/arch/riscv32/bits/float.h
new file mode 100644
index 00000000..719c7908
--- /dev/null
+++ b/arch/riscv32/bits/float.h
@@ -0,0 +1,16 @@
+#define FLT_EVAL_METHOD 0
+
+#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L
+#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
+#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L
+#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L
+
+#define LDBL_MANT_DIG 113
+#define LDBL_MIN_EXP (-16381)
+#define LDBL_MAX_EXP 16384
+
+#define LDBL_DIG 33
+#define LDBL_MIN_10_EXP (-4931)
+#define LDBL_MAX_10_EXP 4932
+
+#define DECIMAL_DIG 36
diff --git a/arch/riscv32/bits/ipcstat.h b/arch/riscv32/bits/ipcstat.h
new file mode 100644
index 00000000..4f4fcb0c
--- /dev/null
+++ b/arch/riscv32/bits/ipcstat.h
@@ -0,0 +1 @@
+#define IPC_STAT 0x102
diff --git a/arch/riscv32/bits/msg.h b/arch/riscv32/bits/msg.h
new file mode 100644
index 00000000..7bbbb2bf
--- /dev/null
+++ b/arch/riscv32/bits/msg.h
@@ -0,0 +1,18 @@
+struct msqid_ds {
+	struct ipc_perm msg_perm;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
+	unsigned long msg_cbytes;
+	msgqnum_t msg_qnum;
+	msglen_t msg_qbytes;
+	pid_t msg_lspid;
+	pid_t msg_lrpid;
+	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
+};
diff --git a/arch/riscv32/bits/posix.h b/arch/riscv32/bits/posix.h
new file mode 100644
index 00000000..8897d37d
--- /dev/null
+++ b/arch/riscv32/bits/posix.h
@@ -0,0 +1,2 @@
+#define _POSIX_V6_ILP32_OFFBIG 1
+#define _POSIX_V7_ILP32_OFFBIG 1
diff --git a/arch/riscv32/bits/reg.h b/arch/riscv32/bits/reg.h
new file mode 100644
index 00000000..0192a293
--- /dev/null
+++ b/arch/riscv32/bits/reg.h
@@ -0,0 +1,2 @@
+#undef __WORDSIZE
+#define __WORDSIZE 32
diff --git a/arch/riscv32/bits/sem.h b/arch/riscv32/bits/sem.h
new file mode 100644
index 00000000..544e3d2a
--- /dev/null
+++ b/arch/riscv32/bits/sem.h
@@ -0,0 +1,18 @@
+struct semid_ds {
+	struct ipc_perm sem_perm;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	unsigned short sem_nsems;
+	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+#else
+	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+	unsigned short sem_nsems;
+#endif
+	long __unused3;
+	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
+};
diff --git a/arch/riscv32/bits/setjmp.h b/arch/riscv32/bits/setjmp.h
new file mode 100644
index 00000000..51e96276
--- /dev/null
+++ b/arch/riscv32/bits/setjmp.h
@@ -0,0 +1 @@
+typedef unsigned long long __jmp_buf[19];
diff --git a/arch/riscv32/bits/shm.h b/arch/riscv32/bits/shm.h
new file mode 100644
index 00000000..725fb469
--- /dev/null
+++ b/arch/riscv32/bits/shm.h
@@ -0,0 +1,31 @@
+#define SHMLBA 4096
+
+struct shmid_ds {
+	struct ipc_perm shm_perm;
+	size_t shm_segsz;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
+	pid_t shm_cpid;
+	pid_t shm_lpid;
+	unsigned long shm_nattch;
+	unsigned long __pad1;
+	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
+};
+
+struct shminfo {
+	unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4];
+};
+
+struct shm_info {
+	int __used_ids;
+	unsigned long shm_tot, shm_rss, shm_swp;
+	unsigned long __swap_attempts, __swap_successes;
+};
diff --git a/arch/riscv32/bits/signal.h b/arch/riscv32/bits/signal.h
new file mode 100644
index 00000000..271e7da6
--- /dev/null
+++ b/arch/riscv32/bits/signal.h
@@ -0,0 +1,120 @@
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+# define MINSIGSTKSZ 2048
+# define SIGSTKSZ 8192
+#endif
+
+typedef unsigned long __riscv_mc_gp_state[32];
+
+struct __riscv_mc_f_ext_state {
+	unsigned int __f[32];
+	unsigned int __fcsr;
+};
+
+struct __riscv_mc_d_ext_state {
+	unsigned long long __f[32];
+	unsigned int __fcsr;
+};
+
+struct __riscv_mc_q_ext_state {
+	unsigned long long __f[64] __attribute__((aligned(16)));
+	unsigned int __fcsr;
+	unsigned int __reserved[3];
+};
+
+union __riscv_mc_fp_state {
+	struct __riscv_mc_f_ext_state __f;
+	struct __riscv_mc_d_ext_state __d;
+	struct __riscv_mc_q_ext_state __q;
+};
+
+typedef struct mcontext_t {
+	__riscv_mc_gp_state __gregs;
+	union __riscv_mc_fp_state __fpregs;
+} mcontext_t;
+
+#if defined(_GNU_SOURCE)
+#define REG_PC 0
+#define REG_RA 1
+#define REG_SP 2
+#define REG_TP 4
+#define REG_S0 8
+#define REG_S1 9
+#define REG_A0 10
+#define REG_S2 18
+#endif
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+typedef unsigned long greg_t;
+typedef unsigned long gregset_t[32];
+typedef union __riscv_mc_fp_state fpregset_t;
+struct sigcontext {
+	gregset_t gregs;
+	fpregset_t fpregs;
+};
+#endif
+
+struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+};
+
+typedef struct __ucontext
+{
+	unsigned long uc_flags;
+	struct __ucontext *uc_link;
+	stack_t uc_stack;
+	sigset_t uc_sigmask;
+	mcontext_t uc_mcontext;
+} ucontext_t;
+
+#define SA_NOCLDSTOP 1
+#define SA_NOCLDWAIT 2
+#define SA_SIGINFO   4
+#define SA_ONSTACK   0x08000000
+#define SA_RESTART   0x10000000
+#define SA_NODEFER   0x40000000
+#define SA_RESETHAND 0x80000000
+#define SA_RESTORER  0x04000000
+
+#endif
+
+#define SIGHUP     1
+#define SIGINT     2
+#define SIGQUIT    3
+#define SIGILL     4
+#define SIGTRAP    5
+#define SIGABRT    6
+#define SIGIOT     SIGABRT
+#define SIGBUS     7
+#define SIGFPE     8
+#define SIGKILL    9
+#define SIGUSR1   10
+#define SIGSEGV   11
+#define SIGUSR2   12
+#define SIGPIPE   13
+#define SIGALRM   14
+#define SIGTERM   15
+#define SIGSTKFLT 16
+#define SIGCHLD   17
+#define SIGCONT   18
+#define SIGSTOP   19
+#define SIGTSTP   20
+#define SIGTTIN   21
+#define SIGTTOU   22
+#define SIGURG    23
+#define SIGXCPU   24
+#define SIGXFSZ   25
+#define SIGVTALRM 26
+#define SIGPROF   27
+#define SIGWINCH  28
+#define SIGIO     29
+#define SIGPOLL   SIGIO
+#define SIGPWR    30
+#define SIGSYS    31
+#define SIGUNUSED SIGSYS
+
+#define _NSIG     65
diff --git a/arch/riscv32/bits/stat.h b/arch/riscv32/bits/stat.h
new file mode 100644
index 00000000..f6d9e864
--- /dev/null
+++ b/arch/riscv32/bits/stat.h
@@ -0,0 +1,18 @@
+struct stat {
+	dev_t st_dev;
+	ino_t st_ino;
+	mode_t st_mode;
+	nlink_t st_nlink;
+	uid_t st_uid;
+	gid_t st_gid;
+	dev_t st_rdev;
+	unsigned long long __pad;
+	off_t st_size;
+	blksize_t st_blksize;
+	int __pad2;
+	blkcnt_t st_blocks;
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	unsigned __unused[2];
+};
diff --git a/arch/riscv32/bits/stdint.h b/arch/riscv32/bits/stdint.h
new file mode 100644
index 00000000..d1b27121
--- /dev/null
+++ b/arch/riscv32/bits/stdint.h
@@ -0,0 +1,20 @@
+typedef int32_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef uint32_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+
+#define INT_FAST16_MIN  INT32_MIN
+#define INT_FAST32_MIN  INT32_MIN
+
+#define INT_FAST16_MAX  INT32_MAX
+#define INT_FAST32_MAX  INT32_MAX
+
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN      INT32_MIN
+#define INTPTR_MAX      INT32_MAX
+#define UINTPTR_MAX     UINT32_MAX
+#define PTRDIFF_MIN     INT32_MIN
+#define PTRDIFF_MAX     INT32_MAX
+#define SIZE_MAX        UINT32_MAX
diff --git a/arch/riscv32/bits/syscall.h.in b/arch/riscv32/bits/syscall.h.in
new file mode 100644
index 00000000..9228d840
--- /dev/null
+++ b/arch/riscv32/bits/syscall.h.in
@@ -0,0 +1,300 @@
+#define __NR_io_setup 0
+#define __NR_io_destroy 1
+#define __NR_io_submit 2
+#define __NR_io_cancel 3
+#define __NR_setxattr 5
+#define __NR_lsetxattr 6
+#define __NR_fsetxattr 7
+#define __NR_getxattr 8
+#define __NR_lgetxattr 9
+#define __NR_fgetxattr 10
+#define __NR_listxattr 11
+#define __NR_llistxattr 12
+#define __NR_flistxattr 13
+#define __NR_removexattr 14
+#define __NR_lremovexattr 15
+#define __NR_fremovexattr 16
+#define __NR_getcwd 17
+#define __NR_lookup_dcookie 18
+#define __NR_eventfd2 19
+#define __NR_epoll_create1 20
+#define __NR_epoll_ctl 21
+#define __NR_epoll_pwait 22
+#define __NR_dup 23
+#define __NR_dup3 24
+#define __NR_fcntl64 25
+#define __NR_inotify_init1 26
+#define __NR_inotify_add_watch 27
+#define __NR_inotify_rm_watch 28
+#define __NR_ioctl 29
+#define __NR_ioprio_set 30
+#define __NR_ioprio_get 31
+#define __NR_flock 32
+#define __NR_mknodat 33
+#define __NR_mkdirat 34
+#define __NR_unlinkat 35
+#define __NR_symlinkat 36
+#define __NR_linkat 37
+#define __NR_umount2 39
+#define __NR_mount 40
+#define __NR_pivot_root 41
+#define __NR_nfsservctl 42
+#define __NR_statfs64 43
+#define __NR_fstatfs64 44
+#define __NR_truncate64 45
+#define __NR_ftruncate64 46
+#define __NR_fallocate 47
+#define __NR_faccessat 48
+#define __NR_chdir 49
+#define __NR_fchdir 50
+#define __NR_chroot 51
+#define __NR_fchmod 52
+#define __NR_fchmodat 53
+#define __NR_fchownat 54
+#define __NR_fchown 55
+#define __NR_openat 56
+#define __NR_close 57
+#define __NR_vhangup 58
+#define __NR_pipe2 59
+#define __NR_quotactl 60
+#define __NR_getdents64 61
+#define __NR__llseek 62
+#define __NR_read 63
+#define __NR_write 64
+#define __NR_readv 65
+#define __NR_writev 66
+#define __NR_pread64 67
+#define __NR_pwrite64 68
+#define __NR_preadv 69
+#define __NR_pwritev 70
+#define __NR_sendfile64 71
+#define __NR_signalfd4 74
+#define __NR_vmsplice 75
+#define __NR_splice 76
+#define __NR_tee 77
+#define __NR_readlinkat 78
+#define __NR_sync 81
+#define __NR_fsync 82
+#define __NR_fdatasync 83
+#define __NR_sync_file_range 84
+#define __NR_timerfd_create 85
+#define __NR_acct 89
+#define __NR_capget 90
+#define __NR_capset 91
+#define __NR_personality 92
+#define __NR_exit 93
+#define __NR_exit_group 94
+#define __NR_waitid 95
+#define __NR_set_tid_address 96
+#define __NR_unshare 97
+#define __NR_set_robust_list 99
+#define __NR_get_robust_list 100
+#define __NR_nanosleep 101
+#define __NR_getitimer 102
+#define __NR_setitimer 103
+#define __NR_kexec_load 104
+#define __NR_init_module 105
+#define __NR_delete_module 106
+#define __NR_timer_create 107
+#define __NR_timer_getoverrun 109
+#define __NR_timer_delete 111
+#define __NR_syslog 116
+#define __NR_ptrace 117
+#define __NR_sched_setparam 118
+#define __NR_sched_setscheduler 119
+#define __NR_sched_getscheduler 120
+#define __NR_sched_getparam 121
+#define __NR_sched_setaffinity 122
+#define __NR_sched_getaffinity 123
+#define __NR_sched_yield 124
+#define __NR_sched_get_priority_max 125
+#define __NR_sched_get_priority_min 126
+#define __NR_restart_syscall 128
+#define __NR_kill 129
+#define __NR_tkill 130
+#define __NR_tgkill 131
+#define __NR_sigaltstack 132
+#define __NR_rt_sigsuspend 133
+#define __NR_rt_sigaction 134
+#define __NR_rt_sigprocmask 135
+#define __NR_rt_sigpending 136
+#define __NR_rt_sigqueueinfo 138
+#define __NR_rt_sigreturn 139
+#define __NR_setpriority 140
+#define __NR_getpriority 141
+#define __NR_reboot 142
+#define __NR_setregid 143
+#define __NR_setgid 144
+#define __NR_setreuid 145
+#define __NR_setuid 146
+#define __NR_setresuid 147
+#define __NR_getresuid 148
+#define __NR_setresgid 149
+#define __NR_getresgid 150
+#define __NR_setfsuid 151
+#define __NR_setfsgid 152
+#define __NR_times 153
+#define __NR_setpgid 154
+#define __NR_getpgid 155
+#define __NR_getsid 156
+#define __NR_setsid 157
+#define __NR_getgroups 158
+#define __NR_setgroups 159
+#define __NR_uname 160
+#define __NR_sethostname 161
+#define __NR_setdomainname 162
+#define __NR_getrusage 165
+#define __NR_umask 166
+#define __NR_prctl 167
+#define __NR_getcpu 168
+#define __NR_getpid 172
+#define __NR_getppid 173
+#define __NR_getuid 174
+#define __NR_geteuid 175
+#define __NR_getgid 176
+#define __NR_getegid 177
+#define __NR_gettid 178
+#define __NR_sysinfo 179
+#define __NR_mq_open 180
+#define __NR_mq_unlink 181
+#define __NR_mq_notify 184
+#define __NR_mq_getsetattr 185
+#define __NR_msgget 186
+#define __NR_msgctl 187
+#define __NR_msgrcv 188
+#define __NR_msgsnd 189
+#define __NR_semget 190
+#define __NR_semctl 191
+#define __NR_semop 193
+#define __NR_shmget 194
+#define __NR_shmctl 195
+#define __NR_shmat 196
+#define __NR_shmdt 197
+#define __NR_socket 198
+#define __NR_socketpair 199
+#define __NR_bind 200
+#define __NR_listen 201
+#define __NR_accept 202
+#define __NR_connect 203
+#define __NR_getsockname 204
+#define __NR_getpeername 205
+#define __NR_sendto 206
+#define __NR_recvfrom 207
+#define __NR_setsockopt 208
+#define __NR_getsockopt 209
+#define __NR_shutdown 210
+#define __NR_sendmsg 211
+#define __NR_recvmsg 212
+#define __NR_readahead 213
+#define __NR_brk 214
+#define __NR_munmap 215
+#define __NR_mremap 216
+#define __NR_add_key 217
+#define __NR_request_key 218
+#define __NR_keyctl 219
+#define __NR_clone 220
+#define __NR_execve 221
+#define __NR_mmap2 222
+#define __NR_fadvise64_64 223
+#define __NR_swapon 224
+#define __NR_swapoff 225
+#define __NR_mprotect 226
+#define __NR_msync 227
+#define __NR_mlock 228
+#define __NR_munlock 229
+#define __NR_mlockall 230
+#define __NR_munlockall 231
+#define __NR_mincore 232
+#define __NR_madvise 233
+#define __NR_remap_file_pages 234
+#define __NR_mbind 235
+#define __NR_get_mempolicy 236
+#define __NR_set_mempolicy 237
+#define __NR_migrate_pages 238
+#define __NR_move_pages 239
+#define __NR_rt_tgsigqueueinfo 240
+#define __NR_perf_event_open 241
+#define __NR_accept4 242
+#define __NR_arch_specific_syscall 244
+#define __NR_prlimit64 261
+#define __NR_fanotify_init 262
+#define __NR_fanotify_mark 263
+#define __NR_name_to_handle_at 264
+#define __NR_open_by_handle_at 265
+#define __NR_syncfs 267
+#define __NR_setns 268
+#define __NR_sendmmsg 269
+#define __NR_process_vm_readv 270
+#define __NR_process_vm_writev 271
+#define __NR_kcmp 272
+#define __NR_finit_module 273
+#define __NR_sched_setattr 274
+#define __NR_sched_getattr 275
+#define __NR_renameat2 276
+#define __NR_seccomp 277
+#define __NR_getrandom 278
+#define __NR_memfd_create 279
+#define __NR_bpf 280
+#define __NR_execveat 281
+#define __NR_userfaultfd 282
+#define __NR_membarrier 283
+#define __NR_mlock2 284
+#define __NR_copy_file_range 285
+#define __NR_preadv2 286
+#define __NR_pwritev2 287
+#define __NR_pkey_mprotect 288
+#define __NR_pkey_alloc 289
+#define __NR_pkey_free 290
+#define __NR_statx 291
+#define __NR_rseq 293
+#define __NR_kexec_file_load 294
+#define __NR_clock_gettime64		403
+#define __NR_clock_settime64		404
+#define __NR_clock_adjtime64		405
+#define __NR_clock_getres_time64	406
+#define __NR_clock_nanosleep_time64	407
+#define __NR_timer_gettime64		408
+#define __NR_timer_settime64		409
+#define __NR_timerfd_gettime64		410
+#define __NR_timerfd_settime64		411
+#define __NR_utimensat_time64		412
+#define __NR_pselect6_time64		413
+#define __NR_ppoll_time64		414
+#define __NR_io_pgetevents_time64	416
+#define __NR_recvmmsg_time64		417
+#define __NR_mq_timedsend_time64	418
+#define __NR_mq_timedreceive_time64	419
+#define __NR_semtimedop_time64		420
+#define __NR_rt_sigtimedwait_time64	421
+#define __NR_futex_time64		422
+#define __NR_sched_rr_get_interval_time64 423
+#define __NR_pidfd_send_signal 424
+#define __NR_io_uring_setup 425
+#define __NR_io_uring_enter 426
+#define __NR_io_uring_register 427
+#define __NR_open_tree		428
+#define __NR_move_mount		429
+#define __NR_fsopen		430
+#define __NR_fsconfig		431
+#define __NR_fsmount		432
+#define __NR_fspick		433
+#define __NR_pidfd_open		434
+#define __NR_clone3		435
+#define __NR_openat2		437
+#define __NR_pidfd_getfd	438
+#define __NR_faccessat2		439
+#define __NR_process_madvise	440
+#define __NR_epoll_pwait2	441
+#define __NR_mount_setattr	442
+#define __NR_landlock_create_ruleset	444
+#define __NR_landlock_add_rule	445
+#define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
+#define __NR_futex __NR_futex_time64
+
+#define __NR_sysriscv __NR_arch_specific_syscall
+#define __NR_riscv_flush_icache (__NR_sysriscv + 15)
diff --git a/arch/riscv32/bits/user.h b/arch/riscv32/bits/user.h
new file mode 100644
index 00000000..0d37de0b
--- /dev/null
+++ b/arch/riscv32/bits/user.h
@@ -0,0 +1,6 @@
+#include <signal.h>
+
+#define ELF_NGREG 32
+#define ELF_NFPREG 33
+typedef unsigned long elf_greg_t, elf_gregset_t[ELF_NGREG];
+typedef union __riscv_mc_fp_state elf_fpregset_t;
diff --git a/arch/riscv32/crt_arch.h b/arch/riscv32/crt_arch.h
new file mode 100644
index 00000000..6b93fcfd
--- /dev/null
+++ b/arch/riscv32/crt_arch.h
@@ -0,0 +1,19 @@
+__asm__(
+".section .sdata,\"aw\"\n"
+".text\n"
+".global " START "\n"
+".type " START ",%function\n"
+START ":\n"
+".weak __global_pointer$\n"
+".hidden __global_pointer$\n"
+".option push\n"
+".option norelax\n\t"
+"lla gp, __global_pointer$\n"
+".option pop\n\t"
+"mv a0, sp\n"
+".weak _DYNAMIC\n"
+".hidden _DYNAMIC\n\t"
+"lla a1, _DYNAMIC\n\t"
+"andi sp, sp, -16\n\t"
+"tail " START "_c"
+);
diff --git a/arch/riscv32/kstat.h b/arch/riscv32/kstat.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/arch/riscv32/kstat.h
diff --git a/arch/riscv32/pthread_arch.h b/arch/riscv32/pthread_arch.h
new file mode 100644
index 00000000..a20d7fba
--- /dev/null
+++ b/arch/riscv32/pthread_arch.h
@@ -0,0 +1,13 @@
+static inline uintptr_t __get_tp()
+{
+	uintptr_t tp;
+	__asm__ __volatile__("mv %0, tp" : "=r"(tp));
+	return tp;
+}
+
+#define TLS_ABOVE_TP
+#define GAP_ABOVE_TP 0
+
+#define DTP_OFFSET 0x800
+
+#define MC_PC __gregs[0]
diff --git a/arch/riscv32/reloc.h b/arch/riscv32/reloc.h
new file mode 100644
index 00000000..59d15f17
--- /dev/null
+++ b/arch/riscv32/reloc.h
@@ -0,0 +1,22 @@
+#if defined __riscv_float_abi_soft
+#define RISCV_FP_SUFFIX "-sf"
+#elif defined __riscv_float_abi_single
+#define RISCV_FP_SUFFIX "-sp"
+#elif defined __riscv_float_abi_double
+#define RISCV_FP_SUFFIX ""
+#endif
+
+#define LDSO_ARCH "riscv32" RISCV_FP_SUFFIX
+
+#define TPOFF_K 0
+
+#define REL_SYMBOLIC    R_RISCV_32
+#define REL_PLT         R_RISCV_JUMP_SLOT
+#define REL_RELATIVE    R_RISCV_RELATIVE
+#define REL_COPY        R_RISCV_COPY
+#define REL_DTPMOD      R_RISCV_TLS_DTPMOD32
+#define REL_DTPOFF      R_RISCV_TLS_DTPREL32
+#define REL_TPOFF       R_RISCV_TLS_TPREL32
+
+#define CRTJMP(pc,sp) __asm__ __volatile__( \
+	"mv sp, %1 ; jr %0" : : "r"(pc), "r"(sp) : "memory" )
diff --git a/arch/riscv32/syscall_arch.h b/arch/riscv32/syscall_arch.h
new file mode 100644
index 00000000..c507f15f
--- /dev/null
+++ b/arch/riscv32/syscall_arch.h
@@ -0,0 +1,80 @@
+#define __SYSCALL_LL_E(x) \
+((union { long long ll; long l[2]; }){ .ll = x }).l[0], \
+((union { long long ll; long l[2]; }){ .ll = x }).l[1]
+#define __SYSCALL_LL_O(x) __SYSCALL_LL_E((x))
+
+#define __asm_syscall(...) \
+	__asm__ __volatile__ ("ecall\n\t" \
+	: "=r"(a0) : __VA_ARGS__ : "memory"); \
+	return a0; \
+
+static inline long __syscall0(long n)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0");
+	__asm_syscall("r"(a7))
+}
+
+static inline long __syscall1(long n, long a)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	__asm_syscall("r"(a7), "0"(a0))
+}
+
+static inline long __syscall2(long n, long a, long b)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	register long a1 __asm__("a1") = b;
+	__asm_syscall("r"(a7), "0"(a0), "r"(a1))
+}
+
+static inline long __syscall3(long n, long a, long b, long c)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	register long a1 __asm__("a1") = b;
+	register long a2 __asm__("a2") = c;
+	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2))
+}
+
+static inline long __syscall4(long n, long a, long b, long c, long d)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	register long a1 __asm__("a1") = b;
+	register long a2 __asm__("a2") = c;
+	register long a3 __asm__("a3") = d;
+	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3))
+}
+
+static inline long __syscall5(long n, long a, long b, long c, long d, long e)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	register long a1 __asm__("a1") = b;
+	register long a2 __asm__("a2") = c;
+	register long a3 __asm__("a3") = d;
+	register long a4 __asm__("a4") = e;
+	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4))
+}
+
+static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
+{
+	register long a7 __asm__("a7") = n;
+	register long a0 __asm__("a0") = a;
+	register long a1 __asm__("a1") = b;
+	register long a2 __asm__("a2") = c;
+	register long a3 __asm__("a3") = d;
+	register long a4 __asm__("a4") = e;
+	register long a5 __asm__("a5") = f;
+	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5))
+}
+
+#define VDSO_USEFUL
+/* We don't have a clock_gettime function.
+#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT_VER "LINUX_2.6" */
+
+#define IPC_64 0
diff --git a/arch/riscv64/bits/signal.h b/arch/riscv64/bits/signal.h
index 287367db..6a53feb7 100644
--- a/arch/riscv64/bits/signal.h
+++ b/arch/riscv64/bits/signal.h
@@ -41,7 +41,9 @@ typedef struct mcontext_t {
 #define REG_SP 2
 #define REG_TP 4
 #define REG_S0 8
+#define REG_S1 9
 #define REG_A0 10
+#define REG_S2 18
 #endif
 
 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
@@ -76,7 +78,6 @@ typedef struct __ucontext
 #define SA_RESTART   0x10000000
 #define SA_NODEFER   0x40000000
 #define SA_RESETHAND 0x80000000
-#define SA_RESTORER  0x04000000
 
 #endif
 
diff --git a/arch/riscv64/bits/syscall.h.in b/arch/riscv64/bits/syscall.h.in
index b534afe8..e362bd0e 100644
--- a/arch/riscv64/bits/syscall.h.in
+++ b/arch/riscv64/bits/syscall.h.in
@@ -299,6 +299,11 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
 #define __NR_sysriscv __NR_arch_specific_syscall
 #define __NR_riscv_flush_icache (__NR_sysriscv + 15)
diff --git a/arch/riscv64/reloc.h b/arch/riscv64/reloc.h
index 1ca13811..7c7c0611 100644
--- a/arch/riscv64/reloc.h
+++ b/arch/riscv64/reloc.h
@@ -17,6 +17,7 @@
 #define REL_DTPMOD      R_RISCV_TLS_DTPMOD64
 #define REL_DTPOFF      R_RISCV_TLS_DTPREL64
 #define REL_TPOFF       R_RISCV_TLS_TPREL64
+#define REL_TLSDESC     R_RISCV_TLSDESC
 
 #define CRTJMP(pc,sp) __asm__ __volatile__( \
 	"mv sp, %1 ; jr %0" : : "r"(pc), "r"(sp) : "memory" )
diff --git a/arch/s390x/bits/syscall.h.in b/arch/s390x/bits/syscall.h.in
index dfc38479..e60711a6 100644
--- a/arch/s390x/bits/syscall.h.in
+++ b/arch/s390x/bits/syscall.h.in
@@ -362,4 +362,10 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_memfd_secret	447
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/sh/bits/syscall.h.in b/arch/sh/bits/syscall.h.in
index ff14f54d..915a79cd 100644
--- a/arch/sh/bits/syscall.h.in
+++ b/arch/sh/bits/syscall.h.in
@@ -409,4 +409,9 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/arch/x32/bits/syscall.h.in b/arch/x32/bits/syscall.h.in
index 5d22fa17..1d065eea 100644
--- a/arch/x32/bits/syscall.h.in
+++ b/arch/x32/bits/syscall.h.in
@@ -308,6 +308,12 @@
 #define __NR_landlock_create_ruleset	(0x40000000 + 444)
 #define __NR_landlock_add_rule	(0x40000000 + 445)
 #define __NR_landlock_restrict_self	(0x40000000 + 446)
+#define __NR_memfd_secret	(0x40000000 + 447)
+#define __NR_process_mrelease	(0x40000000 + 448)
+#define __NR_futex_waitv	(0x40000000 + 449)
+#define __NR_set_mempolicy_home_node	(0x40000000 + 450)
+#define __NR_cachestat		(0x40000000 + 451)
+#define __NR_fchmodat2		(0x40000000 + 452)
 
 
 #define __NR_rt_sigaction (0x40000000 + 512)
diff --git a/arch/x86_64/bits/syscall.h.in b/arch/x86_64/bits/syscall.h.in
index c3882de7..6543bbba 100644
--- a/arch/x86_64/bits/syscall.h.in
+++ b/arch/x86_64/bits/syscall.h.in
@@ -355,4 +355,10 @@
 #define __NR_landlock_create_ruleset	444
 #define __NR_landlock_add_rule	445
 #define __NR_landlock_restrict_self	446
+#define __NR_memfd_secret	447
+#define __NR_process_mrelease	448
+#define __NR_futex_waitv	449
+#define __NR_set_mempolicy_home_node	450
+#define __NR_cachestat		451
+#define __NR_fchmodat2		452
 
diff --git a/compat/time32/__xstat.c b/compat/time32/__xstat.c
index acfbd3cc..e52b5deb 100644
--- a/compat/time32/__xstat.c
+++ b/compat/time32/__xstat.c
@@ -3,22 +3,22 @@
 
 struct stat32;
 
-int __fxstat64(int ver, int fd, struct stat32 *buf)
+int __fxstat(int ver, int fd, struct stat32 *buf)
 {
 	return __fstat_time32(fd, buf);
 }
 
-int __fxstatat64(int ver, int fd, const char *path, struct stat32 *buf, int flag)
+int __fxstatat(int ver, int fd, const char *path, struct stat32 *buf, int flag)
 {
 	return __fstatat_time32(fd, path, buf, flag);
 }
 
-int __lxstat64(int ver, const char *path, struct stat32 *buf)
+int __lxstat(int ver, const char *path, struct stat32 *buf)
 {
 	return __lstat_time32(path, buf);
 }
 
-int __xstat64(int ver, const char *path, struct stat32 *buf)
+int __xstat(int ver, const char *path, struct stat32 *buf)
 {
 	return __stat_time32(path, buf);
 }
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
index ed5119bd..d99cb651 100644
--- a/compat/time32/aio_suspend_time32.c
+++ b/compat/time32/aio_suspend_time32.c
@@ -7,5 +7,3 @@ int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct
 	return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
-
-weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/fstat_time32.c b/compat/time32/fstat_time32.c
index 3e084398..e5d52022 100644
--- a/compat/time32/fstat_time32.c
+++ b/compat/time32/fstat_time32.c
@@ -13,5 +13,3 @@ int __fstat_time32(int fd, struct stat32 *restrict st32)
 	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
 	return r;
 }
-
-weak_alias(fstat, fstat64);
diff --git a/compat/time32/fstatat_time32.c b/compat/time32/fstatat_time32.c
index 85dcb008..31d42e63 100644
--- a/compat/time32/fstatat_time32.c
+++ b/compat/time32/fstatat_time32.c
@@ -13,5 +13,3 @@ int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict
 	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
 	return r;
 }
-
-weak_alias(fstatat, fstatat64);
diff --git a/compat/time32/lstat_time32.c b/compat/time32/lstat_time32.c
index c1257a14..28cb5a0b 100644
--- a/compat/time32/lstat_time32.c
+++ b/compat/time32/lstat_time32.c
@@ -13,5 +13,3 @@ int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
 	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
 	return r;
 }
-
-weak_alias(lstat, lstat64);
diff --git a/compat/time32/stat_time32.c b/compat/time32/stat_time32.c
index 8c6121da..b154b0f9 100644
--- a/compat/time32/stat_time32.c
+++ b/compat/time32/stat_time32.c
@@ -13,5 +13,3 @@ int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
 	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
 	return r;
 }
-
-weak_alias(stat, stat64);
diff --git a/configure b/configure
index 6f5453f5..bc9fbe48 100755
--- a/configure
+++ b/configure
@@ -328,6 +328,7 @@ i?86*) ARCH=i386 ;;
 x86_64-x32*|x32*|x86_64*x32) ARCH=x32 ;;
 x86_64-nt64*) ARCH=nt64 ;;
 x86_64*) ARCH=x86_64 ;;
+loongarch64*) ARCH=loongarch64 ;;
 m68k*) ARCH=m68k ;;
 mips64*|mipsisa64*) ARCH=mips64 ;;
 mips*) ARCH=mips ;;
@@ -336,6 +337,7 @@ or1k*) ARCH=or1k ;;
 powerpc64*|ppc64*) ARCH=powerpc64 ;;
 powerpc*|ppc*) ARCH=powerpc ;;
 riscv64*) ARCH=riscv64 ;;
+riscv32*) ARCH=riscv32 ;;
 sh[1-9bel-]*|sh|superh*) ARCH=sh ;;
 s390x*) ARCH=s390x ;;
 unknown) fail "$0: unable to detect target arch; try $0 --target=..." ;;
@@ -354,6 +356,14 @@ tryflag CFLAGS_C99FSE -fexcess-precision=standard \
 tryflag CFLAGS_C99FSE -frounding-math
 
 #
+# Semantically we want to insist that our sources follow the
+# C rules for type-based aliasing, but most if not all real-world
+# compilers are known or suspected to have critical bugs in their
+# type-based aliasing analysis. See for example GCC bug 107107.
+#
+tryflag CFLAGS_C99FSE -fno-strict-aliasing
+
+#
 # We may use the may_alias attribute if __GNUC__ is defined, so
 # if the compiler defines __GNUC__ but does not provide it,
 # it must be defined away as part of the CFLAGS.
@@ -436,7 +446,20 @@ xno|x) printf "disabled\n" ; optimize=no ;;
 *) printf "custom\n" ;;
 esac
 
-test "$optimize" = no || tryflag CFLAGS_AUTO -Os || tryflag CFLAGS_AUTO -O2
+if test "$optimize" = no ; then :
+else
+tryflag CFLAGS_AUTO -O2
+tryflag CFLAGS_AUTO -fno-align-jumps
+tryflag CFLAGS_AUTO -fno-align-functions
+tryflag CFLAGS_AUTO -fno-align-loops
+tryflag CFLAGS_AUTO -fno-align-labels
+tryflag CFLAGS_AUTO -fira-region=one
+tryflag CFLAGS_AUTO -fira-hoist-pressure
+tryflag CFLAGS_AUTO -freorder-blocks-algorithm=simple \
+|| tryflag CFLAGS_AUTO -fno-reorder-blocks
+tryflag CFLAGS_AUTO -fno-prefetch-loop-arrays
+tryflag CFLAGS_AUTO -fno-tree-ch
+fi
 test "$optimize" = yes && optimize="internal,malloc,string"
 
 if fnmatch 'no|size' "$optimize" ; then :
@@ -650,6 +673,19 @@ if test "$ARCH" = "aarch64" ; then
 trycppif __AARCH64EB__ "$t" && SUBARCH=${SUBARCH}_be
 fi
 
+if test "$ARCH" = "loongarch64" ; then
+trycppif __loongarch_soft_float "$t" && SUBARCH=${SUBARCH}-sf
+trycppif __loongarch_single_float "$t" && SUBARCH=${SUBARCH}-sp
+printf "checking whether assembler support FCSRs... "
+echo "__asm__(\"movfcsr2gr \$t0,\$fcsr0\");" > "$tmpc"
+if $CC -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+printf "yes\n"
+else
+printf "no\n"
+CFLAGS_AUTO="$CFLAGS_AUTO -DBROKEN_LOONGARCH_FCSR_ASM"
+fi
+fi
+
 if test "$ARCH" = "m68k" ; then
 if trycppif "__HAVE_68881__" ; then : ;
 elif trycppif "__mcffpu__" ; then SUBARCH="-fp64"
@@ -692,7 +728,7 @@ trycppif __LITTLE_ENDIAN__ "$t" && SUBARCH=${SUBARCH}le
 trycppif _SOFT_FLOAT "$t" && fail "$0: error: soft-float not supported on powerpc64"
 fi
 
-if test "$ARCH" = "riscv64" ; then
+if test "$ARCH" = "riscv64" -o "$ARCH" = "riscv32" ; then
 trycppif __riscv_float_abi_soft "$t" && SUBARCH=${SUBARCH}-sf
 trycppif __riscv_float_abi_single "$t" && SUBARCH=${SUBARCH}-sp
 fi
diff --git a/include/aio.h b/include/aio.h
index 453c41b7..a938fcad 100644
--- a/include/aio.h
+++ b/include/aio.h
@@ -49,7 +49,7 @@ int aio_fsync(int, struct aiocb *);
 
 int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sigevent *__restrict);
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define aiocb64 aiocb
 #define aio_read64 aio_read
 #define aio_write64 aio_write
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index 581925a4..9c1327a1 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -188,6 +188,36 @@ typedef enum __ns_type {
 	ns_t_sink = 40,
 	ns_t_opt = 41,
 	ns_t_apl = 42,
+	ns_t_ds = 43,
+	ns_t_sshfp = 44,
+	ns_t_ipseckey = 45,
+	ns_t_rrsig = 46,
+	ns_t_nsec = 47,
+	ns_t_dnskey = 48,
+	ns_t_dhcid = 49,
+	ns_t_nsec3 = 50,
+	ns_t_nsec3param = 51,
+	ns_t_tlsa = 52,
+	ns_t_smimea = 53,
+	ns_t_hip = 55,
+	ns_t_ninfo = 56,
+	ns_t_rkey = 57,
+	ns_t_talink = 58,
+	ns_t_cds = 59,
+	ns_t_cdnskey = 60,
+	ns_t_openpgpkey = 61,
+	ns_t_csync = 62,
+	ns_t_spf = 99,
+	ns_t_uinfo = 100,
+	ns_t_uid = 101,
+	ns_t_gid = 102,
+	ns_t_unspec = 103,
+	ns_t_nid = 104,
+	ns_t_l32 = 105,
+	ns_t_l64 = 106,
+	ns_t_lp = 107,
+	ns_t_eui48 = 108,
+	ns_t_eui64 = 109,
 	ns_t_tkey = 249,
 	ns_t_tsig = 250,
 	ns_t_ixfr = 251,
@@ -196,6 +226,11 @@ typedef enum __ns_type {
 	ns_t_maila = 254,
 	ns_t_any = 255,
 	ns_t_zxfr = 256,
+	ns_t_uri = 256,
+	ns_t_caa = 257,
+	ns_t_avc = 258,
+	ns_t_ta = 32768,
+	ns_t_dlv = 32769,
 	ns_t_max = 65536
 } ns_type;
 
@@ -430,12 +465,48 @@ typedef struct {
 #define T_NAPTR		ns_t_naptr
 #define T_A6		ns_t_a6
 #define T_DNAME		ns_t_dname
+#define T_DS		ns_t_ds
+#define T_SSHFP		ns_t_sshfp
+#define T_IPSECKEY	ns_t_ipseckey
+#define T_RRSIG		ns_t_rrsig
+#define T_NSEC		ns_t_nsec
+#define T_DNSKEY	ns_t_dnskey
+#define T_DHCID		ns_t_dhcid
+#define T_NSEC3		ns_t_nsec3
+#define T_NSEC3PARAM	ns_t_nsec3param
+#define T_TLSA		ns_t_tlsa
+#define T_SMIMEA	ns_t_smimea
+#define T_HIP		ns_t_hip
+#define T_NINFO		ns_t_ninfo
+#define T_RKEY		ns_t_rkey
+#define T_TALINK	ns_t_talink
+#define T_CDS		ns_t_cds
+#define T_CDNSKEY	ns_t_cdnskey
+#define T_OPENPGPKEY	ns_t_openpgpkey
+#define T_CSYNC		ns_t_csync
+#define T_SPF		ns_t_spf
+#define T_UINFO		ns_t_uinfo
+#define T_UID		ns_t_uid
+#define T_GID		ns_t_gid
+#define T_UNSPEC	ns_t_unspec
+#define T_NID		ns_t_nid
+#define T_L32		ns_t_l32
+#define T_L64		ns_t_l64
+#define T_LP		ns_t_lp
+#define T_EUI48		ns_t_eui48
+#define T_EUI64		ns_t_eui64
+#define T_TKEY		ns_t_tkey
 #define	T_TSIG		ns_t_tsig
 #define	T_IXFR		ns_t_ixfr
 #define T_AXFR		ns_t_axfr
 #define T_MAILB		ns_t_mailb
 #define T_MAILA		ns_t_maila
 #define T_ANY		ns_t_any
+#define T_URI		ns_t_uri
+#define T_CAA		ns_t_caa
+#define T_AVC		ns_t_avc
+#define T_TA		ns_t_ta
+#define T_DLV		ns_t_dlv
 
 #define C_IN		ns_c_in
 #define C_CHAOS		ns_c_chaos
diff --git a/include/dirent.h b/include/dirent.h
index 650ecf64..2d8fffb2 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -56,7 +56,7 @@ int getdents(int, struct dirent *, size_t);
 int versionsort(const struct dirent **, const struct dirent **);
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define dirent64 dirent
 #define readdir64 readdir
 #define readdir64_r readdir_r
diff --git a/include/elf.h b/include/elf.h
index 86e2f0bb..3d5e13e4 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -315,7 +315,8 @@ typedef struct {
 #define EM_RISCV	243
 #define EM_BPF		247
 #define EM_CSKY		252
-#define EM_NUM		253
+#define EM_LOONGARCH	258
+#define EM_NUM		259
 
 #define EM_ALPHA	0x9026
 
@@ -385,7 +386,8 @@ typedef struct {
 #define SHT_PREINIT_ARRAY 16
 #define SHT_GROUP	  17
 #define SHT_SYMTAB_SHNDX  18
-#define	SHT_NUM		  19
+#define SHT_RELR	  19
+#define	SHT_NUM		  20
 #define SHT_LOOS	  0x60000000
 #define SHT_GNU_ATTRIBUTES 0x6ffffff5
 #define SHT_GNU_HASH	  0x6ffffff6
@@ -436,6 +438,7 @@ typedef struct {
 } Elf64_Chdr;
 
 #define ELFCOMPRESS_ZLIB	1
+#define ELFCOMPRESS_ZSTD	2
 #define ELFCOMPRESS_LOOS	0x60000000
 #define ELFCOMPRESS_HIOS	0x6fffffff
 #define ELFCOMPRESS_LOPROC	0x70000000
@@ -556,6 +559,11 @@ typedef struct {
 
 
 
+typedef Elf32_Word Elf32_Relr;
+typedef Elf64_Xword Elf64_Relr;
+
+
+
 #define ELF32_R_SYM(val)		((val) >> 8)
 #define ELF32_R_TYPE(val)		((val) & 0xff)
 #define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
@@ -696,7 +704,14 @@ typedef struct {
 #define NT_MIPS_DSP	0x800
 #define NT_MIPS_FP_MODE	0x801
 #define NT_MIPS_MSA	0x802
+#define NT_RISCV_CSR	0x900
+#define NT_RISCV_VECTOR	0x901
 #define NT_VERSION	1
+#define NT_LOONGARCH_CPUCFG	0xa00
+#define NT_LOONGARCH_CSR	0xa01
+#define NT_LOONGARCH_LSX	0xa02
+#define NT_LOONGARCH_LASX	0xa03
+#define NT_LOONGARCH_LBT	0xa04
 
 
 
@@ -754,7 +769,10 @@ typedef struct {
 #define DT_PREINIT_ARRAY 32
 #define DT_PREINIT_ARRAYSZ 33
 #define DT_SYMTAB_SHNDX	34
-#define	DT_NUM		35
+#define DT_RELRSZ	35
+#define DT_RELR		36
+#define DT_RELRENT	37
+#define	DT_NUM		38
 #define DT_LOOS		0x6000000d
 #define DT_HIOS		0x6ffff000
 #define DT_LOPROC	0x70000000
@@ -3244,6 +3262,7 @@ enum
 #define R_RISCV_TLS_DTPREL64    9
 #define R_RISCV_TLS_TPREL32     10
 #define R_RISCV_TLS_TPREL64     11
+#define R_RISCV_TLSDESC         12
 
 #define R_RISCV_BRANCH          16
 #define R_RISCV_JAL             17
@@ -3270,16 +3289,11 @@ enum
 #define R_RISCV_SUB16           38
 #define R_RISCV_SUB32           39
 #define R_RISCV_SUB64           40
-#define R_RISCV_GNU_VTINHERIT   41
-#define R_RISCV_GNU_VTENTRY     42
+#define R_RISCV_GOT32_PCREL     41
 #define R_RISCV_ALIGN           43
 #define R_RISCV_RVC_BRANCH      44
 #define R_RISCV_RVC_JUMP        45
 #define R_RISCV_RVC_LUI         46
-#define R_RISCV_GPREL_I         47
-#define R_RISCV_GPREL_S         48
-#define R_RISCV_TPREL_I         49
-#define R_RISCV_TPREL_S         50
 #define R_RISCV_RELAX           51
 #define R_RISCV_SUB6            52
 #define R_RISCV_SET6            53
@@ -3287,6 +3301,110 @@ enum
 #define R_RISCV_SET16           55
 #define R_RISCV_SET32           56
 #define R_RISCV_32_PCREL        57
+#define R_RISCV_IRELATIVE       58
+#define R_RISCV_PLT32           59
+#define R_RISCV_SET_ULEB128     60
+#define R_RISCV_SUB_ULEB128     61
+#define R_RISCV_TLSDESC_HI20    62
+#define R_RISCV_TLSDESC_LOAD_LO12 63
+#define R_RISCV_TLSDESC_ADD_LO12  64
+#define R_RISCV_TLSDESC_CALL    65
+
+#define EF_LARCH_ABI_MODIFIER_MASK    0x07
+#define EF_LARCH_ABI_SOFT_FLOAT       0x01
+#define EF_LARCH_ABI_SINGLE_FLOAT     0x02
+#define EF_LARCH_ABI_DOUBLE_FLOAT     0x03
+#define EF_LARCH_OBJABI_V1            0x40
+
+#define R_LARCH_NONE                        0
+#define R_LARCH_32                          1
+#define R_LARCH_64                          2
+#define R_LARCH_RELATIVE                    3
+#define R_LARCH_COPY                        4
+#define R_LARCH_JUMP_SLOT                   5
+#define R_LARCH_TLS_DTPMOD32                6
+#define R_LARCH_TLS_DTPMOD64                7
+#define R_LARCH_TLS_DTPREL32                8
+#define R_LARCH_TLS_DTPREL64                9
+#define R_LARCH_TLS_TPREL32                 10
+#define R_LARCH_TLS_TPREL64                 11
+#define R_LARCH_IRELATIVE                   12
+#define R_LARCH_MARK_LA                     20
+#define R_LARCH_MARK_PCREL                  21
+#define R_LARCH_SOP_PUSH_PCREL              22
+#define R_LARCH_SOP_PUSH_ABSOLUTE           23
+#define R_LARCH_SOP_PUSH_DUP                24
+#define R_LARCH_SOP_PUSH_GPREL              25
+#define R_LARCH_SOP_PUSH_TLS_TPREL          26
+#define R_LARCH_SOP_PUSH_TLS_GOT            27
+#define R_LARCH_SOP_PUSH_TLS_GD             28
+#define R_LARCH_SOP_PUSH_PLT_PCREL          29
+#define R_LARCH_SOP_ASSERT                  30
+#define R_LARCH_SOP_NOT                     31
+#define R_LARCH_SOP_SUB                     32
+#define R_LARCH_SOP_SL                      33
+#define R_LARCH_SOP_SR                      34
+#define R_LARCH_SOP_ADD                     35
+#define R_LARCH_SOP_AND                     36
+#define R_LARCH_SOP_IF_ELSE                 37
+#define R_LARCH_SOP_POP_32_S_10_5           38
+#define R_LARCH_SOP_POP_32_U_10_12          39
+#define R_LARCH_SOP_POP_32_S_10_12          40
+#define R_LARCH_SOP_POP_32_S_10_16          41
+#define R_LARCH_SOP_POP_32_S_10_16_S2       42
+#define R_LARCH_SOP_POP_32_S_5_20           43
+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2   44
+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2  45
+#define R_LARCH_SOP_POP_32_U                46
+#define R_LARCH_ADD8                        47
+#define R_LARCH_ADD16                       48
+#define R_LARCH_ADD24                       49
+#define R_LARCH_ADD32                       50
+#define R_LARCH_ADD64                       51
+#define R_LARCH_SUB8                        52
+#define R_LARCH_SUB16                       53
+#define R_LARCH_SUB24                       54
+#define R_LARCH_SUB32                       55
+#define R_LARCH_SUB64                       56
+#define R_LARCH_GNU_VTINHERIT               57
+#define R_LARCH_GNU_VTENTRY                 58
+#define R_LARCH_B16                         64
+#define R_LARCH_B21                         65
+#define R_LARCH_B26                         66
+#define R_LARCH_ABS_HI20                    67
+#define R_LARCH_ABS_LO12                    68
+#define R_LARCH_ABS64_LO20                  69
+#define R_LARCH_ABS64_HI12                  70
+#define R_LARCH_PCALA_HI20                  71
+#define R_LARCH_PCALA_LO12                  72
+#define R_LARCH_PCALA64_LO20                73
+#define R_LARCH_PCALA64_HI12                74
+#define R_LARCH_GOT_PC_HI20                 75
+#define R_LARCH_GOT_PC_LO12                 76
+#define R_LARCH_GOT64_PC_LO20               77
+#define R_LARCH_GOT64_PC_HI12               78
+#define R_LARCH_GOT_HI20                    79
+#define R_LARCH_GOT_LO12                    80
+#define R_LARCH_GOT64_LO20                  81
+#define R_LARCH_GOT64_HI12                  82
+#define R_LARCH_TLS_LE_HI20                 83
+#define R_LARCH_TLS_LE_LO12                 84
+#define R_LARCH_TLS_LE64_LO20               85
+#define R_LARCH_TLS_LE64_HI12               86
+#define R_LARCH_TLS_IE_PC_HI20              87
+#define R_LARCH_TLS_IE_PC_LO12              88
+#define R_LARCH_TLS_IE64_PC_LO20            89
+#define R_LARCH_TLS_IE64_PC_HI12            90
+#define R_LARCH_TLS_IE_HI20                 91
+#define R_LARCH_TLS_IE_LO12                 92
+#define R_LARCH_TLS_IE64_LO20               93
+#define R_LARCH_TLS_IE64_HI12               94
+#define R_LARCH_TLS_LD_PC_HI20              95
+#define R_LARCH_TLS_LD_HI20                 96
+#define R_LARCH_TLS_GD_PC_HI20              97
+#define R_LARCH_TLS_GD_HI20                 98
+#define R_LARCH_32_PCREL                    99
+#define R_LARCH_RELAX                       100
 
 #ifdef __cplusplus
 }
diff --git a/include/fcntl.h b/include/fcntl.h
index b664cdc4..53f98a8b 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -184,7 +184,6 @@ struct f_owner_ex {
 #define SPLICE_F_MORE 4
 #define SPLICE_F_GIFT 8
 int fallocate(int, int, off_t, off_t);
-#define fallocate64 fallocate
 int name_to_handle_at(int, const char *, struct file_handle *, int *, int);
 int open_by_handle_at(int, struct file_handle *, int);
 ssize_t readahead(int, off_t, size_t);
@@ -195,7 +194,7 @@ ssize_t tee(int, int, size_t, unsigned);
 #define loff_t off_t
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define F_GETLK64 F_GETLK
 #define F_SETLK64 F_SETLK
 #define F_SETLKW64 F_SETLKW
@@ -207,6 +206,9 @@ ssize_t tee(int, int, size_t, unsigned);
 #define posix_fadvise64 posix_fadvise
 #define posix_fallocate64 posix_fallocate
 #define off64_t off_t
+#if defined(_GNU_SOURCE)
+#define fallocate64 fallocate
+#endif
 #endif
 
 #ifdef __cplusplus
diff --git a/include/ftw.h b/include/ftw.h
index b15c062a..d0445e8a 100644
--- a/include/ftw.h
+++ b/include/ftw.h
@@ -29,7 +29,7 @@ struct FTW {
 int ftw(const char *, int (*)(const char *, const struct stat *, int), int);
 int nftw(const char *, int (*)(const char *, const struct stat *, int, struct FTW *), int, int);
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define ftw64 ftw
 #define nftw64 nftw
 #endif
diff --git a/include/glob.h b/include/glob.h
index 4a562a20..fed06745 100644
--- a/include/glob.h
+++ b/include/glob.h
@@ -39,7 +39,7 @@ void globfree(glob_t *);
 #define GLOB_NOMATCH 3
 #define GLOB_NOSYS   4
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define glob64 glob
 #define globfree64 globfree
 #define glob64_t glob_t
diff --git a/include/netdb.h b/include/netdb.h
index d096c781..3af065e2 100644
--- a/include/netdb.h
+++ b/include/netdb.h
@@ -44,6 +44,7 @@ struct addrinfo {
 #define EAI_NONAME     -2
 #define EAI_AGAIN      -3
 #define EAI_FAIL       -4
+#define EAI_NODATA     -5
 #define EAI_FAMILY     -6
 #define EAI_SOCKTYPE   -7
 #define EAI_SERVICE    -8
diff --git a/include/poll.h b/include/poll.h
index 472e4b84..272dc34a 100644
--- a/include/poll.h
+++ b/include/poll.h
@@ -36,7 +36,7 @@ struct pollfd {
 
 int poll (struct pollfd *, nfds_t, int);
 
-#ifdef _GNU_SOURCE
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
 #define __NEED_time_t
 #define __NEED_struct_timespec
 #define __NEED_sigset_t
@@ -45,7 +45,7 @@ int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *);
 #endif
 
 #if _REDIR_TIME64
-#ifdef _GNU_SOURCE
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
 __REDIR(ppoll, __ppoll_time64);
 #endif
 #endif
diff --git a/include/sched.h b/include/sched.h
index fda4b484..204c34f5 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -124,7 +124,7 @@ __CPU_op_func_S(XOR, ^)
 #define CPU_ALLOC(n) ((cpu_set_t *)calloc(1,CPU_ALLOC_SIZE(n)))
 #define CPU_FREE(set) free(set)
 
-#define CPU_SETSIZE 128
+#define CPU_SETSIZE 1024
 
 #define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set)
 #define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set)
diff --git a/include/stdc-predef.h b/include/stdc-predef.h
index af1a2799..642bad2d 100644
--- a/include/stdc-predef.h
+++ b/include/stdc-predef.h
@@ -7,7 +7,12 @@
 #define __STDC_IEC_559__ 1
 #endif
 
+#if !defined(__STDC_UTF_16__)
 #define __STDC_UTF_16__ 1
+#endif
+
+#if !defined(__STDC_UTF_32__)
 #define __STDC_UTF_32__ 1
+#endif
 
 #endif
diff --git a/include/stdio.h b/include/stdio.h
index d1ed01f0..cb858618 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -205,7 +205,7 @@ typedef struct _IO_cookie_io_functions_t {
 FILE *fopencookie(void *, const char *, cookie_io_functions_t);
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define tmpfile64 tmpfile
 #define fopen64 fopen
 #define freopen64 freopen
diff --git a/include/stdlib.h b/include/stdlib.h
index b507ca33..475190bf 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -95,7 +95,7 @@ size_t __ctype_get_mb_cur_max(void);
 #define WTERMSIG(s) ((s) & 0x7f)
 #define WSTOPSIG(s) WEXITSTATUS(s)
 #define WIFEXITED(s) (!WTERMSIG(s))
-#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
+#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00)
 #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
 
 int posix_memalign (void **, size_t, size_t);
@@ -163,7 +163,7 @@ double strtod_l(const char *__restrict, char **__restrict, struct __locale_struc
 long double strtold_l(const char *__restrict, char **__restrict, struct __locale_struct *);
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define mkstemp64 mkstemp
 #define mkostemp64 mkostemp
 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
diff --git a/include/string.h b/include/string.h
index 43ad0942..83e2b946 100644
--- a/include/string.h
+++ b/include/string.h
@@ -73,6 +73,7 @@ char *strsignal(int);
 char *strerror_l (int, locale_t);
 int strcoll_l (const char *, const char *, locale_t);
 size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t);
+void *memmem(const void *, size_t, const void *, size_t);
 #endif
 
 #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
@@ -92,12 +93,8 @@ void explicit_bzero (void *, size_t);
 int strverscmp (const char *, const char *);
 char *strchrnul(const char *, int);
 char *strcasestr(const char *, const char *);
-void *memmem(const void *, size_t, const void *, size_t);
 void *memrchr(const void *, int, size_t);
 void *mempcpy(void *, const void *, size_t);
-#ifndef __cplusplus
-char *basename();
-#endif
 #endif
 
 #ifdef __cplusplus
diff --git a/include/strings.h b/include/strings.h
index db0960b4..b7a5ea08 100644
--- a/include/strings.h
+++ b/include/strings.h
@@ -5,6 +5,7 @@
 extern "C" {
 #endif
 
+#include <features.h>
 
 #define __NEED_size_t
 #define __NEED_locale_t
diff --git a/include/sys/mman.h b/include/sys/mman.h
index 80a3baae..3d5d0f9c 100644
--- a/include/sys/mman.h
+++ b/include/sys/mman.h
@@ -141,7 +141,7 @@ int mincore (void *, size_t, unsigned char *);
 int shm_open (const char *, int, mode_t);
 int shm_unlink (const char *);
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define mmap64 mmap
 #define off64_t off_t
 #endif
diff --git a/include/sys/resource.h b/include/sys/resource.h
index 3068328d..e8bfbe1f 100644
--- a/include/sys/resource.h
+++ b/include/sys/resource.h
@@ -95,7 +95,7 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
 
 #define RLIM_NLIMITS RLIMIT_NLIMITS
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define RLIM64_INFINITY RLIM_INFINITY
 #define RLIM64_SAVED_CUR RLIM_SAVED_CUR
 #define RLIM64_SAVED_MAX RLIM_SAVED_MAX
diff --git a/include/sys/sendfile.h b/include/sys/sendfile.h
index e7570d8e..253a041b 100644
--- a/include/sys/sendfile.h
+++ b/include/sys/sendfile.h
@@ -10,7 +10,7 @@ extern "C" {
 
 ssize_t sendfile(int, int, off_t *, size_t);
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define sendfile64 sendfile
 #define off64_t off_t
 #endif
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 10d446c4..6690192d 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -18,6 +18,13 @@ extern "C" {
 #define __NEED_blkcnt_t
 #define __NEED_struct_timespec
 
+#ifdef _GNU_SOURCE
+#define __NEED_int64_t
+#define __NEED_uint64_t
+#define __NEED_uint32_t
+#define __NEED_uint16_t
+#endif
+
 #include <bits/alltypes.h>
 
 #include <bits/stat.h>
@@ -98,7 +105,55 @@ int lchmod(const char *, mode_t);
 #define S_IEXEC S_IXUSR
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_GNU_SOURCE)
+#define STATX_TYPE 1U
+#define STATX_MODE 2U
+#define STATX_NLINK 4U
+#define STATX_UID 8U
+#define STATX_GID 0x10U
+#define STATX_ATIME 0x20U
+#define STATX_MTIME 0x40U
+#define STATX_CTIME 0x80U
+#define STATX_INO 0x100U
+#define STATX_SIZE 0x200U
+#define STATX_BLOCKS 0x400U
+#define STATX_BASIC_STATS 0x7ffU
+#define STATX_BTIME 0x800U
+#define STATX_ALL 0xfffU
+
+struct statx_timestamp {
+	int64_t tv_sec;
+	uint32_t tv_nsec, __pad;
+};
+
+struct statx {
+	uint32_t stx_mask;
+	uint32_t stx_blksize;
+	uint64_t stx_attributes;
+	uint32_t stx_nlink;
+	uint32_t stx_uid;
+	uint32_t stx_gid;
+	uint16_t stx_mode;
+	uint16_t __pad0[1];
+	uint64_t stx_ino;
+	uint64_t stx_size;
+	uint64_t stx_blocks;
+	uint64_t stx_attributes_mask;
+	struct statx_timestamp stx_atime;
+	struct statx_timestamp stx_btime;
+	struct statx_timestamp stx_ctime;
+	struct statx_timestamp stx_mtime;
+	uint32_t stx_rdev_major;
+	uint32_t stx_rdev_minor;
+	uint32_t stx_dev_major;
+	uint32_t stx_dev_minor;
+	uint64_t __pad1[14];
+};
+
+int statx(int, const char *__restrict, int, unsigned, struct statx *__restrict);
+#endif
+
+#if defined(_LARGEFILE64_SOURCE)
 #define stat64 stat
 #define fstat64 fstat
 #define lstat64 lstat
diff --git a/include/sys/statfs.h b/include/sys/statfs.h
index 6f4c6230..7a2e11cd 100644
--- a/include/sys/statfs.h
+++ b/include/sys/statfs.h
@@ -18,7 +18,7 @@ typedef struct __fsid_t {
 int statfs (const char *, struct statfs *);
 int fstatfs (int, struct statfs *);
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define statfs64 statfs
 #define fstatfs64 fstatfs
 #define fsblkcnt64_t fsblkcnt_t
diff --git a/include/sys/statvfs.h b/include/sys/statvfs.h
index 793490b6..71d9d1f9 100644
--- a/include/sys/statvfs.h
+++ b/include/sys/statvfs.h
@@ -23,7 +23,8 @@ struct statvfs {
 	unsigned long f_fsid;
 #endif
 	unsigned long f_flag, f_namemax;
-	int __reserved[6];
+	unsigned int f_type;
+	int __reserved[5];
 };
 
 int statvfs (const char *__restrict, struct statvfs *__restrict);
@@ -42,7 +43,7 @@ int fstatvfs (int, struct statvfs *);
 #define ST_NODIRATIME  2048
 #define ST_RELATIME    4096
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define statvfs64 statvfs
 #define fstatvfs64 fstatvfs
 #define fsblkcnt64_t fsblkcnt_t
diff --git a/include/sys/types.h b/include/sys/types.h
index 0c35541d..3363374f 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -71,7 +71,7 @@ typedef unsigned long long u_quad_t;
 #include <sys/select.h>
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define blkcnt64_t blkcnt_t
 #define fsblkcnt64_t fsblkcnt_t
 #define fsfilcnt64_t fsfilcnt_t
diff --git a/include/sys/uio.h b/include/sys/uio.h
index 00f73a2f..8b5e3de7 100644
--- a/include/sys/uio.h
+++ b/include/sys/uio.h
@@ -29,7 +29,7 @@ ssize_t writev (int, const struct iovec *, int);
 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
 ssize_t preadv (int, const struct iovec *, int, off_t);
 ssize_t pwritev (int, const struct iovec *, int, off_t);
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define preadv64 preadv
 #define pwritev64 pwritev
 #define off64_t off_t
@@ -39,6 +39,13 @@ ssize_t pwritev (int, const struct iovec *, int, off_t);
 #ifdef _GNU_SOURCE
 ssize_t process_vm_writev(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long);
 ssize_t process_vm_readv(pid_t, const struct iovec *, unsigned long, const struct iovec *, unsigned long, unsigned long);
+ssize_t preadv2 (int, const struct iovec *, int, off_t, int);
+ssize_t pwritev2 (int, const struct iovec *, int, off_t, int);
+#define RWF_HIPRI 0x00000001
+#define RWF_DSYNC 0x00000002
+#define RWF_SYNC 0x00000004
+#define RWF_NOWAIT 0x00000008
+#define RWF_APPEND 0x00000010
 #endif
 
 #ifdef __cplusplus
diff --git a/include/sys/wait.h b/include/sys/wait.h
index d4b1f2e1..8ced671b 100644
--- a/include/sys/wait.h
+++ b/include/sys/wait.h
@@ -50,7 +50,7 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
 #define WSTOPSIG(s) WEXITSTATUS(s)
 #define WCOREDUMP(s) ((s) & 0x80)
 #define WIFEXITED(s) (!WTERMSIG(s))
-#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
+#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00)
 #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
 #define WIFCONTINUED(s) ((s) == 0xffff)
 
diff --git a/include/unistd.h b/include/unistd.h
index 80be3b26..5bc7f798 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -198,7 +198,7 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned);
 pid_t gettid(void);
 #endif
 
-#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+#if defined(_LARGEFILE64_SOURCE)
 #define lseek64 lseek
 #define pread64 pread
 #define pwrite64 pwrite
@@ -425,6 +425,8 @@ pid_t gettid(void);
 #define _SC_XOPEN_STREAMS	246
 #define _SC_THREAD_ROBUST_PRIO_INHERIT	247
 #define _SC_THREAD_ROBUST_PRIO_PROTECT	248
+#define _SC_MINSIGSTKSZ	249
+#define _SC_SIGSTKSZ	250
 
 #define _CS_PATH	0
 #define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	1
diff --git a/ldso/dlstart.c b/ldso/dlstart.c
index 20d50f2c..259f5e18 100644
--- a/ldso/dlstart.c
+++ b/ldso/dlstart.c
@@ -140,6 +140,21 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv)
 		size_t *rel_addr = (void *)(base + rel[0]);
 		*rel_addr = base + rel[2];
 	}
+
+	rel = (void *)(base+dyn[DT_RELR]);
+	rel_size = dyn[DT_RELRSZ];
+	size_t *relr_addr = 0;
+	for (; rel_size; rel++, rel_size-=sizeof(size_t)) {
+		if ((rel[0]&1) == 0) {
+			relr_addr = (void *)(base + rel[0]);
+			*relr_addr++ += base;
+		} else {
+			for (size_t i=0, bitmap=rel[0]; bitmap>>=1; i++)
+				if (bitmap&1)
+					relr_addr[i] += base;
+			relr_addr += 8*sizeof(size_t)-1;
+		}
+	}
 #endif
 
 	stage2_func dls2;
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 5b9c8be4..324aa859 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -21,15 +21,23 @@
 #include <sys/membarrier.h>
 #include "pthread_impl.h"
 #include "fork_impl.h"
-#include "libc.h"
 #include "dynlink.h"
 
+static size_t ldso_page_size;
+#ifndef PAGE_SIZE
+#define PAGE_SIZE ldso_page_size
+#endif
+
+#include "libc.h"
+
 #define malloc __libc_malloc
 #define calloc __libc_calloc
 #define realloc __libc_realloc
 #define free __libc_free
 
-static void error(const char *, ...);
+static void error_impl(const char *, ...);
+static void error_noop(const char *, ...);
+static void (*error)(const char *, ...) = error_noop;
 
 #define MAXP2(a,b) (-(-(a)&-(b)))
 #define ALIGN(x,y) ((x)+(y)-1 & -(y))
@@ -149,6 +157,8 @@ static struct fdpic_dummy_loadmap app_dummy_loadmap;
 
 struct debug *_dl_debug_addr = &debug;
 
+extern weak hidden char __ehdr_start[];
+
 extern hidden int __malloc_replaced;
 
 hidden void (*const __init_array_start)(void)=0, (*const __fini_array_start)(void)=0;
@@ -208,7 +218,8 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt)
 	size_t i;
 	for (i=0; i<cnt; i++) a[i] = 0;
 	for (; v[0]; v+=2) if (v[0]-1<cnt-1) {
-		a[0] |= 1UL<<v[0];
+		if (v[0] < 8*sizeof(long))
+			a[0] |= 1UL<<v[0];
 		a[v[0]] = v[1];
 	}
 }
@@ -334,6 +345,40 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
 	return find_sym2(dso, s, need_def, 0);
 }
 
+static struct symdef get_lfs64(const char *name)
+{
+	const char *p;
+	static const char lfs64_list[] =
+		"aio_cancel\0aio_error\0aio_fsync\0aio_read\0aio_return\0"
+		"aio_suspend\0aio_write\0alphasort\0creat\0fallocate\0"
+		"fgetpos\0fopen\0freopen\0fseeko\0fsetpos\0fstat\0"
+		"fstatat\0fstatfs\0fstatvfs\0ftello\0ftruncate\0ftw\0"
+		"getdents\0getrlimit\0glob\0globfree\0lio_listio\0"
+		"lockf\0lseek\0lstat\0mkostemp\0mkostemps\0mkstemp\0"
+		"mkstemps\0mmap\0nftw\0open\0openat\0posix_fadvise\0"
+		"posix_fallocate\0pread\0preadv\0prlimit\0pwrite\0"
+		"pwritev\0readdir\0scandir\0sendfile\0setrlimit\0"
+		"stat\0statfs\0statvfs\0tmpfile\0truncate\0versionsort\0"
+		"__fxstat\0__fxstatat\0__lxstat\0__xstat\0";
+	size_t l;
+	char buf[16];
+	for (l=0; name[l]; l++) {
+		if (l >= sizeof buf) goto nomatch;
+		buf[l] = name[l];
+	}
+	if (!strcmp(name, "readdir64_r"))
+		return find_sym(&ldso, "readdir_r", 1);
+	if (l<2 || name[l-2]!='6' || name[l-1]!='4')
+		goto nomatch;
+	buf[l-=2] = 0;
+	for (p=lfs64_list; *p; p++) {
+		if (!strcmp(buf, p)) return find_sym(&ldso, buf, 1);
+		while (*p) p++;
+	}
+nomatch:
+	return (struct symdef){ 0 };
+}
+
 static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
 {
 	unsigned char *base = dso->base;
@@ -387,6 +432,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 			def = (sym->st_info>>4) == STB_LOCAL
 				? (struct symdef){ .dso = dso, .sym = sym }
 				: find_sym(ctx, name, type==REL_PLT);
+			if (!def.sym) def = get_lfs64(name);
 			if (!def.sym && (sym->st_shndx != SHN_UNDEF
 			    || sym->st_info>>4 != STB_WEAK)) {
 				if (dso->lazy && (type==REL_PLT || type==REL_GOT)) {
@@ -471,7 +517,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 			break;
 #endif
 		case REL_TLSDESC:
-			if (stride<3) addend = reloc_addr[1];
+			if (stride<3) addend = reloc_addr[!TLSDESC_BACKWARDS];
 			if (def.dso->tls_id > static_tls_cnt) {
 				struct td_index *new = malloc(sizeof *new);
 				if (!new) {
@@ -496,13 +542,13 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 					+ addend;
 #endif
 			}
-#ifdef TLSDESC_BACKWARDS
 			/* Some archs (32-bit ARM at least) invert the order of
 			 * the descriptor members. Fix them up here. */
-			size_t tmp = reloc_addr[0];
-			reloc_addr[0] = reloc_addr[1];
-			reloc_addr[1] = tmp;
-#endif
+			if (TLSDESC_BACKWARDS) {
+				size_t tmp = reloc_addr[0];
+				reloc_addr[0] = reloc_addr[1];
+				reloc_addr[1] = tmp;
+			}
 			break;
 		default:
 			error("Error relocating %s: unsupported relocation type %d",
@@ -513,6 +559,24 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 	}
 }
 
+static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size)
+{
+	if (dso == &ldso) return; /* self-relocation was done in _dlstart */
+	unsigned char *base = dso->base;
+	size_t *reloc_addr;
+	for (; relr_size; relr++, relr_size-=sizeof(size_t))
+		if ((relr[0]&1) == 0) {
+			reloc_addr = laddr(dso, relr[0]);
+			*reloc_addr++ += (size_t)base;
+		} else {
+			int i = 0;
+			for (size_t bitmap=relr[0]; (bitmap>>=1); i++)
+				if (bitmap&1)
+					reloc_addr[i] += (size_t)base;
+			reloc_addr += 8*sizeof(size_t)-1;
+		}
+}
+
 static void redo_lazy_relocs()
 {
 	struct dso *p = lazy_head, *next;
@@ -866,7 +930,7 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size)
 		case ENOENT:
 		case ENOTDIR:
 		case EACCES:
-			break;
+			return 0;
 		default:
 			return -1;
 		}
@@ -1355,13 +1419,17 @@ static void reloc_all(struct dso *p)
 			2+(dyn[DT_PLTREL]==DT_RELA));
 		do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2);
 		do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3);
-
-		if (head != &ldso && p->relro_start != p->relro_end &&
-		    mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ)
-		    && errno != ENOSYS) {
-			error("Error relocating %s: RELRO protection failed: %m",
-				p->name);
-			if (runtime) longjmp(*rtld_fail, 1);
+		if (!DL_FDPIC)
+			do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]);
+
+		if (head != &ldso && p->relro_start != p->relro_end) {
+			long ret = __syscall(SYS_mprotect, laddr(p, p->relro_start),
+				p->relro_end-p->relro_start, PROT_READ);
+			if (ret != 0 && ret != -ENOSYS) {
+				error("Error relocating %s: RELRO protection failed: %m",
+					p->name);
+				if (runtime) longjmp(*rtld_fail, 1);
+			}
 		}
 
 		p->relocated = 1;
@@ -1659,11 +1727,12 @@ hidden void __dls2(unsigned char *base, size_t *sp)
 	} else {
 		ldso.base = base;
 	}
-	Ehdr *ehdr = (void *)ldso.base;
+	Ehdr *ehdr = __ehdr_start ? (void *)__ehdr_start : (void *)ldso.base;
 	ldso.name = ldso.shortname = "libc.so";
 	ldso.phnum = ehdr->e_phnum;
 	ldso.phdr = laddr(&ldso, ehdr->e_phoff);
 	ldso.phentsize = ehdr->e_phentsize;
+	search_vec(auxv, &ldso_page_size, AT_PAGESZ);
 	kernel_mapped_dso(&ldso);
 	decode_dyn(&ldso);
 
@@ -1756,6 +1825,9 @@ void __dls3(size_t *sp, size_t *auxv)
 		env_preload = getenv("LD_PRELOAD");
 	}
 
+	/* Activate error handler function */
+	error = error_impl;
+
 	/* If the main program was already loaded by the kernel,
 	 * AT_PHDR will point to some location other than the dynamic
 	 * linker's program headers. */
@@ -1923,6 +1995,10 @@ void __dls3(size_t *sp, size_t *auxv)
 			size_t *ptr = (size_t *) app.dynv[i+1];
 			*ptr = (size_t)&debug;
 		}
+		if (app.dynv[i]==DT_DEBUG_INDIRECT_REL) {
+			size_t *ptr = (size_t *)((size_t)&app.dynv[i] + app.dynv[i+1]);
+			*ptr = (size_t)&debug;
+		}
 	}
 
 	/* This must be done before final relocations, since it calls
@@ -2345,7 +2421,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void
 	return ret;
 }
 
-static void error(const char *fmt, ...)
+static void error_impl(const char *fmt, ...)
 {
 	va_list ap;
 	va_start(ap, fmt);
@@ -2359,3 +2435,7 @@ static void error(const char *fmt, ...)
 	__dl_vseterr(fmt, ap);
 	va_end(ap);
 }
+
+static void error_noop(const char *fmt, ...)
+{
+}
diff --git a/src/aio/aio.c b/src/aio/aio.c
index a1a3e791..d7e063bf 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -82,6 +82,8 @@ static size_t io_thread_stack_size;
 
 static struct aio_queue *__aio_get_queue(int fd, int need)
 {
+	sigset_t allmask, origmask;
+	int masked = 0;
 	if (fd < 0) {
 		errno = EBADF;
 		return 0;
@@ -93,6 +95,9 @@ static struct aio_queue *__aio_get_queue(int fd, int need)
 	if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) {
 		pthread_rwlock_unlock(&maplock);
 		if (fcntl(fd, F_GETFD) < 0) return 0;
+		sigfillset(&allmask);
+		masked = 1;
+		pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
 		pthread_rwlock_wrlock(&maplock);
 		if (!io_thread_stack_size) {
 			unsigned long val = __getauxval(AT_MINSIGSTKSZ);
@@ -119,6 +124,7 @@ static struct aio_queue *__aio_get_queue(int fd, int need)
 	if (q) pthread_mutex_lock(&q->lock);
 out:
 	pthread_rwlock_unlock(&maplock);
+	if (masked) pthread_sigmask(SIG_SETMASK, &origmask, 0);
 	return q;
 }
 
@@ -401,18 +407,26 @@ void __aio_atfork(int who)
 	if (who<0) {
 		pthread_rwlock_rdlock(&maplock);
 		return;
+	} else if (!who) {
+		pthread_rwlock_unlock(&maplock);
+		return;
 	}
-	if (who>0 && map) for (int a=0; a<(-1U/2+1)>>24; a++)
+	aio_fd_cnt = 0;
+	if (pthread_rwlock_tryrdlock(&maplock)) {
+		/* Obtaining lock may fail if _Fork was called nor via
+		 * fork. In this case, no further aio is possible from
+		 * child and we can just null out map so __aio_close
+		 * does not attempt to do anything. */
+		map = 0;
+		return;
+	}
+	if (map) for (int a=0; a<(-1U/2+1)>>24; a++)
 		if (map[a]) for (int b=0; b<256; b++)
 			if (map[a][b]) for (int c=0; c<256; c++)
 				if (map[a][b][c]) for (int d=0; d<256; d++)
 					map[a][b][c][d] = 0;
-	pthread_rwlock_unlock(&maplock);
+	/* Re-initialize the rwlock rather than unlocking since there
+	 * may have been more than one reference on it in the parent.
+	 * We are not a lock holder anyway; the thread in the parent was. */
+	pthread_rwlock_init(&maplock, 0);
 }
-
-weak_alias(aio_cancel, aio_cancel64);
-weak_alias(aio_error, aio_error64);
-weak_alias(aio_fsync, aio_fsync64);
-weak_alias(aio_read, aio_read64);
-weak_alias(aio_write, aio_write64);
-weak_alias(aio_return, aio_return64);
diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c
index 1c1060e3..1f0c9aaa 100644
--- a/src/aio/aio_suspend.c
+++ b/src/aio/aio_suspend.c
@@ -9,7 +9,7 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec
 {
 	int i, tid = 0, ret, expect = 0;
 	struct timespec at;
-	volatile int dummy_fut, *pfut;
+	volatile int dummy_fut = 0, *pfut;
 	int nzcnt = 0;
 	const struct aiocb *cb = 0;
 
@@ -73,7 +73,3 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec
 		}
 	}
 }
-
-#if !_REDIR_TIME64
-weak_alias(aio_suspend, aio_suspend64);
-#endif
diff --git a/src/aio/lio_listio.c b/src/aio/lio_listio.c
index 0799c15d..a672812f 100644
--- a/src/aio/lio_listio.c
+++ b/src/aio/lio_listio.c
@@ -139,5 +139,3 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st
 
 	return 0;
 }
-
-weak_alias(lio_listio, lio_listio64);
diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
index 3baaed32..60d3e745 100644
--- a/src/conf/sysconf.c
+++ b/src/conf/sysconf.c
@@ -4,6 +4,7 @@
 #include <sys/resource.h>
 #include <signal.h>
 #include <sys/sysinfo.h>
+#include <sys/auxv.h>
 #include "syscall.h"
 #include "libc.h"
 
@@ -19,6 +20,8 @@
 #define JT_AVPHYS_PAGES JT(9)
 #define JT_ZERO JT(10)
 #define JT_DELAYTIMER_MAX JT(11)
+#define JT_MINSIGSTKSZ JT(12)
+#define JT_SIGSTKSZ JT(13)
 
 #define RLIM(x) (-32768|(RLIMIT_ ## x))
 
@@ -165,6 +168,9 @@ long sysconf(int name)
 		[_SC_XOPEN_STREAMS] = JT_ZERO,
 		[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1,
 		[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1,
+
+		[_SC_MINSIGSTKSZ] = JT_MINSIGSTKSZ,
+		[_SC_SIGSTKSZ] = JT_SIGSTKSZ,
 	};
 
 	if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) {
@@ -212,6 +218,13 @@ long sysconf(int name)
 		mem *= si.mem_unit;
 		mem /= PAGE_SIZE;
 		return (mem > LONG_MAX) ? LONG_MAX : mem;
+	case JT_MINSIGSTKSZ & 255:
+	case JT_SIGSTKSZ & 255: ;
+		long val = __getauxval(AT_MINSIGSTKSZ);
+		if (val < MINSIGSTKSZ) val = MINSIGSTKSZ;
+		if (values[name] == JT_SIGSTKSZ)
+			val += SIGSTKSZ - MINSIGSTKSZ;
+		return val;
 	case JT_ZERO & 255:
 		return 0;
 	}
diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c
index bee672eb..ab2624e2 100644
--- a/src/dirent/alphasort.c
+++ b/src/dirent/alphasort.c
@@ -5,5 +5,3 @@ int alphasort(const struct dirent **a, const struct dirent **b)
 {
 	return strcoll((*a)->d_name, (*b)->d_name);
 }
-
-weak_alias(alphasort, alphasort64);
diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c
index 569fc705..5a03b363 100644
--- a/src/dirent/readdir.c
+++ b/src/dirent/readdir.c
@@ -25,5 +25,3 @@ struct dirent *readdir(DIR *dir)
 	dir->tell = de->d_off;
 	return de;
 }
-
-weak_alias(readdir, readdir64);
diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c
index e2a818f3..0d5de5f5 100644
--- a/src/dirent/readdir_r.c
+++ b/src/dirent/readdir_r.c
@@ -25,5 +25,3 @@ int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **re
 	*result = buf;
 	return 0;
 }
-
-weak_alias(readdir_r, readdir64_r);
diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c
index 7ee195dd..7456b9b8 100644
--- a/src/dirent/scandir.c
+++ b/src/dirent/scandir.c
@@ -43,5 +43,3 @@ int scandir(const char *path, struct dirent ***res,
 	*res = names;
 	return cnt;
 }
-
-weak_alias(scandir, scandir64);
diff --git a/src/dirent/versionsort.c b/src/dirent/versionsort.c
index d4c48923..97696105 100644
--- a/src/dirent/versionsort.c
+++ b/src/dirent/versionsort.c
@@ -6,6 +6,3 @@ int versionsort(const struct dirent **a, const struct dirent **b)
 {
 	return strverscmp((*a)->d_name, (*b)->d_name);
 }
-
-#undef versionsort64
-weak_alias(versionsort, versionsort64);
diff --git a/src/fcntl/creat.c b/src/fcntl/creat.c
index 8f8aab64..c9c43910 100644
--- a/src/fcntl/creat.c
+++ b/src/fcntl/creat.c
@@ -4,5 +4,3 @@ int creat(const char *filename, mode_t mode)
 {
 	return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode);
 }
-
-weak_alias(creat, creat64);
diff --git a/src/fcntl/open.c b/src/fcntl/open.c
index 1d817a2d..4c3c8275 100644
--- a/src/fcntl/open.c
+++ b/src/fcntl/open.c
@@ -19,5 +19,3 @@ int open(const char *filename, int flags, ...)
 
 	return __syscall_ret(fd);
 }
-
-weak_alias(open, open64);
diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c
index ad165ec3..83a9e0d0 100644
--- a/src/fcntl/openat.c
+++ b/src/fcntl/openat.c
@@ -15,5 +15,3 @@ int openat(int fd, const char *filename, int flags, ...)
 
 	return syscall_cp(SYS_openat, fd, filename, flags|O_LARGEFILE, mode);
 }
-
-weak_alias(openat, openat64);
diff --git a/src/fcntl/posix_fadvise.c b/src/fcntl/posix_fadvise.c
index 75b8e1ae..07346d21 100644
--- a/src/fcntl/posix_fadvise.c
+++ b/src/fcntl/posix_fadvise.c
@@ -14,5 +14,3 @@ int posix_fadvise(int fd, off_t base, off_t len, int advice)
 		__SYSCALL_LL_E(len), advice);
 #endif
 }
-
-weak_alias(posix_fadvise, posix_fadvise64);
diff --git a/src/fcntl/posix_fallocate.c b/src/fcntl/posix_fallocate.c
index c57a24ae..80a65cbf 100644
--- a/src/fcntl/posix_fallocate.c
+++ b/src/fcntl/posix_fallocate.c
@@ -6,5 +6,3 @@ int posix_fallocate(int fd, off_t base, off_t len)
 	return -__syscall(SYS_fallocate, fd, 0, __SYSCALL_LL_E(base),
 		__SYSCALL_LL_E(len));
 }
-
-weak_alias(posix_fallocate, posix_fallocate64);
diff --git a/src/fenv/loongarch64/fenv.S b/src/fenv/loongarch64/fenv.S
new file mode 100644
index 00000000..9c38599e
--- /dev/null
+++ b/src/fenv/loongarch64/fenv.S
@@ -0,0 +1,78 @@
+#ifndef __loongarch_soft_float
+
+#ifdef BROKEN_LOONGARCH_FCSR_ASM
+#define FCSR $r0
+#else
+#define FCSR $fcsr0
+#endif
+
+.global feclearexcept
+.type   feclearexcept,@function
+feclearexcept:
+	li.w    $t0, 0x1f0000
+	and     $a0, $a0, $t0
+	movfcsr2gr $t1, FCSR
+	andn    $t1, $t1, $a0
+	movgr2fcsr FCSR, $t1
+	li.w    $a0, 0
+	jr      $ra
+
+.global feraiseexcept
+.type   feraiseexcept,@function
+feraiseexcept:
+	li.w    $t0, 0x1f0000
+	and     $a0, $a0, $t0
+	movfcsr2gr $t1, FCSR
+	or      $t1, $t1, $a0
+	movgr2fcsr FCSR, $t1
+	li.w    $a0, 0
+	jr      $ra
+
+.global fetestexcept
+.type   fetestexcept,@function
+fetestexcept:
+	li.w    $t0, 0x1f0000
+	and     $a0, $a0, $t0
+	movfcsr2gr $t1, FCSR
+	and     $a0, $t1, $a0
+	jr      $ra
+
+.global fegetround
+.type   fegetround,@function
+fegetround:
+	movfcsr2gr $t0, FCSR
+	andi    $a0, $t0, 0x300
+	jr      $ra
+
+.global __fesetround
+.hidden __fesetround
+.type   __fesetround,@function
+__fesetround:
+	li.w    $t0, 0x300
+	and     $a0, $a0, $t0
+	movfcsr2gr $t1, FCSR
+	andn    $t1, $t1, $t0
+	or      $t1, $t1, $a0
+	movgr2fcsr FCSR, $t1
+	li.w    $a0, 0
+	jr      $ra
+
+.global fegetenv
+.type   fegetenv,@function
+fegetenv:
+	movfcsr2gr $t0, FCSR
+	st.w    $t0, $a0, 0
+	li.w    $a0, 0
+	jr      $ra
+
+.global fesetenv
+.type   fesetenv,@function
+fesetenv:
+	addi.d  $t0, $a0, 1
+	beq     $t0, $r0, 1f
+	ld.w    $t0, $a0, 0
+1:	movgr2fcsr FCSR, $t0
+	li.w    $a0, 0
+	jr      $ra
+
+#endif
diff --git a/src/fenv/riscv32/fenv-sf.c b/src/fenv/riscv32/fenv-sf.c
new file mode 100644
index 00000000..ecd3cb5c
--- /dev/null
+++ b/src/fenv/riscv32/fenv-sf.c
@@ -0,0 +1,3 @@
+#ifndef __riscv_flen
+#include "../fenv.c"
+#endif
diff --git a/src/fenv/riscv32/fenv.S b/src/fenv/riscv32/fenv.S
new file mode 100644
index 00000000..0ea78bf9
--- /dev/null
+++ b/src/fenv/riscv32/fenv.S
@@ -0,0 +1,56 @@
+#ifdef __riscv_flen
+
+.global feclearexcept
+.type feclearexcept, %function
+feclearexcept:
+	csrc fflags, a0
+	li a0, 0
+	ret
+
+.global feraiseexcept
+.type feraiseexcept, %function
+feraiseexcept:
+	csrs fflags, a0
+	li a0, 0
+	ret
+
+.global fetestexcept
+.type fetestexcept, %function
+fetestexcept:
+	frflags t0
+	and a0, t0, a0
+	ret
+
+.global fegetround
+.type fegetround, %function
+fegetround:
+	frrm a0
+	ret
+
+.global __fesetround
+.type __fesetround, %function
+__fesetround:
+	fsrm t0, a0
+	li a0, 0
+	ret
+
+.global fegetenv
+.type fegetenv, %function
+fegetenv:
+	frcsr t0
+	sw t0, 0(a0)
+	li a0, 0
+	ret
+
+.global fesetenv
+.type fesetenv, %function
+fesetenv:
+	li t2, -1
+	li t1, 0
+	beq a0, t2, 1f
+	lw t1, 0(a0)
+1:	fscsr t1
+	li a0, 0
+	ret
+
+#endif
diff --git a/src/internal/atomic.h b/src/internal/atomic.h
index 96c1552d..8f71c8cd 100644
--- a/src/internal/atomic.h
+++ b/src/internal/atomic.h
@@ -194,7 +194,7 @@ static inline void a_store(volatile int *p, int v)
 
 #ifndef a_barrier
 #define a_barrier a_barrier
-static void a_barrier()
+static inline void a_barrier()
 {
 	volatile int tmp = 0;
 	a_cas(&tmp, 0, 0);
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 51c0639f..40c743e2 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -73,6 +73,10 @@ struct fdpic_dummy_loadmap {
 #define DL_NOMMU_SUPPORT 0
 #endif
 
+#ifndef TLSDESC_BACKWARDS
+#define TLSDESC_BACKWARDS 0
+#endif
+
 #if !DL_FDPIC
 #define IS_RELATIVE(x,s) ( \
 	(R_TYPE(x) == REL_RELATIVE) || \
@@ -92,8 +96,12 @@ struct fdpic_dummy_loadmap {
 #define DT_DEBUG_INDIRECT 0
 #endif
 
+#ifndef DT_DEBUG_INDIRECT_REL
+#define DT_DEBUG_INDIRECT_REL 0
+#endif
+
 #define AUX_CNT 32
-#define DYN_CNT 32
+#define DYN_CNT 37
 
 typedef void (*stage2_func)(unsigned char *, size_t *);
 
diff --git a/src/internal/emulate_wait4.c b/src/internal/emulate_wait4.c
new file mode 100644
index 00000000..f6303412
--- /dev/null
+++ b/src/internal/emulate_wait4.c
@@ -0,0 +1,55 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+#ifndef SYS_wait4
+hidden long __emulate_wait4(int pid, int *status, int options, void *kru, int cp)
+{
+	idtype_t t;
+	int r;
+	siginfo_t info;
+
+	info.si_pid = 0;
+	if (pid < -1) {
+		t = P_PGID;
+		pid = -pid;
+	} else if (pid == -1) {
+		t = P_ALL;
+	} else if (pid == 0) {
+		t = P_PGID;
+	} else {
+		t = P_PID;
+	}
+
+	if (cp) r = __syscall_cp(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+	else r = __syscall(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+
+	if (r<0) return r;
+
+	if (info.si_pid && status) {
+		int sw=0;
+		switch (info.si_code) {
+		case CLD_CONTINUED:
+			sw = 0xffff;
+			break;
+		case CLD_DUMPED:
+			sw = info.si_status&0x7f | 0x80;
+			break;
+		case CLD_EXITED:
+			sw = (info.si_status&0xff) << 8;
+			break;
+		case CLD_KILLED:
+			sw = info.si_status&0x7f;
+			break;
+		case CLD_STOPPED:
+		case CLD_TRAPPED:
+			/* see ptrace(2); the high bits of si_status can contain */
+			/* PTRACE_EVENT_ values which must be preserved */
+			sw = (info.si_status << 8) + 0x7f;
+			break;
+		}
+		*status = sw;
+	}
+
+	return info.si_pid;
+}
+#endif
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h
index 5892c13b..f995fce2 100644
--- a/src/internal/fork_impl.h
+++ b/src/internal/fork_impl.h
@@ -2,7 +2,6 @@
 
 extern hidden volatile int *const __at_quick_exit_lockptr;
 extern hidden volatile int *const __atexit_lockptr;
-extern hidden volatile int *const __dlerror_lockptr;
 extern hidden volatile int *const __gettext_lockptr;
 extern hidden volatile int *const __locale_lockptr;
 extern hidden volatile int *const __random_lockptr;
@@ -17,3 +16,6 @@ extern hidden volatile int *const __vmlock_lockptr;
 
 hidden void __malloc_atfork(int);
 hidden void __ldso_atfork(int);
+hidden void __pthread_key_atfork(int);
+
+hidden void __post_Fork(int);
diff --git a/src/internal/ksigaction.h b/src/internal/ksigaction.h
index 8ebd5938..ef333f33 100644
--- a/src/internal/ksigaction.h
+++ b/src/internal/ksigaction.h
@@ -6,8 +6,13 @@
 struct k_sigaction {
 	void (*handler)(int);
 	unsigned long flags;
+#ifdef SA_RESTORER
 	void (*restorer)(void);
+#endif
 	unsigned mask[2];
+#ifndef SA_RESTORER
+	void *unused;
+#endif
 };
 
 hidden void __restore(), __restore_rt();
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 4f41e1dc..33d981f9 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -58,7 +58,7 @@ hidden long __syscall_ret(unsigned long),
 #define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
 #define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
 
-static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, long c, long d, long e, long f)
+static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, syscall_arg_t b, syscall_arg_t c, syscall_arg_t d, syscall_arg_t e, syscall_arg_t f)
 {
 	long r;
 	if (cp) r = __syscall_cp(sys, a, b, c, d, e, f);
@@ -71,9 +71,9 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l
 	return r;
 }
 #define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \
-	(long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f))
+	__scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f))
 #define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \
-	(long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f))
+	__scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f))
 
 /* fixup legacy 16-bit junk */
 
@@ -391,6 +391,18 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l
 #define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__)
 #define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__))
 
+#ifdef SYS_wait4
+#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d)
+#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d)
+#else
+hidden long __emulate_wait4(int, int *, int, void *, int);
+#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0)
+#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1)
+#endif
+
+#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d))
+#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d))
+
 hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned);
 
 hidden void *__vdsosym(const char *, const char *);
diff --git a/src/ipc/semtimedop.c b/src/ipc/semtimedop.c
index 1632e7b0..a104af21 100644
--- a/src/ipc/semtimedop.c
+++ b/src/ipc/semtimedop.c
@@ -7,7 +7,8 @@
 #define IS32BIT(x) !((x)+0x80000000ULL>>32)
 #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
 
-#if !defined(SYS_semtimedop) && !defined(SYS_ipc)
+#if !defined(SYS_semtimedop) && !defined(SYS_ipc) || \
+	SYS_semtimedop == SYS_semtimedop_time64
 #define NO_TIME32 1
 #else
 #define NO_TIME32 0
diff --git a/src/ldso/dlerror.c b/src/ldso/dlerror.c
index afe59253..dae0f3a9 100644
--- a/src/ldso/dlerror.c
+++ b/src/ldso/dlerror.c
@@ -3,8 +3,7 @@
 #include <stdarg.h>
 #include "pthread_impl.h"
 #include "dynlink.h"
-#include "lock.h"
-#include "fork_impl.h"
+#include "atomic.h"
 
 #define malloc __libc_malloc
 #define calloc __libc_calloc
@@ -23,28 +22,31 @@ char *dlerror()
 		return s;
 }
 
-static volatile int freebuf_queue_lock[1];
-static void **freebuf_queue;
-volatile int *const __dlerror_lockptr = freebuf_queue_lock;
+/* Atomic singly-linked list, used to store list of thread-local dlerror
+ * buffers for deferred free. They cannot be freed at thread exit time
+ * because, by the time it's known they can be freed, the exiting thread
+ * is in a highly restrictive context where it cannot call (even the
+ * libc-internal) free. It also can't take locks; thus the atomic list. */
+
+static void *volatile freebuf_queue;
 
 void __dl_thread_cleanup(void)
 {
 	pthread_t self = __pthread_self();
-	if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
-		LOCK(freebuf_queue_lock);
-		void **p = (void **)self->dlerror_buf;
-		*p = freebuf_queue;
-		freebuf_queue = p;
-		UNLOCK(freebuf_queue_lock);
-	}
+	if (!self->dlerror_buf || self->dlerror_buf == (void *)-1)
+		return;
+	void *h;
+	do {
+		h = freebuf_queue;
+		*(void **)self->dlerror_buf = h;
+	} while (a_cas_p(&freebuf_queue, h, self->dlerror_buf) != h);
 }
 
 hidden void __dl_vseterr(const char *fmt, va_list ap)
 {
-	LOCK(freebuf_queue_lock);
-	void **q = freebuf_queue;
-	freebuf_queue = 0;
-	UNLOCK(freebuf_queue_lock);
+	void **q;
+	do q = freebuf_queue;
+	while (q && a_cas_p(&freebuf_queue, q, 0) != q);
 
 	while (q) {
 		void **p = *q;
diff --git a/src/ldso/loongarch64/dlsym.s b/src/ldso/loongarch64/dlsym.s
new file mode 100644
index 00000000..26fabcdb
--- /dev/null
+++ b/src/ldso/loongarch64/dlsym.s
@@ -0,0 +1,7 @@
+.global dlsym
+.hidden __dlsym
+.type   dlsym,@function
+dlsym:
+	move      $a2, $ra
+	la.global $t0, __dlsym
+	jr        $t0
diff --git a/src/ldso/riscv32/dlsym.s b/src/ldso/riscv32/dlsym.s
new file mode 100644
index 00000000..2bafd72d
--- /dev/null
+++ b/src/ldso/riscv32/dlsym.s
@@ -0,0 +1,6 @@
+.global dlsym
+.hidden __dlsym
+.type dlsym, %function
+dlsym:
+	mv a2, ra
+	tail __dlsym
diff --git a/src/ldso/riscv64/tlsdesc.s b/src/ldso/riscv64/tlsdesc.s
new file mode 100644
index 00000000..bef8b322
--- /dev/null
+++ b/src/ldso/riscv64/tlsdesc.s
@@ -0,0 +1,32 @@
+.text
+.global __tlsdesc_static
+.hidden __tlsdesc_static
+.type __tlsdesc_static,%function
+__tlsdesc_static:
+	ld a0,8(a0)
+	jr t0
+
+.global __tlsdesc_dynamic
+.hidden __tlsdesc_dynamic
+.type __tlsdesc_dynamic,%function
+__tlsdesc_dynamic:
+	add sp,sp,-16
+	sd t1,(sp)
+	sd t2,8(sp)
+
+	ld t2,-8(tp) # t2=dtv
+
+	ld a0,8(a0)  # a0=&{modidx,off}
+	ld t1,8(a0)  # t1=off
+	ld a0,(a0)   # a0=modidx
+	sll a0,a0,3  # a0=8*modidx
+
+	add a0,a0,t2 # a0=dtv+8*modidx
+	ld a0,(a0)   # a0=dtv[modidx]
+	add a0,a0,t1 # a0=dtv[modidx]+off
+	sub a0,a0,tp # a0=dtv[modidx]+off-tp
+
+	ld t1,(sp)
+	ld t2,8(sp)
+	add sp,sp,16
+	jr t0
diff --git a/src/ldso/sh/dlsym.s b/src/ldso/sh/dlsym.s
index 11a6fff5..34f3c35c 100644
--- a/src/ldso/sh/dlsym.s
+++ b/src/ldso/sh/dlsym.s
@@ -5,7 +5,7 @@
 dlsym:
 	mov.l L1, r0
 1:	braf  r0
-	 mov.l @r15, r6
+	 sts pr, r6
 
 .align 2
 L1:	.long __dlsym@PLT-(1b+4-.)
diff --git a/src/legacy/ftw.c b/src/legacy/ftw.c
index 506bd29c..e757fc6f 100644
--- a/src/legacy/ftw.c
+++ b/src/legacy/ftw.c
@@ -7,5 +7,3 @@ int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int
 	 * actually undefined, but works on all real-world machines. */
 	return nftw(path, (int (*)())fn, fd_limit, FTW_PHYS);
 }
-
-weak_alias(ftw, ftw64);
diff --git a/src/linux/cache.c b/src/linux/cache.c
index 0eb051c2..e76f7812 100644
--- a/src/linux/cache.c
+++ b/src/linux/cache.c
@@ -21,7 +21,7 @@ weak_alias(__cachectl, cachectl);
 #ifdef SYS_riscv_flush_icache
 
 #define VDSO_FLUSH_ICACHE_SYM "__vdso_flush_icache"
-#define VDSO_FLUSH_ICACHE_VER "LINUX_4.5"
+#define VDSO_FLUSH_ICACHE_VER "LINUX_4.15"
 
 static void *volatile vdso_func;
 
@@ -45,6 +45,7 @@ int __riscv_flush_icache(void *start, void *end, unsigned long int flags)
 		if (!r) return r;
 		if (r != -ENOSYS) return __syscall_ret(r);
 	}
+	return syscall(SYS_riscv_flush_icache, start, end, flags);
 }
 weak_alias(__riscv_flush_icache, riscv_flush_icache);
 #endif
diff --git a/src/linux/clone.c b/src/linux/clone.c
index 8c1af7d3..257c1cec 100644
--- a/src/linux/clone.c
+++ b/src/linux/clone.c
@@ -4,18 +4,62 @@
 #include <sched.h>
 #include "pthread_impl.h"
 #include "syscall.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+struct clone_start_args {
+	int (*func)(void *);
+	void *arg;
+	sigset_t sigmask;
+};
+
+static int clone_start(void *arg)
+{
+	struct clone_start_args *csa = arg;
+	__post_Fork(0);
+	__restore_sigs(&csa->sigmask);
+	return csa->func(csa->arg);
+}
 
 int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
 {
+	struct clone_start_args csa;
 	va_list ap;
-	pid_t *ptid, *ctid;
-	void  *tls;
+	pid_t *ptid = 0, *ctid = 0;
+	void  *tls = 0;
+
+	/* Flags that produce an invalid thread/TLS state are disallowed. */
+	int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID;
+
+	if ((flags & badflags) || !stack)
+		return __syscall_ret(-EINVAL);
 
 	va_start(ap, arg);
-	ptid = va_arg(ap, pid_t *);
-	tls  = va_arg(ap, void *);
-	ctid = va_arg(ap, pid_t *);
+	if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID))
+	 	ptid = va_arg(ap, pid_t *);
+	if (flags & CLONE_CHILD_SETTID) {
+		tls = va_arg(ap, void *);
+		ctid = va_arg(ap, pid_t *);
+	}
 	va_end(ap);
 
-	return __syscall_ret(__clone(func, stack, flags, arg, ptid, tls, ctid));
+	/* If CLONE_VM is used, it's impossible to give the child a consistent
+	 * thread structure. In this case, the best we can do is assume the
+	 * caller is content with an extremely restrictive execution context
+	 * like the one vfork() would provide. */
+	if (flags & CLONE_VM) return __syscall_ret(
+		__clone(func, stack, flags, arg, ptid, tls, ctid));
+
+	__block_all_sigs(&csa.sigmask);
+	LOCK(__abort_lock);
+
+	/* Setup the a wrapper start function for the child process to do
+	 * mimic _Fork in producing a consistent execution state. */
+	csa.func = func;
+	csa.arg = arg;
+	int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid);
+
+	__post_Fork(ret);
+	__restore_sigs(&csa.sigmask);
+	return __syscall_ret(ret);
 }
diff --git a/src/linux/epoll.c b/src/linux/epoll.c
index 93baa814..e56e8f4c 100644
--- a/src/linux/epoll.c
+++ b/src/linux/epoll.c
@@ -5,6 +5,7 @@
 
 int epoll_create(int size)
 {
+	if (size<=0) return __syscall_ret(-EINVAL);
 	return epoll_create1(0);
 }
 
diff --git a/src/linux/fallocate.c b/src/linux/fallocate.c
index 7d68bc8f..9146350e 100644
--- a/src/linux/fallocate.c
+++ b/src/linux/fallocate.c
@@ -7,6 +7,3 @@ int fallocate(int fd, int mode, off_t base, off_t len)
 	return syscall(SYS_fallocate, fd, mode, __SYSCALL_LL_E(base),
 		__SYSCALL_LL_E(len));
 }
-
-#undef fallocate64
-weak_alias(fallocate, fallocate64);
diff --git a/src/linux/getdents.c b/src/linux/getdents.c
index 796c1e5c..97f76e14 100644
--- a/src/linux/getdents.c
+++ b/src/linux/getdents.c
@@ -8,5 +8,3 @@ int getdents(int fd, struct dirent *buf, size_t len)
 	if (len>INT_MAX) len = INT_MAX;
 	return syscall(SYS_getdents, fd, buf, len);
 }
-
-weak_alias(getdents, getdents64);
diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c
index 343f7360..f64fe7e1 100644
--- a/src/linux/membarrier.c
+++ b/src/linux/membarrier.c
@@ -35,7 +35,7 @@ int __membarrier(int cmd, int flags)
 		__tl_lock();
 		sem_init(&barrier_sem, 0, 0);
 		struct sigaction sa = {
-			.sa_flags = SA_RESTART,
+			.sa_flags = SA_RESTART | SA_ONSTACK,
 			.sa_handler = bcast_barrier
 		};
 		memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
diff --git a/src/linux/preadv2.c b/src/linux/preadv2.c
new file mode 100644
index 00000000..5e7ab70f
--- /dev/null
+++ b/src/linux/preadv2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t preadv2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_preadv
+	if (!flags) {
+		if (ofs==-1) return readv(fd, iov, count);
+		return syscall_cp(SYS_preadv, fd, iov, count,
+			(long)(ofs), (long)(ofs>>32));
+	}
+#endif
+	return syscall_cp(SYS_preadv2, fd, iov, count,
+		(long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/prlimit.c b/src/linux/prlimit.c
index 3df9ffba..fcf45aab 100644
--- a/src/linux/prlimit.c
+++ b/src/linux/prlimit.c
@@ -21,6 +21,3 @@ int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlim
 	}
 	return r;
 }
-
-#undef prlimit64
-weak_alias(prlimit, prlimit64);
diff --git a/src/linux/pwritev2.c b/src/linux/pwritev2.c
new file mode 100644
index 00000000..ece90d7c
--- /dev/null
+++ b/src/linux/pwritev2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t pwritev2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_pwritev
+	if (!flags) {
+		if (ofs==-1) return writev(fd, iov, count);
+		return syscall_cp(SYS_pwritev, fd, iov, count,
+			(long)(ofs), (long)(ofs>>32));
+	}
+#endif
+	return syscall_cp(SYS_pwritev2, fd, iov, count,
+		(long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/sendfile.c b/src/linux/sendfile.c
index 9afe6dd6..fc1577d3 100644
--- a/src/linux/sendfile.c
+++ b/src/linux/sendfile.c
@@ -5,5 +5,3 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count)
 {
 	return syscall(SYS_sendfile, out_fd, in_fd, ofs, count);
 }
-
-weak_alias(sendfile, sendfile64);
diff --git a/src/linux/statx.c b/src/linux/statx.c
new file mode 100644
index 00000000..4616bff4
--- /dev/null
+++ b/src/linux/statx.c
@@ -0,0 +1,42 @@
+#define _GNU_SOURCE
+#include <sys/stat.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/sysmacros.h>
+#include <errno.h>
+
+int statx(int dirfd, const char *restrict path, int flags, unsigned mask, struct statx *restrict stx)
+{
+	int ret = __syscall(SYS_statx, dirfd, path, flags, mask, stx);
+
+#ifndef SYS_fstatat
+	return __syscall_ret(ret);
+#endif
+
+	if (ret != -ENOSYS) return __syscall_ret(ret);
+
+	struct stat st;
+	ret = fstatat(dirfd, path, &st, flags);
+	if (ret) return ret;
+
+	stx->stx_dev_major = major(st.st_dev);
+	stx->stx_dev_minor = minor(st.st_dev);
+	stx->stx_ino = st.st_ino;
+	stx->stx_mode = st.st_mode;
+	stx->stx_nlink = st.st_nlink;
+	stx->stx_uid = st.st_uid;
+	stx->stx_gid = st.st_gid;
+	stx->stx_size = st.st_size;
+	stx->stx_blksize = st.st_blksize;
+	stx->stx_blocks = st.st_blocks;
+	stx->stx_atime.tv_sec = st.st_atim.tv_sec;
+	stx->stx_atime.tv_nsec = st.st_atim.tv_nsec;
+	stx->stx_mtime.tv_sec = st.st_mtim.tv_sec;
+	stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec;
+	stx->stx_ctime.tv_sec = st.st_ctim.tv_sec;
+	stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec;
+	stx->stx_btime = (struct statx_timestamp){.tv_sec=0, .tv_nsec=0};
+	stx->stx_mask = STATX_BASIC_STATS;
+
+	return 0;
+}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index 83650e34..fb08c0d0 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -12,7 +12,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
 	if (ru) {
 		long long kru64[18];
 		r = __syscall(SYS_wait4_time64, pid, status, options, kru64);
-		if (!r) {
+		if (r > 0) {
 			ru->ru_utime = (struct timeval)
 				{ .tv_sec = kru64[0], .tv_usec = kru64[1] };
 			ru->ru_stime = (struct timeval)
@@ -26,7 +26,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
 	}
 #endif
 	char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
-	r = __syscall(SYS_wait4, pid, status, options, dest);
+	r = __sys_wait4(pid, status, options, dest);
 	if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
 		long kru[4];
 		memcpy(kru, dest, 4*sizeof(long));
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
index 3047c27b..7fb2e1ef 100644
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -49,10 +49,10 @@ static const unsigned char charmaps[] =
 "ucs4\0utf32\0\0\313"
 "ucs2\0\0\314"
 "eucjp\0\0\320"
-"shiftjis\0sjis\0\0\321"
+"shiftjis\0sjis\0cp932\0\0\321"
 "iso2022jp\0\0\322"
 "gb18030\0\0\330"
-"gbk\0\0\331"
+"gbk\0cp936\0windows936\0\0\331"
 "gb2312\0\0\332"
 "big5\0bigfive\0cp950\0big5hkscs\0\0\340"
 "euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
@@ -340,6 +340,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
 				c++;
 				d -= 159;
 			}
+			if (c>=84) goto ilseq;
 			c = jis0208[c][d];
 			if (!c) goto ilseq;
 			break;
@@ -403,6 +404,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
 			if (c < 128) break;
 			if (c < 0xa1) goto ilseq;
 		case GBK:
+			if (c == 128) {
+				c = 0x20ac;
+				break;
+			}
 		case GB18030:
 			if (c < 128) break;
 			c -= 0x81;
diff --git a/src/malloc/mallocng/free.c b/src/malloc/mallocng/free.c
index 418a085c..43f32aad 100644
--- a/src/malloc/mallocng/free.c
+++ b/src/malloc/mallocng/free.c
@@ -119,7 +119,7 @@ void free(void *p)
 	if (((uintptr_t)(start-1) ^ (uintptr_t)end) >= 2*PGSZ && g->last_idx) {
 		unsigned char *base = start + (-(uintptr_t)start & (PGSZ-1));
 		size_t len = (end-base) & -PGSZ;
-		if (len) {
+		if (len && USE_MADV_FREE) {
 			int e = errno;
 			madvise(base, len, MADV_FREE);
 			errno = e;
diff --git a/src/malloc/mallocng/glue.h b/src/malloc/mallocng/glue.h
index 151c48b8..77f4c812 100644
--- a/src/malloc/mallocng/glue.h
+++ b/src/malloc/mallocng/glue.h
@@ -24,6 +24,8 @@
 #define realloc __libc_realloc
 #define free __libc_free
 
+#define USE_MADV_FREE 0
+
 #if USE_REAL_ASSERT
 #include <assert.h>
 #else
diff --git a/src/math/acoshl.c b/src/math/acoshl.c
index 8d4b43f6..943cec17 100644
--- a/src/math/acoshl.c
+++ b/src/math/acoshl.c
@@ -10,14 +10,18 @@ long double acoshl(long double x)
 long double acoshl(long double x)
 {
 	union ldshape u = {x};
-	int e = u.i.se & 0x7fff;
+	int e = u.i.se;
 
 	if (e < 0x3fff + 1)
-		/* |x| < 2, invalid if x < 1 or nan */
+		/* 0 <= x < 2, invalid if x < 1 */
 		return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1)));
 	if (e < 0x3fff + 32)
-		/* |x| < 0x1p32 */
+		/* 2 <= x < 0x1p32 */
 		return logl(2*x - 1/(x+sqrtl(x*x-1)));
+	if (e & 0x8000)
+		/* x < 0 or x = -0, invalid */
+		return (x - x) / (x - x);
+	/* 0x1p32 <= x or nan */
 	return logl(x) + 0.693147180559945309417232121458176568L;
 }
 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
diff --git a/src/math/logf.c b/src/math/logf.c
index 7ee5d7fe..e4c2237c 100644
--- a/src/math/logf.c
+++ b/src/math/logf.c
@@ -53,7 +53,7 @@ float logf(float x)
 	tmp = ix - OFF;
 	i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
 	k = (int32_t)tmp >> 23; /* arithmetic shift */
-	iz = ix - (tmp & 0x1ff << 23);
+	iz = ix - (tmp & 0xff800000);
 	invc = T[i].invc;
 	logc = T[i].logc;
 	z = (double_t)asfloat(iz);
diff --git a/src/math/powl.c b/src/math/powl.c
index 5b6da07b..6f64ea71 100644
--- a/src/math/powl.c
+++ b/src/math/powl.c
@@ -212,25 +212,33 @@ long double powl(long double x, long double y)
 	}
 	if (x == 1.0)
 		return 1.0; /* 1**y = 1, even if y is nan */
-	if (x == -1.0 && !isfinite(y))
-		return 1.0; /* -1**inf = 1 */
 	if (y == 0.0)
 		return 1.0; /* x**0 = 1, even if x is nan */
 	if (y == 1.0)
 		return x;
-	if (y >= LDBL_MAX) {
-		if (x > 1.0 || x < -1.0)
-			return INFINITY;
-		if (x != 0.0)
-			return 0.0;
-	}
-	if (y <= -LDBL_MAX) {
-		if (x > 1.0 || x < -1.0)
+	/* if y*log2(x) < log2(LDBL_TRUE_MIN)-1 then x^y uflows to 0
+	   if y*log2(x) > -log2(LDBL_TRUE_MIN)+1 > LDBL_MAX_EXP then x^y oflows
+	   if |x|!=1 then |log2(x)| > |log(x)| > LDBL_EPSILON/2 so
+	   x^y oflows/uflows if |y|*LDBL_EPSILON/2 > -log2(LDBL_TRUE_MIN)+1 */
+	if (fabsl(y) > 2*(-LDBL_MIN_EXP+LDBL_MANT_DIG+1)/LDBL_EPSILON) {
+		/* y is not an odd int */
+		if (x == -1.0)
+			return 1.0;
+		if (y == INFINITY) {
+			if (x > 1.0 || x < -1.0)
+				return INFINITY;
 			return 0.0;
-		if (x != 0.0 || y == -INFINITY)
+		}
+		if (y == -INFINITY) {
+			if (x > 1.0 || x < -1.0)
+				return 0.0;
 			return INFINITY;
+		}
+		if ((x > 1.0 || x < -1.0) == (y > 0))
+			return huge * huge;
+		return twom10000 * twom10000;
 	}
-	if (x >= LDBL_MAX) {
+	if (x == INFINITY) {
 		if (y > 0.0)
 			return INFINITY;
 		return 0.0;
@@ -253,7 +261,7 @@ long double powl(long double x, long double y)
 			yoddint = 1;
 	}
 
-	if (x <= -LDBL_MAX) {
+	if (x == -INFINITY) {
 		if (y > 0.0) {
 			if (yoddint)
 				return -INFINITY;
diff --git a/src/math/riscv32/copysign.c b/src/math/riscv32/copysign.c
new file mode 100644
index 00000000..c7854178
--- /dev/null
+++ b/src/math/riscv32/copysign.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double copysign(double x, double y)
+{
+	__asm__ ("fsgnj.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../copysign.c"
+
+#endif
diff --git a/src/math/riscv32/copysignf.c b/src/math/riscv32/copysignf.c
new file mode 100644
index 00000000..a125611a
--- /dev/null
+++ b/src/math/riscv32/copysignf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float copysignf(float x, float y)
+{
+	__asm__ ("fsgnj.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../copysignf.c"
+
+#endif
diff --git a/src/math/riscv32/fabs.c b/src/math/riscv32/fabs.c
new file mode 100644
index 00000000..5290b6f0
--- /dev/null
+++ b/src/math/riscv32/fabs.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fabs(double x)
+{
+	__asm__ ("fabs.d %0, %1" : "=f"(x) : "f"(x));
+	return x;
+}
+
+#else
+
+#include "../fabs.c"
+
+#endif
diff --git a/src/math/riscv32/fabsf.c b/src/math/riscv32/fabsf.c
new file mode 100644
index 00000000..f5032e35
--- /dev/null
+++ b/src/math/riscv32/fabsf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fabsf(float x)
+{
+	__asm__ ("fabs.s %0, %1" : "=f"(x) : "f"(x));
+	return x;
+}
+
+#else
+
+#include "../fabsf.c"
+
+#endif
diff --git a/src/math/riscv32/fma.c b/src/math/riscv32/fma.c
new file mode 100644
index 00000000..99b05713
--- /dev/null
+++ b/src/math/riscv32/fma.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fma(double x, double y, double z)
+{
+	__asm__ ("fmadd.d %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+	return x;
+}
+
+#else
+
+#include "../fma.c"
+
+#endif
diff --git a/src/math/riscv32/fmaf.c b/src/math/riscv32/fmaf.c
new file mode 100644
index 00000000..f9dc47ed
--- /dev/null
+++ b/src/math/riscv32/fmaf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaf(float x, float y, float z)
+{
+	__asm__ ("fmadd.s %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+	return x;
+}
+
+#else
+
+#include "../fmaf.c"
+
+#endif
diff --git a/src/math/riscv32/fmax.c b/src/math/riscv32/fmax.c
new file mode 100644
index 00000000..023709cd
--- /dev/null
+++ b/src/math/riscv32/fmax.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmax(double x, double y)
+{
+	__asm__ ("fmax.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../fmax.c"
+
+#endif
diff --git a/src/math/riscv32/fmaxf.c b/src/math/riscv32/fmaxf.c
new file mode 100644
index 00000000..863d2bd1
--- /dev/null
+++ b/src/math/riscv32/fmaxf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaxf(float x, float y)
+{
+	__asm__ ("fmax.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../fmaxf.c"
+
+#endif
diff --git a/src/math/riscv32/fmin.c b/src/math/riscv32/fmin.c
new file mode 100644
index 00000000..a4e3b067
--- /dev/null
+++ b/src/math/riscv32/fmin.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmin(double x, double y)
+{
+	__asm__ ("fmin.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../fmin.c"
+
+#endif
diff --git a/src/math/riscv32/fminf.c b/src/math/riscv32/fminf.c
new file mode 100644
index 00000000..32156e80
--- /dev/null
+++ b/src/math/riscv32/fminf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fminf(float x, float y)
+{
+	__asm__ ("fmin.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+	return x;
+}
+
+#else
+
+#include "../fminf.c"
+
+#endif
diff --git a/src/math/riscv32/sqrt.c b/src/math/riscv32/sqrt.c
new file mode 100644
index 00000000..867a504c
--- /dev/null
+++ b/src/math/riscv32/sqrt.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double sqrt(double x)
+{
+	__asm__ ("fsqrt.d %0, %1" : "=f"(x) : "f"(x));
+	return x;
+}
+
+#else
+
+#include "../sqrt.c"
+
+#endif
diff --git a/src/math/riscv32/sqrtf.c b/src/math/riscv32/sqrtf.c
new file mode 100644
index 00000000..610c2cf8
--- /dev/null
+++ b/src/math/riscv32/sqrtf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float sqrtf(float x)
+{
+	__asm__ ("fsqrt.s %0, %1" : "=f"(x) : "f"(x));
+	return x;
+}
+
+#else
+
+#include "../sqrtf.c"
+
+#endif
diff --git a/src/math/sqrtl.c b/src/math/sqrtl.c
index 1b9f19c7..a231b3f2 100644
--- a/src/math/sqrtl.c
+++ b/src/math/sqrtl.c
@@ -205,7 +205,7 @@ long double sqrtl(long double x)
 	top = (top + 0x3fff) >> 1;
 
 	/* r ~ 1/sqrt(m) */
-	static const uint64_t three = 0xc0000000;
+	const uint64_t three = 0xc0000000;
 	uint64_t r, s, d, u, i;
 	i = (ix.hi >> 42) % 128;
 	r = (uint32_t)__rsqrt_tab[i] << 16;
@@ -227,7 +227,7 @@ long double sqrtl(long double x)
 	r = mul64(u, r) << 1;
 	/* |r sqrt(m) - 1| < 0x1.c001p-59, switch to 128bit */
 
-	static const u128 threel = {.hi=three<<32, .lo=0};
+	const u128 threel = {.hi=three<<32, .lo=0};
 	u128 rl, sl, dl, ul;
 	rl.hi = r;
 	rl.lo = 0;
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index c3f66995..b02b81c3 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring)
 	if (optstring[i] == ':') {
 		optarg = 0;
 		if (optstring[i+1] != ':' || optpos) {
-			optarg = argv[optind++] + optpos;
+			optarg = argv[optind++];
+			if (optpos) optarg += optpos;
 			optpos = 0;
 		}
 		if (optind > argc) {
diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c
index bf676307..a5558d81 100644
--- a/src/misc/getrlimit.c
+++ b/src/misc/getrlimit.c
@@ -26,5 +26,3 @@ int getrlimit(int resource, struct rlimit *rlim)
 	return ret;
 #endif
 }
-
-weak_alias(getrlimit, getrlimit64);
diff --git a/src/misc/lockf.c b/src/misc/lockf.c
index 16a80bec..0162442b 100644
--- a/src/misc/lockf.c
+++ b/src/misc/lockf.c
@@ -28,5 +28,3 @@ int lockf(int fd, int op, off_t size)
 	errno = EINVAL;
 	return -1;
 }
-
-weak_alias(lockf, lockf64);
diff --git a/src/misc/mntent.c b/src/misc/mntent.c
index d404fbe3..78bf0cd0 100644
--- a/src/misc/mntent.c
+++ b/src/misc/mntent.c
@@ -20,6 +20,42 @@ int endmntent(FILE *f)
 	return 1;
 }
 
+static char *unescape_ent(char *beg)
+{
+	char *dest = beg;
+	const char *src = beg;
+	while (*src) {
+		const char *val;
+		unsigned char cval = 0;
+		if (*src != '\\') {
+			*dest++ = *src++;
+			continue;
+		}
+		if (src[1] == '\\') {
+			++src;
+			*dest++ = *src++;
+			continue;
+		}
+		val = src + 1;
+		for (int i = 0; i < 3; ++i) {
+			if (*val >= '0' && *val <= '7') {
+				cval <<= 3;
+				cval += *val++ - '0';
+			} else {
+				break;
+			}
+		}
+		if (cval) {
+			*dest++ = cval;
+			src = val;
+		} else {
+			*dest++ = *src++;
+		}
+	}
+	*dest = 0;
+	return beg;
+}
+
 struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
 {
 	int n[8], use_internal = (linebuf == SENTINEL);
@@ -45,7 +81,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
 		len = strlen(linebuf);
 		if (len > INT_MAX) continue;
 		for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len;
-		sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
+		sscanf(linebuf, " %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %n%*[^ \t]%n %d %d",
 			n, n+1, n+2, n+3, n+4, n+5, n+6, n+7,
 			&mnt->mnt_freq, &mnt->mnt_passno);
 	} while (linebuf[n[0]] == '#' || n[1]==len);
@@ -55,10 +91,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
 	linebuf[n[5]] = 0;
 	linebuf[n[7]] = 0;
 
-	mnt->mnt_fsname = linebuf+n[0];
-	mnt->mnt_dir = linebuf+n[2];
-	mnt->mnt_type = linebuf+n[4];
-	mnt->mnt_opts = linebuf+n[6];
+	mnt->mnt_fsname = unescape_ent(linebuf+n[0]);
+	mnt->mnt_dir = unescape_ent(linebuf+n[2]);
+	mnt->mnt_type = unescape_ent(linebuf+n[4]);
+	mnt->mnt_opts = unescape_ent(linebuf+n[6]);
 
 	return mnt;
 }
diff --git a/src/misc/nftw.c b/src/misc/nftw.c
index 8dcff7fe..71bc62ee 100644
--- a/src/misc/nftw.c
+++ b/src/misc/nftw.c
@@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
 	int err;
 	struct FTW lev;
 
+	st.st_dev = st.st_ino = 0;
+
 	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
 		if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
 			type = FTW_SLN;
@@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int,
 		type = FTW_F;
 	}
 
-	if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
+	if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev)
 		return 0;
 	
 	new.chain = h;
@@ -138,5 +140,3 @@ int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, str
 	pthread_setcancelstate(cs, 0);
 	return r;
 }
-
-weak_alias(nftw, nftw64);
diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c
index 5b713cf3..edb413fa 100644
--- a/src/misc/setrlimit.c
+++ b/src/misc/setrlimit.c
@@ -49,5 +49,3 @@ int setrlimit(int resource, const struct rlimit *rlim)
 	return __syscall_ret(ret);
 #endif
 }
-
-weak_alias(setrlimit, setrlimit64);
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
index 7dc0c1be..710202f9 100644
--- a/src/misc/syslog.c
+++ b/src/misc/syslog.c
@@ -11,6 +11,7 @@
 #include <fcntl.h>
 #include "lock.h"
 #include "fork_impl.h"
+#include "locale_impl.h"
 
 static volatile int lock[1];
 static char log_ident[32];
@@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap)
 
 	now = time(NULL);
 	gmtime_r(&now, &tm);
-	strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+	strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE);
 
 	pid = (log_opt & LOG_PID) ? getpid() : 0;
 	l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",
diff --git a/src/mman/mmap.c b/src/mman/mmap.c
index eff88d82..43e5e029 100644
--- a/src/mman/mmap.c
+++ b/src/mman/mmap.c
@@ -37,5 +37,3 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
 }
 
 weak_alias(__mmap, mmap);
-
-weak_alias(mmap, mmap64);
diff --git a/src/mq/mq_notify.c b/src/mq/mq_notify.c
index 221591c7..0e1e6c7a 100644
--- a/src/mq/mq_notify.c
+++ b/src/mq/mq_notify.c
@@ -4,11 +4,14 @@
 #include <sys/socket.h>
 #include <signal.h>
 #include <unistd.h>
+#include <semaphore.h>
 #include "syscall.h"
 
 struct args {
-	pthread_barrier_t barrier;
+	sem_t sem;
 	int sock;
+	mqd_t mqd;
+	int err;
 	const struct sigevent *sev;
 };
 
@@ -20,8 +23,19 @@ static void *start(void *p)
 	int s = args->sock;
 	void (*func)(union sigval) = args->sev->sigev_notify_function;
 	union sigval val = args->sev->sigev_value;
+	struct sigevent sev2;
+	static const char zeros[32];
+	int err;
+
+	sev2.sigev_notify = SIGEV_THREAD;
+	sev2.sigev_signo = s;
+	sev2.sigev_value.sival_ptr = (void *)&zeros;
+
+	args->err = err = -__syscall(SYS_mq_notify, args->mqd, &sev2);
+	sem_post(&args->sem);
+	if (err) return 0;
 
-	pthread_barrier_wait(&args->barrier);
+	pthread_detach(pthread_self());
 	n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL);
 	close(s);
 	if (n==sizeof buf && buf[sizeof buf - 1] == 1)
@@ -35,8 +49,8 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
 	pthread_attr_t attr;
 	pthread_t td;
 	int s;
-	struct sigevent sev2;
-	static const char zeros[32];
+	int cs;
+	sigset_t allmask, origmask;
 
 	if (!sev || sev->sigev_notify != SIGEV_THREAD)
 		return syscall(SYS_mq_notify, mqd, sev);
@@ -44,30 +58,35 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
 	s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0);
 	if (s < 0) return -1;
 	args.sock = s;
+	args.mqd = mqd;
 
 	if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes;
 	else pthread_attr_init(&attr);
-	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-	pthread_barrier_init(&args.barrier, 0, 2);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+	sem_init(&args.sem, 0, 0);
 
+	sigfillset(&allmask);
+	pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
 	if (pthread_create(&td, &attr, start, &args)) {
 		__syscall(SYS_close, s);
+		pthread_sigmask(SIG_SETMASK, &origmask, 0);
 		errno = EAGAIN;
 		return -1;
 	}
+	pthread_sigmask(SIG_SETMASK, &origmask, 0);
 
-	pthread_barrier_wait(&args.barrier);
-	pthread_barrier_destroy(&args.barrier);
-
-	sev2.sigev_notify = SIGEV_THREAD;
-	sev2.sigev_signo = s;
-	sev2.sigev_value.sival_ptr = (void *)&zeros;
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+	sem_wait(&args.sem);
+	sem_destroy(&args.sem);
 
-	if (syscall(SYS_mq_notify, mqd, &sev2) < 0) {
-		pthread_cancel(td);
+	if (args.err) {
 		__syscall(SYS_close, s);
+		pthread_join(td, 0);
+		pthread_setcancelstate(cs, 0);
+		errno = args.err;
 		return -1;
 	}
 
+	pthread_setcancelstate(cs, 0);
 	return 0;
 }
diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c
index c94819e7..7824997e 100644
--- a/src/multibyte/mbrtowc.c
+++ b/src/multibyte/mbrtowc.c
@@ -8,7 +8,7 @@ size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate
 	static unsigned internal_state;
 	unsigned c;
 	const unsigned char *s = (const void *)src;
-	const unsigned N = n;
+	const size_t N = n;
 	wchar_t dummy;
 
 	if (!st) st = (void *)&internal_state;
diff --git a/src/network/accept4.c b/src/network/accept4.c
index 59ab1726..765a38ed 100644
--- a/src/network/accept4.c
+++ b/src/network/accept4.c
@@ -9,6 +9,10 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int
 	if (!flg) return accept(fd, addr, len);
 	int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0);
 	if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret;
+	if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) {
+		errno = EINVAL;
+		return -1;
+	}
 	ret = accept(fd, addr, len);
 	if (ret<0) return ret;
 	if (flg & SOCK_CLOEXEC)
diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
index e6ee19d9..09813112 100644
--- a/src/network/dns_parse.c
+++ b/src/network/dns_parse.c
@@ -1,7 +1,7 @@
 #include <string.h>
 #include "lookup.h"
 
-int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
+int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx)
 {
 	int qdcount, ancount;
 	const unsigned char *p;
@@ -12,21 +12,20 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
 	p = r+12;
 	qdcount = r[4]*256 + r[5];
 	ancount = r[6]*256 + r[7];
-	if (qdcount+ancount > 64) return -1;
 	while (qdcount--) {
 		while (p-r < rlen && *p-1U < 127) p++;
-		if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+		if (p>r+rlen-6)
 			return -1;
 		p += 5 + !!*p;
 	}
 	while (ancount--) {
 		while (p-r < rlen && *p-1U < 127) p++;
-		if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+		if (p>r+rlen-12)
 			return -1;
 		p += 1 + !!*p;
 		len = p[8]*256 + p[9];
-		if (p+len > r+rlen) return -1;
-		if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
+		if (len+10 > r+rlen-p) return -1;
+		if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1;
 		p += 10 + len;
 	}
 	return 0;
diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c
index 9596580e..56b71503 100644
--- a/src/network/gai_strerror.c
+++ b/src/network/gai_strerror.c
@@ -6,7 +6,7 @@ static const char msgs[] =
 	"Name does not resolve\0"
 	"Try again\0"
 	"Non-recoverable error\0"
-	"Unknown error\0"
+	"Name has no usable address\0"
 	"Unrecognized address family or invalid length\0"
 	"Unrecognized socket type\0"
 	"Unrecognized service\0"
diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
index efaab306..64ad259a 100644
--- a/src/network/getaddrinfo.c
+++ b/src/network/getaddrinfo.c
@@ -16,6 +16,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
 	char canon[256], *outcanon;
 	int nservs, naddrs, nais, canon_len, i, j, k;
 	int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
+	int no_family = 0;
 	struct aibuf *out;
 
 	if (!host && !serv) return EAI_NONAME;
@@ -66,9 +67,11 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
 				pthread_setcancelstate(
 					PTHREAD_CANCEL_DISABLE, &cs);
 				int r = connect(s, ta[i], tl[i]);
+				int saved_errno = errno;
 				pthread_setcancelstate(cs, 0);
 				close(s);
 				if (!r) continue;
+				errno = saved_errno;
 			}
 			switch (errno) {
 			case EADDRNOTAVAIL:
@@ -80,7 +83,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
 			default:
 				return EAI_SYSTEM;
 			}
-			if (family == tf[i]) return EAI_NONAME;
+			if (family == tf[i]) no_family = 1;
 			family = tf[1-i];
 		}
 	}
@@ -91,6 +94,8 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
 	naddrs = __lookup_name(addrs, canon, host, family, flags);
 	if (naddrs < 0) return naddrs;
 
+	if (no_family) return EAI_NODATA;
+
 	nais = nservs * naddrs;
 	canon_len = strlen(canon);
 	out = calloc(1, nais * sizeof(*out) + canon_len + 1);
diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c
index 598e2241..c3cacaac 100644
--- a/src/network/gethostbyaddr.c
+++ b/src/network/gethostbyaddr.c
@@ -20,5 +20,5 @@ struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)
 		err = gethostbyaddr_r(a, l, af, h,
 			(void *)(h+1), size-sizeof *h, &res, &h_errno);
 	} while (err == ERANGE);
-	return err ? 0 : h;
+	return res;
 }
diff --git a/src/network/gethostbyaddr_r.c b/src/network/gethostbyaddr_r.c
index 0f1e61aa..ceaf3935 100644
--- a/src/network/gethostbyaddr_r.c
+++ b/src/network/gethostbyaddr_r.c
@@ -54,10 +54,11 @@ int gethostbyaddr_r(const void *a, socklen_t l, int af,
 	case EAI_OVERFLOW:
 		return ERANGE;
 	default:
-	case EAI_MEMORY:
-	case EAI_SYSTEM:
 	case EAI_FAIL:
 		*err = NO_RECOVERY;
+		return EBADMSG;
+	case EAI_SYSTEM:
+		*err = NO_RECOVERY;
 		return errno;
 	case 0:
 		break;
diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c
index dc9d6621..bd0da7f8 100644
--- a/src/network/gethostbyname2.c
+++ b/src/network/gethostbyname2.c
@@ -21,5 +21,5 @@ struct hostent *gethostbyname2(const char *name, int af)
 		err = gethostbyname2_r(name, af, h,
 			(void *)(h+1), size-sizeof *h, &res, &h_errno);
 	} while (err == ERANGE);
-	return err ? 0 : h;
+	return res;
 }
diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c
index fc894877..a5eb67fe 100644
--- a/src/network/gethostbyname2_r.c
+++ b/src/network/gethostbyname2_r.c
@@ -22,7 +22,10 @@ int gethostbyname2_r(const char *name, int af,
 	if (cnt<0) switch (cnt) {
 	case EAI_NONAME:
 		*err = HOST_NOT_FOUND;
-		return ENOENT;
+		return 0;
+	case EAI_NODATA:
+		*err = NO_DATA;
+		return 0;
 	case EAI_AGAIN:
 		*err = TRY_AGAIN;
 		return EAGAIN;
@@ -30,7 +33,6 @@ int gethostbyname2_r(const char *name, int af,
 	case EAI_FAIL:
 		*err = NO_RECOVERY;
 		return EBADMSG;
-	case EAI_MEMORY:
 	case EAI_SYSTEM:
 		*err = NO_RECOVERY;
 		return errno;
diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c
index fed75bd8..74df4d6c 100644
--- a/src/network/getifaddrs.c
+++ b/src/network/getifaddrs.c
@@ -39,8 +39,8 @@ struct ifaddrs_storage {
 };
 
 struct ifaddrs_ctx {
-	struct ifaddrs_storage *first;
-	struct ifaddrs_storage *last;
+	struct ifaddrs *first;
+	struct ifaddrs *last;
 	struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
 };
 
@@ -195,9 +195,9 @@ static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
 	}
 
 	if (ifs->ifa.ifa_name) {
-		if (!ctx->first) ctx->first = ifs;
-		if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa;
-		ctx->last = ifs;
+		if (!ctx->first) ctx->first = &ifs->ifa;
+		if (ctx->last) ctx->last->ifa_next = &ifs->ifa;
+		ctx->last = &ifs->ifa;
 	} else {
 		free(ifs);
 	}
@@ -210,7 +210,7 @@ int getifaddrs(struct ifaddrs **ifap)
 	int r;
 	memset(ctx, 0, sizeof *ctx);
 	r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
-	if (r == 0) *ifap = &ctx->first->ifa;
-	else freeifaddrs(&ctx->first->ifa);
+	if (r == 0) *ifap = ctx->first;
+	else freeifaddrs(ctx->first);
 	return r;
 }
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
index 949e1811..133c15b3 100644
--- a/src/network/getnameinfo.c
+++ b/src/network/getnameinfo.c
@@ -58,6 +58,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i
 		if ((p=strchr(line, '#'))) *p++='\n', *p=0;
 
 		for (p=line; *p && !isspace(*p); p++);
+		if (!*p) continue;
 		*p++ = 0;
 		if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0)
 			continue;
@@ -108,10 +109,10 @@ static void reverse_services(char *buf, int port, int dgram)
 	__fclose_ca(f);
 }
 
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
 {
 	if (rr != RR_PTR) return 0;
-	if (__dn_expand(packet, (const unsigned char *)packet + 512,
+	if (__dn_expand(packet, (const unsigned char *)packet + plen,
 	    data, c, 256) <= 0)
 		*(char *)c = 0;
 	return 0;
@@ -161,8 +162,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
 			query[3] = 0; /* don't need AD flag */
 			int rlen = __res_send(query, qlen, reply, sizeof reply);
 			buf[0] = 0;
-			if (rlen > 0)
+			if (rlen > 0) {
+				if (rlen > sizeof reply) rlen = sizeof reply;
 				__dns_parse(reply, rlen, dns_parse_callback, buf);
+			}
 		}
 		if (!*buf) {
 			if (flags & NI_NAMEREQD) return EAI_NONAME;
diff --git a/src/network/getservbyport_r.c b/src/network/getservbyport_r.c
index b7f21c6b..e4cc3079 100644
--- a/src/network/getservbyport_r.c
+++ b/src/network/getservbyport_r.c
@@ -26,7 +26,7 @@ int getservbyport_r(int port, const char *prots,
 	/* Align buffer */
 	i = (uintptr_t)buf & sizeof(char *)-1;
 	if (!i) i = sizeof(char *);
-	if (buflen < 3*sizeof(char *)-i)
+	if (buflen <= 3*sizeof(char *)-i)
 		return ERANGE;
 	buf += sizeof(char *)-i;
 	buflen -= sizeof(char *)-i;
@@ -46,6 +46,8 @@ int getservbyport_r(int port, const char *prots,
 	case EAI_MEMORY:
 	case EAI_SYSTEM:
 		return ENOMEM;
+	case EAI_OVERFLOW:
+		return ERANGE;
 	default:
 		return ENOENT;
 	case 0:
diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c
index d36c3689..bcbdd9ef 100644
--- a/src/network/inet_pton.c
+++ b/src/network/inet_pton.c
@@ -54,6 +54,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0)
 			if (s[j]!='.' || (i<6 && brk<0)) return 0;
 			need_v4=1;
 			i++;
+			ip[i&7]=0;
 			break;
 		}
 		s += j+1;
diff --git a/src/network/lookup.h b/src/network/lookup.h
index ef662725..54b2f8b5 100644
--- a/src/network/lookup.h
+++ b/src/network/lookup.h
@@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in
 hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);
 hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
 
-hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *);
 
 #endif
diff --git a/src/network/lookup_ipliteral.c b/src/network/lookup_ipliteral.c
index 2fddab73..1e766206 100644
--- a/src/network/lookup_ipliteral.c
+++ b/src/network/lookup_ipliteral.c
@@ -15,7 +15,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil
 	struct in6_addr a6;
 	if (__inet_aton(name, &a4) > 0) {
 		if (family == AF_INET6) /* wrong family */
-			return EAI_NONAME;
+			return EAI_NODATA;
 		memcpy(&buf[0].addr, &a4, sizeof a4);
 		buf[0].family = AF_INET;
 		buf[0].scopeid = 0;
@@ -34,7 +34,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil
 	if (inet_pton(AF_INET6, name, &a6) <= 0)
 		return 0;
 	if (family == AF_INET) /* wrong family */
-		return EAI_NONAME;
+		return EAI_NODATA;
 
 	memcpy(&buf[0].addr, &a6, sizeof a6);
 	buf[0].family = AF_INET6;
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index b5232ce8..35218185 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -79,7 +79,7 @@ static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati
 		case 0:
 			continue;
 		default:
-			badfam = EAI_NONAME;
+			badfam = EAI_NODATA;
 			break;
 		}
 
@@ -102,45 +102,50 @@ struct dpc_ctx {
 	struct address *addrs;
 	char *canon;
 	int cnt;
+	int rrtype;
 };
 
 #define RR_A 1
 #define RR_CNAME 5
 #define RR_AAAA 28
 
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+#define ABUF_SIZE 4800
+
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
 {
 	char tmp[256];
+	int family;
 	struct dpc_ctx *ctx = c;
-	if (ctx->cnt >= MAXADDRS) return -1;
+	if (rr == RR_CNAME) {
+		if (__dn_expand(packet, (const unsigned char *)packet + plen,
+		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
+			strcpy(ctx->canon, tmp);
+		return 0;
+	}
+	if (ctx->cnt >= MAXADDRS) return 0;
+	if (rr != ctx->rrtype) return 0;
 	switch (rr) {
 	case RR_A:
 		if (len != 4) return -1;
-		ctx->addrs[ctx->cnt].family = AF_INET;
-		ctx->addrs[ctx->cnt].scopeid = 0;
-		memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
+		family = AF_INET;
 		break;
 	case RR_AAAA:
 		if (len != 16) return -1;
-		ctx->addrs[ctx->cnt].family = AF_INET6;
-		ctx->addrs[ctx->cnt].scopeid = 0;
-		memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
-		break;
-	case RR_CNAME:
-		if (__dn_expand(packet, (const unsigned char *)packet + 512,
-		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
-			strcpy(ctx->canon, tmp);
+		family = AF_INET6;
 		break;
 	}
+	ctx->addrs[ctx->cnt].family = family;
+	ctx->addrs[ctx->cnt].scopeid = 0;
+	memcpy(ctx->addrs[ctx->cnt++].addr, data, len);
 	return 0;
 }
 
 static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf)
 {
-	unsigned char qbuf[2][280], abuf[2][512];
+	unsigned char qbuf[2][280], abuf[2][ABUF_SIZE];
 	const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
 	unsigned char *ap[2] = { abuf[0], abuf[1] };
-	int qlens[2], alens[2];
+	int qlens[2], alens[2], qtypes[2];
 	int i, nq = 0;
 	struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
 	static const struct { int af; int rr; } afrr[2] = {
@@ -153,7 +158,8 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
 			qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr,
 				0, 0, 0, qbuf[nq], sizeof *qbuf);
 			if (qlens[nq] == -1)
-				return EAI_NONAME;
+				return 0;
+			qtypes[nq] = afrr[i].rr;
 			qbuf[nq][3] = 0; /* don't need AD flag */
 			/* Ensure query IDs are distinct. */
 			if (nq && qbuf[nq][0] == qbuf[0][0])
@@ -171,11 +177,14 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
 		if ((abuf[i][3] & 15) != 0) return EAI_FAIL;
 	}
 
-	for (i=0; i<nq; i++)
+	for (i=nq-1; i>=0; i--) {
+		ctx.rrtype = qtypes[i];
+		if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i];
 		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
+	}
 
 	if (ctx.cnt) return ctx.cnt;
-	return EAI_NONAME;
+	return EAI_NODATA;
 }
 
 static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
diff --git a/src/network/res_mkquery.c b/src/network/res_mkquery.c
index 33f50cb9..614bf786 100644
--- a/src/network/res_mkquery.c
+++ b/src/network/res_mkquery.c
@@ -13,6 +13,7 @@ int __res_mkquery(int op, const char *dname, int class, int type,
 	int n;
 
 	if (l && dname[l-1]=='.') l--;
+	if (l && dname[l-1]=='.') return -1;
 	n = 17+l+!!l;
 	if (l>253 || buflen<n || op>15u || class>255u || type>255u)
 		return -1;
diff --git a/src/network/res_msend.c b/src/network/res_msend.c
index 3e018009..86c2fcf4 100644
--- a/src/network/res_msend.c
+++ b/src/network/res_msend.c
@@ -1,5 +1,6 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <stdint.h>
@@ -16,17 +17,65 @@
 
 static void cleanup(void *p)
 {
-	__syscall(SYS_close, (intptr_t)p);
+	struct pollfd *pfd = p;
+	for (int i=0; pfd[i].fd >= -1; i++)
+		if (pfd[i].fd >= 0) __syscall(SYS_close, pfd[i].fd);
 }
 
 static unsigned long mtime()
 {
 	struct timespec ts;
-	clock_gettime(CLOCK_REALTIME, &ts);
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS)
+		clock_gettime(CLOCK_REALTIME, &ts);
 	return (unsigned long)ts.tv_sec * 1000
 		+ ts.tv_nsec / 1000000;
 }
 
+static int start_tcp(struct pollfd *pfd, int family, const void *sa, socklen_t sl, const unsigned char *q, int ql)
+{
+	struct msghdr mh = {
+		.msg_name = (void *)sa,
+		.msg_namelen = sl,
+		.msg_iovlen = 2,
+		.msg_iov = (struct iovec [2]){
+			{ .iov_base = (uint8_t[]){ ql>>8, ql }, .iov_len = 2 },
+			{ .iov_base = (void *)q, .iov_len = ql } }
+	};
+	int r;
+	int fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+	pfd->fd = fd;
+	pfd->events = POLLOUT;
+	if (!setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
+	    &(int){1}, sizeof(int))) {
+		r = sendmsg(fd, &mh, MSG_FASTOPEN|MSG_NOSIGNAL);
+		if (r == ql+2) pfd->events = POLLIN;
+		if (r >= 0) return r;
+		if (errno == EINPROGRESS) return 0;
+	}
+	r = connect(fd, sa, sl);
+	if (!r || errno == EINPROGRESS) return 0;
+	close(fd);
+	pfd->fd = -1;
+	return -1;
+}
+
+static void step_mh(struct msghdr *mh, size_t n)
+{
+	/* Adjust iovec in msghdr to skip first n bytes. */
+	while (mh->msg_iovlen && n >= mh->msg_iov->iov_len) {
+		n -= mh->msg_iov->iov_len;
+		mh->msg_iov++;
+		mh->msg_iovlen--;
+	}
+	if (!mh->msg_iovlen) return;
+	mh->msg_iov->iov_base = (char *)mh->msg_iov->iov_base + n;
+	mh->msg_iov->iov_len -= n;
+}
+
+/* Internal contract for __res_msend[_rc]: asize must be >=512, nqueries
+ * must be sufficiently small to be safe as VLA size. In practice it's
+ * either 1 or 2, anyway. */
+
 int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 	const int *qlens, unsigned char *const *answers, int *alens, int asize,
 	const struct resolvconf *conf)
@@ -44,7 +93,10 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 	int next;
 	int i, j;
 	int cs;
-	struct pollfd pfd;
+	struct pollfd pfd[nqueries+2];
+	int qpos[nqueries], apos[nqueries];
+	unsigned char alen_buf[nqueries][2];
+	int r;
 	unsigned long t0, t1, t2;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
@@ -68,29 +120,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 	}
 
 	/* Get local address and open/bind a socket */
-	sa.sin.sin_family = family;
 	fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
 
 	/* Handle case where system lacks IPv6 support */
 	if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) {
+		for (i=0; i<nns && conf->ns[nns].family == AF_INET6; i++);
+		if (i==nns) {
+			pthread_setcancelstate(cs, 0);
+			return -1;
+		}
 		fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
 		family = AF_INET;
+		sl = sizeof sa.sin;
 	}
-	if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
-		if (fd >= 0) close(fd);
-		pthread_setcancelstate(cs, 0);
-		return -1;
-	}
-
-	/* Past this point, there are no errors. Each individual query will
-	 * yield either no reply (indicated by zero length) or an answer
-	 * packet which is up to the caller to interpret. */
-
-	pthread_cleanup_push(cleanup, (void *)(intptr_t)fd);
-	pthread_setcancelstate(cs, 0);
 
 	/* Convert any IPv4 addresses in a mixed environment to v4-mapped */
-	if (family == AF_INET6) {
+	if (fd >= 0 && family == AF_INET6) {
 		setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
 		for (i=0; i<nns; i++) {
 			if (ns[i].sin.sin_family != AF_INET) continue;
@@ -104,16 +149,38 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 		}
 	}
 
+	sa.sin.sin_family = family;
+	if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
+		if (fd >= 0) close(fd);
+		pthread_setcancelstate(cs, 0);
+		return -1;
+	}
+
+	/* Past this point, there are no errors. Each individual query will
+	 * yield either no reply (indicated by zero length) or an answer
+	 * packet which is up to the caller to interpret. */
+
+	for (i=0; i<nqueries; i++) pfd[i].fd = -1;
+	pfd[nqueries].fd = fd;
+	pfd[nqueries].events = POLLIN;
+	pfd[nqueries+1].fd = -2;
+
+	pthread_cleanup_push(cleanup, pfd);
+	pthread_setcancelstate(cs, 0);
+
 	memset(alens, 0, sizeof *alens * nqueries);
 
-	pfd.fd = fd;
-	pfd.events = POLLIN;
 	retry_interval = timeout / attempts;
 	next = 0;
 	t0 = t2 = mtime();
 	t1 = t2 - retry_interval;
 
 	for (; t2-t0 < timeout; t2=mtime()) {
+		/* This is the loop exit condition: that all queries
+		 * have an accepted answer. */
+		for (i=0; i<nqueries && alens[i]>0; i++);
+		if (i==nqueries) break;
+
 		if (t2-t1 >= retry_interval) {
 			/* Query all configured namservers in parallel */
 			for (i=0; i<nqueries; i++)
@@ -127,10 +194,20 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 		}
 
 		/* Wait for a response, or until time to retry */
-		if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue;
+		if (poll(pfd, nqueries+1, t1+retry_interval-t2) <= 0) continue;
 
-		while ((rlen = recvfrom(fd, answers[next], asize, 0,
-		  (void *)&sa, (socklen_t[1]){sl})) >= 0) {
+		while (next < nqueries) {
+			struct msghdr mh = {
+				.msg_name = (void *)&sa,
+				.msg_namelen = sl,
+				.msg_iovlen = 1,
+				.msg_iov = (struct iovec []){
+					{ .iov_base = (void *)answers[next],
+					  .iov_len = asize }
+				}
+			};
+			rlen = recvmsg(fd, &mh, 0);
+			if (rlen < 0) break;
 
 			/* Ignore non-identifiable packets */
 			if (rlen < 4) continue;
@@ -170,12 +247,72 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
 			else
 				memcpy(answers[i], answers[next], rlen);
 
-			if (next == nqueries) goto out;
+			/* Ignore further UDP if all slots full or TCP-mode */
+			if (next == nqueries) pfd[nqueries].events = 0;
+
+			/* If answer is truncated (TC bit), fallback to TCP */
+			if ((answers[i][2] & 2) || (mh.msg_flags & MSG_TRUNC)) {
+				alens[i] = -1;
+				pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
+				r = start_tcp(pfd+i, family, ns+j, sl, queries[i], qlens[i]);
+				pthread_setcancelstate(cs, 0);
+				if (r >= 0) {
+					qpos[i] = r;
+					apos[i] = 0;
+				}
+				continue;
+			}
+		}
+
+		for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLOUT) {
+			struct msghdr mh = {
+				.msg_iovlen = 2,
+				.msg_iov = (struct iovec [2]){
+					{ .iov_base = (uint8_t[]){ qlens[i]>>8, qlens[i] }, .iov_len = 2 },
+					{ .iov_base = (void *)queries[i], .iov_len = qlens[i] } }
+			};
+			step_mh(&mh, qpos[i]);
+			r = sendmsg(pfd[i].fd, &mh, MSG_NOSIGNAL);
+			if (r < 0) goto out;
+			qpos[i] += r;
+			if (qpos[i] == qlens[i]+2)
+				pfd[i].events = POLLIN;
+		}
+
+		for (i=0; i<nqueries; i++) if (pfd[i].revents & POLLIN) {
+			struct msghdr mh = {
+				.msg_iovlen = 2,
+				.msg_iov = (struct iovec [2]){
+					{ .iov_base = alen_buf[i], .iov_len = 2 },
+					{ .iov_base = answers[i], .iov_len = asize } }
+			};
+			step_mh(&mh, apos[i]);
+			r = recvmsg(pfd[i].fd, &mh, 0);
+			if (r <= 0) goto out;
+			apos[i] += r;
+			if (apos[i] < 2) continue;
+			int alen = alen_buf[i][0]*256 + alen_buf[i][1];
+			if (alen < 13) goto out;
+			if (apos[i] < alen+2 && apos[i] < asize+2)
+				continue;
+			int rcode = answers[i][3] & 15;
+			if (rcode != 0 && rcode != 3)
+				goto out;
+
+			/* Storing the length here commits the accepted answer.
+			 * Immediately close TCP socket so as not to consume
+			 * resources we no longer need. */
+			alens[i] = alen;
+			__syscall(SYS_close, pfd[i].fd);
+			pfd[i].fd = -1;
 		}
 	}
 out:
 	pthread_cleanup_pop(1);
 
+	/* Disregard any incomplete TCP results */
+	for (i=0; i<nqueries; i++) if (alens[i]<0) alens[i] = 0;
+
 	return 0;
 }
 
diff --git a/src/network/res_send.c b/src/network/res_send.c
index ee4abf1f..9593164d 100644
--- a/src/network/res_send.c
+++ b/src/network/res_send.c
@@ -1,8 +1,16 @@
 #include <resolv.h>
+#include <string.h>
 
 int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen)
 {
-	int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen);
+	int r;
+	if (anslen < 512) {
+		unsigned char buf[512];
+		r = __res_send(msg, msglen, buf, sizeof buf);
+		if (r >= 0) memcpy(answer, buf, r < anslen ? r : anslen);
+		return r;
+	}
+	r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen);
 	return r<0 || !anslen ? -1 : anslen;
 }
 
diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c
index 80cc5f41..acdfdf29 100644
--- a/src/network/sendmsg.c
+++ b/src/network/sendmsg.c
@@ -8,13 +8,16 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
 {
 #if LONG_MAX > INT_MAX
 	struct msghdr h;
-	struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c;
+	/* Kernels before 2.6.38 set SCM_MAX_FD to 255, allocate enough
+	 * space to support an SCM_RIGHTS ancillary message with 255 fds.
+	 * Kernels since 2.6.38 set SCM_MAX_FD to 253. */
+	struct cmsghdr chbuf[CMSG_SPACE(255*sizeof(int))/sizeof(struct cmsghdr)+1], *c;
 	if (msg) {
 		h = *msg;
 		h.__pad1 = h.__pad2 = 0;
 		msg = &h;
 		if (h.msg_controllen) {
-			if (h.msg_controllen > 1024) {
+			if (h.msg_controllen > sizeof chbuf) {
 				errno = ENOMEM;
 				return -1;
 			}
diff --git a/src/process/_Fork.c b/src/process/_Fork.c
index da063868..9c07792d 100644
--- a/src/process/_Fork.c
+++ b/src/process/_Fork.c
@@ -5,25 +5,16 @@
 #include "lock.h"
 #include "pthread_impl.h"
 #include "aio_impl.h"
+#include "fork_impl.h"
 
 static void dummy(int x) { }
 weak_alias(dummy, __aio_atfork);
 
-pid_t _Fork(void)
+void __post_Fork(int ret)
 {
-	pid_t ret;
-	sigset_t set;
-	__block_all_sigs(&set);
-	__aio_atfork(-1);
-	LOCK(__abort_lock);
-#ifdef SYS_fork
-	ret = __syscall(SYS_fork);
-#else
-	ret = __syscall(SYS_clone, SIGCHLD, 0);
-#endif
 	if (!ret) {
 		pthread_t self = __pthread_self();
-		self->tid = __syscall(SYS_gettid);
+		self->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
 		self->robust_list.off = 0;
 		self->robust_list.pending = 0;
 		self->next = self->prev = self;
@@ -32,7 +23,21 @@ pid_t _Fork(void)
 		if (libc.need_locks) libc.need_locks = -1;
 	}
 	UNLOCK(__abort_lock);
-	__aio_atfork(!ret);
+	if (!ret) __aio_atfork(1);
+}
+
+pid_t _Fork(void)
+{
+	pid_t ret;
+	sigset_t set;
+	__block_all_sigs(&set);
+	LOCK(__abort_lock);
+#ifdef SYS_fork
+	ret = __syscall(SYS_fork);
+#else
+	ret = __syscall(SYS_clone, SIGCHLD, 0);
+#endif
+	__post_Fork(ret);
 	__restore_sigs(&set);
 	return __syscall_ret(ret);
 }
diff --git a/src/process/aarch64/vfork.s b/src/process/aarch64/vfork.s
new file mode 100644
index 00000000..429bec8c
--- /dev/null
+++ b/src/process/aarch64/vfork.s
@@ -0,0 +1,9 @@
+.global vfork
+.type vfork,%function
+vfork:
+	mov x8, 220    // SYS_clone
+	mov x0, 0x4111 // SIGCHLD | CLONE_VM | CLONE_VFORK
+	mov x1, 0
+	svc 0
+	.hidden __syscall_ret
+	b __syscall_ret
diff --git a/src/process/fork.c b/src/process/fork.c
index 54bc2892..56f19313 100644
--- a/src/process/fork.c
+++ b/src/process/fork.c
@@ -9,7 +9,6 @@ static volatile int *const dummy_lockptr = 0;
 
 weak_alias(dummy_lockptr, __at_quick_exit_lockptr);
 weak_alias(dummy_lockptr, __atexit_lockptr);
-weak_alias(dummy_lockptr, __dlerror_lockptr);
 weak_alias(dummy_lockptr, __gettext_lockptr);
 weak_alias(dummy_lockptr, __locale_lockptr);
 weak_alias(dummy_lockptr, __random_lockptr);
@@ -24,7 +23,6 @@ weak_alias(dummy_lockptr, __vmlock_lockptr);
 static volatile int *const *const atfork_locks[] = {
 	&__at_quick_exit_lockptr,
 	&__atexit_lockptr,
-	&__dlerror_lockptr,
 	&__gettext_lockptr,
 	&__locale_lockptr,
 	&__random_lockptr,
@@ -38,6 +36,8 @@ static volatile int *const *const atfork_locks[] = {
 static void dummy(int x) { }
 weak_alias(dummy, __fork_handler);
 weak_alias(dummy, __malloc_atfork);
+weak_alias(dummy, __aio_atfork);
+weak_alias(dummy, __pthread_key_atfork);
 weak_alias(dummy, __ldso_atfork);
 
 static void dummy_0(void) { }
@@ -52,6 +52,8 @@ pid_t fork(void)
 	int need_locks = libc.need_locks > 0;
 	if (need_locks) {
 		__ldso_atfork(-1);
+		__pthread_key_atfork(-1);
+		__aio_atfork(-1);
 		__inhibit_ptc();
 		for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
 			if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
@@ -77,6 +79,8 @@ pid_t fork(void)
 				if (ret) UNLOCK(*atfork_locks[i]);
 				else **atfork_locks[i] = 0;
 		__release_ptc();
+		if (ret) __aio_atfork(0);
+		__pthread_key_atfork(!ret);
 		__ldso_atfork(!ret);
 	}
 	__restore_sigs(&set);
diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c
index 728551b3..8294598b 100644
--- a/src/process/posix_spawn.c
+++ b/src/process/posix_spawn.c
@@ -4,6 +4,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <sys/wait.h>
 #include "syscall.h"
 #include "lock.h"
@@ -156,7 +157,11 @@ static int child(void *args_vp)
 fail:
 	/* Since sizeof errno < PIPE_BUF, the write is atomic. */
 	ret = -ret;
-	if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0);
+	if (ret) {
+		int r;
+		do r = __syscall(SYS_write, p, &ret, sizeof ret);
+		while (r<0 && r!=-EPIPE);
+	}
 	_exit(127);
 }
 
diff --git a/src/process/riscv64/vfork.s b/src/process/riscv64/vfork.s
new file mode 100644
index 00000000..c93dca23
--- /dev/null
+++ b/src/process/riscv64/vfork.s
@@ -0,0 +1,12 @@
+.global vfork
+.type vfork,@function
+vfork:
+	/* riscv does not have SYS_vfork, so we must use clone instead */
+	/* note: riscv's clone = clone(flags, sp, ptidptr, tls, ctidptr) */
+	li a7, 220
+	li a0, 0x100 | 0x4000 | 17 /* flags = CLONE_VM | CLONE_VFORK | SIGCHLD */
+	mv a1, sp
+	/* the other arguments are ignoreable */
+	ecall
+	.hidden __syscall_ret
+	j __syscall_ret
diff --git a/src/process/waitpid.c b/src/process/waitpid.c
index 1b65bf05..80231862 100644
--- a/src/process/waitpid.c
+++ b/src/process/waitpid.c
@@ -3,5 +3,5 @@
 
 pid_t waitpid(pid_t pid, int *status, int options)
 {
-	return syscall_cp(SYS_wait4, pid, status, options, 0);
+	return sys_wait4_cp(pid, status, options, 0);
 }
diff --git a/src/regex/glob.c b/src/regex/glob.c
index 9de080ed..87bae084 100644
--- a/src/regex/glob.c
+++ b/src/regex/glob.c
@@ -265,7 +265,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i
 			if (append(&tail, pat, strlen(pat), 0))
 				return GLOB_NOSPACE;
 			cnt++;
-		} else
+		} else if (!error)
 			return GLOB_NOMATCH;
 	}
 
@@ -306,6 +306,3 @@ void globfree(glob_t *g)
 	g->gl_pathc = 0;
 	g->gl_pathv = NULL;
 }
-
-weak_alias(glob, glob64);
-weak_alias(globfree, globfree64);
diff --git a/src/search/hsearch.c b/src/search/hsearch.c
index b3ac8796..2634a67f 100644
--- a/src/search/hsearch.c
+++ b/src/search/hsearch.c
@@ -41,9 +41,9 @@ static int resize(size_t nel, struct hsearch_data *htab)
 {
 	size_t newsize;
 	size_t i, j;
+	size_t oldsize = htab->__tab->mask + 1;
 	ENTRY *e, *newe;
 	ENTRY *oldtab = htab->__tab->entries;
-	ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1;
 
 	if (nel > MAXSIZE)
 		nel = MAXSIZE;
@@ -56,7 +56,7 @@ static int resize(size_t nel, struct hsearch_data *htab)
 	htab->__tab->mask = newsize - 1;
 	if (!oldtab)
 		return 1;
-	for (e = oldtab; e < oldend; e++)
+	for (e = oldtab; e < oldtab + oldsize; e++)
 		if (e->key) {
 			for (i=keyhash(e->key),j=1; ; i+=j++) {
 				newe = htab->__tab->entries + (i & htab->__tab->mask);
diff --git a/src/select/poll.c b/src/select/poll.c
index c84c8a99..7883dfab 100644
--- a/src/select/poll.c
+++ b/src/select/poll.c
@@ -8,8 +8,13 @@ int poll(struct pollfd *fds, nfds_t n, int timeout)
 #ifdef SYS_poll
 	return syscall_cp(SYS_poll, fds, n, timeout);
 #else
+#if SYS_ppoll_time64 == SYS_ppoll
+	typedef long long ppoll_ts_t[2];
+#else
+	typedef long ppoll_ts_t[2];
+#endif
 	return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ?
-		&((struct timespec){ .tv_sec = timeout/1000,
-		.tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8);
+		((ppoll_ts_t){ timeout/1000, timeout%1000*1000000 }) : 0,
+		0, _NSIG/8);
 #endif
 }
diff --git a/src/linux/ppoll.c b/src/select/ppoll.c
index e614600a..9a0bf929 100644
--- a/src/linux/ppoll.c
+++ b/src/select/ppoll.c
@@ -1,4 +1,4 @@
-#define _GNU_SOURCE
+#define _BSD_SOURCE
 #include <poll.h>
 #include <signal.h>
 #include <errno.h>
diff --git a/src/select/select.c b/src/select/select.c
index 8a786884..f1d72863 100644
--- a/src/select/select.c
+++ b/src/select/select.c
@@ -33,6 +33,7 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict
 			((syscall_arg_t[]){ 0, _NSIG/8 }));
 	if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
 		return __syscall_ret(r);
+	s = CLAMP(s);
 #endif
 #ifdef SYS_select
 	return syscall_cp(SYS_select, n, rfds, wfds, efds,
diff --git a/src/setjmp/loongarch64/longjmp.S b/src/setjmp/loongarch64/longjmp.S
new file mode 100644
index 00000000..896d2e26
--- /dev/null
+++ b/src/setjmp/loongarch64/longjmp.S
@@ -0,0 +1,32 @@
+.global _longjmp
+.global longjmp
+.type   _longjmp,@function
+.type   longjmp,@function
+_longjmp:
+longjmp:
+	ld.d    $ra, $a0, 0
+	ld.d    $sp, $a0, 8
+	ld.d    $r21,$a0, 16
+	ld.d    $fp, $a0, 24
+	ld.d    $s0, $a0, 32
+	ld.d    $s1, $a0, 40
+	ld.d    $s2, $a0, 48
+	ld.d    $s3, $a0, 56
+	ld.d    $s4, $a0, 64
+	ld.d    $s5, $a0, 72
+	ld.d    $s6, $a0, 80
+	ld.d    $s7, $a0, 88
+	ld.d    $s8, $a0, 96
+#ifndef __loongarch_soft_float
+	fld.d   $fs0, $a0, 104
+	fld.d   $fs1, $a0, 112
+	fld.d   $fs2, $a0, 120
+	fld.d   $fs3, $a0, 128
+	fld.d   $fs4, $a0, 136
+	fld.d   $fs5, $a0, 144
+	fld.d   $fs6, $a0, 152
+	fld.d   $fs7, $a0, 160
+#endif
+	sltui   $a0, $a1, 1
+	add.d   $a0, $a0, $a1
+	jr      $ra
diff --git a/src/setjmp/loongarch64/setjmp.S b/src/setjmp/loongarch64/setjmp.S
new file mode 100644
index 00000000..d158a3d2
--- /dev/null
+++ b/src/setjmp/loongarch64/setjmp.S
@@ -0,0 +1,34 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp,@function
+.type _setjmp,@function
+.type setjmp,@function
+__setjmp:
+_setjmp:
+setjmp:
+	st.d    $ra, $a0, 0
+	st.d    $sp, $a0, 8
+	st.d    $r21,$a0, 16
+	st.d    $fp, $a0, 24
+	st.d    $s0, $a0, 32
+	st.d    $s1, $a0, 40
+	st.d    $s2, $a0, 48
+	st.d    $s3, $a0, 56
+	st.d    $s4, $a0, 64
+	st.d    $s5, $a0, 72
+	st.d    $s6, $a0, 80
+	st.d    $s7, $a0, 88
+	st.d    $s8, $a0, 96
+#ifndef __loongarch_soft_float
+	fst.d   $fs0, $a0, 104
+	fst.d   $fs1, $a0, 112
+	fst.d   $fs2, $a0, 120
+	fst.d   $fs3, $a0, 128
+	fst.d   $fs4, $a0, 136
+	fst.d   $fs5, $a0, 144
+	fst.d   $fs6, $a0, 152
+	fst.d   $fs7, $a0, 160
+#endif
+	move    $a0, $zero
+	jr      $ra
diff --git a/src/setjmp/powerpc/longjmp.S b/src/setjmp/powerpc/longjmp.S
index 611389fe..465e4cd7 100644
--- a/src/setjmp/powerpc/longjmp.S
+++ b/src/setjmp/powerpc/longjmp.S
@@ -42,10 +42,10 @@ longjmp:
 	bl 1f
 	.hidden __hwcap
 	.long __hwcap-.
-1:	mflr 4
-	lwz 5, 0(4)
-	lwzx 4, 4, 5
-	andis. 4, 4, 0x80
+1:	mflr 6
+	lwz 5, 0(6)
+	lwzx 6, 6, 5
+	andis. 6, 6, 0x80
 	beq 1f
 	.long 0x11c35b01 /* evldd 14,88(3) */
 	.long 0x11e36301 /* ... */
diff --git a/src/setjmp/riscv32/longjmp.S b/src/setjmp/riscv32/longjmp.S
new file mode 100644
index 00000000..f9cb3318
--- /dev/null
+++ b/src/setjmp/riscv32/longjmp.S
@@ -0,0 +1,42 @@
+.global __longjmp
+.global _longjmp
+.global longjmp
+.type __longjmp, %function
+.type _longjmp,  %function
+.type longjmp,   %function
+__longjmp:
+_longjmp:
+longjmp:
+	lw s0,    0(a0)
+	lw s1,    4(a0)
+	lw s2,    8(a0)
+	lw s3,    12(a0)
+	lw s4,    16(a0)
+	lw s5,    20(a0)
+	lw s6,    24(a0)
+	lw s7,    28(a0)
+	lw s8,    32(a0)
+	lw s9,    36(a0)
+	lw s10,   40(a0)
+	lw s11,   44(a0)
+	lw sp,    48(a0)
+	lw ra,    52(a0)
+
+#ifndef __riscv_float_abi_soft
+	fld fs0,  56(a0)
+	fld fs1,  64(a0)
+	fld fs2,  72(a0)
+	fld fs3,  80(a0)
+	fld fs4,  88(a0)
+	fld fs5,  96(a0)
+	fld fs6,  104(a0)
+	fld fs7,  112(a0)
+	fld fs8,  120(a0)
+	fld fs9,  128(a0)
+	fld fs10, 136(a0)
+	fld fs11, 144(a0)
+#endif
+
+	seqz a0, a1
+	add a0, a0, a1
+	ret
diff --git a/src/setjmp/riscv32/setjmp.S b/src/setjmp/riscv32/setjmp.S
new file mode 100644
index 00000000..8a75cf55
--- /dev/null
+++ b/src/setjmp/riscv32/setjmp.S
@@ -0,0 +1,41 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp, %function
+.type _setjmp,  %function
+.type setjmp,   %function
+__setjmp:
+_setjmp:
+setjmp:
+	sw s0,    0(a0)
+	sw s1,    4(a0)
+	sw s2,    8(a0)
+	sw s3,    12(a0)
+	sw s4,    16(a0)
+	sw s5,    20(a0)
+	sw s6,    24(a0)
+	sw s7,    28(a0)
+	sw s8,    32(a0)
+	sw s9,    36(a0)
+	sw s10,   40(a0)
+	sw s11,   44(a0)
+	sw sp,    48(a0)
+	sw ra,    52(a0)
+
+#ifndef __riscv_float_abi_soft
+	fsd fs0,  56(a0)
+	fsd fs1,  64(a0)
+	fsd fs2,  72(a0)
+	fsd fs3,  80(a0)
+	fsd fs4,  88(a0)
+	fsd fs5,  96(a0)
+	fsd fs6,  104(a0)
+	fsd fs7,  112(a0)
+	fsd fs8,  120(a0)
+	fsd fs9,  128(a0)
+	fsd fs10, 136(a0)
+	fsd fs11, 144(a0)
+#endif
+
+	li a0, 0
+	ret
diff --git a/src/signal/mips/restore.s b/src/signal/loongarch64/restore.s
index b6dadce0..d90a8ebb 100644
--- a/src/signal/mips/restore.s
+++ b/src/signal/loongarch64/restore.s
@@ -1,15 +1,10 @@
-.set noreorder
-
 .global __restore_rt
-.hidden __restore_rt
-.type   __restore_rt,@function
-__restore_rt:
-	li $2, 4193
-	syscall
-
 .global __restore
+.hidden __restore_rt
 .hidden __restore
+.type   __restore_rt,@function
 .type   __restore,@function
+__restore_rt:
 __restore:
-	li $2, 4119
-	syscall
+	li.w    $a7, 139
+	syscall 0
diff --git a/src/signal/loongarch64/sigsetjmp.s b/src/signal/loongarch64/sigsetjmp.s
new file mode 100644
index 00000000..9c0e3ae2
--- /dev/null
+++ b/src/signal/loongarch64/sigsetjmp.s
@@ -0,0 +1,25 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp,@function
+.type __sigsetjmp,@function
+sigsetjmp:
+__sigsetjmp:
+	beq     $a1, $zero, 1f
+	st.d    $ra, $a0, 184
+	st.d    $s0, $a0, 200  #184+8+8
+	move    $s0, $a0
+
+	la.global  $t0, setjmp
+	jirl       $ra, $t0, 0
+
+	move    $a1, $a0        # Return from 'setjmp' or 'longjmp'
+	move    $a0, $s0
+	ld.d    $ra, $a0, 184
+	ld.d    $s0, $a0, 200 #184+8+8
+
+.hidden __sigsetjmp_tail
+	la.global  $t0, __sigsetjmp_tail
+	jr         $t0
+1:
+	la.global  $t0, setjmp
+	jr         $t0
diff --git a/src/signal/mips64/restore.s b/src/signal/mips64/restore.s
deleted file mode 100644
index 401f8e73..00000000
--- a/src/signal/mips64/restore.s
+++ /dev/null
@@ -1,11 +0,0 @@
-.set	noreorder
-.global	__restore_rt
-.global	__restore
-.hidden __restore_rt
-.hidden __restore
-.type	__restore_rt,@function
-.type	__restore,@function
-__restore_rt:
-__restore:
-	li	$2,5211
-	syscall
diff --git a/src/signal/mipsn32/restore.s b/src/signal/mipsn32/restore.s
deleted file mode 100644
index 4cd4e1b4..00000000
--- a/src/signal/mipsn32/restore.s
+++ /dev/null
@@ -1,11 +0,0 @@
-.set	noreorder
-.global	__restore_rt
-.global	__restore
-.hidden __restore_rt
-.hidden __restore
-.type	__restore_rt,@function
-.type	__restore,@function
-__restore_rt:
-__restore:
-	li	$2,6211
-	syscall
diff --git a/src/signal/riscv32/restore.s b/src/signal/riscv32/restore.s
new file mode 100644
index 00000000..40012c75
--- /dev/null
+++ b/src/signal/riscv32/restore.s
@@ -0,0 +1,8 @@
+.global __restore
+.type __restore, %function
+__restore:
+.global __restore_rt
+.type __restore_rt, %function
+__restore_rt:
+	li a7, 139 # SYS_rt_sigreturn
+	ecall
diff --git a/src/signal/riscv32/sigsetjmp.s b/src/signal/riscv32/sigsetjmp.s
new file mode 100644
index 00000000..c1caeab1
--- /dev/null
+++ b/src/signal/riscv32/sigsetjmp.s
@@ -0,0 +1,23 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp, %function
+.type __sigsetjmp, %function
+sigsetjmp:
+__sigsetjmp:
+	bnez a1, 1f
+	tail setjmp
+1:
+
+	sw ra, 152(a0)
+	sw s0, 164(a0)
+	mv s0, a0
+
+	call setjmp
+
+	mv a1, a0
+	mv a0, s0
+	lw s0, 164(a0)
+	lw ra, 152(a0)
+
+.hidden __sigsetjmp_tail
+	tail __sigsetjmp_tail
diff --git a/src/signal/sh/sigsetjmp.s b/src/signal/sh/sigsetjmp.s
index 1e2270be..f0f604e2 100644
--- a/src/signal/sh/sigsetjmp.s
+++ b/src/signal/sh/sigsetjmp.s
@@ -27,7 +27,7 @@ __sigsetjmp:
 
 	mov.l 3f, r0
 4:	braf r0
-	 mov.l @(4+8,r4), r8
+	 mov.l @(4+8,r6), r8
 
 9:	mov.l 5f, r0
 6:	braf r0
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
index 2203471b..e45308fa 100644
--- a/src/signal/sigaction.c
+++ b/src/signal/sigaction.c
@@ -44,8 +44,11 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact
 			}
 		}
 		ksa.handler = sa->sa_handler;
-		ksa.flags = sa->sa_flags | SA_RESTORER;
+		ksa.flags = sa->sa_flags;
+#ifdef SA_RESTORER
+		ksa.flags |= SA_RESTORER;
 		ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
+#endif
 		memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
 	}
 	int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
diff --git a/src/stat/__xstat.c b/src/stat/__xstat.c
index 630936a0..b4560df7 100644
--- a/src/stat/__xstat.c
+++ b/src/stat/__xstat.c
@@ -22,11 +22,6 @@ int __xstat(int ver, const char *path, struct stat *buf)
 	return stat(path, buf);
 }
 
-weak_alias(__fxstat, __fxstat64);
-weak_alias(__fxstatat, __fxstatat64);
-weak_alias(__lxstat, __lxstat64);
-weak_alias(__xstat, __xstat64);
-
 #endif
 
 int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev)
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
index bc581050..92c9d1b0 100644
--- a/src/stat/fchmodat.c
+++ b/src/stat/fchmodat.c
@@ -5,13 +5,16 @@
 
 int fchmodat(int fd, const char *path, mode_t mode, int flag)
 {
-	if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag);
+	if (!flag) return syscall(SYS_fchmodat, fd, path, mode);
+
+	int ret = __syscall(SYS_fchmodat2, fd, path, mode, flag);
+	if (ret != -ENOSYS) return __syscall_ret(ret);
 
 	if (flag != AT_SYMLINK_NOFOLLOW)
 		return __syscall_ret(-EINVAL);
 
 	struct stat st;
-	int ret, fd2;
+	int fd2;
 	char proc[15+3*sizeof(int)];
 
 	if (fstatat(fd, path, &st, flag))
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
index 27db0ccb..fd28b8ac 100644
--- a/src/stat/fstat.c
+++ b/src/stat/fstat.c
@@ -11,7 +11,3 @@ int __fstat(int fd, struct stat *st)
 }
 
 weak_alias(__fstat, fstat);
-
-#if !_REDIR_TIME64
-weak_alias(fstat, fstat64);
-#endif
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index 74c51cf5..9eed063b 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -36,6 +36,7 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric
 {
 	struct statx stx;
 
+	flag |= AT_NO_AUTOMOUNT;
 	int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx);
 	if (ret) return ret;
 
@@ -151,7 +152,3 @@ int __fstatat(int fd, const char *restrict path, struct stat *restrict st, int f
 }
 
 weak_alias(__fstatat, fstatat);
-
-#if !_REDIR_TIME64
-weak_alias(fstatat, fstatat64);
-#endif
diff --git a/src/stat/lstat.c b/src/stat/lstat.c
index 6fe004de..6822fcae 100644
--- a/src/stat/lstat.c
+++ b/src/stat/lstat.c
@@ -5,7 +5,3 @@ int lstat(const char *restrict path, struct stat *restrict buf)
 {
 	return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
 }
-
-#if !_REDIR_TIME64
-weak_alias(lstat, lstat64);
-#endif
diff --git a/src/stat/stat.c b/src/stat/stat.c
index ea70efc4..23570e7a 100644
--- a/src/stat/stat.c
+++ b/src/stat/stat.c
@@ -5,7 +5,3 @@ int stat(const char *restrict path, struct stat *restrict buf)
 {
 	return fstatat(AT_FDCWD, path, buf, 0);
 }
-
-#if !_REDIR_TIME64
-weak_alias(stat, stat64);
-#endif
diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c
index f65d1b54..bc12da8b 100644
--- a/src/stat/statvfs.c
+++ b/src/stat/statvfs.c
@@ -39,6 +39,7 @@ static void fixup(struct statvfs *out, const struct statfs *in)
 	out->f_fsid = in->f_fsid.__val[0];
 	out->f_flag = in->f_flags;
 	out->f_namemax = in->f_namelen;
+	out->f_type = in->f_type;
 }
 
 int statvfs(const char *restrict path, struct statvfs *restrict buf)
@@ -56,8 +57,3 @@ int fstatvfs(int fd, struct statvfs *buf)
 	fixup(buf, &kbuf);
 	return 0;
 }
-
-weak_alias(statvfs, statvfs64);
-weak_alias(statfs, statfs64);
-weak_alias(fstatvfs, fstatvfs64);
-weak_alias(fstatfs, fstatfs64);
diff --git a/src/stdio/fgetpos.c b/src/stdio/fgetpos.c
index 50813d2c..392f7323 100644
--- a/src/stdio/fgetpos.c
+++ b/src/stdio/fgetpos.c
@@ -7,5 +7,3 @@ int fgetpos(FILE *restrict f, fpos_t *restrict pos)
 	*(long long *)pos = off;
 	return 0;
 }
-
-weak_alias(fgetpos, fgetpos64);
diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c
index 6171f398..4a100b39 100644
--- a/src/stdio/fgets.c
+++ b/src/stdio/fgets.c
@@ -12,13 +12,14 @@ char *fgets(char *restrict s, int n, FILE *restrict f)
 
 	FLOCK(f);
 
-	if (n--<=1) {
+	if (n<=1) {
 		f->mode |= f->mode-1;
 		FUNLOCK(f);
-		if (n) return 0;
+		if (n<1) return 0;
 		*s = 0;
 		return s;
 	}
+	n--;
 
 	while (n) {
 		if (f->rpos != f->rend) {
diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c
index e1b91e12..80bc341e 100644
--- a/src/stdio/fopen.c
+++ b/src/stdio/fopen.c
@@ -29,5 +29,3 @@ FILE *fopen(const char *restrict filename, const char *restrict mode)
 	__syscall(SYS_close, fd);
 	return 0;
 }
-
-weak_alias(fopen, fopen64);
diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c
index 615d4b47..1641a4c5 100644
--- a/src/stdio/freopen.c
+++ b/src/stdio/freopen.c
@@ -40,6 +40,8 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re
 		fclose(f2);
 	}
 
+	f->mode = 0;
+	f->locale = 0;
 	FUNLOCK(f);
 	return f;
 
@@ -49,5 +51,3 @@ fail:
 	fclose(f);
 	return NULL;
 }
-
-weak_alias(freopen, freopen64);
diff --git a/src/stdio/fseek.c b/src/stdio/fseek.c
index c07f7e95..c7425802 100644
--- a/src/stdio/fseek.c
+++ b/src/stdio/fseek.c
@@ -46,5 +46,3 @@ int fseek(FILE *f, long off, int whence)
 }
 
 weak_alias(__fseeko, fseeko);
-
-weak_alias(fseeko, fseeko64);
diff --git a/src/stdio/fsetpos.c b/src/stdio/fsetpos.c
index 77ab8d82..779cb3cc 100644
--- a/src/stdio/fsetpos.c
+++ b/src/stdio/fsetpos.c
@@ -4,5 +4,3 @@ int fsetpos(FILE *f, const fpos_t *pos)
 {
 	return __fseeko(f, *(const long long *)pos, SEEK_SET);
 }
-
-weak_alias(fsetpos, fsetpos64);
diff --git a/src/stdio/ftell.c b/src/stdio/ftell.c
index 1a2afbbc..1e1a08d8 100644
--- a/src/stdio/ftell.c
+++ b/src/stdio/ftell.c
@@ -37,5 +37,3 @@ long ftell(FILE *f)
 }
 
 weak_alias(__ftello, ftello);
-
-weak_alias(ftello, ftello64);
diff --git a/src/stdio/open_wmemstream.c b/src/stdio/open_wmemstream.c
index ed1b561d..b8ae4a79 100644
--- a/src/stdio/open_wmemstream.c
+++ b/src/stdio/open_wmemstream.c
@@ -40,8 +40,12 @@ fail:
 static size_t wms_write(FILE *f, const unsigned char *buf, size_t len)
 {
 	struct cookie *c = f->cookie;
-	size_t len2;
+	size_t len2 = f->wpos - f->wbase;
 	wchar_t *newbuf;
+	if (len2) {
+		f->wpos = f->wbase;
+		if (wms_write(f, f->wbase, len2) < len2) return 0;
+	}
 	if (len + c->pos >= c->space) {
 		len2 = 2*c->space+1 | c->pos+len+1;
 		if (len2 > SSIZE_MAX/4) return 0;
diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c
index 080a4262..c64da405 100644
--- a/src/stdio/pclose.c
+++ b/src/stdio/pclose.c
@@ -7,7 +7,7 @@ int pclose(FILE *f)
 	int status, r;
 	pid_t pid = f->pipe_pid;
 	fclose(f);
-	while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR);
+	while ((r=__sys_wait4(pid, &status, 0, 0)) == -EINTR);
 	if (r<0) return __syscall_ret(r);
 	return status;
 }
diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c
index ae493987..2fa8803f 100644
--- a/src/stdio/tmpfile.c
+++ b/src/stdio/tmpfile.c
@@ -27,5 +27,3 @@ FILE *tmpfile(void)
 	}
 	return 0;
 }
-
-weak_alias(tmpfile, tmpfile64);
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index 9b961e7f..497c5e19 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -52,7 +52,7 @@ static const unsigned char states[]['z'-'A'+1] = {
 		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
 		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
-		S('c') = CHAR, S('C') = INT,
+		S('c') = INT, S('C') = UINT,
 		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
 		S('m') = NOARG,
 		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -62,7 +62,7 @@ static const unsigned char states[]['z'-'A'+1] = {
 		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
 		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
-		S('c') = INT, S('s') = PTR, S('n') = PTR,
+		S('c') = UINT, S('s') = PTR, S('n') = PTR,
 		S('l') = LLPRE,
 	}, { /* 2: ll-prefixed */
 		S('d') = LLONG, S('i') = LLONG,
@@ -132,7 +132,7 @@ static void pop_arg(union arg *arg, int type, va_list *ap)
 
 static void out(FILE *f, const char *s, size_t l)
 {
-	if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
+	if (!ferror(f)) __fwritex((void *)s, l, f);
 }
 
 static void pad(FILE *f, char c, int w, int l, int fl)
@@ -437,7 +437,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 	unsigned st, ps;
 	int cnt=0, l=0;
 	size_t i;
-	char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+	char buf[sizeof(uintmax_t)*3];
 	const char *prefix;
 	int t, pl;
 	wchar_t wc[2], *ws;
@@ -478,8 +478,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 		if (*s=='*') {
 			if (isdigit(s[1]) && s[2]=='$') {
 				l10n=1;
-				nl_type[s[1]-'0'] = INT;
-				w = nl_arg[s[1]-'0'].i;
+				if (!f) nl_type[s[1]-'0'] = INT, w = 0;
+				else w = nl_arg[s[1]-'0'].i;
 				s+=3;
 			} else if (!l10n) {
 				w = f ? va_arg(*ap, int) : 0;
@@ -491,8 +491,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 		/* Read precision */
 		if (*s=='.' && s[1]=='*') {
 			if (isdigit(s[2]) && s[3]=='$') {
-				nl_type[s[2]-'0'] = INT;
-				p = nl_arg[s[2]-'0'].i;
+				if (!f) nl_type[s[2]-'0'] = INT, p = 0;
+				else p = nl_arg[s[2]-'0'].i;
 				s+=4;
 			} else if (!l10n) {
 				p = f ? va_arg(*ap, int) : 0;
@@ -521,13 +521,18 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 		if (st==NOARG) {
 			if (argpos>=0) goto inval;
 		} else {
-			if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
-			else if (f) pop_arg(&arg, st, ap);
+			if (argpos>=0) {
+				if (!f) nl_type[argpos]=st;
+				else arg=nl_arg[argpos];
+			} else if (f) pop_arg(&arg, st, ap);
 			else return 0;
 		}
 
 		if (!f) continue;
 
+		/* Do not process any new directives once in error state. */
+		if (ferror(f)) return -1;
+
 		z = buf + sizeof(buf);
 		prefix = "-+   0X0x";
 		pl = 0;
@@ -583,6 +588,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 			}
 			p = MAX(p, z-a + !arg.i);
 			break;
+		narrow_c:
 		case 'c':
 			*(a=z-(p=1))=arg.i;
 			fl &= ~ZERO_PAD;
@@ -597,6 +603,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 			fl &= ~ZERO_PAD;
 			break;
 		case 'C':
+			if (!arg.i) goto narrow_c;
 			wc[0] = arg.i;
 			wc[1] = 0;
 			arg.p = wc;
@@ -672,7 +679,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
 
 	FLOCK(f);
 	olderr = f->flags & F_ERR;
-	if (f->mode < 1) f->flags &= ~F_ERR;
+	f->flags &= ~F_ERR;
 	if (!f->buf_size) {
 		saved_buf = f->buf;
 		f->buf = internal_buf;
@@ -688,7 +695,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
 		f->buf_size = 0;
 		f->wpos = f->wbase = f->wend = 0;
 	}
-	if (f->flags & F_ERR) ret = -1;
+	if (ferror(f)) ret = -1;
 	f->flags |= olderr;
 	FUNLOCK(f);
 	va_end(ap2);
diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c
index 85b036c3..59d5471b 100644
--- a/src/stdio/vfwprintf.c
+++ b/src/stdio/vfwprintf.c
@@ -45,7 +45,7 @@ static const unsigned char states[]['z'-'A'+1] = {
 		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
 		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
-		S('c') = CHAR, S('C') = INT,
+		S('c') = INT, S('C') = UINT,
 		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
 		S('m') = NOARG,
 		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -55,7 +55,7 @@ static const unsigned char states[]['z'-'A'+1] = {
 		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
 		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
 		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
-		S('c') = INT, S('s') = PTR, S('n') = PTR,
+		S('c') = UINT, S('s') = PTR, S('n') = PTR,
 		S('l') = LLPRE,
 	}, { /* 2: ll-prefixed */
 		S('d') = LLONG, S('i') = LLONG,
@@ -125,7 +125,13 @@ static void pop_arg(union arg *arg, int type, va_list *ap)
 
 static void out(FILE *f, const wchar_t *s, size_t l)
 {
-	while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f);
+	while (l-- && !ferror(f)) fputwc(*s++, f);
+}
+
+static void pad(FILE *f, int n, int fl)
+{
+	if ((fl & LEFT_ADJ) || !n || ferror(f)) return;
+	fprintf(f, "%*s", n, "");
 }
 
 static int getint(wchar_t **s) {
@@ -242,6 +248,10 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
 		}
 
 		if (!f) continue;
+
+		/* Do not process any new directives once in error state. */
+		if (ferror(f)) return -1;
+
 		t = s[-1];
 		if (ps && (t&15)==3) t&=~32;
 
@@ -258,25 +268,22 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
 			}
 			continue;
 		case 'c':
+		case 'C':
 			if (w<1) w=1;
-			if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
-			fputwc(btowc(arg.i), f);
-			if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, "");
+			pad(f, w-1, fl);
+			out(f, &(wchar_t){t=='C' ? arg.i : btowc(arg.i)}, 1);
+			pad(f, w-1, fl^LEFT_ADJ);
 			l = w;
 			continue;
-		case 'C':
-			fputwc(arg.i, f);
-			l = 1;
-			continue;
 		case 'S':
 			a = arg.p;
 			z = a + wcsnlen(a, p<0 ? INT_MAX : p);
 			if (p<0 && *z) goto overflow;
 			p = z-a;
 			if (w<p) w=p;
-			if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+			pad(f, w-p, fl);
 			out(f, a, p);
-			if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+			pad(f, w-p, fl^LEFT_ADJ);
 			l=w;
 			continue;
 		case 'm':
@@ -289,14 +296,14 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
 			if (p<0 && *bs) goto overflow;
 			p=l;
 			if (w<p) w=p;
-			if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+			pad(f, w-p, fl);
 			bs = arg.p;
 			while (l--) {
 				i=mbtowc(&wc, bs, MB_LEN_MAX);
 				bs+=i;
-				fputwc(wc, f);
+				out(f, &wc, 1);
 			}
-			if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
+			pad(f, w-p, fl^LEFT_ADJ);
 			l=w;
 			continue;
 		}
@@ -340,8 +347,8 @@ overflow:
 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
 {
 	va_list ap2;
-	int nl_type[NL_ARGMAX] = {0};
-	union arg nl_arg[NL_ARGMAX];
+	int nl_type[NL_ARGMAX+1] = {0};
+	union arg nl_arg[NL_ARGMAX+1];
 	int olderr;
 	int ret;
 
@@ -357,7 +364,7 @@ int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
 	olderr = f->flags & F_ERR;
 	f->flags &= ~F_ERR;
 	ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
-	if (f->flags & F_ERR) ret = -1;
+	if (ferror(f)) ret = -1;
 	f->flags |= olderr;
 	FUNLOCK(f);
 	va_end(ap2);
diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c
index b3510a63..409b9c85 100644
--- a/src/stdio/vsnprintf.c
+++ b/src/stdio/vsnprintf.c
@@ -45,11 +45,6 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
 		.cookie = &c,
 	};
 
-	if (n > INT_MAX) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-
 	*c.s = 0;
 	return vfprintf(&f, fmt, ap);
 }
diff --git a/src/stdio/vswprintf.c b/src/stdio/vswprintf.c
index 7f98c5c9..5e9a4dad 100644
--- a/src/stdio/vswprintf.c
+++ b/src/stdio/vswprintf.c
@@ -18,6 +18,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l)
 	if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1)
 		return -1;
 	while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) {
+		if (!i) i=1;
 		s+=i;
 		l-=i;
 		c->l--;
@@ -50,9 +51,6 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis
 
 	if (!n) {
 		return -1;
-	} else if (n > INT_MAX) {
-		errno = EOVERFLOW;
-		return -1;
 	}
 	r = vfwprintf(&f, fmt, ap);
 	sw_write(&f, 0, 0);
diff --git a/src/string/strverscmp.c b/src/string/strverscmp.c
index 4daf276d..16c1da22 100644
--- a/src/string/strverscmp.c
+++ b/src/string/strverscmp.c
@@ -18,9 +18,9 @@ int strverscmp(const char *l0, const char *r0)
 		else if (c!='0') z=0;
 	}
 
-	if (l[dp]!='0' && r[dp]!='0') {
-		/* If we're not looking at a digit sequence that began
-		 * with a zero, longest digit string is greater. */
+	if (l[dp]-'1'<9U && r[dp]-'1'<9U) {
+		/* If we're looking at non-degenerate digit sequences starting
+		 * with nonzero digits, longest digit string is greater. */
 		for (j=i; isdigit(l[j]); j++)
 			if (!isdigit(r[j])) return 1;
 		if (isdigit(r[j])) return -1;
diff --git a/src/string/wcscmp.c b/src/string/wcscmp.c
index 26eeee70..286ec3ea 100644
--- a/src/string/wcscmp.c
+++ b/src/string/wcscmp.c
@@ -3,5 +3,5 @@
 int wcscmp(const wchar_t *l, const wchar_t *r)
 {
 	for (; *l==*r && *l && *r; l++, r++);
-	return *l - *r;
+	return *l < *r ? -1 : *l > *r;
 }
diff --git a/src/string/wcsncmp.c b/src/string/wcsncmp.c
index 4ab32a92..2b3558bf 100644
--- a/src/string/wcsncmp.c
+++ b/src/string/wcsncmp.c
@@ -3,5 +3,5 @@
 int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n)
 {
 	for (; n && *l==*r && *l && *r; n--, l++, r++);
-	return n ? *l - *r : 0;
+	return n ? (*l < *r ? -1 : *l > *r) : 0;
 }
diff --git a/src/string/wmemcmp.c b/src/string/wmemcmp.c
index 2a193263..717d77b1 100644
--- a/src/string/wmemcmp.c
+++ b/src/string/wmemcmp.c
@@ -3,5 +3,5 @@
 int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
 {
 	for (; n && *l==*r; n--, l++, r++);
-	return n ? *l-*r : 0;
+	return n ? (*l < *r ? -1 : *l > *r) : 0;
 }
diff --git a/src/temp/__randname.c b/src/temp/__randname.c
index 2bce37a0..e9b970f1 100644
--- a/src/temp/__randname.c
+++ b/src/temp/__randname.c
@@ -1,5 +1,6 @@
 #include <time.h>
 #include <stdint.h>
+#include "pthread_impl.h"
 
 /* This assumes that a check for the
    template size has already been made */
@@ -10,7 +11,7 @@ char *__randname(char *template)
 	unsigned long r;
 
 	__clock_gettime(CLOCK_REALTIME, &ts);
-	r = ts.tv_nsec*65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template;
+	r = ts.tv_sec + ts.tv_nsec + __pthread_self()->tid * 65537UL;
 	for (i=0; i<6; i++, r>>=5)
 		template[i] = 'A'+(r&15)+(r&16)*2;
 
diff --git a/src/temp/mkostemp.c b/src/temp/mkostemp.c
index d8dcb805..e3dfdd91 100644
--- a/src/temp/mkostemp.c
+++ b/src/temp/mkostemp.c
@@ -5,5 +5,3 @@ int mkostemp(char *template, int flags)
 {
 	return __mkostemps(template, 0, flags);
 }
-
-weak_alias(mkostemp, mkostemp64);
diff --git a/src/temp/mkostemps.c b/src/temp/mkostemps.c
index ef24eeae..093d2380 100644
--- a/src/temp/mkostemps.c
+++ b/src/temp/mkostemps.c
@@ -26,4 +26,3 @@ int __mkostemps(char *template, int len, int flags)
 }
 
 weak_alias(__mkostemps, mkostemps);
-weak_alias(__mkostemps, mkostemps64);
diff --git a/src/temp/mkstemp.c b/src/temp/mkstemp.c
index 166b8afe..76c835bb 100644
--- a/src/temp/mkstemp.c
+++ b/src/temp/mkstemp.c
@@ -4,5 +4,3 @@ int mkstemp(char *template)
 {
 	return __mkostemps(template, 0, 0);
 }
-
-weak_alias(mkstemp, mkstemp64);
diff --git a/src/temp/mkstemps.c b/src/temp/mkstemps.c
index 6b7531b5..f8eabfec 100644
--- a/src/temp/mkstemps.c
+++ b/src/temp/mkstemps.c
@@ -5,5 +5,3 @@ int mkstemps(char *template, int len)
 {
 	return __mkostemps(template, len, 0);
 }
-
-weak_alias(mkstemps, mkstemps64);
diff --git a/src/thread/loongarch64/__set_thread_area.s b/src/thread/loongarch64/__set_thread_area.s
new file mode 100644
index 00000000..021307fc
--- /dev/null
+++ b/src/thread/loongarch64/__set_thread_area.s
@@ -0,0 +1,7 @@
+.global __set_thread_area
+.hidden __set_thread_area
+.type   __set_thread_area,@function
+__set_thread_area:
+	move $tp, $a0
+	move $a0, $zero
+	jr   $ra
diff --git a/src/thread/loongarch64/__unmapself.s b/src/thread/loongarch64/__unmapself.s
new file mode 100644
index 00000000..719ad056
--- /dev/null
+++ b/src/thread/loongarch64/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type   __unmapself, @function
+__unmapself:
+	li.d    $a7, 215   # call munmap
+	syscall 0
+	li.d    $a7, 93    # call exit
+	syscall 0
diff --git a/src/thread/loongarch64/clone.s b/src/thread/loongarch64/clone.s
new file mode 100644
index 00000000..a165b365
--- /dev/null
+++ b/src/thread/loongarch64/clone.s
@@ -0,0 +1,29 @@
+#__clone(func, stack, flags, arg, ptid, tls, ctid)
+#         a0,    a1,   a2,    a3,  a4,  a5,   a6
+# sys_clone(flags, stack, ptid, ctid, tls)
+#            a0,    a1,   a2,    a3,  a4
+
+.global __clone
+.hidden __clone
+.type __clone,@function
+__clone:
+	bstrins.d $a1, $zero, 3, 0   #stack to 16 align
+	# Save function pointer and argument pointer on new thread stack
+	addi.d  $a1, $a1, -16
+	st.d    $a0, $a1, 0     # save function pointer
+	st.d    $a3, $a1, 8     # save argument pointer
+	or      $a0, $a2, $zero
+	or      $a2, $a4, $zero
+	or      $a3, $a6, $zero
+	or      $a4, $a5, $zero
+	ori     $a7, $zero, 220
+	syscall 0               # call clone
+
+	beqz    $a0, 1f         # whether child process
+	jirl    $zero, $ra, 0   # parent process return
+1:
+	ld.d    $t8, $sp, 0     # function pointer
+	ld.d    $a0, $sp, 8     # argument pointer
+	jirl    $ra, $t8, 0     # call the user's function
+	ori     $a7, $zero, 93
+	syscall 0               # child process exit
diff --git a/src/thread/loongarch64/syscall_cp.s b/src/thread/loongarch64/syscall_cp.s
new file mode 100644
index 00000000..c057a97b
--- /dev/null
+++ b/src/thread/loongarch64/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type   __syscall_cp_asm,@function
+
+__syscall_cp_asm:
+__cp_begin:
+	ld.w $a0, $a0, 0
+	bnez $a0, __cp_cancel
+	move $t8, $a1    # reserve system call number
+	move $a0, $a2
+	move $a1, $a3
+	move $a2, $a4
+	move $a3, $a5
+	move $a4, $a6
+	move $a5, $a7
+	move $a7, $t8
+	syscall 0
+__cp_end:
+	jr $ra
+__cp_cancel:
+	la.local $t8, __cancel
+	jr $t8
diff --git a/src/thread/pthread_atfork.c b/src/thread/pthread_atfork.c
index 76497401..26d32543 100644
--- a/src/thread/pthread_atfork.c
+++ b/src/thread/pthread_atfork.c
@@ -1,7 +1,13 @@
 #include <pthread.h>
+#include <errno.h>
 #include "libc.h"
 #include "lock.h"
 
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
+
 static struct atfork_funcs {
 	void (*prepare)(void);
 	void (*parent)(void);
@@ -34,7 +40,7 @@ void __fork_handler(int who)
 int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
 {
 	struct atfork_funcs *new = malloc(sizeof *new);
-	if (!new) return -1;
+	if (!new) return ENOMEM;
 
 	LOCK(lock);
 	new->next = funcs;
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
index 2f9d5e97..139a6fc8 100644
--- a/src/thread/pthread_cancel.c
+++ b/src/thread/pthread_cancel.c
@@ -56,7 +56,12 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
 
 	_sigaddset(&uc->uc_sigmask, SIGCANCEL);
 
-	if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {
+	if (self->cancelasync) {
+		pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0);
+		__cancel();
+	}
+
+	if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {
 		uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel;
 #ifdef CANCEL_GOT
 		uc->uc_mcontext.MC_GOT = CANCEL_GOT;
@@ -77,7 +82,7 @@ void __testcancel()
 static void init_cancellation()
 {
 	struct sigaction sa = {
-		.sa_flags = SA_SIGINFO | SA_RESTART,
+		.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK,
 		.sa_sigaction = cancel_handler
 	};
 	memset(&sa.sa_mask, -1, _NSIG/8);
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index 6f187ee8..087f6206 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -107,6 +107,16 @@ _Noreturn void __pthread_exit(void *result)
 
 	/* At this point we are committed to thread termination. */
 
+	/* After the kernel thread exits, its tid may be reused. Clear it
+	 * to prevent inadvertent use and inform functions that would use
+	 * it that it's no longer available. At this point the killlock
+	 * may be released, since functions that use it will consistently
+	 * see the thread as having exited. Release it now so that no
+	 * remaining locks (except thread list) are held if we end up
+	 * resetting need_locks below. */
+	self->tid = 0;
+	UNLOCK(self->killlock);
+
 	/* Process robust list in userspace to handle non-pshared mutexes
 	 * and the detached thread case where the robust list head will
 	 * be invalid when the kernel would process it. */
@@ -159,12 +169,6 @@ _Noreturn void __pthread_exit(void *result)
 	a_store(&self->detach_state, DT_EXITED);
 	__wake(&self->detach_state, 1, 1);
 
-	/* After the kernel thread exits, its tid may be reused. Clear it
-	 * to prevent inadvertent use and inform functions that would use
-	 * it that it's no longer available. */
-	self->tid = 0;
-	UNLOCK(self->killlock);
-
 	for (;;) __syscall(SYS_exit, 0);
 }
 
diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c
index 77772af2..d73a500e 100644
--- a/src/thread/pthread_detach.c
+++ b/src/thread/pthread_detach.c
@@ -5,8 +5,12 @@ static int __pthread_detach(pthread_t t)
 {
 	/* If the cas fails, detach state is either already-detached
 	 * or exiting/exited, and pthread_join will trap or cleanup. */
-	if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE)
-		return __pthread_join(t, 0);
+	if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) {
+		int cs;
+		__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+		__pthread_join(t, 0);
+		__pthread_setcancelstate(cs, 0);
+	}
 	return 0;
 }
 
diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c
index d1120941..39770c7a 100644
--- a/src/thread/pthread_key_create.c
+++ b/src/thread/pthread_key_create.c
@@ -1,4 +1,5 @@
 #include "pthread_impl.h"
+#include "fork_impl.h"
 
 volatile size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
 void *__pthread_tsd_main[PTHREAD_KEYS_MAX] = { 0 };
@@ -20,6 +21,13 @@ static void dummy_0(void)
 weak_alias(dummy_0, __tl_lock);
 weak_alias(dummy_0, __tl_unlock);
 
+void __pthread_key_atfork(int who)
+{
+	if (who<0) __pthread_rwlock_rdlock(&key_lock);
+	else if (!who) __pthread_rwlock_unlock(&key_lock);
+	else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
+}
+
 int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
 {
 	pthread_t self = __pthread_self();
diff --git a/src/thread/riscv32/__set_thread_area.s b/src/thread/riscv32/__set_thread_area.s
new file mode 100644
index 00000000..828154d2
--- /dev/null
+++ b/src/thread/riscv32/__set_thread_area.s
@@ -0,0 +1,6 @@
+.global __set_thread_area
+.type   __set_thread_area, %function
+__set_thread_area:
+	mv tp, a0
+	li a0, 0
+	ret
diff --git a/src/thread/riscv32/__unmapself.s b/src/thread/riscv32/__unmapself.s
new file mode 100644
index 00000000..2849119c
--- /dev/null
+++ b/src/thread/riscv32/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type __unmapself, %function
+__unmapself:
+	li a7, 215 # SYS_munmap
+	ecall
+	li a7, 93  # SYS_exit
+	ecall
diff --git a/src/thread/riscv32/clone.s b/src/thread/riscv32/clone.s
new file mode 100644
index 00000000..3102239d
--- /dev/null
+++ b/src/thread/riscv32/clone.s
@@ -0,0 +1,34 @@
+# __clone(func, stack, flags, arg, ptid, tls, ctid)
+#           a0,    a1,    a2,  a3,   a4,  a5,   a6
+
+# syscall(SYS_clone, flags, stack, ptid, tls, ctid)
+#                a7     a0,    a1,   a2,  a3,   a4
+
+.global __clone
+.type  __clone, %function
+__clone:
+	# Save func and arg to stack
+	addi a1, a1, -16
+	sw a0, 0(a1)
+	sw a3, 4(a1)
+
+	# Call SYS_clone
+	mv a0, a2
+	mv a2, a4
+	mv a3, a5
+	mv a4, a6
+	li a7, 220 # SYS_clone
+	ecall
+
+	beqz a0, 1f
+	# Parent
+	ret
+
+	# Child
+1:      lw a1, 0(sp)
+	lw a0, 4(sp)
+	jalr a1
+
+	# Exit
+	li a7, 93 # SYS_exit
+	ecall
diff --git a/src/thread/riscv32/syscall_cp.s b/src/thread/riscv32/syscall_cp.s
new file mode 100644
index 00000000..079d1ba0
--- /dev/null
+++ b/src/thread/riscv32/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type __syscall_cp_asm, %function
+__syscall_cp_asm:
+__cp_begin:
+	lw t0, 0(a0)
+	bnez t0, __cp_cancel
+
+	mv t0, a1
+	mv a0, a2
+	mv a1, a3
+	mv a2, a4
+	mv a3, a5
+	mv a4, a6
+	mv a5, a7
+	lw a6, 0(sp)
+	mv a7, t0
+	ecall
+__cp_end:
+	ret
+__cp_cancel:
+	tail __cancel
diff --git a/src/thread/sem_getvalue.c b/src/thread/sem_getvalue.c
index d9d83071..c0b7762d 100644
--- a/src/thread/sem_getvalue.c
+++ b/src/thread/sem_getvalue.c
@@ -1,8 +1,9 @@
 #include <semaphore.h>
+#include <limits.h>
 
 int sem_getvalue(sem_t *restrict sem, int *restrict valp)
 {
 	int val = sem->__val[0];
-	*valp = val < 0 ? 0 : val;
+	*valp = val & SEM_VALUE_MAX;
 	return 0;
 }
diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c
index 31e3293d..5c2517f2 100644
--- a/src/thread/sem_post.c
+++ b/src/thread/sem_post.c
@@ -1,17 +1,21 @@
 #include <semaphore.h>
+#include <limits.h>
 #include "pthread_impl.h"
 
 int sem_post(sem_t *sem)
 {
-	int val, waiters, priv = sem->__val[2];
+	int val, new, waiters, priv = sem->__val[2];
 	do {
 		val = sem->__val[0];
 		waiters = sem->__val[1];
-		if (val == SEM_VALUE_MAX) {
+		if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) {
 			errno = EOVERFLOW;
 			return -1;
 		}
-	} while (a_cas(sem->__val, val, val+1+(val<0)) != val);
-	if (val<0 || waiters) __wake(sem->__val, 1, priv);
+		new = val + 1;
+		if (waiters <= 1)
+			new &= ~0x80000000;
+	} while (a_cas(sem->__val, val, new) != val);
+	if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv);
 	return 0;
 }
diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
index 58d3ebfe..aa67376c 100644
--- a/src/thread/sem_timedwait.c
+++ b/src/thread/sem_timedwait.c
@@ -1,4 +1,5 @@
 #include <semaphore.h>
+#include <limits.h>
 #include "pthread_impl.h"
 
 static void cleanup(void *p)
@@ -13,14 +14,15 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
 	if (!sem_trywait(sem)) return 0;
 
 	int spins = 100;
-	while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin();
+	while (spins-- && !(sem->__val[0] & SEM_VALUE_MAX) && !sem->__val[1])
+		a_spin();
 
 	while (sem_trywait(sem)) {
-		int r;
+		int r, priv = sem->__val[2];
 		a_inc(sem->__val+1);
-		a_cas(sem->__val, 0, -1);
+		a_cas(sem->__val, 0, 0x80000000);
 		pthread_cleanup_push(cleanup, (void *)(sem->__val+1));
-		r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]);
+		r = __timedwait_cp(sem->__val, 0x80000000, CLOCK_REALTIME, at, priv);
 		pthread_cleanup_pop(1);
 		if (r) {
 			errno = r;
diff --git a/src/thread/sem_trywait.c b/src/thread/sem_trywait.c
index 04edf46b..beb435da 100644
--- a/src/thread/sem_trywait.c
+++ b/src/thread/sem_trywait.c
@@ -1,12 +1,12 @@
 #include <semaphore.h>
+#include <limits.h>
 #include "pthread_impl.h"
 
 int sem_trywait(sem_t *sem)
 {
 	int val;
-	while ((val=sem->__val[0]) > 0) {
-		int new = val-1-(val==1 && sem->__val[1]);
-		if (a_cas(sem->__val, val, new)==val) return 0;
+	while ((val=sem->__val[0]) & SEM_VALUE_MAX) {
+		if (a_cas(sem->__val, val, val-1)==val) return 0;
 	}
 	errno = EAGAIN;
 	return -1;
diff --git a/src/thread/synccall.c b/src/thread/synccall.c
index d58c851f..38597254 100644
--- a/src/thread/synccall.c
+++ b/src/thread/synccall.c
@@ -11,7 +11,7 @@ weak_alias(dummy_0, __tl_unlock);
 
 static int target_tid;
 static void (*callback)(void *), *context;
-static sem_t target_sem, caller_sem;
+static sem_t target_sem, caller_sem, exit_sem;
 
 static void dummy(void *p)
 {
@@ -33,7 +33,7 @@ static void handler(int sig)
 	/* Inform caller we've complered the callback and wait
 	 * for the caller to release us to return. */
 	sem_post(&caller_sem);
-	sem_wait(&target_sem);
+	sem_wait(&exit_sem);
 
 	/* Inform caller we are returning and state is destroyable. */
 	sem_post(&caller_sem);
@@ -45,7 +45,7 @@ void __synccall(void (*func)(void *), void *ctx)
 {
 	sigset_t oldmask;
 	int cs, i, r;
-	struct sigaction sa = { .sa_flags = SA_RESTART, .sa_handler = handler };
+	struct sigaction sa = { .sa_flags = SA_RESTART | SA_ONSTACK, .sa_handler = handler };
 	pthread_t self = __pthread_self(), td;
 	int count = 0;
 
@@ -62,6 +62,7 @@ void __synccall(void (*func)(void *), void *ctx)
 
 	sem_init(&target_sem, 0, 0);
 	sem_init(&caller_sem, 0, 0);
+	sem_init(&exit_sem, 0, 0);
 
 	if (!libc.threads_minus_1 || __syscall(SYS_gettid) != self->tid)
 		goto single_threaded;
@@ -107,12 +108,13 @@ single_threaded:
 	/* Only release the caught threads once all threads, including the
 	 * caller, have returned from the callback function. */
 	for (i=0; i<count; i++)
-		sem_post(&target_sem);
+		sem_post(&exit_sem);
 	for (i=0; i<count; i++)
 		sem_wait(&caller_sem);
 
 	sem_destroy(&caller_sem);
 	sem_destroy(&target_sem);
+	sem_destroy(&exit_sem);
 
 	pthread_setcancelstate(cs, 0);
 	__tl_unlock();
diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c
index 2824ec6d..b42f5a6d 100644
--- a/src/time/__year_to_secs.c
+++ b/src/time/__year_to_secs.c
@@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap)
 		return 31536000*(y-70) + 86400*leaps;
 	}
 
-	int cycles, centuries, leaps, rem;
+	int cycles, centuries, leaps, rem, dummy;
 
-	if (!is_leap) is_leap = &(int){0};
+	if (!is_leap) is_leap = &dummy;
 	cycles = (year-100) / 400;
 	rem = (year-100) % 400;
 	if (rem < 0) {
diff --git a/src/time/clock_getcpuclockid.c b/src/time/clock_getcpuclockid.c
index 8a0e2d4c..bce1e8ab 100644
--- a/src/time/clock_getcpuclockid.c
+++ b/src/time/clock_getcpuclockid.c
@@ -8,6 +8,7 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clk)
 	struct timespec ts;
 	clockid_t id = (-pid-1)*8U + 2;
 	int ret = __syscall(SYS_clock_getres, id, &ts);
+	if (ret == -EINVAL) ret = -ESRCH;
 	if (ret) return -ret;
 	*clk = id;
 	return 0;
diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
index c7e66a51..4d2ec22f 100644
--- a/src/time/clock_gettime.c
+++ b/src/time/clock_gettime.c
@@ -42,6 +42,9 @@ static int cgt_init(clockid_t clk, struct timespec *ts)
 			p = cgt_time32_wrap;
 		}
 	}
+#ifdef VDSO_CGT_WORKAROUND
+	if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0;
+#endif
 #endif
 	int (*f)(clockid_t, struct timespec *) =
 		(int (*)(clockid_t, struct timespec *))p;
diff --git a/src/time/strftime.c b/src/time/strftime.c
index cc53d536..c40246db 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <langinfo.h>
 #include <locale.h>
+#include <ctype.h>
 #include <time.h>
 #include <limits.h>
 #include "locale_impl.h"
@@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
 		pad = 0;
 		if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
 		if ((plus = (*f == '+'))) f++;
-		width = strtoul(f, &p, 10);
+		if (isdigit(*f)) {
+			width = strtoul(f, &p, 10);
+		} else {
+			width = 0;
+			p = (void *)f;
+		}
 		if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
 			if (!width && p!=f) width = 1;
 		} else {
diff --git a/src/time/timer_create.c b/src/time/timer_create.c
index 4bef2390..9216b3ab 100644
--- a/src/time/timer_create.c
+++ b/src/time/timer_create.c
@@ -43,6 +43,8 @@ static void *start(void *arg)
 	union sigval val = args->sev->sigev_value;
 
 	pthread_barrier_wait(&args->b);
+	if (self->cancel)
+		return 0;
 	for (;;) {
 		siginfo_t si;
 		while (sigwaitinfo(SIGTIMER_SET, &si) < 0);
@@ -59,7 +61,7 @@ static void *start(void *arg)
 
 int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)
 {
-	volatile static int init = 0;
+	static volatile int init = 0;
 	pthread_t td;
 	pthread_attr_t attr;
 	int r;
@@ -113,8 +115,10 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
 		ksev.sigev_signo = SIGTIMER;
 		ksev.sigev_notify = SIGEV_THREAD_ID;
 		ksev.sigev_tid = td->tid;
-		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0)
+		if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {
 			timerid = -1;
+			td->cancel = 1;
+		}
 		td->timer_id = timerid;
 		pthread_barrier_wait(&args.b);
 		if (timerid < 0) return -1;
diff --git a/src/unistd/dup3.c b/src/unistd/dup3.c
index f919f791..40798bde 100644
--- a/src/unistd/dup3.c
+++ b/src/unistd/dup3.c
@@ -9,12 +9,14 @@ int __dup3(int old, int new, int flags)
 	int r;
 #ifdef SYS_dup2
 	if (old==new) return __syscall_ret(-EINVAL);
-	if (flags & O_CLOEXEC) {
+	if (flags) {
 		while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
 		if (r!=-ENOSYS) return __syscall_ret(r);
+		if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL);
 	}
 	while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
-	if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
+	if (r >= 0 && (flags & O_CLOEXEC))
+		__syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
 #else
 	while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
 #endif
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
index 557503eb..43052dd7 100644
--- a/src/unistd/faccessat.c
+++ b/src/unistd/faccessat.c
@@ -53,7 +53,7 @@ int faccessat(int fd, const char *filename, int amode, int flag)
 	if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
 		ret = -EBUSY;
 	__syscall(SYS_close, p[0]);
-	__syscall(SYS_wait4, pid, &status, __WCLONE, 0);
+	__sys_wait4(pid, &status, __WCLONE, 0);
 
 	__restore_sigs(&set);
 
diff --git a/src/unistd/ftruncate.c b/src/unistd/ftruncate.c
index b41be0fa..54ff34bc 100644
--- a/src/unistd/ftruncate.c
+++ b/src/unistd/ftruncate.c
@@ -5,5 +5,3 @@ int ftruncate(int fd, off_t length)
 {
 	return syscall(SYS_ftruncate, fd, __SYSCALL_LL_O(length));
 }
-
-weak_alias(ftruncate, ftruncate64);
diff --git a/src/unistd/lseek.c b/src/unistd/lseek.c
index b4984f3e..f5b66682 100644
--- a/src/unistd/lseek.c
+++ b/src/unistd/lseek.c
@@ -12,4 +12,3 @@ off_t __lseek(int fd, off_t offset, int whence)
 }
 
 weak_alias(__lseek, lseek);
-weak_alias(__lseek, lseek64);
diff --git a/src/unistd/mipsn32/lseek.c b/src/unistd/mipsn32/lseek.c
index 60e74a51..0f6cbcaa 100644
--- a/src/unistd/mipsn32/lseek.c
+++ b/src/unistd/mipsn32/lseek.c
@@ -17,4 +17,3 @@ off_t __lseek(int fd, off_t offset, int whence)
 }
 
 weak_alias(__lseek, lseek);
-weak_alias(__lseek, lseek64);
diff --git a/src/unistd/pipe2.c b/src/unistd/pipe2.c
index f24f74fb..a096990b 100644
--- a/src/unistd/pipe2.c
+++ b/src/unistd/pipe2.c
@@ -8,6 +8,7 @@ int pipe2(int fd[2], int flag)
 	if (!flag) return pipe(fd);
 	int ret = __syscall(SYS_pipe2, fd, flag);
 	if (ret != -ENOSYS) return __syscall_ret(ret);
+	if (flag & ~(O_CLOEXEC|O_NONBLOCK)) return __syscall_ret(-EINVAL);
 	ret = pipe(fd);
 	if (ret) return ret;
 	if (flag & O_CLOEXEC) {
diff --git a/src/unistd/pread.c b/src/unistd/pread.c
index 5681b045..b03fb0ad 100644
--- a/src/unistd/pread.c
+++ b/src/unistd/pread.c
@@ -5,5 +5,3 @@ ssize_t pread(int fd, void *buf, size_t size, off_t ofs)
 {
 	return syscall_cp(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs));
 }
-
-weak_alias(pread, pread64);
diff --git a/src/unistd/preadv.c b/src/unistd/preadv.c
index 8376d60f..890ab403 100644
--- a/src/unistd/preadv.c
+++ b/src/unistd/preadv.c
@@ -8,5 +8,3 @@ ssize_t preadv(int fd, const struct iovec *iov, int count, off_t ofs)
 	return syscall_cp(SYS_preadv, fd, iov, count,
 		(long)(ofs), (long)(ofs>>32));
 }
-
-weak_alias(preadv, preadv64);
diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c
index ca376576..869b69f0 100644
--- a/src/unistd/pwrite.c
+++ b/src/unistd/pwrite.c
@@ -5,5 +5,3 @@ ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
 {
 	return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL_PRW(ofs));
 }
-
-weak_alias(pwrite, pwrite64);
diff --git a/src/unistd/pwritev.c b/src/unistd/pwritev.c
index f5a612c4..becf9deb 100644
--- a/src/unistd/pwritev.c
+++ b/src/unistd/pwritev.c
@@ -8,5 +8,3 @@ ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs)
 	return syscall_cp(SYS_pwritev, fd, iov, count,
 		(long)(ofs), (long)(ofs>>32));
 }
-
-weak_alias(pwritev, pwritev64);
diff --git a/src/unistd/setxid.c b/src/unistd/setxid.c
index 487c1a16..a629ed4b 100644
--- a/src/unistd/setxid.c
+++ b/src/unistd/setxid.c
@@ -30,5 +30,5 @@ int __setxid(int nr, int id, int eid, int sid)
 	 * trigger the safety kill above. */
 	struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .ret = 1 };
 	__synccall(do_setxid, &c);
-	return __syscall_ret(c.ret);
+	return __syscall_ret(c.ret > 0 ? -EAGAIN : c.ret);
 }
diff --git a/src/unistd/truncate.c b/src/unistd/truncate.c
index 97296800..077351e1 100644
--- a/src/unistd/truncate.c
+++ b/src/unistd/truncate.c
@@ -5,5 +5,3 @@ int truncate(const char *path, off_t length)
 {
 	return syscall(SYS_truncate, path, __SYSCALL_LL_O(length));
 }
-
-weak_alias(truncate, truncate64);
diff --git a/src/unistd/x32/lseek.c b/src/unistd/x32/lseek.c
index 32636429..5f93292f 100644
--- a/src/unistd/x32/lseek.c
+++ b/src/unistd/x32/lseek.c
@@ -12,4 +12,3 @@ off_t __lseek(int fd, off_t offset, int whence)
 }
 
 weak_alias(__lseek, lseek);
-weak_alias(__lseek, lseek64);
diff --git a/tools/install.sh b/tools/install.sh
index d913b60b..855a8ca2 100755
--- a/tools/install.sh
+++ b/tools/install.sh
@@ -48,7 +48,9 @@ trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
 umask 077
 
 if test "$symlink" ; then
+umask 000
 ln -s "$1" "$tmp"
+umask 077
 else
 cat < "$1" > "$tmp"
 chmod "$mode" "$tmp"