Merge "Properly fail with ESRCH when pthread_killing an exited thread."
diff --git a/libc/Android.bp b/libc/Android.bp
index cc0a2bb..1fc3062 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -792,6 +792,16 @@
                     "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
                 ],
             },
+            cortex_a76: {
+                srcs: [
+                    "arch-arm/denver/bionic/__strcat_chk.S",
+                    "arch-arm/denver/bionic/__strcpy_chk.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                ],
+            },
             denver: {
                 srcs: [
                     "arch-arm/denver/bionic/__strcat_chk.S",
@@ -964,6 +974,19 @@
                     "arch-arm/cortex-a15/bionic/strcmp.S",
                 ],
             },
+            cortex_a76: {
+                srcs: [
+                    "arch-arm/cortex-a7/bionic/memset.S",
+                    "arch-arm/denver/bionic/memcpy.S",
+
+                    "arch-arm/krait/bionic/strcmp.S",
+                ],
+                exclude_srcs: [
+                    "arch-arm/cortex-a15/bionic/memset.S",
+                    "arch-arm/cortex-a15/bionic/memcpy.S",
+                    "arch-arm/cortex-a15/bionic/strcmp.S",
+                ],
+            },
             denver: {
                 srcs: [
                     "arch-arm/denver/bionic/memcpy.S",
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 5f22c74..207035a 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -424,13 +424,18 @@
   return buffer_len;
 }
 
-int async_safe_format_fd(int fd, const char* format, ...) {
+int async_safe_format_fd_va_list(int fd, const char* format, va_list args) {
   FdOutputStream os(fd);
+  out_vformat(os, format, args);
+  return os.total;
+}
+
+int async_safe_format_fd(int fd, const char* format, ...) {
   va_list args;
   va_start(args, format);
-  out_vformat(os, format, args);
+  int result = async_safe_format_fd_va_list(fd, format, args);
   va_end(args);
-  return os.total;
+  return result;
 }
 
 static int write_stderr(const char* tag, const char* msg) {
diff --git a/libc/async_safe/include/async_safe/log.h b/libc/async_safe/include/async_safe/log.h
index 415b48e..df68062 100644
--- a/libc/async_safe/include/async_safe/log.h
+++ b/libc/async_safe/include/async_safe/log.h
@@ -90,6 +90,7 @@
 int async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format, va_list args);
 
 int async_safe_format_fd(int fd, const char* format , ...) __printflike(2, 3);
+int async_safe_format_fd_va_list(int fd, const char* format, va_list args);
 int async_safe_format_log(int pri, const char* tag, const char* fmt, ...) __printflike(3, 4);
 int async_safe_format_log_va_list(int pri, const char* tag, const char* fmt, va_list ap);
 int async_safe_write_log(int pri, const char* tag, const char* msg);
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index 11ebf52..9a9fee2 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -188,6 +188,8 @@
     async_safe_fatal_va_list("fdsan", fmt, va);
   } else {
     async_safe_format_log_va_list(ANDROID_LOG_ERROR, "fdsan", fmt, va);
+    va_end(va);
+    va_start(va, fmt);
     size_t len =
         async_safe_format_buffer_va_list(abort_message.buf, sizeof(abort_message.buf), fmt, va);
     abort_message.size = len + sizeof(size_t);
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 0def359..5f76354 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -133,7 +133,9 @@
     __cxa_atexit(__libc_fini,structors->fini_array,nullptr);
   }
 
-  exit(slingshot(args.argc, args.argv, args.envp));
+  exit(slingshot(args.argc - __libc_shared_globals->initial_linker_arg_count,
+                 args.argv + __libc_shared_globals->initial_linker_arg_count,
+                 args.envp));
 }
 
 extern "C" uint32_t android_get_application_target_sdk_version();
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 3df8b18..41b2657 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -71,7 +71,7 @@
   sigset64_t mutable_ss;
   sigset64_t* mutable_ss_ptr = nullptr;
   if (ss != nullptr) {
-    mutable_ss = filter_reserved_signals(*ss);
+    mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK);
     mutable_ss_ptr = &mutable_ss;
   }
 
@@ -121,7 +121,7 @@
   sigset64_t mutable_ss;
   sigset64_t* mutable_ss_ptr = nullptr;
   if (ss != nullptr) {
-    mutable_ss = filter_reserved_signals(*ss);
+    mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK);
     mutable_ss_ptr = &mutable_ss;
   }
 
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index fb57d1c..42dcccd 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -43,7 +43,7 @@
   if (bionic_new_action != nullptr) {
     kernel_new_action.sa_flags = bionic_new_action->sa_flags;
     kernel_new_action.sa_handler = bionic_new_action->sa_handler;
-    kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask);
+    kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask, SIG_SETMASK);
 #if defined(SA_RESTORER)
     kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
 #if defined(__aarch64__)
@@ -122,7 +122,7 @@
       kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
     }
 #endif
-    kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
+    kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask, SIG_SETMASK);
   }
 
   return __rt_sigaction(signal,
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index 175182b..d6be09a 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -263,7 +263,7 @@
   sigset64_t mutable_set;
   sigset64_t* mutable_set_ptr = nullptr;
   if (set) {
-    mutable_set = filter_reserved_signals(*set);
+    mutable_set = filter_reserved_signals(*set, SIG_SETMASK);
     mutable_set_ptr = &mutable_set;
   }
   return __rt_sigsuspend(mutable_set_ptr, sizeof(*set));
@@ -279,7 +279,7 @@
   sigset64_t mutable_set;
   sigset64_t* mutable_set_ptr = nullptr;
   if (set) {
-    mutable_set = filter_reserved_signals(*set);
+    mutable_set = filter_reserved_signals(*set, SIG_SETMASK);
     mutable_set_ptr = &mutable_set;
   }
   return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set));
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
index 36866f3..5f70f32 100644
--- a/libc/bionic/sigprocmask.cpp
+++ b/libc/bionic/sigprocmask.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 #include "private/sigrtmin.h"
@@ -65,10 +66,16 @@
 int sigprocmask64(int how,
                   const sigset64_t* new_set,
                   sigset64_t* old_set) __attribute__((__noinline__)) {
+  // how is only checked for validity if new_set is provided.
+  if (new_set && how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) {
+    errno = EINVAL;
+    return -1;
+  }
+
   sigset64_t mutable_new_set;
   sigset64_t* mutable_new_set_ptr = nullptr;
   if (new_set) {
-    mutable_new_set = filter_reserved_signals(*new_set);
+    mutable_new_set = filter_reserved_signals(*new_set, how);
     mutable_new_set_ptr = &mutable_new_set;
   }
   return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 1cf2abc..29d902c 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -31,9 +31,139 @@
 }
 
 static const Pair _sys_error_strings[] = {
-#define  __BIONIC_ERRDEF(x,y,z)  { x, z },
-#include "private/bionic_errdefs.h"
-  { 0, nullptr }
+    {0, "Success"},
+    {EPERM, "Operation not permitted"},
+    {ENOENT, "No such file or directory"},
+    {ESRCH, "No such process"},
+    {EINTR, "Interrupted system call"},
+    {EIO, "I/O error"},
+    {ENXIO, "No such device or address"},
+    {E2BIG, "Argument list too long"},
+    {ENOEXEC, "Exec format error"},
+    {EBADF, "Bad file descriptor"},
+    {ECHILD, "No child processes"},
+    {EAGAIN, "Try again"},
+    {ENOMEM, "Out of memory"},
+    {EACCES, "Permission denied"},
+    {EFAULT, "Bad address"},
+    {ENOTBLK, "Block device required"},
+    {EBUSY, "Device or resource busy"},
+    {EEXIST, "File exists"},
+    {EXDEV, "Cross-device link"},
+    {ENODEV, "No such device"},
+    {ENOTDIR, "Not a directory"},
+    {EISDIR, "Is a directory"},
+    {EINVAL, "Invalid argument"},
+    {ENFILE, "File table overflow"},
+    {EMFILE, "Too many open files"},
+    {ENOTTY, "Not a typewriter"},
+    {ETXTBSY, "Text file busy"},
+    {EFBIG, "File too large"},
+    {ENOSPC, "No space left on device"},
+    {ESPIPE, "Illegal seek"},
+    {EROFS, "Read-only file system"},
+    {EMLINK, "Too many links"},
+    {EPIPE, "Broken pipe"},
+    {EDOM, "Math argument out of domain of func"},
+    {ERANGE, "Math result not representable"},
+    {EDEADLK, "Resource deadlock would occur"},
+    {ENAMETOOLONG, "File name too long"},
+    {ENOLCK, "No record locks available"},
+    {ENOSYS, "Function not implemented"},
+    {ENOTEMPTY, "Directory not empty"},
+    {ELOOP, "Too many symbolic links encountered"},
+    {ENOMSG, "No message of desired type"},
+    {EIDRM, "Identifier removed"},
+    {ECHRNG, "Channel number out of range"},
+    {EL2NSYNC, "Level 2 not synchronized"},
+    {EL3HLT, "Level 3 halted"},
+    {EL3RST, "Level 3 reset"},
+    {ELNRNG, "Link number out of range"},
+    {EUNATCH, "Protocol driver not attached"},
+    {ENOCSI, "No CSI structure available"},
+    {EL2HLT, "Level 2 halted"},
+    {EBADE, "Invalid exchange"},
+    {EBADR, "Invalid request descriptor"},
+    {EXFULL, "Exchange full"},
+    {ENOANO, "No anode"},
+    {EBADRQC, "Invalid request code"},
+    {EBADSLT, "Invalid slot"},
+    {EBFONT, "Bad font file format"},
+    {ENOSTR, "Device not a stream"},
+    {ENODATA, "No data available"},
+    {ETIME, "Timer expired"},
+    {ENOSR, "Out of streams resources"},
+    {ENONET, "Machine is not on the network"},
+    {ENOPKG, "Package not installed"},
+    {EREMOTE, "Object is remote"},
+    {ENOLINK, "Link has been severed"},
+    {EADV, "Advertise error"},
+    {ESRMNT, "Srmount error"},
+    {ECOMM, "Communication error on send"},
+    {EPROTO, "Protocol error"},
+    {EMULTIHOP, "Multihop attempted"},
+    {EDOTDOT, "RFS specific error"},
+    {EBADMSG, "Not a data message"},
+    {EOVERFLOW, "Value too large for defined data type"},
+    {ENOTUNIQ, "Name not unique on network"},
+    {EBADFD, "File descriptor in bad state"},
+    {EREMCHG, "Remote address changed"},
+    {ELIBACC, "Can not access a needed shared library"},
+    {ELIBBAD, "Accessing a corrupted shared library"},
+    {ELIBSCN, ".lib section in a.out corrupted"},
+    {ELIBMAX, "Attempting to link in too many shared libraries"},
+    {ELIBEXEC, "Cannot exec a shared library directly"},
+    {EILSEQ, "Illegal byte sequence"},
+    {ERESTART, "Interrupted system call should be restarted"},
+    {ESTRPIPE, "Streams pipe error"},
+    {EUSERS, "Too many users"},
+    {ENOTSOCK, "Socket operation on non-socket"},
+    {EDESTADDRREQ, "Destination address required"},
+    {EMSGSIZE, "Message too long"},
+    {EPROTOTYPE, "Protocol wrong type for socket"},
+    {ENOPROTOOPT, "Protocol not available"},
+    {EPROTONOSUPPORT, "Protocol not supported"},
+    {ESOCKTNOSUPPORT, "Socket type not supported"},
+    {EOPNOTSUPP, "Operation not supported on transport endpoint"},
+    {EPFNOSUPPORT, "Protocol family not supported"},
+    {EAFNOSUPPORT, "Address family not supported by protocol"},
+    {EADDRINUSE, "Address already in use"},
+    {EADDRNOTAVAIL, "Cannot assign requested address"},
+    {ENETDOWN, "Network is down"},
+    {ENETUNREACH, "Network is unreachable"},
+    {ENETRESET, "Network dropped connection because of reset"},
+    {ECONNABORTED, "Software caused connection abort"},
+    {ECONNRESET, "Connection reset by peer"},
+    {ENOBUFS, "No buffer space available"},
+    {EISCONN, "Transport endpoint is already connected"},
+    {ENOTCONN, "Transport endpoint is not connected"},
+    {ESHUTDOWN, "Cannot send after transport endpoint shutdown"},
+    {ETOOMANYREFS, "Too many references: cannot splice"},
+    {ETIMEDOUT, "Connection timed out"},
+    {ECONNREFUSED, "Connection refused"},
+    {EHOSTDOWN, "Host is down"},
+    {EHOSTUNREACH, "No route to host"},
+    {EALREADY, "Operation already in progress"},
+    {EINPROGRESS, "Operation now in progress"},
+    {ESTALE, "Stale NFS file handle"},
+    {EUCLEAN, "Structure needs cleaning"},
+    {ENOTNAM, "Not a XENIX named type file"},
+    {ENAVAIL, "No XENIX semaphores available"},
+    {EISNAM, "Is a named type file"},
+    {EREMOTEIO, "Remote I/O error"},
+    {EDQUOT, "Quota exceeded"},
+    {ENOMEDIUM, "No medium found"},
+    {EMEDIUMTYPE, "Wrong medium type"},
+    {ECANCELED, "Operation Canceled"},
+    {ENOKEY, "Required key not available"},
+    {EKEYEXPIRED, "Key has expired"},
+    {EKEYREVOKED, "Key has been revoked"},
+    {EKEYREJECTED, "Key was rejected by service"},
+    {EOWNERDEAD, "Owner died"},
+    {ENOTRECOVERABLE, "State not recoverable"},
+    {ERFKILL, "Operation not possible due to RF-kill"},
+    {EHWPOISON, "Memory page has hardware error"},
+    {0, nullptr}
 };
 
 extern "C" __LIBC_HIDDEN__ const char* __strerror_lookup(int error_number) {
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index ebce900..3a8f926 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -51,12 +51,6 @@
  * compiler/build system based on the API level you claimed to target.
  */
 #define __ANDROID_API__ __ANDROID_API_FUTURE__
-#else
-/**
- * `__ANDROID_NDK__` is defined for code that's built by the NDK
- * rather than as part of the OS.
- */
-#define __ANDROID_NDK__ 1
 #endif
 
 /** Names the Gingerbread API level (9), for comparisons against __ANDROID_API__. */
diff --git a/libc/include/bits/sysconf.h b/libc/include/bits/sysconf.h
index 2cbbb11..8607adf 100644
--- a/libc/include/bits/sysconf.h
+++ b/libc/include/bits/sysconf.h
@@ -73,6 +73,7 @@
 #define _SC_XOPEN_LEGACY        0x0024
 #define _SC_ATEXIT_MAX          0x0025
 #define _SC_IOV_MAX             0x0026
+#define _SC_UIO_MAXIOV _SC_IOV_MAX
 #define _SC_PAGESIZE            0x0027
 #define _SC_PAGE_SIZE           0x0028
 #define _SC_XOPEN_UNIX          0x0029
diff --git a/libc/private/bionic_errdefs.h b/libc/private/bionic_errdefs.h
deleted file mode 100644
index 3c3c9d7..0000000
--- a/libc/private/bionic_errdefs.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/* the following corresponds to the error codes of the Linux kernel used by the Android platform
- * these are distinct from the OpenBSD ones, which is why we need to redeclare them here
- *
- * this file may be included several times to define either error constants or their
- * string representation
- */
-
-#ifndef __BIONIC_ERRDEF
-#error "__BIONIC_ERRDEF must be defined before including this file"
-#endif
-__BIONIC_ERRDEF( 0              ,   0, "Success" )
-__BIONIC_ERRDEF( EPERM          ,   1, "Operation not permitted" )
-__BIONIC_ERRDEF( ENOENT         ,   2, "No such file or directory" )
-__BIONIC_ERRDEF( ESRCH          ,   3, "No such process" )
-__BIONIC_ERRDEF( EINTR          ,   4, "Interrupted system call" )
-__BIONIC_ERRDEF( EIO            ,   5, "I/O error" )
-__BIONIC_ERRDEF( ENXIO          ,   6, "No such device or address" )
-__BIONIC_ERRDEF( E2BIG          ,   7, "Argument list too long" )
-__BIONIC_ERRDEF( ENOEXEC        ,   8, "Exec format error" )
-__BIONIC_ERRDEF( EBADF          ,   9, "Bad file descriptor" )
-__BIONIC_ERRDEF( ECHILD         ,  10, "No child processes" )
-__BIONIC_ERRDEF( EAGAIN         ,  11, "Try again" )
-__BIONIC_ERRDEF( ENOMEM         ,  12, "Out of memory" )
-__BIONIC_ERRDEF( EACCES         ,  13, "Permission denied" )
-__BIONIC_ERRDEF( EFAULT         ,  14, "Bad address" )
-__BIONIC_ERRDEF( ENOTBLK        ,  15, "Block device required" )
-__BIONIC_ERRDEF( EBUSY          ,  16, "Device or resource busy" )
-__BIONIC_ERRDEF( EEXIST         ,  17, "File exists" )
-__BIONIC_ERRDEF( EXDEV          ,  18, "Cross-device link" )
-__BIONIC_ERRDEF( ENODEV         ,  19, "No such device" )
-__BIONIC_ERRDEF( ENOTDIR        ,  20, "Not a directory" )
-__BIONIC_ERRDEF( EISDIR         ,  21, "Is a directory" )
-__BIONIC_ERRDEF( EINVAL         ,  22, "Invalid argument" )
-__BIONIC_ERRDEF( ENFILE         ,  23, "File table overflow" )
-__BIONIC_ERRDEF( EMFILE         ,  24, "Too many open files" )
-__BIONIC_ERRDEF( ENOTTY         ,  25, "Not a typewriter" )
-__BIONIC_ERRDEF( ETXTBSY        ,  26, "Text file busy" )
-__BIONIC_ERRDEF( EFBIG          ,  27, "File too large" )
-__BIONIC_ERRDEF( ENOSPC         ,  28, "No space left on device" )
-__BIONIC_ERRDEF( ESPIPE         ,  29, "Illegal seek" )
-__BIONIC_ERRDEF( EROFS          ,  30, "Read-only file system" )
-__BIONIC_ERRDEF( EMLINK         ,  31, "Too many links" )
-__BIONIC_ERRDEF( EPIPE          ,  32, "Broken pipe" )
-__BIONIC_ERRDEF( EDOM           ,  33, "Math argument out of domain of func" )
-__BIONIC_ERRDEF( ERANGE         ,  34, "Math result not representable" )
-__BIONIC_ERRDEF( EDEADLK        ,  35, "Resource deadlock would occur" )
-__BIONIC_ERRDEF( ENAMETOOLONG   ,  36, "File name too long" )
-__BIONIC_ERRDEF( ENOLCK         ,  37, "No record locks available" )
-__BIONIC_ERRDEF( ENOSYS         ,  38, "Function not implemented" )
-__BIONIC_ERRDEF( ENOTEMPTY      ,  39, "Directory not empty" )
-__BIONIC_ERRDEF( ELOOP          ,  40, "Too many symbolic links encountered" )
-__BIONIC_ERRDEF( ENOMSG         ,  42, "No message of desired type" )
-__BIONIC_ERRDEF( EIDRM          ,  43, "Identifier removed" )
-__BIONIC_ERRDEF( ECHRNG         ,  44, "Channel number out of range" )
-__BIONIC_ERRDEF( EL2NSYNC       ,  45, "Level 2 not synchronized" )
-__BIONIC_ERRDEF( EL3HLT         ,  46, "Level 3 halted" )
-__BIONIC_ERRDEF( EL3RST         ,  47, "Level 3 reset" )
-__BIONIC_ERRDEF( ELNRNG         ,  48, "Link number out of range" )
-__BIONIC_ERRDEF( EUNATCH        ,  49, "Protocol driver not attached" )
-__BIONIC_ERRDEF( ENOCSI         ,  50, "No CSI structure available" )
-__BIONIC_ERRDEF( EL2HLT         ,  51, "Level 2 halted" )
-__BIONIC_ERRDEF( EBADE          ,  52, "Invalid exchange" )
-__BIONIC_ERRDEF( EBADR          ,  53, "Invalid request descriptor" )
-__BIONIC_ERRDEF( EXFULL         ,  54, "Exchange full" )
-__BIONIC_ERRDEF( ENOANO         ,  55, "No anode" )
-__BIONIC_ERRDEF( EBADRQC        ,  56, "Invalid request code" )
-__BIONIC_ERRDEF( EBADSLT        ,  57, "Invalid slot" )
-__BIONIC_ERRDEF( EBFONT         ,  59, "Bad font file format" )
-__BIONIC_ERRDEF( ENOSTR         ,  60, "Device not a stream" )
-__BIONIC_ERRDEF( ENODATA        ,  61, "No data available" )
-__BIONIC_ERRDEF( ETIME          ,  62, "Timer expired" )
-__BIONIC_ERRDEF( ENOSR          ,  63, "Out of streams resources" )
-__BIONIC_ERRDEF( ENONET         ,  64, "Machine is not on the network" )
-__BIONIC_ERRDEF( ENOPKG         ,  65, "Package not installed" )
-__BIONIC_ERRDEF( EREMOTE        ,  66, "Object is remote" )
-__BIONIC_ERRDEF( ENOLINK        ,  67, "Link has been severed" )
-__BIONIC_ERRDEF( EADV           ,  68, "Advertise error" )
-__BIONIC_ERRDEF( ESRMNT         ,  69, "Srmount error" )
-__BIONIC_ERRDEF( ECOMM          ,  70, "Communication error on send" )
-__BIONIC_ERRDEF( EPROTO         ,  71, "Protocol error" )
-__BIONIC_ERRDEF( EMULTIHOP      ,  72, "Multihop attempted" )
-__BIONIC_ERRDEF( EDOTDOT        ,  73, "RFS specific error" )
-__BIONIC_ERRDEF( EBADMSG        ,  74, "Not a data message" )
-__BIONIC_ERRDEF( EOVERFLOW      ,  75, "Value too large for defined data type" )
-__BIONIC_ERRDEF( ENOTUNIQ       ,  76, "Name not unique on network" )
-__BIONIC_ERRDEF( EBADFD         ,  77, "File descriptor in bad state" )
-__BIONIC_ERRDEF( EREMCHG        ,  78, "Remote address changed" )
-__BIONIC_ERRDEF( ELIBACC        ,  79, "Can not access a needed shared library" )
-__BIONIC_ERRDEF( ELIBBAD        ,  80, "Accessing a corrupted shared library" )
-__BIONIC_ERRDEF( ELIBSCN        ,  81, ".lib section in a.out corrupted" )
-__BIONIC_ERRDEF( ELIBMAX        ,  82, "Attempting to link in too many shared libraries" )
-__BIONIC_ERRDEF( ELIBEXEC       ,  83, "Cannot exec a shared library directly" )
-__BIONIC_ERRDEF( EILSEQ         ,  84, "Illegal byte sequence" )
-__BIONIC_ERRDEF( ERESTART       ,  85, "Interrupted system call should be restarted" )
-__BIONIC_ERRDEF( ESTRPIPE       ,  86, "Streams pipe error" )
-__BIONIC_ERRDEF( EUSERS         ,  87, "Too many users" )
-__BIONIC_ERRDEF( ENOTSOCK       ,  88, "Socket operation on non-socket" )
-__BIONIC_ERRDEF( EDESTADDRREQ   ,  89, "Destination address required" )
-__BIONIC_ERRDEF( EMSGSIZE       ,  90, "Message too long" )
-__BIONIC_ERRDEF( EPROTOTYPE     ,  91, "Protocol wrong type for socket" )
-__BIONIC_ERRDEF( ENOPROTOOPT    ,  92, "Protocol not available" )
-__BIONIC_ERRDEF( EPROTONOSUPPORT,  93, "Protocol not supported" )
-__BIONIC_ERRDEF( ESOCKTNOSUPPORT,  94, "Socket type not supported" )
-__BIONIC_ERRDEF( EOPNOTSUPP     ,  95, "Operation not supported on transport endpoint" )
-__BIONIC_ERRDEF( EPFNOSUPPORT   ,  96, "Protocol family not supported" )
-__BIONIC_ERRDEF( EAFNOSUPPORT   ,  97, "Address family not supported by protocol" )
-__BIONIC_ERRDEF( EADDRINUSE     ,  98, "Address already in use" )
-__BIONIC_ERRDEF( EADDRNOTAVAIL  ,  99, "Cannot assign requested address" )
-__BIONIC_ERRDEF( ENETDOWN       , 100, "Network is down" )
-__BIONIC_ERRDEF( ENETUNREACH    , 101, "Network is unreachable" )
-__BIONIC_ERRDEF( ENETRESET      , 102, "Network dropped connection because of reset" )
-__BIONIC_ERRDEF( ECONNABORTED   , 103, "Software caused connection abort" )
-__BIONIC_ERRDEF( ECONNRESET     , 104, "Connection reset by peer" )
-__BIONIC_ERRDEF( ENOBUFS        , 105, "No buffer space available" )
-__BIONIC_ERRDEF( EISCONN        , 106, "Transport endpoint is already connected" )
-__BIONIC_ERRDEF( ENOTCONN       , 107, "Transport endpoint is not connected" )
-__BIONIC_ERRDEF( ESHUTDOWN      , 108, "Cannot send after transport endpoint shutdown" )
-__BIONIC_ERRDEF( ETOOMANYREFS   , 109, "Too many references: cannot splice" )
-__BIONIC_ERRDEF( ETIMEDOUT      , 110, "Connection timed out" )
-__BIONIC_ERRDEF( ECONNREFUSED   , 111, "Connection refused" )
-__BIONIC_ERRDEF( EHOSTDOWN      , 112, "Host is down" )
-__BIONIC_ERRDEF( EHOSTUNREACH   , 113, "No route to host" )
-__BIONIC_ERRDEF( EALREADY       , 114, "Operation already in progress" )
-__BIONIC_ERRDEF( EINPROGRESS    , 115, "Operation now in progress" )
-__BIONIC_ERRDEF( ESTALE         , 116, "Stale NFS file handle" )
-__BIONIC_ERRDEF( EUCLEAN        , 117, "Structure needs cleaning" )
-__BIONIC_ERRDEF( ENOTNAM        , 118, "Not a XENIX named type file" )
-__BIONIC_ERRDEF( ENAVAIL        , 119, "No XENIX semaphores available" )
-__BIONIC_ERRDEF( EISNAM         , 120, "Is a named type file" )
-__BIONIC_ERRDEF( EREMOTEIO      , 121, "Remote I/O error" )
-__BIONIC_ERRDEF( EDQUOT         , 122, "Quota exceeded" )
-__BIONIC_ERRDEF( ENOMEDIUM      , 123, "No medium found" )
-__BIONIC_ERRDEF( EMEDIUMTYPE    , 124, "Wrong medium type" )
-__BIONIC_ERRDEF( ECANCELED      , 125, "Operation Canceled" )
-__BIONIC_ERRDEF( ENOKEY         , 126, "Required key not available" )
-__BIONIC_ERRDEF( EKEYEXPIRED    , 127, "Key has expired" )
-__BIONIC_ERRDEF( EKEYREVOKED    , 128, "Key has been revoked" )
-__BIONIC_ERRDEF( EKEYREJECTED   , 129, "Key was rejected by service" )
-__BIONIC_ERRDEF( EOWNERDEAD     , 130, "Owner died" )
-__BIONIC_ERRDEF( ENOTRECOVERABLE, 131, "State not recoverable" )
-
-#undef __BIONIC_ERRDEF
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index eee33c9..8c00551 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -47,6 +47,11 @@
 // Globals shared between the dynamic linker and libc.so.
 struct libc_shared_globals {
   FdTable fd_table;
+
+  // When the linker is invoked on a binary (e.g. `linker64 /system/bin/date`),
+  // record the number of arguments passed to the linker itself rather than to
+  // the program it's loading. Typically 0, sometimes 1.
+  int initial_linker_arg_count;
 };
 
 __LIBC_HIDDEN__ extern libc_shared_globals* __libc_shared_globals;
diff --git a/libc/private/sigrtmin.h b/libc/private/sigrtmin.h
index ea8673d..431a1dd 100644
--- a/libc/private/sigrtmin.h
+++ b/libc/private/sigrtmin.h
@@ -32,6 +32,8 @@
 
 #include <signal.h>
 
+#include "bionic_macros.h"
+
 // Realtime signals reserved for internal use:
 //   32 (__SIGRTMIN + 0)        POSIX timers
 //   33 (__SIGRTMIN + 1)        libbacktrace
@@ -42,9 +44,29 @@
 // in <android/legacy_signal_inlines.h> to match.
 
 #define __SIGRT_RESERVED 4
-static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset) {
-  for (int signo = __SIGRTMIN; signo < __SIGRTMIN + __SIGRT_RESERVED; ++signo) {
-    sigdelset64(&sigset, signo);
+static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
+  int (*block)(sigset64_t*, int);
+  int (*unblock)(sigset64_t*, int);
+  switch (how) {
+    case SIG_BLOCK:
+      __BIONIC_FALLTHROUGH;
+    case SIG_SETMASK:
+      block = sigaddset64;
+      unblock = sigdelset64;
+      break;
+
+    case SIG_UNBLOCK:
+      block = sigdelset64;
+      unblock = sigaddset64;
+      break;
   }
+
+  // The POSIX timer signal must be blocked.
+  block(&sigset, __SIGRTMIN + 0);
+
+  // Everything else must remain unblocked.
+  unblock(&sigset, __SIGRTMIN + 1);
+  unblock(&sigset, __SIGRTMIN + 2);
+  unblock(&sigset, __SIGRTMIN + 3);
   return sigset;
 }
diff --git a/libdl/Android.bp b/libdl/Android.bp
index 0efde34..13c8714 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -3,6 +3,7 @@
 //
 cc_library_static {
     name: "libdl_static",
+    defaults: ["linux_bionic_supported"],
     recovery_available: true,
 
     srcs: [
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e1fe50f..b605ed9 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -289,7 +289,7 @@
 }
 
 soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
-                     struct stat* file_stat, off64_t file_offset,
+                     const struct stat* file_stat, off64_t file_offset,
                      uint32_t rtld_flags) {
   if (strlen(name) >= PATH_MAX) {
     async_safe_fatal("library name \"%s\" too long", name);
@@ -918,8 +918,7 @@
 
   if (OpenArchiveFd(fd, "", handle) != 0) {
     // invalid zip-file (?)
-    CloseArchive(handle);
-    close(fd);
+    CloseArchive(*handle);
     return false;
   }
 
@@ -1012,6 +1011,28 @@
   return true;
 }
 
+static int open_library_at_path(ZipArchiveCache* zip_archive_cache,
+                                const char* path, off64_t* file_offset,
+                                std::string* realpath) {
+  int fd = -1;
+  if (strstr(path, kZipFileSeparator) != nullptr) {
+    fd = open_library_in_zipfile(zip_archive_cache, path, file_offset, realpath);
+  }
+
+  if (fd == -1) {
+    fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
+    if (fd != -1) {
+      *file_offset = 0;
+      if (!realpath_fd(fd, realpath)) {
+        PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", path);
+        *realpath = path;
+      }
+    }
+  }
+
+  return fd;
+}
+
 static int open_library_on_paths(ZipArchiveCache* zip_archive_cache,
                                  const char* name, off64_t* file_offset,
                                  const std::vector<std::string>& paths,
@@ -1022,22 +1043,7 @@
       continue;
     }
 
-    int fd = -1;
-    if (strstr(buf, kZipFileSeparator) != nullptr) {
-      fd = open_library_in_zipfile(zip_archive_cache, buf, file_offset, realpath);
-    }
-
-    if (fd == -1) {
-      fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
-      if (fd != -1) {
-        *file_offset = 0;
-        if (!realpath_fd(fd, realpath)) {
-          PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.", buf);
-          *realpath = buf;
-        }
-      }
-    }
-
+    int fd = open_library_at_path(zip_archive_cache, buf, file_offset, realpath);
     if (fd != -1) {
       return fd;
     }
@@ -1099,6 +1105,11 @@
   return fd;
 }
 
+int open_executable(const char* path, off64_t* file_offset, std::string* realpath) {
+  ZipArchiveCache zip_archive_cache;
+  return open_library_at_path(&zip_archive_cache, path, file_offset, realpath);
+}
+
 const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
 #if !defined(__LP64__)
   // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
diff --git a/linker/linker.h b/linker/linker.h
index 7aa7e5f..dd45f67 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -103,6 +103,8 @@
 
 soinfo* find_containing_library(const void* p);
 
+int open_executable(const char* path, off64_t* file_offset, std::string* realpath);
+
 void do_android_get_LD_LIBRARY_PATH(char*, size_t);
 void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
 void* do_dlopen(const char* name,
diff --git a/linker/linker_logger.cpp b/linker/linker_logger.cpp
index 4c6603b..d0e5072 100644
--- a/linker/linker_logger.cpp
+++ b/linker/linker_logger.cpp
@@ -106,8 +106,8 @@
   static CachedProperty debug_ld_all("debug.ld.all");
   flags_ |= ParseProperty(debug_ld_all.Get());
 
-  // Ignore processes started without argv (http://b/33276926).
-  if (g_argv[0] == nullptr) {
+  // Safeguard against a NULL g_argv. Ignore processes started without argv (http://b/33276926).
+  if (g_argv == nullptr || g_argv[0] == nullptr) {
     return;
   }
 
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index c5e0b96..f7c496a 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -35,10 +35,12 @@
 #include "linker_phdr.h"
 #include "linker_utils.h"
 
+#include "private/bionic_auxv.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
 
+#include "android-base/unique_fd.h"
 #include "android-base/strings.h"
 #include "android-base/stringprintf.h"
 #ifdef __ANDROID__
@@ -52,7 +54,7 @@
 extern void __libc_init_globals(KernelArgumentBlock&);
 extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
 
-extern "C" void _start();
+__LIBC_HIDDEN__ extern "C" void _start();
 
 static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 
@@ -182,22 +184,41 @@
 
 extern "C" int __system_properties_init(void);
 
-static const char* get_executable_path() {
-  static std::string executable_path;
-  if (executable_path.empty()) {
-    if (!is_init()) {
-      char path[PATH_MAX];
-      ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
-      if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
-        async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
-      }
-      executable_path = std::string(path, path_len);
-    } else {
-      executable_path = "/init";
+struct ExecutableInfo {
+  std::string path;
+  struct stat file_stat;
+  const ElfW(Phdr)* phdr;
+  size_t phdr_count;
+  ElfW(Addr) entry_point;
+};
+
+static ExecutableInfo get_executable_info(KernelArgumentBlock& args) {
+  ExecutableInfo result = {};
+
+  if (is_init()) {
+    // /proc fs is not mounted when init starts. Therefore we can't use
+    // /proc/self/exe for init.
+    stat("/init", &result.file_stat);
+    result.path = "/init";
+  } else {
+    // Stat "/proc/self/exe" instead of executable_path because
+    // the executable could be unlinked by this point and it should
+    // not cause a crash (see http://b/31084669)
+    if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &result.file_stat)) != 0) {
+      async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
     }
+    char path[PATH_MAX];
+    ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
+    if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) {
+      async_safe_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno));
+    }
+    result.path = std::string(path, path_len);
   }
 
-  return executable_path.c_str();
+  result.phdr = reinterpret_cast<const ElfW(Phdr)*>(args.getauxval(AT_PHDR));
+  result.phdr_count = args.getauxval(AT_PHNUM);
+  result.entry_point = args.getauxval(AT_ENTRY);
+  return result;
 }
 
 #if defined(__LP64__)
@@ -206,21 +227,62 @@
 static char kLinkerPath[] = "/system/bin/linker";
 #endif
 
-static void __linker_cannot_link(const char* argv0) {
-  async_safe_format_fd(STDERR_FILENO,
-                       "CANNOT LINK EXECUTABLE \"%s\": %s\n",
-                       argv0,
-                       linker_get_error_buffer());
+__printflike(1, 2)
+static void __linker_error(const char* fmt, ...) {
+  va_list ap;
 
-  async_safe_format_log(ANDROID_LOG_FATAL,
-                        "linker",
-                        "CANNOT LINK EXECUTABLE \"%s\": %s",
-                        argv0,
-                        linker_get_error_buffer());
+  va_start(ap, fmt);
+  async_safe_format_fd_va_list(STDERR_FILENO, fmt, ap);
+  va_end(ap);
+
+  va_start(ap, fmt);
+  async_safe_format_log_va_list(ANDROID_LOG_FATAL, "linker", fmt, ap);
+  va_end(ap);
+
   _exit(EXIT_FAILURE);
 }
 
-static ElfW(Addr) linker_main(KernelArgumentBlock& args) {
+static void __linker_cannot_link(const char* argv0) {
+  __linker_error("CANNOT LINK EXECUTABLE \"%s\": %s\n",
+                 argv0,
+                 linker_get_error_buffer());
+}
+
+// Load an executable. Normally the kernel has already loaded the executable when the linker
+// starts. The linker can be invoked directly on an executable, though, and then the linker must
+// load it. This function doesn't load dependencies or resolve relocations.
+static ExecutableInfo load_executable(const char* orig_path) {
+  ExecutableInfo result = {};
+
+  if (orig_path[0] != '/') {
+    __linker_error("error: expected absolute path: \"%s\"\n", orig_path);
+  }
+
+  off64_t file_offset;
+  android::base::unique_fd fd(open_executable(orig_path, &file_offset, &result.path));
+  if (fd.get() == -1) {
+    __linker_error("error: unable to open file \"%s\"\n", orig_path);
+  }
+
+  if (TEMP_FAILURE_RETRY(fstat(fd.get(), &result.file_stat)) == -1) {
+    __linker_error("error: unable to stat \"%s\": %s\n", result.path.c_str(), strerror(errno));
+  }
+
+  ElfReader elf_reader;
+  if (!elf_reader.Read(result.path.c_str(), fd.get(), file_offset, result.file_stat.st_size)) {
+    __linker_error("error: %s\n", linker_get_error_buffer());
+  }
+  if (!elf_reader.Load(nullptr)) {
+    __linker_error("error: %s\n", linker_get_error_buffer());
+  }
+
+  result.phdr = elf_reader.loaded_phdr();
+  result.phdr_count = elf_reader.phdr_count();
+  result.entry_point = elf_reader.entry_point();
+  return result;
+}
+
+static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) {
   ProtectedDataGuard guard;
 
 #if TIMING
@@ -274,31 +336,25 @@
     }
   }
 
-  struct stat file_stat;
-  // Stat "/proc/self/exe" instead of executable_path because
-  // the executable could be unlinked by this point and it should
-  // not cause a crash (see http://b/31084669)
-  if (!is_init()) {
-    if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
-      async_safe_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
-    }
-  } else {
-    // /proc fs is not mounted when init starts. Therefore we can't use
-    // /proc/self/exe for init.
-    stat("/init", &file_stat);
-  }
+  const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) :
+                                                get_executable_info(args);
+
+  // Assign to a static variable for the sake of the debug map, which needs
+  // a C-style string to last until the program exits.
+  static std::string exe_path = exe_info.path;
 
   // Initialize the main exe's soinfo.
-  const char* executable_path = get_executable_path();
-  soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
+  soinfo* si = soinfo_alloc(&g_default_namespace,
+                            exe_path.c_str(), &exe_info.file_stat,
+                            0, RTLD_GLOBAL);
   somain = si;
-  si->phdr = reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR));
-  si->phnum = args.getauxval(AT_PHNUM);
+  si->phdr = exe_info.phdr;
+  si->phnum = exe_info.phdr_count;
   get_elf_base_from_phdr(si->phdr, si->phnum, &si->base, &si->load_bias);
   si->size = phdr_table_get_load_size(si->phdr, si->phnum);
   si->dynamic = nullptr;
   si->set_main_executable();
-  init_link_map_head(*si, executable_path);
+  init_link_map_head(*si, exe_path.c_str());
 
   // Register the main executable and the linker upfront to have
   // gdb aware of them before loading the rest of the dependency
@@ -336,7 +392,7 @@
   parse_LD_LIBRARY_PATH(ldpath_env);
   parse_LD_PRELOAD(ldpreload_env);
 
-  std::vector<android_namespace_t*> namespaces = init_default_namespaces(executable_path);
+  std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_path.c_str());
 
   if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
 
@@ -437,7 +493,7 @@
   fflush(stdout);
 #endif
 
-  ElfW(Addr) entry = args.getauxval(AT_ENTRY);
+  ElfW(Addr) entry = exe_info.entry_point;
   TRACE("[ Ready to execute \"%s\" @ %p ]", si->get_realpath(), reinterpret_cast<void*>(entry));
   return entry;
 }
@@ -502,12 +558,22 @@
   __libc_init_sysinfo(args);
 #endif
 
+  // When the linker is run by itself (rather than as an interpreter for
+  // another program), AT_BASE is 0.
   ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
   if (linker_addr == 0) {
-    // When the linker is run by itself (rather than as an interpreter for
-    // another program), AT_BASE is 0. In that case, the AT_PHDR and AT_PHNUM
-    // aux values describe the linker, so use the phdr to find the linker's
-    // base address.
+    // Detect an attempt to run the linker on itself (e.g.
+    // `linker64 /system/bin/linker64`). If the kernel loaded this instance of
+    // the linker, then AT_ENTRY will refer to &_start. If it doesn't, then
+    // something else must have loaded this instance of the linker. It's
+    // simpler if we only allow one copy of the linker to be loaded at a time.
+    if (args.getauxval(AT_ENTRY) != reinterpret_cast<uintptr_t>(&_start)) {
+      // The first linker already relocated this one and set up TLS, so we don't
+      // need further libc initialization.
+      __linker_error("error: linker cannot load itself\n");
+    }
+    // Otherwise, the AT_PHDR and AT_PHNUM aux values describe this linker
+    // instance, so use the phdr to find the linker's base address.
     ElfW(Addr) load_bias;
     get_elf_base_from_phdr(
       reinterpret_cast<ElfW(Phdr)*>(args.getauxval(AT_PHDR)), args.getauxval(AT_PHNUM),
@@ -565,28 +631,38 @@
   // Initialize the linker's static libc's globals
   __libc_init_globals(args);
 
-  // store argc/argv/envp to use them for calling constructors
-  g_argc = args.argc;
-  g_argv = args.argv;
-  g_envp = args.envp;
-
   // Initialize the linker's own global variables
   tmp_linker_so.call_constructors();
 
-  // If the linker is not acting as PT_INTERP entry_point is equal to
-  // _start. Which means that the linker is running as an executable and
-  // already linked by PT_INTERP.
-  //
-  // This happens when user tries to run 'adb shell /system/bin/linker'
-  // see also https://code.google.com/p/android/issues/detail?id=63174
-  ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
-  if (reinterpret_cast<ElfW(Addr)>(&_start) == entry_point) {
-    async_safe_format_fd(STDOUT_FILENO,
-                     "This is %s, the helper program for dynamic executables.\n",
-                     args.argv[0]);
-    exit(0);
+  // When the linker is run directly rather than acting as PT_INTERP, parse
+  // arguments and determine the executable to load. When it's instead acting
+  // as PT_INTERP, AT_ENTRY will refer to the loaded executable rather than the
+  // linker's _start.
+  const char* exe_to_load = nullptr;
+  if (args.getauxval(AT_ENTRY) == reinterpret_cast<uintptr_t>(&_start)) {
+    if (args.argc <= 1 || !strcmp(args.argv[1], "--help")) {
+      async_safe_format_fd(STDOUT_FILENO,
+         "Usage: %s program [arguments...]\n"
+         "       %s path.zip!/program [arguments...]\n"
+         "\n"
+         "A helper program for linking dynamic executables. Typically, the kernel loads\n"
+         "this program because it's the PT_INTERP of a dynamic executable.\n"
+         "\n"
+         "This program can also be run directly to load and run a dynamic executable. The\n"
+         "executable can be inside a zip file if it's stored uncompressed and at a\n"
+         "page-aligned offset.\n",
+         args.argv[0], args.argv[0]);
+      exit(0);
+    }
+    exe_to_load = args.argv[1];
+    __libc_shared_globals->initial_linker_arg_count = 1;
   }
 
+  // store argc/argv/envp to use them for calling constructors
+  g_argc = args.argc - __libc_shared_globals->initial_linker_arg_count;
+  g_argv = args.argv + __libc_shared_globals->initial_linker_arg_count;
+  g_envp = args.envp;
+
   // Initialize static variables. Note that in order to
   // get correct libdl_info we need to call constructors
   // before get_libdl_info().
@@ -595,7 +671,7 @@
   init_link_map_head(*solinker, kLinkerPath);
 
   args.abort_message_ptr = &g_abort_message;
-  ElfW(Addr) start_address = linker_main(args);
+  ElfW(Addr) start_address = linker_main(args, exe_to_load);
 
   INFO("[ Jumping to _start (%p)... ]", reinterpret_cast<void*>(start_address));
 
diff --git a/linker/linker_main.h b/linker/linker_main.h
index b37b947..47d4bdb 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -50,7 +50,7 @@
 
 std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path);
 soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
-                     struct stat* file_stat, off64_t file_offset,
+                     const struct stat* file_stat, off64_t file_offset,
                      uint32_t rtld_flags);
 
 bool find_libraries(android_namespace_t* ns,
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 9b9ce94..0eee089 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -54,6 +54,7 @@
   const ElfW(Dyn)* dynamic() const { return dynamic_; }
   const char* get_string(ElfW(Word) index) const;
   bool is_mapped_by_caller() const { return mapped_by_caller_; }
+  ElfW(Addr) entry_point() const { return header_.e_entry + load_bias_; }
 
  private:
   bool ReadElfHeader();
diff --git a/linker/linker_utils.cpp b/linker/linker_utils.cpp
index 789d5c1..6b9aec9 100644
--- a/linker/linker_utils.cpp
+++ b/linker/linker_utils.cpp
@@ -98,8 +98,8 @@
           while (out_ptr > buf && *--out_ptr != '/') {
           }
           if (in_ptr[0] == 0) {
-            // retain '/'
-            out_ptr++;
+            // retain '/' (or write the initial '/' for "/..")
+            *out_ptr++ = '/';
           }
           continue;
         }
diff --git a/linker/tests/linker_utils_test.cpp b/linker/tests/linker_utils_test.cpp
index dce223a..e406af5 100644
--- a/linker/tests/linker_utils_test.cpp
+++ b/linker/tests/linker_utils_test.cpp
@@ -58,6 +58,9 @@
   ASSERT_TRUE(normalize_path("/a/../../b", &output));
   ASSERT_EQ("/b", output);
 
+  ASSERT_TRUE(normalize_path("/..", &output));
+  ASSERT_EQ("/", output);
+
   output = "unchanged";
   ASSERT_FALSE(normalize_path("root///dir/.///dir2/somedir/../zipfile!/dir/dir9//..///afile", &output));
   ASSERT_EQ("unchanged", output);
diff --git a/tests/Android.bp b/tests/Android.bp
index 5ba6b3d..4ad51da 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -466,6 +466,8 @@
     required: [
         "cfi_test_helper",
         "cfi_test_helper2",
+        "exec_linker_helper",
+        "exec_linker_helper_lib",
         "libtest_dt_runpath_a",
         "libtest_dt_runpath_b",
         "libtest_dt_runpath_c",
diff --git a/tests/SignalUtils.h b/tests/SignalUtils.h
index ece28ba..a2faf0a 100644
--- a/tests/SignalUtils.h
+++ b/tests/SignalUtils.h
@@ -55,3 +55,12 @@
  private:
   sigset64_t old_mask_;
 };
+
+// uint64_t equivalents of sigsetops.
+static inline void SignalSetAdd(uint64_t* sigset, int signo) {
+  *sigset |= 1ULL << (signo - 1);
+}
+
+static inline void SignalSetDel(uint64_t* sigset, int signo) {
+  *sigset &= ~(1ULL << (signo - 1));
+}
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index 44fab01..cb98cae 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -79,21 +79,61 @@
   ASSERT_EQ(3370318, lib_global_protected_get_serial());
 }
 
-TEST(dl, exec_linker) {
 #if defined(__BIONIC__)
 #if defined(__LP64__)
   static constexpr const char* kPathToLinker = "/system/bin/linker64";
 #else
   static constexpr const char* kPathToLinker = "/system/bin/linker";
 #endif
+#endif
+
+TEST(dl, exec_linker) {
+#if defined(__BIONIC__)
+  std::string usage_prefix = std::string("Usage: ") + kPathToLinker;
   ExecTestHelper eth;
-  std::string expected_output = std::string("This is ") + kPathToLinker +
-                                ", the helper program for dynamic executables.\n";
-  eth.SetArgs( { kPathToLinker, nullptr });
+  eth.SetArgs({ kPathToLinker, nullptr });
+  eth.Run([&]() { execve(kPathToLinker, eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
+  ASSERT_EQ(0u, eth.GetOutput().find(usage_prefix)) << "Test output:\n" << eth.GetOutput();
+#endif
+}
+
+TEST(dl, exec_linker_load_file) {
+#if defined(__BIONIC__)
+  std::string helper = GetTestlibRoot() +
+      "/exec_linker_helper/exec_linker_helper";
+  std::string expected_output =
+      "ctor: argc=1 argv[0]=" + helper + "\n" +
+      "main: argc=1 argv[0]=" + helper + "\n" +
+      "helper_func called\n";
+  ExecTestHelper eth;
+  eth.SetArgs({ kPathToLinker, helper.c_str(), nullptr });
   eth.Run([&]() { execve(kPathToLinker, eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str());
 #endif
 }
 
+TEST(dl, exec_linker_load_from_zip) {
+#if defined(__BIONIC__)
+  std::string helper = GetTestlibRoot() +
+      "/libdlext_test_zip/libdlext_test_zip_zipaligned.zip!/libdir/exec_linker_helper";
+  std::string expected_output =
+      "ctor: argc=1 argv[0]=" + helper + "\n" +
+      "main: argc=1 argv[0]=" + helper + "\n" +
+      "helper_func called\n";
+  ExecTestHelper eth;
+  eth.SetArgs({ kPathToLinker, helper.c_str(), nullptr });
+  eth.Run([&]() { execve(kPathToLinker, eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str());
+#endif
+}
+
+TEST(dl, exec_linker_load_self) {
+#if defined(__BIONIC__)
+  std::string error_message = "error: linker cannot load itself\n";
+  ExecTestHelper eth;
+  eth.SetArgs({ kPathToLinker, kPathToLinker, nullptr });
+  eth.Run([&]() { execve(kPathToLinker, eth.GetArgs(), eth.GetEnv()); }, EXIT_FAILURE, error_message.c_str());
+#endif
+}
+
 TEST(dl, preinit_system_calls) {
 #if defined(__BIONIC__)
   std::string helper = GetTestlibRoot() +
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 24a8648..1c36dcf 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -33,6 +33,10 @@
 #include <android-base/strings.h>
 #include <private/android_filesystem_config.h>
 
+#if defined(__BIONIC__)
+#include <android-base/properties.h>
+#endif
+
 // Generated android_ids array
 #include "generated_android_ids.h"
 
@@ -217,6 +221,7 @@
   check_get_passwd("u1_i0", 199000, TYPE_APP);
 }
 
+#if defined(__BIONIC__)
 template <typename T>
 static void expect_ids(const T& ids) {
   std::set<typename T::key_type> expected_ids;
@@ -243,6 +248,12 @@
   expect_range(AID_SHARED_GID_START, AID_SHARED_GID_END);
   expect_range(AID_ISOLATED_START, AID_ISOLATED_END);
 
+  // Upgrading devices launched before API level 28 may not comply with the below check.
+  // Due to the difficulty in changing uids after launch, it is waived for these devices.
+  if (android::base::GetIntProperty("ro.product.first_api_level", 0) < 28) {
+    return;
+  }
+
   // Ensure that no other ids were returned.
   auto return_differences = [&ids, &expected_ids] {
     std::vector<typename T::key_type> missing_from_ids;
@@ -263,6 +274,7 @@
   };
   EXPECT_EQ(expected_ids, ids) << return_differences();
 }
+#endif
 
 TEST(pwd, getpwent_iterate) {
 #if defined(__BIONIC__)
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 2d35c51..5c4eb42 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -852,3 +852,19 @@
     defaults: ["bionic_testlib_defaults"],
     srcs: ["ld_config_test_helper_lib3.cpp"],
 }
+
+cc_test {
+    name: "exec_linker_helper",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["exec_linker_helper.cpp"],
+    shared_libs: ["exec_linker_helper_lib"],
+    ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
+cc_test_library {
+    name: "exec_linker_helper_lib",
+    host_supported: false,
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["exec_linker_helper_lib.cpp"],
+}
diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk
index 62ed4c7..19fd64b 100644
--- a/tests/libs/Android.build.dlext_testzip.mk
+++ b/tests/libs/Android.build.dlext_testzip.mk
@@ -32,7 +32,9 @@
 
 my_shared_libs := \
   $(call intermediates-dir-for,SHARED_LIBRARIES,libdlext_test_zip,,,$(bionic_2nd_arch_prefix))/libdlext_test_zip.so \
-  $(call intermediates-dir-for,SHARED_LIBRARIES,libatest_simple_zip,,,$(bionic_2nd_arch_prefix))/libatest_simple_zip.so
+  $(call intermediates-dir-for,SHARED_LIBRARIES,libatest_simple_zip,,,$(bionic_2nd_arch_prefix))/libatest_simple_zip.so \
+  $(call intermediates-dir-for,NATIVE_TESTS,exec_linker_helper,,,$(bionic_2nd_arch_prefix))/exec_linker_helper \
+  $(call intermediates-dir-for,SHARED_LIBRARIES,exec_linker_helper_lib,,,$(bionic_2nd_arch_prefix))/exec_linker_helper_lib.so
 
 $(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBS := $(my_shared_libs)
 $(LOCAL_BUILT_MODULE): $(my_shared_libs) $(BIONIC_TESTS_ZIPALIGN)
diff --git a/tests/libs/exec_linker_helper.cpp b/tests/libs/exec_linker_helper.cpp
new file mode 100644
index 0000000..01a61e0
--- /dev/null
+++ b/tests/libs/exec_linker_helper.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+extern "C" void _start();
+const char* helper_func();
+
+__attribute__((constructor))
+static void ctor(int argc, char* argv[]) {
+  printf("ctor: argc=%d argv[0]=%s\n", argc, argv[0]);
+}
+
+int main(int argc, char* argv[]) {
+  printf("main: argc=%d argv[0]=%s\n", argc, argv[0]);
+  printf("%s\n", helper_func());
+  return 0;
+}
diff --git a/tests/libs/exec_linker_helper_lib.cpp b/tests/libs/exec_linker_helper_lib.cpp
new file mode 100644
index 0000000..b46f482
--- /dev/null
+++ b/tests/libs/exec_linker_helper_lib.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Verify that the linker can find exec_linker_helper_lib.so using the
+// executable's $ORIGIN runpath, even when the executable is inside a zip file.
+
+const char* helper_func() {
+  return "helper_func called";
+}
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 05339a6..dde0be1 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -74,6 +74,8 @@
     sigset64_t ss;
     sigemptyset64(&ss);
     sigaddset64(&ss, SIGUSR1 + offset);
+    // TIMER_SIGNAL.
+    sigaddset64(&ss, __SIGRTMIN);
     sigaddset64(&ss, SIGRTMIN + offset);
     return ss;
   }
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 52a097b..dd27aef 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -22,6 +22,7 @@
 
 #include <thread>
 
+#include <android-base/macros.h>
 #include <gtest/gtest.h>
 
 #include "SignalUtils.h"
@@ -339,6 +340,17 @@
 
 static void ClearSignalMask() {
   uint64_t sigset = 0;
+  SignalSetAdd(&sigset, __SIGRTMIN);
+  if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
+    abort();
+  }
+}
+
+static void FillSignalMask() {
+  uint64_t sigset = ~0ULL;
+  for (int signo = __SIGRTMIN + 1; signo < SIGRTMIN; ++signo) {
+    SignalSetDel(&sigset, signo);
+  }
   if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
     abort();
   }
@@ -352,40 +364,27 @@
   return sigset;
 }
 
-enum class SignalMaskFunctionType {
-  RtAware,
-  RtNonaware,
-};
-
-#if defined(__LP64__) || !defined(__BIONIC__)
-constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtAware;
-#else
-constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtNonaware;
-#endif
-
-static void TestSignalMaskFiltered(uint64_t sigset, SignalMaskFunctionType type) {
-  for (int signo = 1; signo <= 64; ++signo) {
+static void TestSignalMaskFiltered(uint64_t sigset) {
+#if defined(__BIONIC__)
+  for (int signo = __SIGRTMIN; signo < SIGRTMIN; ++signo) {
     bool signal_blocked = sigset & (1ULL << (signo - 1));
-    if (signo == SIGKILL || signo == SIGSTOP) {
-      // SIGKILL and SIGSTOP shouldn't be blocked.
-      EXPECT_EQ(false, signal_blocked) << "signal " << signo;
-    } else if (signo < __SIGRTMIN) {
-      // Everything else should be blocked.
+    if (signo == __SIGRTMIN) {
+      // TIMER_SIGNAL must be blocked.
       EXPECT_EQ(true, signal_blocked) << "signal " << signo;
-    } else if (signo >= __SIGRTMIN && signo < SIGRTMIN) {
-      // Reserved signals must not be blocked.
+    } else {
+      // The other reserved signals must not be blocked.
       EXPECT_EQ(false, signal_blocked) << "signal " << signo;
-    } else if (type == SignalMaskFunctionType::RtAware) {
-      // Realtime signals should be blocked, unless we blocked using a non-rt aware function.
-      EXPECT_EQ(true, signal_blocked) << "signal " << signo;
     }
   }
+#else
+  UNUSED(sigset);
+#endif
 }
 
-static void TestSignalMaskFunction(std::function<void()> fn, SignalMaskFunctionType fn_type) {
+static void TestSignalMaskFunction(std::function<void()> fn) {
   ClearSignalMask();
   fn();
-  TestSignalMaskFiltered(GetSignalMask(), fn_type);
+  TestSignalMaskFiltered(GetSignalMask());
 }
 
 TEST(signal, sigaction_filter) {
@@ -397,7 +396,7 @@
   sigaction(SIGUSR1, &sa, nullptr);
   raise(SIGUSR1);
   ASSERT_NE(0ULL, sigset);
-  TestSignalMaskFiltered(sigset, sigset_type);
+  TestSignalMaskFiltered(sigset);
 }
 
 TEST(signal, sigaction64_filter) {
@@ -409,111 +408,135 @@
   sigaction64(SIGUSR1, &sa, nullptr);
   raise(SIGUSR1);
   ASSERT_NE(0ULL, sigset);
-  TestSignalMaskFiltered(sigset, SignalMaskFunctionType::RtAware);
+  TestSignalMaskFiltered(sigset);
 }
 
 TEST(signal, sigprocmask_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask64_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask64_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask64_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask64_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, sigprocmask_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, sigprocmask64_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, pthread_sigmask_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, pthread_sigmask64_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
 }
 
 // glibc filters out signals via sigfillset, not the actual underlying functions.
 TEST(signal, sigset_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        for (int i = 1; i <= 64; ++i) {
-          sigset(i, SIG_HOLD);
-        }
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    for (int i = 1; i <= 64; ++i) {
+      sigset(i, SIG_HOLD);
+    }
+  });
 #endif
 }
 
 TEST(signal, sighold_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        for (int i = 1; i <= 64; ++i) {
-          sighold(i);
-        }
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    for (int i = 1; i <= 64; ++i) {
+      sighold(i);
+    }
+  });
 #endif
 }
 
@@ -525,23 +548,17 @@
 
 TEST(signal, sigblock_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        int mask = ~0U;
-        ASSERT_EQ(0, sigblock(mask));
-      },
-      SignalMaskFunctionType::RtNonaware);
+  TestSignalMaskFunction([]() {
+    sigblock(~0U);
+  });
 #endif
 }
 
 TEST(signal, sigsetmask_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        int mask = ~0U;
-        ASSERT_EQ(0, sigsetmask(mask));
-      },
-      SignalMaskFunctionType::RtNonaware);
+  TestSignalMaskFunction([]() {
+    sigsetmask(~0U);
+  });
 #endif
 }
 
diff --git a/tests/spawn_test.cpp b/tests/spawn_test.cpp
index a5e7e56..04b66d3 100644
--- a/tests/spawn_test.cpp
+++ b/tests/spawn_test.cpp
@@ -396,7 +396,13 @@
   // Check that's what happens...
   ProcStatus ps = {};
   GetChildStatus(&sa, &ps);
-  EXPECT_EQ(static_cast<uint64_t>(1 << (SIGALRM - 1)), ps.sigblk);
+
+  // TIMER_SIGNAL should also be blocked.
+  uint64_t expected_blocked = 0;
+  SignalSetAdd(&expected_blocked, SIGALRM);
+  SignalSetAdd(&expected_blocked, __SIGRTMIN + 0);
+  EXPECT_EQ(expected_blocked, ps.sigblk);
+
   EXPECT_EQ(static_cast<uint64_t>(0), ps.sigign);
 
   ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
@@ -421,8 +427,15 @@
   // Check that's what happens...
   ProcStatus ps = {};
   GetChildStatus(&sa, &ps);
-  EXPECT_EQ(static_cast<uint64_t>(0), ps.sigblk);
-  EXPECT_EQ(static_cast<uint64_t>(1 << (SIGCONT - 1)), ps.sigign);
+
+  // TIMER_SIGNAL should be blocked.
+  uint64_t expected_blocked = 0;
+  SignalSetAdd(&expected_blocked, __SIGRTMIN + 0);
+  EXPECT_EQ(expected_blocked, ps.sigblk);
+
+  uint64_t expected_ignored = 0;
+  SignalSetAdd(&expected_ignored, SIGCONT);
+  EXPECT_EQ(expected_ignored, ps.sigign);
 
   ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
 }
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 1f7f555..da083de 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -886,6 +886,8 @@
   VerifySysconf(_SC_XOPEN_VERSION, "_SC_XOPEN_VERSION", [](long v){return v == _XOPEN_VERSION && errno == 0;});
   VERIFY_SYSCONF_POSITIVE(_SC_ATEXIT_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
+  VERIFY_SYSCONF_POSITIVE(_SC_UIO_MAXIOV);
+  EXPECT_EQ(sysconf(_SC_IOV_MAX), sysconf(_SC_UIO_MAXIOV));
   VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
   VerifySysconf(_SC_PAGE_SIZE, "_SC_PAGE_SIZE",
diff --git a/tests/utils.h b/tests/utils.h
index f07bd58..c8656dc 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -184,6 +184,9 @@
   char** GetEnv() {
     return const_cast<char**>(env_.data());
   }
+  const std::string& GetOutput() {
+    return output_;
+  }
 
   void SetArgs(const std::vector<const char*>& args) {
     args_ = args;
@@ -212,24 +215,25 @@
 
     // Parent.
     close(fds[1]);
-    std::string output;
+    output_.clear();
     char buf[BUFSIZ];
     ssize_t bytes_read;
     while ((bytes_read = TEMP_FAILURE_RETRY(read(fds[0], buf, sizeof(buf)))) > 0) {
-      output.append(buf, bytes_read);
+      output_.append(buf, bytes_read);
     }
     close(fds[0]);
 
-    std::string error_msg("Test output:\n" + output);
+    std::string error_msg("Test output:\n" + output_);
     AssertChildExited(pid, expected_exit_status, &error_msg);
     if (expected_output != nullptr) {
-      ASSERT_EQ(expected_output, output);
+      ASSERT_EQ(expected_output, output_);
     }
   }
 
  private:
   std::vector<const char*> args_;
   std::vector<const char*> env_;
+  std::string output_;
 };
 #endif