Merge "versioner: compile with `clang -include foo.h -`."
diff --git a/README.md b/README.md
index 61314b6..cb9c454 100644
--- a/README.md
+++ b/README.md
@@ -171,6 +171,10 @@
      contents for external/kernel-headers/.
   2. Run update_all.py to scrub those headers and import them into bionic.
 
+Note that if you're actually just trying to expose device-specific headers to
+build your device drivers, you shouldn't modify bionic. Instead use
+`TARGET_DEVICE_KERNEL_HEADERS` and friends described in [config.mk](https://android.googlesource.com/platform/build/+/master/core/config.mk#186).
+
 
 Updating tzdata
 ---------------
@@ -327,19 +331,54 @@
 32-bit ABI bugs
 ---------------
 
-This probably belongs in the NDK documentation rather than here, but these
-are the known ABI bugs in the 32-bit ABI:
+### `off_t` is 32-bit.
 
- * `time_t` is 32-bit. <http://b/5819737>. In the 64-bit ABI, time_t is
-   64-bit.
+On 32-bit Android, `off_t` is a signed 32-bit integer. This limits functions
+that use `off_t` to working on files no larger than 2GiB.
 
- * `off_t` is 32-bit. There is `off64_t`, and in newer releases there is
-   almost-complete support for `_FILE_OFFSET_BITS`. Unfortunately our stdio
-   implementation uses 32-bit offsets and -- worse -- function pointers to
-   functions that use 32-bit offsets, so there's no good way to implement
-   the last few pieces <http://b/24807045>. In the 64-bit ABI, off_t is
-   off64_t.
+Android does not require the `_LARGEFILE_SOURCE` macro to be used to make
+`fseeko` and `ftello` available. Instead they're always available from API
+level 24 where they were introduced, and never available before then.
 
- * `sigset_t` is too small on ARM and x86 (but correct on MIPS), so support
-   for real-time signals is broken. <http://b/5828899> In the 64-bit ABI,
-   `sigset_t` is the correct size for every architecture.
+Android also does not require the `_LARGEFILE64_SOURCE` macro to be used
+to make `off64_t` and corresponding functions such as `ftruncate64` available.
+Instead, whatever subset of those functions was available at your target API
+level will be visible.
+
+There are a couple of exceptions to note. Firstly, `off64_t` and the single
+function `lseek64` were available right from the beginning in API 3. Secondly,
+Android has always silently inserted `O_LARGEFILE` into any open call, so if
+all you need are functions like `read` that don't take/return `off_t`, large
+files have always worked.
+
+Android support for `_FILE_OFFSET_BITS=64` (which turns `off_t` into `off64_t`
+and replaces each `off_t` function with its `off64_t` counterpart, such as
+`lseek` in the source becoming `lseek64` at runtime) was added late. Even when
+it became available for the platform, it wasn't available from the NDK until
+r15. Before NDK r15, `_FILE_OFFSET_BITS=64` silently did nothing: all code
+compiled with that was actually using a 32-bit `off_t`. With a new enough NDK,
+the situation becomes complicated. If you're targeting an API before 21, almost
+all functions that take an `off_t` become unavailable. You've asked for their
+64-bit equivalents, and none of them (except `lseek`/`lseek64`) exist. As you
+increase your target API level, you'll have more and more of the functions
+available. API 12 adds some of the `<unistd.h>` functions, API 21 adds `mmap`,
+and by API 24 you have everything including `<stdio.h>`. See the
+[linker map](libc/libc.map.txt) for full details.
+
+In the 64-bit ABI, `off_t` is always 64-bit.
+
+### `sigset_t` is too small for real-time signals.
+
+On 32-bit Android, `sigset_t` is too small for ARM and x86 (but correct for
+MIPS). This means that there is no support for real-time signals in 32-bit
+code.
+
+In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
+
+### `time_t` is 32-bit.
+
+On 32-bit Android, `time_t` is 32-bit. The header `<time64.h>` and type
+`time64_t` exist as a workaround, but the kernel interfaces exposed on 32-bit
+Android all use the 32-bit `time_t`.
+
+In the 64-bit ABI, `time_t` is 64-bit.
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 3f95aa1..0edba65 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -35,6 +35,17 @@
         "time_benchmark.cpp",
         "unistd_benchmark.cpp",
     ],
+    static_libs: ["libBionicBenchmarksUtils"],
+}
+
+cc_defaults {
+    name: "bionic-benchmarks-extras-defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wunused",
+    ],
 }
 
 // Build benchmarks for the device (with bionic's .so). Run with:
@@ -63,3 +74,19 @@
         },
     },
 }
+
+cc_library_static {
+    name: "libBionicBenchmarksUtils",
+    defaults: ["bionic-benchmarks-extras-defaults"],
+    srcs: ["util.cpp"],
+    host_supported: true,
+}
+
+cc_test {
+    name: "bionic-benchmarks-tests",
+    defaults: ["bionic-benchmarks-extras-defaults"],
+    srcs: [
+        "tests/benchmark_test.cpp",
+    ],
+    static_libs: ["libBionicBenchmarksUtils"],
+}
diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
index 86a7c35..2ab65a8 100644
--- a/benchmarks/string_benchmark.cpp
+++ b/benchmarks/string_benchmark.cpp
@@ -18,188 +18,246 @@
 #include <string.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 constexpr auto KB = 1024;
 
-#define AT_COMMON_SIZES \
-    Arg(8)->Arg(64)->Arg(512)->Arg(1*KB)->Arg(8*KB)->Arg(16*KB)->Arg(32*KB)->Arg(64*KB)
+// NOTE: these constants are temporary replacements for AT_COMMON_SIZES until
+// the new interface for Bionic benchmarks is implemented.
 
-// TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
+// Set all four to 0 to test normal alignment.
+#define AT_SRC_ALIGN 0
+#define AT_DST_ALIGN 0
+
+#define AT_ALIGNED_TWOBUF \
+    Args({(8), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(512), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(1*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(8*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(16*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(32*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64*KB), AT_SRC_ALIGN, AT_DST_ALIGN})
+
+#define AT_ALIGNED_ONEBUF \
+    Args({(8), AT_SRC_ALIGN})->Args({(64), AT_SRC_ALIGN})->Args({(512), AT_SRC_ALIGN})-> \
+    Args({(1*KB), AT_SRC_ALIGN})->Args({(8*KB), AT_SRC_ALIGN})->Args({(16*KB), AT_SRC_ALIGN})-> \
+    Args({(32*KB), AT_SRC_ALIGN})->Args({(64*KB), AT_SRC_ALIGN})
 
 static void BM_string_memcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* src = new char[nbytes]; char* dst = new char[nbytes];
-  memset(src, 'x', nbytes);
-  memset(dst, 'x', nbytes);
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'x');
 
   volatile int c __attribute__((unused)) = 0;
   while (state.KeepRunning()) {
-    c += memcmp(dst, src, nbytes);
+    c += memcmp(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] src;
-  delete[] dst;
 }
-BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcmp)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* src = new char[nbytes]; char* dst = new char[nbytes];
-  memset(src, 'x', nbytes);
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
 
   while (state.KeepRunning()) {
-    memcpy(dst, src, nbytes);
+    memcpy(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] src;
-  delete[] dst;
 }
-BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcpy)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memmove_non_overlapping(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes, 'x');
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
 
   while (state.KeepRunning()) {
-    memmove(dst.data(), src.data(), nbytes);
+    memmove(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_non_overlapping)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_non_overlapping)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> buf(nbytes + 1, 'x');
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf(3 * alignment + nbytes + 1, 'x');
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
 
   while (state.KeepRunning()) {
-    memmove(buf.data(), buf.data() + 1, nbytes); // Worst-case overlap.
+    memmove(buf_aligned, buf_aligned + 1, nbytes);  // Worst-case overlap.
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> buf(nbytes + 1, 'x');
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
 
   while (state.KeepRunning()) {
-    memmove(buf.data() + 1, buf.data(), nbytes); // Worst-case overlap.
+    memmove(buf_aligned + 1, buf_aligned, nbytes);  // Worst-case overlap.
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_memset(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* dst = new char[nbytes];
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtr(&buf, alignment, nbytes + 1);
 
   while (state.KeepRunning()) {
-    memset(dst, 0, nbytes);
+    memset(buf_aligned, 0, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] dst;
 }
-BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memset)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_strlen(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* s = new char[nbytes];
-  memset(s, 'x', nbytes);
-  s[nbytes - 1] = 0;
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
+  buf_aligned[nbytes - 1] = '\0';
 
   volatile int c __attribute__((unused)) = 0;
   while (state.KeepRunning()) {
-    c += strlen(s);
+    c += strlen(buf_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] s;
 }
-BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strlen)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_strcat_copy_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes + 2);
-  src[nbytes - 1] = '\0';
-  dst[0] = 'y';
-  dst[1] = 'y';
-  dst[2] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes + 2);
+  src_aligned[nbytes - 1] = '\0';
+  dst_aligned[0] = 'y';
+  dst_aligned[1] = 'y';
+  dst_aligned[2] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[2] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[2] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_copy_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_copy_only)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcat_seek_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(3, 'x');
-  std::vector<char> dst(nbytes + 2, 'y');
-  src[2] = '\0';
-  dst[nbytes - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, 3, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes + 2, 'y');
+  src_aligned[2] = '\0';
+  dst_aligned[nbytes - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[nbytes - 1] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[nbytes - 1] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_seek_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_seek_only)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes / 2, 'x');
-  std::vector<char> dst(nbytes / 2, 'y');
-  src[nbytes / 2 - 1] = '\0';
-  dst[nbytes / 2 - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes / 2, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
+  src_aligned[nbytes / 2 - 1] = '\0';
+  dst_aligned[nbytes / 2 - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[nbytes / 2 - 1] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[nbytes / 2 - 1] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes);
-  src[nbytes - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
+  src_aligned[nbytes - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcpy(dst.data(), src.data());
+    strcpy(dst_aligned, src_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcpy)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> s1(nbytes, 'x');
-  std::vector<char> s2(nbytes, 'x');
-  s1[nbytes - 1] = '\0';
-  s2[nbytes - 1] = '\0';
+  const size_t s1_alignment = state.range(1);
+  const size_t s2_alignment = state.range(2);
+
+  std::vector<char> s1;
+  std::vector<char> s2;
+  char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
+  char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
+  s1_aligned[nbytes - 1] = '\0';
+  s2_aligned[nbytes - 1] = '\0';
 
   volatile int c __attribute__((unused));
   while (state.KeepRunning()) {
-    c = strcmp(s1.data(), s2.data());
+    c = strcmp(s1_aligned, s2_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcmp)->AT_ALIGNED_TWOBUF;
diff --git a/benchmarks/tests/benchmark_test.cpp b/benchmarks/tests/benchmark_test.cpp
new file mode 100644
index 0000000..df7b686
--- /dev/null
+++ b/benchmarks/tests/benchmark_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <util.h>
+
+TEST(benchmark, memory_align) {
+  std::vector<char> buf(100);
+  for (size_t alignment = 1; alignment <= 32; alignment *= 2) {
+    for (size_t or_mask = 0; or_mask < alignment; ++or_mask) {
+      uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedMemory(buf.data(), alignment,
+                                                                           or_mask));
+      ASSERT_EQ(aligned_ptr % alignment, or_mask);
+      ASSERT_EQ(aligned_ptr & alignment, alignment);
+    }
+  }
+}
+
+TEST(benchmark, ptr_align) {
+  std::vector<char> buf;
+  for (size_t alignment = 1; alignment <= 2048; alignment *= 2) {
+    uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedPtr(&buf, alignment, 100));
+    ASSERT_EQ(aligned_ptr & alignment, alignment);
+    ASSERT_EQ(aligned_ptr & (alignment - 1), 0u);
+  }
+}
diff --git a/benchmarks/util.cpp b/benchmarks/util.cpp
new file mode 100644
index 0000000..d9641cf
--- /dev/null
+++ b/benchmarks/util.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <cstdlib>
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask) {
+  if ((alignment & (alignment - 1)) != 0) {
+    fprintf(stderr, "warning: alignment passed into GetAlignedMemory is not a power of two.\n");
+    std::abort();
+  }
+  if (or_mask > alignment) {
+    fprintf(stderr, "warning: or_mask passed into GetAlignedMemory is too high.\n");
+    std::abort();
+  }
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(orig_ptr);
+  if (alignment > 0) {
+    // When setting the alignment, set it to exactly the alignment chosen.
+    // The pointer returned will be guaranteed not to be aligned to anything
+    // more than that.
+    ptr += alignment - (ptr & (alignment - 1));
+    ptr |= alignment | or_mask;
+  }
+
+  return reinterpret_cast<char*>(ptr);
+}
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes) {
+  buf->resize(nbytes + 3 * alignment);
+  return GetAlignedMemory(buf->data(), alignment, 0);
+}
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte) {
+  char* buf_aligned = GetAlignedPtr(buf, alignment, nbytes);
+  memset(buf_aligned, fill_byte, nbytes);
+  return buf_aligned;
+}
+
+#if defined(__APPLE__)
+
+// Darwin doesn't support this, so do nothing.
+bool LockToCPU(int) {
+  return false;
+}
+
+#else
+
+bool LockToCPU(int cpu_to_lock) {
+  cpu_set_t cpuset;
+
+  CPU_ZERO(&cpuset);
+  if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+    perror("sched_getaffinity failed");
+    return false;
+  }
+
+  if (cpu_to_lock < 0) {
+    // Lock to the last active core we find.
+    for (int i = 0; i < CPU_SETSIZE; i++) {
+      if (CPU_ISSET(i, &cpuset)) {
+        cpu_to_lock = i;
+      }
+    }
+  } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
+    printf("Cpu %d does not exist.\n", cpu_to_lock);
+    return false;
+  }
+
+  if (cpu_to_lock < 0) {
+    printf("Cannot find any valid cpu to lock.\n");
+    return false;
+  }
+
+  CPU_ZERO(&cpuset);
+  CPU_SET(cpu_to_lock, &cpuset);
+  if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+    perror("sched_setaffinity failed");
+    return false;
+  }
+
+  return true;
+}
+
+#endif
diff --git a/benchmarks/util.h b/benchmarks/util.h
new file mode 100644
index 0000000..bd3d515
--- /dev/null
+++ b/benchmarks/util.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_BENCHMARKS_UTIL_H_
+#define _BIONIC_BENCHMARKS_UTIL_H_
+
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask);
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes);
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
+
+bool LockToCPU(int cpu_to_lock);
+
+#endif // _BIONIC_BENCHMARKS_UTIL_H
diff --git a/libc/Android.bp b/libc/Android.bp
index 4f6ff1a..701a1b0 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -13,6 +13,7 @@
     "bionic/sigblock.c",
     "bionic/siginterrupt.c",
     "bionic/sigsetmask.c",
+    "stdio/fmemopen.cpp",
     "stdio/fread.c",
     "stdio/parsefloat.c",
     "stdio/refill.c",
@@ -41,6 +42,7 @@
     "-Wextra",
     "-Wunused",
     "-Wno-deprecated-declarations",
+    "-Wno-gcc-compat",
     "-Wframe-larger-than=2048",
 
     // Try to catch typical 32-bit assumptions that break with 64-bit pointers.
@@ -237,9 +239,11 @@
         "upstream-freebsd/lib/libc/string/wcspbrk.c",
         "upstream-freebsd/lib/libc/string/wcsrchr.c",
         "upstream-freebsd/lib/libc/string/wcsspn.c",
+        "upstream-freebsd/lib/libc/string/wcsstr.c",
         "upstream-freebsd/lib/libc/string/wcstok.c",
         "upstream-freebsd/lib/libc/string/wmemchr.c",
         "upstream-freebsd/lib/libc/string/wmemcmp.c",
+        "upstream-freebsd/lib/libc/string/wmemcpy.c",
         "upstream-freebsd/lib/libc/string/wmemmove.c",
         "upstream-freebsd/lib/libc/string/wmemset.c",
     ],
@@ -385,7 +389,6 @@
     name: "libc_openbsd_ndk",
     defaults: ["libc_defaults"],
     srcs: [
-        "upstream-openbsd/lib/libc/compat-43/killpg.c",
         "upstream-openbsd/lib/libc/gen/alarm.c",
         "upstream-openbsd/lib/libc/gen/ctype_.c",
         "upstream-openbsd/lib/libc/gen/daemon.c",
@@ -438,7 +441,6 @@
         "upstream-openbsd/lib/libc/stdio/fgetwc.c",
         "upstream-openbsd/lib/libc/stdio/fgetws.c",
         "upstream-openbsd/lib/libc/stdio/flags.c",
-        "upstream-openbsd/lib/libc/stdio/fmemopen.c",
         "upstream-openbsd/lib/libc/stdio/fpurge.c",
         "upstream-openbsd/lib/libc/stdio/fputs.c",
         "upstream-openbsd/lib/libc/stdio/fputwc.c",
@@ -501,9 +503,7 @@
         "upstream-openbsd/lib/libc/string/strspn.c",
         "upstream-openbsd/lib/libc/string/strstr.c",
         "upstream-openbsd/lib/libc/string/strtok.c",
-        "upstream-openbsd/lib/libc/string/wmemcpy.c",
         "upstream-openbsd/lib/libc/string/wcslcpy.c",
-        "upstream-openbsd/lib/libc/string/wcsstr.c",
         "upstream-openbsd/lib/libc/string/wcswidth.c",
     ],
 
@@ -776,6 +776,106 @@
 }
 
 // ========================================================
+// libc_fortify.a - container for our FORITFY
+// implementation details
+// ========================================================
+cc_library_static {
+    defaults: ["libc_defaults"],
+    srcs: ["bionic/fortify.cpp"],
+
+    name: "libc_fortify",
+
+    // Disable FORTIFY for the compilation of these, so we don't end up having
+    // FORTIFY silently call itself.
+    cflags: ["-U_FORTIFY_SOURCE"],
+
+    arch: {
+        arm: {
+            cflags: ["-DNO___MEMCPY_CHK"],
+            srcs: [
+                "arch-arm/generic/bionic/__memcpy_chk.S",
+            ],
+            cortex_a7: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a7/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a53: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a53/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a53_a57: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a8: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a9: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a9/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a15: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
+                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
+                ],
+            },
+            cortex_a73: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/denver/bionic/__strcat_chk.S",
+                    "arch-arm/denver/bionic/__strcpy_chk.S",
+                ],
+            },
+            denver: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/denver/bionic/__strcat_chk.S",
+                    "arch-arm/denver/bionic/__strcpy_chk.S",
+                ],
+            },
+            krait: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/krait/bionic/__strcat_chk.S",
+                    "arch-arm/krait/bionic/__strcpy_chk.S",
+                ],
+            },
+            kryo: {
+                cflags: ["-DNO___STRCAT_CHK", "-DNO___STRCPY_CHK"],
+                srcs: [
+                    "arch-arm/krait/bionic/__strcat_chk.S",
+                    "arch-arm/krait/bionic/__strcpy_chk.S",
+                ],
+            },
+        },
+        arm64: {
+            cflags: ["-DNO___MEMCPY_CHK"],
+            srcs: [
+                "arch-arm64/generic/bionic/__memcpy_chk.S",
+            ],
+        },
+    },
+}
+
+// ========================================================
 // libc_bionic.a - home-grown C library code
 // ========================================================
 
@@ -804,9 +904,6 @@
         // debuggerd will look for the abort message in libc.so's copy.
         "bionic/android_set_abort_message.cpp",
 
-        "bionic/__memcpy_chk.cpp",
-        "bionic/__strcat_chk.cpp",
-        "bionic/__strcpy_chk.cpp",
         "bionic/strchr.cpp",
         "bionic/strnlen.c",
         "bionic/strrchr.cpp",
@@ -832,15 +929,10 @@
                 "arch-arm/bionic/syscall.S",
                 "arch-arm/bionic/vfork.S",
             ],
-            exclude_srcs: [
-                "bionic/__memcpy_chk.cpp",
-            ],
             cortex_a7: {
                 srcs: [
                     "arch-arm/cortex-a7/bionic/memset.S",
                     "arch-arm/cortex-a7/bionic/memcpy.S",
-                    "arch-arm/cortex-a7/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a7/bionic/__strcpy_chk.S",
 
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
                     "arch-arm/cortex-a15/bionic/strcat.S",
@@ -856,15 +948,11 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a53: {
                 srcs: [
                     "arch-arm/cortex-a53/bionic/memcpy.S",
-                    "arch-arm/cortex-a53/bionic/__strcat_chk.S",
-                    "arch-arm/cortex-a53/bionic/__strcpy_chk.S",
 
                     "arch-arm/cortex-a7/bionic/memset.S",
 
@@ -882,8 +970,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a53_a57: {
@@ -892,10 +978,8 @@
                     "arch-arm/cortex-a15/bionic/memset.S",
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
                     "arch-arm/cortex-a15/bionic/strcat.S",
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
                     "arch-arm/cortex-a15/bionic/strcmp.S",
                     "arch-arm/cortex-a15/bionic/strcpy.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
                     "arch-arm/cortex-a15/bionic/strlen.S",
 
                     "arch-arm/denver/bionic/memmove.S",
@@ -906,8 +990,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a8: {
@@ -916,10 +998,8 @@
                     "arch-arm/cortex-a15/bionic/memset.S",
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
                     "arch-arm/cortex-a15/bionic/strcat.S",
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
                     "arch-arm/cortex-a15/bionic/strcmp.S",
                     "arch-arm/cortex-a15/bionic/strcpy.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
                     "arch-arm/cortex-a15/bionic/strlen.S",
 
                     "arch-arm/denver/bionic/memmove.S",
@@ -930,8 +1010,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a9: {
@@ -940,10 +1018,8 @@
                     "arch-arm/cortex-a9/bionic/memset.S",
                     "arch-arm/cortex-a9/bionic/stpcpy.S",
                     "arch-arm/cortex-a9/bionic/strcat.S",
-                    "arch-arm/cortex-a9/bionic/__strcat_chk.S",
                     "arch-arm/cortex-a9/bionic/strcmp.S",
                     "arch-arm/cortex-a9/bionic/strcpy.S",
-                    "arch-arm/cortex-a9/bionic/__strcpy_chk.S",
                     "arch-arm/cortex-a9/bionic/strlen.S",
 
                     "arch-arm/denver/bionic/memmove.S",
@@ -954,8 +1030,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a15: {
@@ -964,10 +1038,8 @@
                     "arch-arm/cortex-a15/bionic/memset.S",
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
                     "arch-arm/cortex-a15/bionic/strcat.S",
-                    "arch-arm/cortex-a15/bionic/__strcat_chk.S",
                     "arch-arm/cortex-a15/bionic/strcmp.S",
                     "arch-arm/cortex-a15/bionic/strcpy.S",
-                    "arch-arm/cortex-a15/bionic/__strcpy_chk.S",
                     "arch-arm/cortex-a15/bionic/strlen.S",
 
                     "arch-arm/denver/bionic/memmove.S",
@@ -978,8 +1050,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             cortex_a73: {
@@ -988,8 +1058,6 @@
 
                     "arch-arm/denver/bionic/memcpy.S",
                     "arch-arm/denver/bionic/memmove.S",
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
 
                     "arch-arm/krait/bionic/strcmp.S",
 
@@ -1004,8 +1072,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             denver: {
@@ -1013,8 +1079,6 @@
                     "arch-arm/denver/bionic/memcpy.S",
                     "arch-arm/denver/bionic/memmove.S",
                     "arch-arm/denver/bionic/memset.S",
-                    "arch-arm/denver/bionic/__strcat_chk.S",
-                    "arch-arm/denver/bionic/__strcpy_chk.S",
 
                     // Use cortex-a15 versions of strcat/strcpy/strlen.
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
@@ -1029,8 +1093,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             krait: {
@@ -1038,8 +1100,6 @@
                     "arch-arm/krait/bionic/memcpy.S",
                     "arch-arm/krait/bionic/memset.S",
                     "arch-arm/krait/bionic/strcmp.S",
-                    "arch-arm/krait/bionic/__strcat_chk.S",
-                    "arch-arm/krait/bionic/__strcpy_chk.S",
 
                     // Use cortex-a15 versions of strcat/strcpy/strlen.
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
@@ -1055,8 +1115,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
             kryo: {
@@ -1064,8 +1122,6 @@
                     "arch-arm/kryo/bionic/memcpy.S",
                     "arch-arm/cortex-a7/bionic/memset.S",
                     "arch-arm/krait/bionic/strcmp.S",
-                    "arch-arm/krait/bionic/__strcat_chk.S",
-                    "arch-arm/krait/bionic/__strcpy_chk.S",
 
                     // Use cortex-a15 versions of strcat/strcpy/strlen.
                     "arch-arm/cortex-a15/bionic/stpcpy.S",
@@ -1081,8 +1137,6 @@
                     "arch-arm/generic/bionic/strcmp.S",
                     "arch-arm/generic/bionic/strcpy.S",
                     "arch-arm/generic/bionic/strlen.c",
-                    "bionic/__strcat_chk.cpp",
-                    "bionic/__strcpy_chk.cpp",
                 ],
             },
         },
@@ -1330,6 +1384,13 @@
 cc_library_static {
     defaults: ["libc_defaults"],
     srcs: [
+        "bionic/NetdClientDispatch.cpp",
+        "bionic/__cmsg_nxthdr.cpp",
+        "bionic/__errno.cpp",
+        "bionic/__gnu_basename.cpp",
+        "bionic/__libc_current_sigrtmax.cpp",
+        "bionic/__libc_current_sigrtmin.cpp",
+        "bionic/__set_errno.cpp",
         "bionic/abort.cpp",
         "bionic/accept.cpp",
         "bionic/accept4.cpp",
@@ -1352,15 +1413,14 @@
         "bionic/clock_nanosleep.cpp",
         "bionic/clone.cpp",
         "bionic/close.cpp",
-        "bionic/__cmsg_nxthdr.cpp",
         "bionic/connect.cpp",
         "bionic/ctype.cpp",
         "bionic/dirent.cpp",
         "bionic/dup2.cpp",
+        "bionic/environ.cpp",
         "bionic/epoll_create.cpp",
         "bionic/epoll_pwait.cpp",
         "bionic/epoll_wait.cpp",
-        "bionic/__errno.cpp",
         "bionic/error.cpp",
         "bionic/eventfd_read.cpp",
         "bionic/eventfd_write.cpp",
@@ -1372,7 +1432,6 @@
         "bionic/fgetxattr.cpp",
         "bionic/flistxattr.cpp",
         "bionic/flockfile.cpp",
-        "bionic/fortify.cpp",
         "bionic/fpclassify.cpp",
         "bionic/fsetxattr.cpp",
         "bionic/ftruncate.cpp",
@@ -1386,16 +1445,15 @@
         "bionic/getpid.cpp",
         "bionic/getpriority.cpp",
         "bionic/gettid.cpp",
-        "bionic/__gnu_basename.cpp",
         "bionic/grp_pwd.cpp",
+        "bionic/icu_wrappers.cpp",
         "bionic/ifaddrs.cpp",
         "bionic/inotify_init.cpp",
         "bionic/ioctl.cpp",
+        "bionic/killpg.cpp",
         "bionic/langinfo.cpp",
         "bionic/lchown.cpp",
         "bionic/lfs64_support.cpp",
-        "bionic/__libc_current_sigrtmax.cpp",
-        "bionic/__libc_current_sigrtmin.cpp",
         "bionic/libc_init_common.cpp",
         "bionic/libgen.cpp",
         "bionic/link.cpp",
@@ -1406,7 +1464,6 @@
         "bionic/mblen.cpp",
         "bionic/mbrtoc16.cpp",
         "bionic/mbrtoc32.cpp",
-        "bionic/mbstate.cpp",
         "bionic/memmem.cpp",
         "bionic/mempcpy.cpp",
         "bionic/mkdir.cpp",
@@ -1414,9 +1471,8 @@
         "bionic/mknod.cpp",
         "bionic/mntent.cpp",
         "bionic/mremap.cpp",
-        "bionic/netdb.cpp",
-        "bionic/NetdClientDispatch.cpp",
         "bionic/net_if.cpp",
+        "bionic/netdb.cpp",
         "bionic/netinet_in.cpp",
         "bionic/nl_types.cpp",
         "bionic/open.cpp",
@@ -1443,7 +1499,6 @@
         "bionic/semaphore.cpp",
         "bionic/send.cpp",
         "bionic/setegid.cpp",
-        "bionic/__set_errno.cpp",
         "bionic/seteuid.cpp",
         "bionic/setpgrp.cpp",
         "bionic/sigaction.cpp",
@@ -1469,21 +1524,24 @@
         "bionic/socket.cpp",
         "bionic/stat.cpp",
         "bionic/statvfs.cpp",
+        "bionic/stdlib_l.cpp",
         "bionic/strchrnul.cpp",
         "bionic/strerror.cpp",
         "bionic/strerror_r.cpp",
+        "bionic/string_l.cpp",
+        "bionic/strings_l.cpp",
         "bionic/strsignal.cpp",
         "bionic/strtold.cpp",
         "bionic/symlink.cpp",
         "bionic/sync_file_range.cpp",
-        "bionic/sysinfo.cpp",
-        "bionic/syslog.cpp",
         "bionic/sys_msg.cpp",
         "bionic/sys_sem.cpp",
         "bionic/sys_shm.cpp",
         "bionic/sys_siglist.c",
         "bionic/sys_signame.c",
         "bionic/sys_time.cpp",
+        "bionic/sysinfo.cpp",
+        "bionic/syslog.cpp",
         "bionic/system_properties.cpp",
         "bionic/tdestroy.cpp",
         "bionic/termios.cpp",
@@ -1493,8 +1551,10 @@
         "bionic/unlink.cpp",
         "bionic/wait.cpp",
         "bionic/wchar.cpp",
+        "bionic/wchar_l.cpp",
         "bionic/wcstod.cpp",
         "bionic/wctype.cpp",
+        "bionic/wcwidth.cpp",
         "bionic/wmempcpy.cpp",
     ],
 
@@ -1640,6 +1700,7 @@
 
     whole_static_libs: [
         "libc_bionic_ndk",
+        "libc_fortify",
         "libc_freebsd",
         "libc_freebsd_large_stack",
         "libc_gdtoa",
@@ -1674,6 +1735,7 @@
         "libc_bionic",
         "libc_bionic_ndk",
         "libc_dns",
+        "libc_fortify",
         "libc_freebsd",
         "libc_freebsd_large_stack",
         "libc_gdtoa",
@@ -1888,6 +1950,8 @@
 
     no_default_compiler_flags: true,
 
+    cflags: ["-Wno-gcc-compat", "-Werror"],
+
     arch: {
         arm: {
             local_include_dirs: ["arch-arm/include"],
@@ -1908,12 +1972,14 @@
             local_include_dirs: ["arch-x86_64/include"],
         },
     },
-    clang: false,
+    clang: true,
 }
 
 cc_defaults {
     name: "crt_so_defaults",
 
+    cflags: ["-Wno-gcc-compat", "-Werror"],
+
     vendor_available: true,
     arch: {
         mips: {
diff --git a/libc/NOTICE b/libc/NOTICE
index c74811c..90de7ef 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -682,6 +682,31 @@
 
 -------------------------------------------------------------------
 
+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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 AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
 Copyright (C) 2013 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -862,22 +887,6 @@
 
      http://www.apache.org/licenses/LICENSE-2.0
 
- Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -2907,6 +2916,25 @@
 
 -------------------------------------------------------------------
 
+Copyright (c) 1996, David Mazieres <dm@uun.org>
+Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
 Copyright (c) 1996-1998, 2008 Theo de Raadt
 Copyright (c) 1997, 2008-2009 Todd C. Miller
 
@@ -5068,23 +5096,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
-Copyright (c) 2009 Ted Unangst
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
--------------------------------------------------------------------
-
 Copyright (c) 2011 The Android Open Source Project
 Copyright (c) 2008 ARM Ltd
 All rights reserved.
@@ -5384,32 +5395,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2013 David Chisnall
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. 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 AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
 Copyright (c) 2013 The NetBSD Foundation, Inc.
 All rights reserved.
 
diff --git a/libc/SECCOMP_WHITELIST_GLOBAL.TXT b/libc/SECCOMP_WHITELIST_GLOBAL.TXT
new file mode 100644
index 0000000..f3e5a98
--- /dev/null
+++ b/libc/SECCOMP_WHITELIST_GLOBAL.TXT
@@ -0,0 +1,18 @@
+# This file is used to populate seccomp's global whitelist policy in
+# combination with SYSCALLS.TXT, SECCOMP_BLACKLIST.TXT and
+# SECCOMP_WHITELIST.TXT.  Unlike the policy used in normal operation this
+# policy is applied globally during the early stage of init, if global seccomp
+# is enabled.
+#
+# See the description at the top of SYSCALLS.TXT for an explanation of the
+# format of the entries in this file.
+#
+# This file is processed by a python script named genseccomp.py.
+
+# syscalls needed to boot android
+int swapon(const char*, int) all
+long keyctl(int, ...) all
+key_serial_t add_key(const char*, const char*, const void*, size_t, key_serial_t) all
+
+# b/62715671
+int finit_module(int, const char*, int) all
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 7ad0093..4297cd6 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -63,17 +63,6 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memcpy_chk)
-        cmp r2, r3
-        bls memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
 ENTRY(memcpy)
         pld     [r1, #64]
diff --git a/libc/arch-arm/cortex-a53/bionic/memcpy.S b/libc/arch-arm/cortex-a53/bionic/memcpy.S
index 7ad0093..4297cd6 100644
--- a/libc/arch-arm/cortex-a53/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a53/bionic/memcpy.S
@@ -63,17 +63,6 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memcpy_chk)
-        cmp r2, r3
-        bls memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
 ENTRY(memcpy)
         pld     [r1, #64]
diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy.S b/libc/arch-arm/cortex-a7/bionic/memcpy.S
index 7ad0093..4297cd6 100644
--- a/libc/arch-arm/cortex-a7/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a7/bionic/memcpy.S
@@ -63,17 +63,6 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memcpy_chk)
-        cmp r2, r3
-        bls memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 // Prototype: void *memcpy (void *dst, const void *src, size_t count).
 ENTRY(memcpy)
         pld     [r1, #64]
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy.S b/libc/arch-arm/cortex-a9/bionic/memcpy.S
index 93a8629..5a986d1 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy.S
@@ -39,18 +39,6 @@
         .thumb
         .thumb_func
 
-ENTRY(__memcpy_chk)
-        cmp         r2, r3
-        bls         memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
         pld     [r1, #0]
         stmfd   sp!, {r0, lr}
diff --git a/libc/arch-arm/denver/bionic/memcpy.S b/libc/arch-arm/denver/bionic/memcpy.S
index 743c74b..8528f28 100644
--- a/libc/arch-arm/denver/bionic/memcpy.S
+++ b/libc/arch-arm/denver/bionic/memcpy.S
@@ -65,18 +65,6 @@
         // arch. The code generated is exactly the same.
         .arch armv7-a
 
-ENTRY(__memcpy_chk)
-        cmp     r2, r3
-        bls     memcpy
-
-        // Preserve lr for backtrace.
-        push    {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        bl      __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
         pld     [r1, #64]
         push    {r0, lr}
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/arch-arm/generic/bionic/__memcpy_chk.S
similarity index 74%
copy from libc/bionic/__memcpy_chk.cpp
copy to libc/arch-arm/generic/bionic/__memcpy_chk.S
index 7b42d99..7ee2a8f 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/arch-arm/generic/bionic/__memcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,18 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
+#include <private/bionic_asm.h>
 
-#include <string.h>
+  .syntax unified
 
-#include "private/bionic_fortify.h"
+ENTRY(__memcpy_chk)
+  cmp         r2, r3
+  bls         memcpy
 
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
-}
+  // Preserve lr for backtrace.
+  push        {lr}
+  .cfi_def_cfa_offset 4
+  .cfi_rel_offset lr, 0
+
+  bl          __memcpy_chk_fail
+END(__memcpy_chk)
diff --git a/libc/arch-arm/generic/bionic/memcpy.S b/libc/arch-arm/generic/bionic/memcpy.S
index a3ebb95..d1e4372 100644
--- a/libc/arch-arm/generic/bionic/memcpy.S
+++ b/libc/arch-arm/generic/bionic/memcpy.S
@@ -37,18 +37,6 @@
 
          .syntax unified
 
-ENTRY(__memcpy_chk)
-        cmp         r2, r3
-        bls         memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
         /* The stack must always be 64-bits aligned to be compliant with the
          * ARM ABI. Since we have to save R0, we might as well save R4
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index de6f432..f22c063 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -42,18 +42,6 @@
         .thumb
         .thumb_func
 
-ENTRY(__memcpy_chk)
-        cmp         r2, r3
-        bls         memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
         pld     [r1, #64]
         stmfd   sp!, {r0, lr}
diff --git a/libc/arch-arm/kryo/bionic/memcpy.S b/libc/arch-arm/kryo/bionic/memcpy.S
index 7e96f7d..e9ee2ac 100644
--- a/libc/arch-arm/kryo/bionic/memcpy.S
+++ b/libc/arch-arm/kryo/bionic/memcpy.S
@@ -34,18 +34,6 @@
 #define PLDSIZE (128) /* L2 cache line size */
 
         .code 32
-ENTRY(__memcpy_chk)
-        cmp         r2, r3
-        bls         memcpy
-
-        // Preserve lr for backtrace.
-        push        {lr}
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        bl          __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
         push            {r0}
         .cfi_def_cfa_offset 4
diff --git a/libc/arch-arm64/denver64/bionic/memcpy.S b/libc/arch-arm64/denver64/bionic/memcpy.S
index 0be2aac..fc487d3 100644
--- a/libc/arch-arm64/denver64/bionic/memcpy.S
+++ b/libc/arch-arm64/denver64/bionic/memcpy.S
@@ -30,19 +30,6 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__memcpy_chk)
-  cmp x2, x3
-  bls memcpy
-
-  // Preserve for accurate backtrace.
-  stp x29, x30, [sp, -16]!
-  .cfi_def_cfa_offset 16
-  .cfi_rel_offset x29, 0
-  .cfi_rel_offset x30, 8
-
-  bl __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
   #include "memcpy_base.S"
 END(memcpy)
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
similarity index 74%
copy from libc/bionic/__memcpy_chk.cpp
copy to libc/arch-arm64/generic/bionic/__memcpy_chk.S
index 7b42d99..4217775 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/arch-arm64/generic/bionic/__memcpy_chk.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,17 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
+#include <private/bionic_asm.h>
 
-#include <string.h>
+ENTRY(__memcpy_chk)
+  cmp x2, x3
+  bls memcpy
 
-#include "private/bionic_fortify.h"
+  // Preserve for accurate backtrace.
+  stp x29, x30, [sp, -16]!
+  .cfi_def_cfa_offset 16
+  .cfi_rel_offset x29, 0
+  .cfi_rel_offset x30, 8
 
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
-}
+  bl __memcpy_chk_fail
+END(__memcpy_chk)
diff --git a/libc/arch-arm64/generic/bionic/memcpy.S b/libc/arch-arm64/generic/bionic/memcpy.S
index 0be2aac..fc487d3 100644
--- a/libc/arch-arm64/generic/bionic/memcpy.S
+++ b/libc/arch-arm64/generic/bionic/memcpy.S
@@ -30,19 +30,6 @@
 
 #include <private/bionic_asm.h>
 
-ENTRY(__memcpy_chk)
-  cmp x2, x3
-  bls memcpy
-
-  // Preserve for accurate backtrace.
-  stp x29, x30, [sp, -16]!
-  .cfi_def_cfa_offset 16
-  .cfi_rel_offset x29, 0
-  .cfi_rel_offset x30, 8
-
-  bl __memcpy_chk_fail
-END(__memcpy_chk)
-
 ENTRY(memcpy)
   #include "memcpy_base.S"
 END(memcpy)
diff --git a/libc/arch-common/bionic/crtbegin.c b/libc/arch-common/bionic/crtbegin.c
index d3a0f07..45c9ea7 100644
--- a/libc/arch-common/bionic/crtbegin.c
+++ b/libc/arch-common/bionic/crtbegin.c
@@ -30,16 +30,13 @@
 #include <stddef.h>
 #include <stdint.h>
 
-__attribute__((__section__(".preinit_array")))
-void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1;
+#define SECTION(name) __attribute__((__section__(name)))
+SECTION(".preinit_array") void (*__PREINIT_ARRAY__)(void) = (void (*)(void)) -1;
+SECTION(".init_array") void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1;
+SECTION(".fini_array") void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1;
+#undef SECTION
 
-__attribute__((__section__(".init_array")))
-void (*__INIT_ARRAY__)(void) = (void (*)(void)) -1;
-
-__attribute__((__section__(".fini_array")))
-void (*__FINI_ARRAY__)(void) = (void (*)(void)) -1;
-
-static void _start_main(void* raw_args) {
+static void _start_main(void* raw_args) __used {
   structors_array_t array;
   array.preinit_array = &__PREINIT_ARRAY__;
   array.init_array = &__INIT_ARRAY__;
diff --git a/libc/bionic/__strcpy_chk.cpp b/libc/bionic/__strcpy_chk.cpp
deleted file mode 100644
index 116fff4..0000000
--- a/libc/bionic/__strcpy_chk.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#undef _FORTIFY_SOURCE
-
-#include <string.h>
-
-#include "private/bionic_fortify.h"
-
-// Runtime implementation of __builtin____strcpy_chk (used directly by compiler, not in headers).
-extern "C" char* __strcpy_chk(char* dst, const char* src, size_t dst_len) {
-  // TODO: optimize so we don't scan src twice.
-  size_t src_len = strlen(src) + 1;
-  __check_buffer_access("strcpy", "write into", src_len, dst_len);
-  return strcpy(dst, src);
-}
diff --git a/libc/bionic/c16rtomb.cpp b/libc/bionic/c16rtomb.cpp
index 77512be..93749c6 100644
--- a/libc/bionic/c16rtomb.cpp
+++ b/libc/bionic/c16rtomb.cpp
@@ -50,18 +50,18 @@
       mbstate_set_byte(state, 2, (c32 & 0x00ff00) >> 8);
       return 0;
     } else if (is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     } else {
       return c32rtomb(s, static_cast<char32_t>(c16), state);
     }
   } else {
     if (!is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     }
 
     char32_t c32 = ((mbstate_get_byte(state, 3) << 16) |
                     (mbstate_get_byte(state, 2) << 8) |
                     (c16 & ~0xdc00)) + 0x10000;
-    return reset_and_return(c32rtomb(s, c32, NULL), state);
+    return mbstate_reset_and_return(c32rtomb(s, c32, NULL), state);
   }
 }
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index d3231c0..ebe9cd3 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -38,7 +38,7 @@
 
   if (s == NULL) {
     // Equivalent to c32rtomb(buf, U'\0', ps).
-    return reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   // POSIX states that if char32_t is a null wide character, a null byte shall
@@ -47,11 +47,11 @@
   // stored.
   if (c32 == U'\0') {
     *s = '\0';
-    reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   if ((c32 & ~0x7f) == 0) {
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/bionic/environ.cpp
similarity index 74%
copy from libc/bionic/__memcpy_chk.cpp
copy to libc/bionic/environ.cpp
index 7b42d99..363c1fd 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/bionic/environ.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,8 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
+#include <unistd.h>
 
-#include <string.h>
-
-#include "private/bionic_fortify.h"
-
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
-}
+// Keep that variable in separate .o file to make sure programs which define
+// their own "environ" are compileable.
+char** environ;
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index 144e133..4a7ff13 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -55,8 +55,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
-
 #include <poll.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -458,3 +456,43 @@
   __check_buffer_access("write", "read from", count, buf_size);
   return write(fd, buf, count);
 }
+
+#if !defined(NO___STRCAT_CHK)
+// Runtime implementation of __builtin____strcat_chk (used directly by compiler, not in headers).
+extern "C" char* __strcat_chk(char* __restrict dst, const char* __restrict src,
+                              size_t dst_buf_size) {
+  char* save = dst;
+  size_t dst_len = __strlen_chk(dst, dst_buf_size);
+
+  dst += dst_len;
+  dst_buf_size -= dst_len;
+
+  while ((*dst++ = *src++) != '\0') {
+    dst_buf_size--;
+    if (__predict_false(dst_buf_size == 0)) {
+      __fortify_fatal("strcat: prevented write past end of %zu-byte buffer", dst_buf_size);
+    }
+  }
+
+  return save;
+}
+#endif // NO___STRCAT_CHK
+
+#if !defined(NO___STRCPY_CHK)
+// Runtime implementation of __builtin____strcpy_chk (used directly by compiler, not in headers).
+extern "C" char* __strcpy_chk(char* dst, const char* src, size_t dst_len) {
+  // TODO: optimize so we don't scan src twice.
+  size_t src_len = strlen(src) + 1;
+  __check_buffer_access("strcpy", "write into", src_len, dst_len);
+  return strcpy(dst, src);
+}
+#endif // NO___STRCPY_CHK
+
+#if !defined(NO___MEMCPY_CHK)
+// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
+extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
+  __check_count("memcpy", "count", count);
+  __check_buffer_access("memcpy", "write into", count, dst_len);
+  return memcpy(dst, src, count);
+}
+#endif // NO___MEMCPY_CHK
diff --git a/libc/bionic/getcwd.cpp b/libc/bionic/getcwd.cpp
index c2a7e23..50487ec 100644
--- a/libc/bionic/getcwd.cpp
+++ b/libc/bionic/getcwd.cpp
@@ -26,7 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
 #include <errno.h>
 #include <malloc.h>
 #include <string.h>
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index 078a0b3..2823662 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -467,7 +467,16 @@
 
 char* getlogin() { // NOLINT: implementing bad function.
   passwd *pw = getpwuid(getuid()); // NOLINT: implementing bad function in terms of bad function.
-  return (pw != NULL) ? pw->pw_name : NULL;
+  return pw ? pw->pw_name : nullptr;
+}
+
+int getlogin_r(char* buf, size_t size) {
+  char* login = getlogin();
+  if (login == nullptr) return errno;
+  size_t login_length = strlen(login) + 1;
+  if (login_length > size) return ERANGE;
+  memcpy(buf, login, login_length);
+  return 0;
 }
 
 void setpwent() {
diff --git a/libc/bionic/icu_wrappers.cpp b/libc/bionic/icu_wrappers.cpp
new file mode 100644
index 0000000..d9f2745
--- /dev/null
+++ b/libc/bionic/icu_wrappers.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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 "private/icu.h"
+
+int8_t __icu_charType(wint_t wc) {
+  typedef int8_t (*u_charType_t)(UChar32);
+  static auto u_charType = reinterpret_cast<u_charType_t>(__find_icu_symbol("u_charType"));
+  return u_charType ? u_charType(wc) : -1;
+}
+
+int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property) {
+  typedef int32_t (*u_getIntPropertyValue_t)(UChar32, UProperty);
+  static auto u_getIntPropertyValue =
+      reinterpret_cast<u_getIntPropertyValue_t>(__find_icu_symbol("u_getIntPropertyValue"));
+  return u_getIntPropertyValue ? u_getIntPropertyValue(wc, property) : 0;
+}
+
+bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) {
+  typedef UBool (*u_hasBinaryProperty_t)(UChar32, UProperty);
+  static auto u_hasBinaryProperty =
+      reinterpret_cast<u_hasBinaryProperty_t>(__find_icu_symbol("u_hasBinaryProperty"));
+  return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc);
+}
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/bionic/killpg.cpp
similarity index 74%
copy from libc/bionic/__memcpy_chk.cpp
copy to libc/bionic/killpg.cpp
index 7b42d99..01a58b3 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/bionic/killpg.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,13 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
+#include <errno.h>
+#include <signal.h>
 
-#include <string.h>
-
-#include "private/bionic_fortify.h"
-
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
+int killpg(pid_t pgrp, int sig) {
+  if (pgrp < 0) {
+    errno = EINVAL;
+    return -1;
+  }
+  return kill(-pgrp, sig);
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index e051762..48fd670 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -59,9 +59,6 @@
 // Not public, but well-known in the BSDs.
 const char* __progname;
 
-// Declared in <unistd.h>.
-char** environ;
-
 #if defined(__i386__)
 __attribute__((__naked__)) static void __libc_int0x80() {
   __asm__ volatile("int $0x80; ret");
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 38e15b7..08c9401 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -37,7 +37,15 @@
 
 #include "private/bionic_macros.h"
 
+#if defined(__BIONIC_BUILD_FOR_ANDROID_SUPPORT)
+#define USE_TLS_SLOT 0
+#else
+#define USE_TLS_SLOT 1
+#endif
+
+#if USE_TLS_SLOT
 #include "bionic/pthread_internal.h"
+#endif
 
 // We only support two locales, the "C" locale (also known as "POSIX"),
 // and the "C.UTF-8" locale (also known as "en_US.UTF-8").
@@ -70,6 +78,10 @@
   }
 }
 
+#if !USE_TLS_SLOT
+static thread_local locale_t g_current_locale;
+#endif
+
 static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT;
 static lconv g_locale;
 
@@ -163,9 +175,16 @@
   return const_cast<char*>(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C");
 }
 
+static locale_t* get_current_locale_ptr() {
+#if USE_TLS_SLOT
+  return &__get_bionic_tls().locale;
+#else
+  return &g_current_locale;
+#endif
+}
+
 locale_t uselocale(locale_t new_locale) {
-  locale_t* locale_storage = &__get_bionic_tls().locale;
-  locale_t old_locale = *locale_storage;
+  locale_t old_locale = *get_current_locale_ptr();
 
   // If this is the first call to uselocale(3) on this thread, we return LC_GLOBAL_LOCALE.
   if (old_locale == NULL) {
@@ -173,64 +192,8 @@
   }
 
   if (new_locale != NULL) {
-    *locale_storage = new_locale;
+    *get_current_locale_ptr() = new_locale;
   }
 
   return old_locale;
 }
-
-int strcasecmp_l(const char* s1, const char* s2, locale_t) {
-  return strcasecmp(s1, s2);
-}
-
-int strcoll_l(const char* s1, const char* s2, locale_t) {
-  return strcoll(s1, s2);
-}
-
-char* strerror_l(int error, locale_t) {
-  return strerror(error);
-}
-
-int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
-  return strncasecmp(s1, s2, n);
-}
-
-double strtod_l(const char* s, char** end_ptr, locale_t) {
-  return strtod(s, end_ptr);
-}
-
-float strtof_l(const char* s, char** end_ptr, locale_t) {
-  return strtof(s, end_ptr);
-}
-
-long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtol(s, end_ptr, base);
-}
-
-long double strtold_l(const char* s, char** end_ptr, locale_t) {
-  return strtold(s, end_ptr);
-}
-
-long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoll(s, end_ptr, base);
-}
-
-unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoul(s, end_ptr, base);
-}
-
-unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoull(s, end_ptr, base);
-}
-
-size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
-  return strxfrm(dst, src, n);
-}
-
-int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
-  return wcscasecmp(ws1, ws2);
-}
-
-int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
-  return wcsncasecmp(ws1, ws2, n);
-}
diff --git a/libc/bionic/mbrtoc16.cpp b/libc/bionic/mbrtoc16.cpp
index 6878a11..2180516 100644
--- a/libc/bionic/mbrtoc16.cpp
+++ b/libc/bionic/mbrtoc16.cpp
@@ -55,7 +55,7 @@
   char16_t trail = mbstate_get_byte(state, 1) << 8 |
                    mbstate_get_byte(state, 0);
   *pc16 = trail;
-  return reset_and_return(mbstate_get_byte(state, 3), state);
+  return mbstate_reset_and_return(mbstate_get_byte(state, 3), state);
 }
 
 size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
@@ -76,13 +76,13 @@
   if (__MB_IS_ERR(nconv)) {
     return nconv;
   } else if (nconv == 0) {
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else if (c32 > 0x10ffff) {
     // Input cannot be encoded as UTF-16.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   } else if (c32 < 0x10000) {
     *pc16 = static_cast<char16_t>(c32);
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else {
     return begin_surrogate(c32, pc16, nconv, state);
   }
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index bd40ecf..f004b78 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -41,7 +41,7 @@
   // Full state verification is done when decoding the sequence (after we have
   // all the bytes).
   if (mbstate_get_byte(state, 3) != 0) {
-    return reset_and_return_illegal(EINVAL, state);
+    return mbstate_reset_and_return_illegal(EINVAL, state);
   }
 
   if (s == NULL) {
@@ -98,7 +98,7 @@
     lower_bound = 0x10000;
   } else {
     // Malformed input; input is not UTF-8. See RFC 3629.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Fill in the state.
@@ -107,7 +107,7 @@
   for (i = 0; i < MIN(bytes_wanted, n); i++) {
     if (!mbsinit(state) && ((*s & 0xc0) != 0x80)) {
       // Malformed input; bad characters in the middle of a character.
-      return reset_and_return_illegal(EILSEQ, state);
+      return mbstate_reset_and_return_illegal(EILSEQ, state);
     }
     mbstate_set_byte(state, bytes_so_far + i, *s++);
   }
@@ -125,14 +125,14 @@
 
   if (c32 < lower_bound) {
     // Malformed input; redundant encoding.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 == 0xfffe || c32 == 0xffff) {
     // Malformed input; invalid code points.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if (pc32 != NULL) {
     *pc32 = c32;
   }
-  return reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
+  return mbstate_reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
 }
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/mbstate.cpp
deleted file mode 100644
index cb327d8..0000000
--- a/libc/bionic/mbstate.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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 "private/bionic_mbstate.h"
-
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
-  return
-    (ps->__seq[2] != 0) ? 3 :
-    (ps->__seq[1] != 0) ? 2 :
-    (ps->__seq[0] != 0) ? 1 : 0;
-}
-
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
-  ps->__seq[i] = static_cast<uint8_t>(byte);
-}
-
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
-  return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return _return;
-}
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index eded56a..dbc9584 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -26,7 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
 #include <errno.h>
 #include <sys/poll.h>
 #include <sys/select.h>
diff --git a/libc/bionic/readlink.cpp b/libc/bionic/readlink.cpp
index a53f933..3bb7bc1 100644
--- a/libc/bionic/readlink.cpp
+++ b/libc/bionic/readlink.cpp
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
-
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
diff --git a/libc/bionic/recv.cpp b/libc/bionic/recv.cpp
index 061cd46..60f264d 100644
--- a/libc/bionic/recv.cpp
+++ b/libc/bionic/recv.cpp
@@ -26,7 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
 #include <sys/socket.h>
 
 ssize_t recv(int socket, void *buf, size_t len, int flags) {
diff --git a/libc/bionic/__strcat_chk.cpp b/libc/bionic/stdlib_l.cpp
similarity index 62%
rename from libc/bionic/__strcat_chk.cpp
rename to libc/bionic/stdlib_l.cpp
index 16b2327..18e9f86 100644
--- a/libc/bionic/__strcat_chk.cpp
+++ b/libc/bionic/stdlib_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,25 +26,34 @@
  * SUCH DAMAGE.
  */
 
-#include <string.h>
+#include <stdlib.h>
+#include <xlocale.h>
 
-#include "private/bionic_fortify.h"
-
-// Runtime implementation of __builtin____strcat_chk (used directly by compiler, not in headers).
-extern "C" char* __strcat_chk(char* __restrict dst, const char* __restrict src,
-                              size_t dst_buf_size) {
-  char* save = dst;
-  size_t dst_len = __strlen_chk(dst, dst_buf_size);
-
-  dst += dst_len;
-  dst_buf_size -= dst_len;
-
-  while ((*dst++ = *src++) != '\0') {
-    dst_buf_size--;
-    if (__predict_false(dst_buf_size == 0)) {
-      __fortify_fatal("strcat: prevented write past end of %zu-byte buffer", dst_buf_size);
-    }
-  }
-
-  return save;
+double strtod_l(const char* s, char** end_ptr, locale_t) {
+  return strtod(s, end_ptr);
 }
+
+float strtof_l(const char* s, char** end_ptr, locale_t) {
+  return strtof(s, end_ptr);
+}
+
+long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtol(s, end_ptr, base);
+}
+
+long double strtold_l(const char* s, char** end_ptr, locale_t) {
+  return strtold(s, end_ptr);
+}
+
+long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoll(s, end_ptr, base);
+}
+
+unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoul(s, end_ptr, base);
+}
+
+unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoull(s, end_ptr, base);
+}
+
diff --git a/libc/bionic/strchr.cpp b/libc/bionic/strchr.cpp
index 5bd3f19..fd8a924 100644
--- a/libc/bionic/strchr.cpp
+++ b/libc/bionic/strchr.cpp
@@ -27,7 +27,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
 #include <string.h>
 
 char* strchr(const char* p, int ch) {
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/bionic/string_l.cpp
similarity index 75%
rename from libc/bionic/__memcpy_chk.cpp
rename to libc/bionic/string_l.cpp
index 7b42d99..66bfb0e 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/bionic/string_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,17 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
-
 #include <string.h>
+#include <xlocale.h>
 
-#include "private/bionic_fortify.h"
+int strcoll_l(const char* s1, const char* s2, locale_t) {
+  return strcoll(s1, s2);
+}
 
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
+char* strerror_l(int error, locale_t) {
+  return strerror(error);
+}
+
+size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
+  return strxfrm(dst, src, n);
 }
diff --git a/libc/bionic/__memcpy_chk.cpp b/libc/bionic/strings_l.cpp
similarity index 74%
copy from libc/bionic/__memcpy_chk.cpp
copy to libc/bionic/strings_l.cpp
index 7b42d99..0983ab1 100644
--- a/libc/bionic/__memcpy_chk.cpp
+++ b/libc/bionic/strings_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,15 +26,13 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
+#include <strings.h>
+#include <xlocale.h>
 
-#include <string.h>
+int strcasecmp_l(const char* s1, const char* s2, locale_t) {
+  return strcasecmp(s1, s2);
+}
 
-#include "private/bionic_fortify.h"
-
-// Runtime implementation of __memcpy_chk (used directly by compiler, not in headers).
-extern "C" void* __memcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) {
-  __check_count("memcpy", "count", count);
-  __check_buffer_access("memcpy", "write into", count, dst_len);
-  return memcpy(dst, src, count);
+int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
+  return strncasecmp(s1, s2, n);
 }
diff --git a/libc/bionic/strrchr.cpp b/libc/bionic/strrchr.cpp
index 3fdb47c..b6c40f4 100644
--- a/libc/bionic/strrchr.cpp
+++ b/libc/bionic/strrchr.cpp
@@ -27,7 +27,6 @@
  * SUCH DAMAGE.
  */
 
-#undef _FORTIFY_SOURCE
 #include <string.h>
 
 char* strrchr(const char* p, int ch) {
diff --git a/libc/bionic/sysconf.cpp b/libc/bionic/sysconf.cpp
index 4a23fec..7325dbd 100644
--- a/libc/bionic/sysconf.cpp
+++ b/libc/bionic/sysconf.cpp
@@ -135,12 +135,12 @@
     case _SC_TIMERS:            return _POSIX_TIMERS;
     case _SC_GETGR_R_SIZE_MAX:  return 1024;
     case _SC_GETPW_R_SIZE_MAX:  return 1024;
-    case _SC_LOGIN_NAME_MAX:    return 256;   // Seems default on linux.
+    case _SC_LOGIN_NAME_MAX:    return LOGIN_NAME_MAX;
     case _SC_THREAD_DESTRUCTOR_ITERATIONS: return PTHREAD_DESTRUCTOR_ITERATIONS;
     case _SC_THREAD_KEYS_MAX:   return PTHREAD_KEYS_MAX;
     case _SC_THREAD_STACK_MIN:    return PTHREAD_STACK_MIN;
     case _SC_THREAD_THREADS_MAX:  return -1; // No specific limit.
-    case _SC_TTY_NAME_MAX:        return 32; // Seems default on linux.
+    case _SC_TTY_NAME_MAX:        return TTY_NAME_MAX;
     case _SC_THREADS:             return _POSIX_THREADS;
     case _SC_THREAD_ATTR_STACKADDR:   return _POSIX_THREAD_ATTR_STACKADDR;
     case _SC_THREAD_ATTR_STACKSIZE:   return _POSIX_THREAD_ATTR_STACKSIZE;
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index 7717e10..62023d6 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -74,7 +74,7 @@
   // character appears as anything but the first byte of a
   // multibyte sequence. Check now to avoid doing it in the loops.
   if (nmc > 0 && mbstate_bytes_so_far(state) > 0 && static_cast<uint8_t>((*src)[0]) < 0x80) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Measure only?
@@ -83,23 +83,23 @@
       if (static_cast<uint8_t>((*src)[i]) < 0x80) {
         // Fast path for plain ASCII characters.
         if ((*src)[i] == '\0') {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
         r = 1;
       } else {
         r = mbrtowc(NULL, *src + i, nmc - i, state);
         if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == 0) {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
       }
     }
-    return reset_and_return(o, state);
+    return mbstate_reset_and_return(o, state);
   }
 
   // Actually convert, updating `dst` and `src`.
@@ -110,26 +110,26 @@
       r = 1;
       if ((*src)[i] == '\0') {
         *src = nullptr;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     } else {
       r = mbrtowc(dst + o, *src + i, nmc - i, state);
       if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
         *src += i;
-        return reset_and_return_illegal(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
         *src += nmc;
-        return reset_and_return(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == 0) {
         *src = NULL;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     }
   }
   *src += i;
-  return reset_and_return(o, state);
+  return mbstate_reset_and_return(o, state);
 }
 
 size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) {
@@ -149,7 +149,7 @@
   mbstate_t* state = (ps == NULL) ? &__private_state : ps;
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   char buf[MB_LEN_MAX];
@@ -210,25 +210,3 @@
 size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps) {
   return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
 }
-
-int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
-  return wcscoll(ws1, ws2);
-}
-
-size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
-  return wcsxfrm(dest, src, n);
-}
-
-long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
-                    locale_t) {
-  return wcstoll(nptr, endptr, base);
-}
-
-unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
-                              int base, locale_t) {
-  return wcstoull(nptr, endptr, base);
-}
-
-long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
-  return wcstold(nptr, endptr);
-}
diff --git a/libc/bionic/wchar_l.cpp b/libc/bionic/wchar_l.cpp
new file mode 100644
index 0000000..6c39e8d
--- /dev/null
+++ b/libc/bionic/wchar_l.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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 <wchar.h>
+#include <xlocale.h>
+
+int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
+  return wcscasecmp(ws1, ws2);
+}
+
+int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
+  return wcsncasecmp(ws1, ws2, n);
+}
+
+int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
+  return wcscoll(ws1, ws2);
+}
+
+size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
+  return wcsxfrm(dest, src, n);
+}
+
+long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
+                    locale_t) {
+  return wcstoll(nptr, endptr, base);
+}
+
+unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
+                              int base, locale_t) {
+  return wcstoull(nptr, endptr, base);
+}
+
+long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
+  return wcstold(nptr, endptr);
+}
diff --git a/libc/bionic/wctype.cpp b/libc/bionic/wctype.cpp
index 8e2acef..05b6e19 100644
--- a/libc/bionic/wctype.cpp
+++ b/libc/bionic/wctype.cpp
@@ -53,12 +53,6 @@
   WC_TYPE_MAX
 };
 
-static bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int)) {
-  typedef UBool (*FnT)(UChar32, UProperty);
-  static auto u_hasBinaryProperty = reinterpret_cast<FnT>(__find_icu_symbol("u_hasBinaryProperty"));
-  return u_hasBinaryProperty ? u_hasBinaryProperty(wc, property) : fallback(wc);
-}
-
 int iswalnum(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_ALNUM, isalnum); }
 int iswalpha(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_ALPHABETIC, isalpha); }
 int iswblank(wint_t wc) { return __icu_hasBinaryProperty(wc, UCHAR_POSIX_BLANK, isblank); }
@@ -155,10 +149,6 @@
   return wctype(property);
 }
 
-int wcwidth(wchar_t wc) {
-  return (wc > 0);
-}
-
 static wctrans_t wctrans_tolower = wctrans_t(1);
 static wctrans_t wctrans_toupper = wctrans_t(2);
 
diff --git a/libc/bionic/wcwidth.cpp b/libc/bionic/wcwidth.cpp
new file mode 100644
index 0000000..9676b5a
--- /dev/null
+++ b/libc/bionic/wcwidth.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 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 <wchar.h>
+
+#include "private/icu.h"
+
+int wcwidth(wchar_t wc) {
+  // Fast-path ASCII.
+  if (wc >= 0x20 && wc < 0x7f) return 1;
+
+  // ASCII NUL is a special case.
+  if (wc == 0) return 0;
+
+  // C0.
+  if (wc < ' ' || (wc >= 0x7f && wc <= 0xa0)) return -1;
+
+  // Now for the i18n part. This isn't defined or standardized, so a lot of the choices are
+  // pretty arbitrary. See https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c for more details.
+
+  // Fancy unicode control characters?
+  switch (__icu_charType(wc)) {
+   case -1:
+    // No icu4c available; give up.
+    return -1;
+   case U_CONTROL_CHAR:
+    return -1;
+   case U_NON_SPACING_MARK:
+   case U_ENCLOSING_MARK:
+   case U_FORMAT_CHAR:
+    return 0;
+  }
+  if (__icu_hasBinaryProperty(wc, UCHAR_DEFAULT_IGNORABLE_CODE_POINT, nullptr)) return 0;
+
+  // Medial and final jamo render as zero width when used correctly.
+  switch (__icu_getIntPropertyValue(wc, UCHAR_HANGUL_SYLLABLE_TYPE)) {
+   case U_HST_VOWEL_JAMO:
+   case U_HST_TRAILING_JAMO:
+    return 0;
+   case U_HST_LEADING_JAMO:
+   case U_HST_LV_SYLLABLE:
+   case U_HST_LVT_SYLLABLE:
+    return 2;
+  }
+
+  if (wc >= 0x3248 && wc <= 0x4dff) {
+    // Circled two-digit CJK "speed sign" numbers. EastAsianWidth is ambiguous,
+    // but wide makes more sense.
+    if (wc <= 0x324f) return 2;
+    // Hexagrams. EastAsianWidth is neutral, but wide seems better.
+    if (wc >= 0x4dc0) return 2;
+  }
+
+  // The EastAsianWidth property is at least defined by the Unicode standard!
+  switch (__icu_getIntPropertyValue(wc, UCHAR_EAST_ASIAN_WIDTH)) {
+   case U_EA_AMBIGUOUS:
+   case U_EA_HALFWIDTH:
+   case U_EA_NARROW:
+   case U_EA_NEUTRAL:
+    return 1;
+   case U_EA_FULLWIDTH:
+   case U_EA_WIDE:
+    return 2;
+  }
+
+  return 0;
+}
diff --git a/libc/include/android/api-level.h b/libc/include/android/api-level.h
index c83c18d..7e3aa99 100644
--- a/libc/include/android/api-level.h
+++ b/libc/include/android/api-level.h
@@ -41,6 +41,8 @@
 
 #ifndef __ANDROID_API__
 #define __ANDROID_API__ __ANDROID_API_FUTURE__
+#else
+#define __ANDROID_NDK__ 1
 #endif
 
 #define __ANDROID_API_G__ 9
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index 82186c7..e26e5f2 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -29,6 +29,8 @@
 #ifndef _ANDROID_LEGACY_STDLIB_INLINES_H_
 #define _ANDROID_LEGACY_STDLIB_INLINES_H_
 
+#include <errno.h>
+#include <float.h>
 #include <stdlib.h>
 #include <sys/cdefs.h>
 
@@ -36,10 +38,16 @@
 
 __BEGIN_DECLS
 
-__noreturn void _Exit(int) __RENAME(_exit);
-
-static __inline float strtof(const char *nptr, char **endptr) {
-  return (float)strtod(nptr, endptr);
+static __inline float strtof(const char* nptr, char** endptr) {
+  double d = strtod(nptr, endptr);
+  if (d > FLT_MAX) {
+    errno = ERANGE;
+    return __builtin_huge_valf();
+  } else if (d < -FLT_MAX) {
+    errno = ERANGE;
+    return -__builtin_huge_valf();
+  }
+  return __BIONIC_CAST(static_cast, float, d);
 }
 
 static __inline double atof(const char *nptr) { return (strtod(nptr, NULL)); }
diff --git a/libc/include/bits/lockf.h b/libc/include/bits/lockf.h
index c24f18b..a8e273e 100644
--- a/libc/include/bits/lockf.h
+++ b/libc/include/bits/lockf.h
@@ -39,11 +39,7 @@
 
 __BEGIN_DECLS
 
-#if defined(__USE_FILE_OFFSET64)
-int lockf(int, int, off_t) __RENAME(lockf64) __INTRODUCED_IN(24);
-#else
-int lockf(int, int, off_t) __INTRODUCED_IN(24);
-#endif
+int lockf(int, int, off_t) __RENAME_IF_FILE_OFFSET64(lockf64) __INTRODUCED_IN(24);
 int lockf64(int, int, off64_t) __INTRODUCED_IN(24);
 
 __END_DECLS
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
index c98022c..f27efdf 100644
--- a/libc/include/fcntl.h
+++ b/libc/include/fcntl.h
@@ -71,8 +71,7 @@
 
 int creat(const char*, mode_t);
 int creat64(const char*, mode_t) __INTRODUCED_IN(21);
-int openat(int, const char*, int, ...) __overloadable
-        __RENAME_CLANG(openat);
+int openat(int, const char*, int, ...) __overloadable __RENAME_CLANG(openat);
 int openat64(int, const char*, int, ...) __INTRODUCED_IN(21);
 int open(const char*, int, ...) __overloadable __RENAME_CLANG(open);
 int open64(const char*, int, ...) __INTRODUCED_IN(21);
@@ -80,17 +79,11 @@
 ssize_t tee(int, int, size_t, unsigned int) __INTRODUCED_IN(21);
 ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) __INTRODUCED_IN(21);
 
-#if defined(__USE_FILE_OFFSET64)
-int fallocate(int, int, off_t, off_t) __RENAME(fallocate64) __INTRODUCED_IN(21);
-int posix_fadvise(int, off_t, off_t, int) __RENAME(posix_fadvise64) __INTRODUCED_IN(21);
-int posix_fallocate(int, off_t, off_t) __RENAME(posix_fallocate64) __INTRODUCED_IN(21);
-#else
-int fallocate(int, int, off_t, off_t) __INTRODUCED_IN(21);
-int posix_fadvise(int, off_t, off_t, int) __INTRODUCED_IN(21);
-int posix_fallocate(int, off_t, off_t) __INTRODUCED_IN(21);
-#endif
+int fallocate(int, int, off_t, off_t) __RENAME_IF_FILE_OFFSET64(fallocate64) __INTRODUCED_IN(21);
 int fallocate64(int, int, off64_t, off64_t) __INTRODUCED_IN(21);
+int posix_fadvise(int, off_t, off_t, int) __RENAME_IF_FILE_OFFSET64(posix_fadvise64) __INTRODUCED_IN(21);
 int posix_fadvise64(int, off64_t, off64_t, int) __INTRODUCED_IN(21);
+int posix_fallocate(int, off_t, off_t) __RENAME_IF_FILE_OFFSET64(posix_fallocate64) __INTRODUCED_IN(21);
 int posix_fallocate64(int, off64_t, off64_t) __INTRODUCED_IN(21);
 
 #if defined(__USE_GNU)
diff --git a/libc/include/limits.h b/libc/include/limits.h
index 157f7a6..51f4fad 100644
--- a/libc/include/limits.h
+++ b/libc/include/limits.h
@@ -137,6 +137,8 @@
 #include <bits/posix_limits.h>
 
 #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#define LOGIN_NAME_MAX 256
+#define TTY_NAME_MAX 32
 
 #define _POSIX_VERSION 200809L
 #define _POSIX2_VERSION _POSIX_VERSION
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index 3cd8ad1..24ddd99 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -225,12 +225,12 @@
 // Implemented as static inlines before 21.
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_FUTURE__
+#if __ANDROID_API__ >= __ANDROID_API_O__
 double strtod_l(const char*, char**, locale_t) __INTRODUCED_IN(26);
 float strtof_l(const char*, char**, locale_t) __INTRODUCED_IN(26);
 long strtol_l(const char*, char**, int, locale_t) __INTRODUCED_IN(26);
 #else
-// Implemented as static inlines.
+// Implemented as static inlines before 26.
 #endif
 
 __END_DECLS
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index d62206d..dd5b345 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -235,10 +235,16 @@
 #endif
 
 /* _FILE_OFFSET_BITS 64 support. */
-#if !defined(__LP64__) && defined(_FILE_OFFSET_BITS)
-#if _FILE_OFFSET_BITS == 64
+#if !defined(__LP64__) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
 #define __USE_FILE_OFFSET64 1
-#endif
+/*
+ * Note that __RENAME_IF_FILE_OFFSET64 is only valid if the off_t and off64_t
+ * functions were both added at the same API level because if you use this,
+ * you only have one declaration to attach __INTRODUCED_IN to.
+ */
+#define __RENAME_IF_FILE_OFFSET64(func) __RENAME(func)
+#else
+#define __RENAME_IF_FILE_OFFSET64(func)
 #endif
 
 #define  __BIONIC__   1
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
index 2611774..b166277 100644
--- a/libc/include/sys/uio.h
+++ b/libc/include/sys/uio.h
@@ -38,13 +38,8 @@
 ssize_t writev(int, const struct iovec*, int);
 
 #if defined(__USE_GNU)
-#if defined(__USE_FILE_OFFSET64)
-ssize_t preadv(int, const struct iovec*, int, off_t) __RENAME(preadv64) __INTRODUCED_IN(24);
-ssize_t pwritev(int, const struct iovec*, int, off_t) __RENAME(pwritev64) __INTRODUCED_IN(24);
-#else
-ssize_t preadv(int, const struct iovec*, int, off_t) __INTRODUCED_IN(24);
-ssize_t pwritev(int, const struct iovec*, int, off_t) __INTRODUCED_IN(24);
-#endif
+ssize_t preadv(int, const struct iovec*, int, off_t) __RENAME_IF_FILE_OFFSET64(preadv64) __INTRODUCED_IN(24);
+ssize_t pwritev(int, const struct iovec*, int, off_t) __RENAME_IF_FILE_OFFSET64(pwritev64) __INTRODUCED_IN(24);
 ssize_t preadv64(int, const struct iovec*, int, off64_t) __INTRODUCED_IN(24);
 ssize_t pwritev64(int, const struct iovec*, int, off64_t) __INTRODUCED_IN(24);
 #endif
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index e024527..8336976 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -118,6 +118,7 @@
 int getresuid(uid_t* __ruid, uid_t* __euid, uid_t* __suid);
 int getresgid(gid_t* __rgid, gid_t* __egid, gid_t* __sgid);
 char* getlogin(void);
+int getlogin_r(char* __buffer, size_t __buffer_size) __INTRODUCED_IN_FUTURE;
 
 long fpathconf(int __fd, int __name);
 long pathconf(const char* __path, int __name);
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index a4212dd..45ca9eb 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1316,6 +1316,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     ___Unwind_Backtrace; # arm
@@ -1532,7 +1537,7 @@
     vfdprintf; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1554,4 +1559,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1238,6 +1238,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1271,4 +1276,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c271a57..8b1d6de 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1341,6 +1341,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     ___Unwind_Backtrace; # arm
@@ -1558,7 +1563,7 @@
     vfdprintf; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1580,4 +1585,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 214c7f5..256ca9e 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1300,6 +1300,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     __accept4; # arm x86 mips
@@ -1373,7 +1378,7 @@
     vfdprintf; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1395,4 +1400,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1238,6 +1238,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1271,4 +1276,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 145b64e..2ebc86c 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1298,6 +1298,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     __accept4; # arm x86 mips
@@ -1372,7 +1377,7 @@
     vfdprintf; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1394,4 +1399,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index bf0341a..ed1e82c 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1238,6 +1238,11 @@
     wctrans_l; # introduced=26
 } LIBC_N;
 
+LIBC_P {
+  global:
+    getlogin_r; # future
+} LIBC_O;
+
 LIBC_PRIVATE {
   global:
     android_getaddrinfofornet;
@@ -1249,7 +1254,7 @@
     free_malloc_leak_info;
     get_malloc_leak_info;
     gMallocLeakZygoteChild;
-} LIBC_O;
+} LIBC_P;
 
 LIBC_DEPRECATED {
   global:
@@ -1271,4 +1276,4 @@
     malloc_disable;
     malloc_enable;
     malloc_iterate;
-} LIBC_O;
+} LIBC_P;
diff --git a/libc/private/bionic_mbstate.h b/libc/private/bionic_mbstate.h
index 018b47c..292959a 100644
--- a/libc/private/bionic_mbstate.h
+++ b/libc/private/bionic_mbstate.h
@@ -43,11 +43,31 @@
 #define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
                          rv == __MB_ERR_INCOMPLETE_SEQUENCE)
 
-size_t mbstate_bytes_so_far(const mbstate_t* ps);
-void mbstate_set_byte(mbstate_t* ps, int i, char byte);
-uint8_t mbstate_get_byte(const mbstate_t* ps, int n);
-size_t reset_and_return_illegal(int _errno, mbstate_t* ps);
-size_t reset_and_return(int _return, mbstate_t* ps);
+static inline __wur size_t mbstate_bytes_so_far(const mbstate_t* ps) {
+  return
+      (ps->__seq[2] != 0) ? 3 :
+      (ps->__seq[1] != 0) ? 2 :
+      (ps->__seq[0] != 0) ? 1 : 0;
+}
+
+static inline void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
+  ps->__seq[i] = static_cast<uint8_t>(byte);
+}
+
+static inline __wur uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
+  return ps->__seq[n];
+}
+
+static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
+  errno = _errno;
+  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+  return __MB_ERR_ILLEGAL_SEQUENCE;
+}
+
+static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
+  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+  return _return;
+}
 
 __END_DECLS
 
diff --git a/libc/private/icu.h b/libc/private/icu.h
index 03fdf66..ae253fa 100644
--- a/libc/private/icu.h
+++ b/libc/private/icu.h
@@ -30,12 +30,14 @@
 #define _PRIVATE_ICU_H
 
 #include <stdint.h>
+#include <wchar.h>
 
 typedef int8_t UBool;
 typedef int32_t UChar32;
 
 enum UProperty {
   UCHAR_ALPHABETIC = 0,
+  UCHAR_DEFAULT_IGNORABLE_CODE_POINT = 5,
   UCHAR_LOWERCASE = 22,
   UCHAR_POSIX_ALNUM = 44,
   UCHAR_POSIX_BLANK = 45,
@@ -44,12 +46,39 @@
   UCHAR_POSIX_XDIGIT = 48,
   UCHAR_UPPERCASE = 30,
   UCHAR_WHITE_SPACE = 31,
+  UCHAR_EAST_ASIAN_WIDTH = 0x1004,
+  UCHAR_HANGUL_SYLLABLE_TYPE = 0x100b,
 };
 
 enum UCharCategory {
+  U_NON_SPACING_MARK = 6,
+  U_ENCLOSING_MARK = 7,
   U_CONTROL_CHAR = 15,
+  U_FORMAT_CHAR = 16,
 };
 
+enum UEastAsianWidth {
+  U_EA_NEUTRAL,
+  U_EA_AMBIGUOUS,
+  U_EA_HALFWIDTH,
+  U_EA_FULLWIDTH,
+  U_EA_NARROW,
+  U_EA_WIDE,
+};
+
+enum UHangulSyllableType {
+  U_HST_NOT_APPLICABLE,
+  U_HST_LEADING_JAMO,
+  U_HST_VOWEL_JAMO,
+  U_HST_TRAILING_JAMO,
+  U_HST_LV_SYLLABLE,
+  U_HST_LVT_SYLLABLE,
+};
+
+int8_t __icu_charType(wint_t wc);
+int32_t __icu_getIntPropertyValue(wint_t wc, UProperty property);
+bool __icu_hasBinaryProperty(wint_t wc, UProperty property, int (*fallback)(int));
+
 void* __find_icu_symbol(const char* symbol_name);
 
 #endif  // _PRIVATE_ICU_H
diff --git a/libc/seccomp/Android.bp b/libc/seccomp/Android.bp
index c341781..a75aa65 100644
--- a/libc/seccomp/Android.bp
+++ b/libc/seccomp/Android.bp
@@ -3,11 +3,17 @@
     srcs: [
         "seccomp_policy.cpp",
         "arm_policy.cpp",
+        "arm_global_policy.cpp",
         "arm64_policy.cpp",
+        "arm64_global_policy.cpp",
         "x86_policy.cpp",
+        "x86_global_policy.cpp",
         "x86_64_policy.cpp",
+        "x86_64_global_policy.cpp",
         "mips_policy.cpp",
+        "mips_global_policy.cpp",
         "mips64_policy.cpp",
+        "mips64_global_policy.cpp",
     ],
     export_include_dirs: ["include"],
     shared: {
diff --git a/libc/seccomp/arm64_global_policy.cpp b/libc/seccomp/arm64_global_policy.cpp
new file mode 100644
index 0000000..1a138b7
--- /dev/null
+++ b/libc/seccomp/arm64_global_policy.cpp
@@ -0,0 +1,43 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter arm64_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 0, 32),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 101, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 18, 27, 26), //setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|getcwd
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 42, 26, 25), //eventfd2|epoll_create1|epoll_ctl|epoll_pwait|dup|dup3|fcntl|inotify_init1|inotify_add_watch|inotify_rm_watch|ioctl|ioprio_set|ioprio_get|flock|mknodat|mkdirat|unlinkat|symlinkat|linkat|renameat|umount2|mount|pivot_root
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 59, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 24, 23), //statfs|fstatfs|truncate|ftruncate|fallocate|faccessat|chdir|fchdir|chroot|fchmod|fchmodat|fchownat|fchown|openat|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 99, 23, 22), //pipe2|quotactl|getdents64|lseek|read|write|readv|writev|pread64|pwrite64|preadv|pwritev|sendfile|pselect6|ppoll|signalfd4|vmsplice|splice|tee|readlinkat|newfstatat|fstat|sync|fsync|fdatasync|sync_file_range|timerfd_create|timerfd_settime|timerfd_gettime|utimensat|acct|capget|capset|personality|exit|exit_group|waitid|set_tid_address|unshare|futex
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 105, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 104, 20, 19), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 19, 18), //init_module|delete_module|timer_create|timer_gettime|timer_getoverrun|timer_settime|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|syslog|ptrace|sched_setparam|sched_setscheduler|sched_getscheduler|sched_getparam|sched_setaffinity|sched_getaffinity|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|restart_syscall|kill|tkill|tgkill|sigaltstack|rt_sigsuspend|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigreturn|setpriority|getpriority|reboot|setregid|setgid|setreuid|setuid|setresuid|getresuid|setresgid|getresgid|setfsuid|setfsgid|times|setpgid|getpgid|getsid|setsid|getgroups|setgroups|uname|sethostname|setdomainname|getrlimit|setrlimit|getrusage|umask|prctl|getcpu|gettimeofday|settimeofday|adjtimex|getpid|getppid|getuid|geteuid|getgid|getegid|gettid|sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 203, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 17, 16), //socket|socketpair|bind|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 16, 15), //connect|getsockname|getpeername|sendto|recvfrom|setsockopt|getsockopt|shutdown|sendmsg|recvmsg|readahead|brk|munmap|mremap|add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 266, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 240, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 226, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 225, 12, 11), //keyctl|clone|execve|mmap|fadvise64|swapon
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 234, 11, 10), //mprotect|msync|mlock|munlock|mlockall|munlockall|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 260, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 9, 8), //rt_tgsigqueueinfo|perf_event_open|accept4|recvmmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 8, 7), //wait4|prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 281, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 5, 4), //clock_adjtime|syncfs|setns|sendmmsg|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 4, 3), //finit_module|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 282, 2, 1), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 288, 1, 0), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t arm64_global_filter_size = sizeof(arm64_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/arm_global_policy.cpp b/libc/seccomp/arm_global_policy.cpp
new file mode 100644
index 0000000..2f9a122
--- /dev/null
+++ b/libc/seccomp/arm_global_policy.cpp
@@ -0,0 +1,143 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter arm_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 132),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 65, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 33, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 124, 123), //restart_syscall|exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 123, 122), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 122, 121), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 22, 120, 119), //lseek|getpid|mount
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 119, 118), //getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 116, 115), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 115, 114), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 113, 112), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 112, 111), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 108, 107), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 107, 106), //acct|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 105, 104), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 104, 103), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 62, 101, 100), //umask|chroot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 100, 99), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 98, 97), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 97, 96), //sethostname|setrlimit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 87, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 80, 92, 91), //getrusage|gettimeofday|settimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 91, 90), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 89, 88), //swapon|reboot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 88, 87), //munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 103, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 85, 84), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 84, 83), //getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 82, 81), //syslog|setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 81, 80), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 77, 76), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 76, 75), //fsync|sigreturn|clone|setdomainname|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 74, 73), //adjtimex|mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 73, 72), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 138, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 70, 69), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 69, 68), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 67, 66), //setfsuid|setfsgid|_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 66, 65), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 309, 33, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 248, 17, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 213, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 59, 58), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 58, 57), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 57, 56), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 55, 54), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 54, 53), //getuid32|getgid32|geteuid32|getegid32|setreuid32|setregid32|getgroups32|setgroups32|fchown32|setresuid32|getresuid32|setresgid32|getresgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 219, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 215, 51, 50), //setuid32|setgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 50, 49), //getdents64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 48, 47), //mincore|madvise|fcntl64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 243, 47, 46), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill|sendfile64|futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 249, 43, 42), //exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 42, 41), //epoll_create|epoll_ctl|epoll_wait|remap_file_pages
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 270, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 269, 40, 39), //set_tid_address|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|statfs64|fstatfs64|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 39, 38), //arm_fadvise64_64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 290, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 286, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 36, 35), //waitid|socket|bind|connect|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 289, 35, 34), //getsockname|getpeername|socketpair
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 292, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 33, 32), //sendto
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 298, 32, 31), //recvfrom|shutdown|setsockopt|getsockopt|sendmsg|recvmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 350, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 327, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 316, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 311, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 310, 27, 26), //add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 26, 25), //keyctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 319, 24, 23), //inotify_init|inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 326, 23, 22), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 338, 20, 19), //fstatat64|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 344, 19, 18), //splice|sync_file_range2|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 348, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 347, 17, 16), //getcpu|epoll_pwait
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 16, 15), //utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 387, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 372, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 369, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 367, 12, 11), //timerfd_create|eventfd|fallocate|timerfd_settime|timerfd_gettime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|recvmmsg|accept4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 370, 11, 10), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 379, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 378, 9, 8), //clock_adjtime|syncfs|sendmmsg|setns|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 386, 8, 7), //finit_module|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983042, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 390, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 388, 5, 4), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 394, 4, 3), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983045, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983043, 2, 1), //__ARM_NR_cacheflush
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983046, 1, 0), //__ARM_NR_set_tls
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t arm_global_filter_size = sizeof(arm_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/include/seccomp_policy.h b/libc/seccomp/include/seccomp_policy.h
index 397f8e4..e337dec 100644
--- a/libc/seccomp/include/seccomp_policy.h
+++ b/libc/seccomp/include/seccomp_policy.h
@@ -21,6 +21,7 @@
 #include <linux/filter.h>
 
 bool set_seccomp_filter();
+bool set_global_seccomp_filter();
 void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size);
 
 #endif
diff --git a/libc/seccomp/mips64_global_policy.cpp b/libc/seccomp/mips64_global_policy.cpp
new file mode 100644
index 0000000..004eda2
--- /dev/null
+++ b/libc/seccomp/mips64_global_policy.cpp
@@ -0,0 +1,97 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter mips64_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5000, 0, 86),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5168, 43, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5077, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5034, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5008, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5005, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5003, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5002, 79, 78), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5004, 78, 77), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5006, 77, 76), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5031, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5023, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5020, 74, 73), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5028, 73, 72), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5032, 72, 71), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5057, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5043, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5038, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5037, 68, 67), //nanosleep|getitimer|setitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5042, 67, 66), //getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5056, 66, 65), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5070, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5062, 64, 63), //execve|exit|wait4|kill|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5076, 63, 62), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5134, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5093, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5091, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5089, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5080, 58, 57), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5090, 57, 56), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5092, 56, 55), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5132, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5110, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5109, 53, 52), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid|syslog|getgid|setuid|setgid|geteuid|getegid|setpgid|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5130, 52, 51), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5133, 51, 50), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5153, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5151, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5137, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5136, 47, 46), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5150, 46, 45), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5152, 45, 44), //pivot_root
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5164, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5163, 43, 42), //prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2|swapon
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5167, 42, 41), //reboot|sethostname|setdomainname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5244, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5211, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5194, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5178, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5172, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5170, 36, 35), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5173, 35, 34), //quotactl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5193, 34, 33), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5208, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5205, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5198, 31, 30), //futex|sched_setaffinity|sched_getaffinity|cacheflush
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5206, 30, 29), //exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5209, 29, 28), //epoll_ctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5239, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5237, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5215, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5214, 25, 24), //rt_sigreturn|set_tid_address|restart_syscall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5226, 24, 23), //fadvise64|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5238, 23, 22), //waitid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5241, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5240, 21, 20), //add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5243, 20, 19), //keyctl|set_thread_area
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5297, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5271, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5252, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5247, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5246, 15, 14), //inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5251, 14, 13), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5267, 13, 12), //newfstatat|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5279, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5276, 11, 10), //getcpu|epoll_pwait|ioprio_set|ioprio_get|utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5295, 10, 9), //fallocate|timerfd_create|timerfd_gettime|timerfd_settime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|accept4|recvmmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5316, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5307, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5300, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5298, 6, 5), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5306, 5, 4), //clock_adjtime|syncfs|sendmmsg|setns|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5315, 4, 3), //finit_module|getdents64|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5319, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5317, 2, 1), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5323, 1, 0), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t mips64_global_filter_size = sizeof(mips64_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/mips_global_policy.cpp b/libc/seccomp/mips_global_policy.cpp
new file mode 100644
index 0000000..b4fa23d
--- /dev/null
+++ b/libc/seccomp/mips_global_policy.cpp
@@ -0,0 +1,125 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter mips_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4001, 0, 114),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4136, 57, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4066, 29, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4041, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4023, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4010, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4008, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4007, 107, 106), //exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4009, 106, 105), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4019, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4013, 104, 103), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4022, 103, 102), //lseek|getpid|mount
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4033, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4026, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4025, 100, 99), //setuid|getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4027, 99, 98), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4036, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4034, 97, 96), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4040, 96, 95), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4057, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4049, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4045, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4044, 92, 91), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4048, 91, 90), //brk|setgid|getgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4054, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4053, 89, 88), //geteuid|getegid|acct|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4056, 88, 87), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4063, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4060, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4058, 85, 84), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4062, 84, 83), //umask|chroot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4065, 83, 82), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4103, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4087, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4074, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4070, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4068, 78, 77), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4072, 77, 76), //setreuid|setregid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4085, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4082, 75, 74), //sethostname|setrlimit|getrlimit|getrusage|gettimeofday|settimeofday|getgroups|setgroups
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4086, 74, 73), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4094, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4090, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4089, 71, 70), //swapon|reboot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4093, 70, 69), //mmap|munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4098, 69, 68), //fchmod|fchown|getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4124, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4116, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4114, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4106, 65, 64), //syslog|setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4115, 64, 63), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4118, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4117, 62, 61), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4123, 61, 60), //fsync|sigreturn|clone|setdomainname|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4131, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4128, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4126, 58, 57), //adjtimex|mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4130, 57, 56), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4134, 56, 55), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4248, 27, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4188, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4169, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4151, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4138, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4137, 50, 49), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4148, 49, 48), //setfsuid|setfsgid|_llseek|getdents|_newselect|flock|msync|readv|writev|cacheflush
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4154, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4153, 47, 46), //getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4168, 46, 45), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4179, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4176, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4175, 43, 42), //bind|connect|getpeername|getsockname|getsockopt|listen
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4178, 42, 41), //recvfrom|recvmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4187, 41, 40), //sendmsg|sendto|setsockopt|shutdown|socket|socketpair|setresuid|getresuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4217, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4203, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4190, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4189, 37, 36), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4202, 36, 35), //setresgid|getresgid|prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4210, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4208, 34, 33), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4216, 33, 32), //mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4246, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4222, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4221, 30, 29), //mincore|madvise|getdents64|fcntl64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4241, 29, 28), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill|sendfile64|futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4247, 28, 27), //exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4316, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4288, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4280, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4278, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4267, 23, 22), //epoll_create|epoll_ctl|epoll_wait|remap_file_pages|set_tid_address|restart_syscall|fadvise64|statfs64|fstatfs64|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4279, 22, 21), //waitid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4282, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4281, 20, 19), //add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4287, 19, 18), //keyctl|set_thread_area|inotify_init|inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4312, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4293, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4292, 16, 15), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4308, 15, 14), //fstatat64|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare|splice|sync_file_range|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4314, 14, 13), //getcpu|epoll_pwait
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4348, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4338, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4319, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4317, 10, 9), //utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4336, 9, 8), //eventfd|fallocate|timerfd_create|timerfd_gettime|timerfd_settime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|accept4|recvmmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4341, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4339, 7, 6), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4347, 6, 5), //clock_adjtime|syncfs|sendmmsg|setns|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4359, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4356, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4355, 3, 2), //finit_module|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4357, 2, 1), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4363, 1, 0), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t mips_global_filter_size = sizeof(mips_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/seccomp_bpfs.h b/libc/seccomp/seccomp_bpfs.h
index 96e127e..a8f47ca 100644
--- a/libc/seccomp/seccomp_bpfs.h
+++ b/libc/seccomp/seccomp_bpfs.h
@@ -22,15 +22,27 @@
 
 extern const struct sock_filter arm_filter[];
 extern const size_t arm_filter_size;
+extern const struct sock_filter arm_global_filter[];
+extern const size_t arm_global_filter_size;
 extern const struct sock_filter arm64_filter[];
 extern const size_t arm64_filter_size;
+extern const struct sock_filter arm64_global_filter[];
+extern const size_t arm64_global_filter_size;
 extern const struct sock_filter x86_filter[];
 extern const size_t x86_filter_size;
+extern const struct sock_filter x86_global_filter[];
+extern const size_t x86_global_filter_size;
 extern const struct sock_filter x86_64_filter[];
 extern const size_t x86_64_filter_size;
+extern const struct sock_filter x86_64_global_filter[];
+extern const size_t x86_64_global_filter_size;
 extern const struct sock_filter mips_filter[];
 extern const size_t mips_filter_size;
+extern const struct sock_filter mips_global_filter[];
+extern const size_t mips_global_filter_size;
 extern const struct sock_filter mips64_filter[];
 extern const size_t mips64_filter_size;
+extern const struct sock_filter mips64_global_filter[];
+extern const size_t mips64_global_filter_size;
 
 #endif
diff --git a/libc/seccomp/seccomp_policy.cpp b/libc/seccomp/seccomp_policy.cpp
index fe83af0..19ef299 100644
--- a/libc/seccomp/seccomp_policy.cpp
+++ b/libc/seccomp/seccomp_policy.cpp
@@ -34,9 +34,13 @@
 #define PRIMARY_ARCH AUDIT_ARCH_AARCH64
 static const struct sock_filter* primary_filter = arm64_filter;
 static const size_t primary_filter_size = arm64_filter_size;
+static const struct sock_filter* primary_global_filter = arm64_global_filter;
+static const size_t primary_global_filter_size = arm64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_ARM
 static const struct sock_filter* secondary_filter = arm_filter;
 static const size_t secondary_filter_size = arm_filter_size;
+static const struct sock_filter* secondary_global_filter = arm_global_filter;
+static const size_t secondary_global_filter_size = arm_global_filter_size;
 
 #elif defined __i386__ || defined __x86_64__
 
@@ -44,9 +48,13 @@
 #define PRIMARY_ARCH AUDIT_ARCH_X86_64
 static const struct sock_filter* primary_filter = x86_64_filter;
 static const size_t primary_filter_size = x86_64_filter_size;
+static const struct sock_filter* primary_global_filter = x86_64_global_filter;
+static const size_t primary_global_filter_size = x86_64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_I386
 static const struct sock_filter* secondary_filter = x86_filter;
 static const size_t secondary_filter_size = x86_filter_size;
+static const struct sock_filter* secondary_global_filter = x86_global_filter;
+static const size_t secondary_global_filter_size = x86_global_filter_size;
 
 #elif defined __mips__ || defined __mips64__
 
@@ -54,9 +62,13 @@
 #define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
 static const struct sock_filter* primary_filter = mips64_filter;
 static const size_t primary_filter_size = mips64_filter_size;
+static const struct sock_filter* primary_global_filter = mips64_global_filter;
+static const size_t primary_global_filter_size = mips64_global_filter_size;
 #define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
 static const struct sock_filter* secondary_filter = mips_filter;
 static const size_t secondary_filter_size = mips_filter_size;
+static const struct sock_filter* secondary_global_filter = mips_global_filter;
+static const size_t secondary_global_filter_size = mips_global_filter_size;
 
 #else
 #error No architecture was defined!
@@ -119,9 +131,23 @@
     return true;
 }
 
-bool set_seccomp_filter() {
+bool _set_seccomp_filter(bool global) {
+    const sock_filter *p, *s;
+    size_t p_size, s_size;
     filter f;
 
+    if (global) {
+        p = primary_global_filter;
+        p_size = primary_global_filter_size;
+        s = secondary_global_filter;
+        s_size = secondary_global_filter_size;
+    } else {
+        p = primary_filter;
+        p_size = primary_filter_size;
+        s = secondary_filter;
+        s_size = secondary_filter_size;
+    }
+
 #ifdef DUAL_ARCH
     // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
     // jump that must be changed to point to the start of the 32-bit policy
@@ -133,8 +159,8 @@
 
     ExamineSyscall(f);
 
-    for (size_t i = 0; i < primary_filter_size; ++i) {
-        f.push_back(primary_filter[i]);
+    for (size_t i = 0; i < p_size; ++i) {
+        f.push_back(p[i]);
     }
     Disallow(f);
 
@@ -145,8 +171,8 @@
 
     ExamineSyscall(f);
 
-    for (size_t i = 0; i < secondary_filter_size; ++i) {
-        f.push_back(secondary_filter[i]);
+    for (size_t i = 0; i < s_size; ++i) {
+        f.push_back(s[i]);
     }
     Disallow(f);
 #endif
@@ -154,6 +180,14 @@
     return install_filter(f);
 }
 
+bool set_seccomp_filter() {
+    return _set_seccomp_filter(false);
+}
+
+bool set_global_seccomp_filter() {
+    return _set_seccomp_filter(true);
+}
+
 void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size) {
 #if defined __aarch64__ || defined __x86_64__ || defined __mips64__
     filter = primary_filter;
diff --git a/libc/seccomp/x86_64_global_policy.cpp b/libc/seccomp/x86_64_global_policy.cpp
new file mode 100644
index 0000000..71be1c1
--- /dev/null
+++ b/libc/seccomp/x86_64_global_policy.cpp
@@ -0,0 +1,97 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter x86_64_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 86),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 175, 43, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 79, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 35, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 5, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 79, 78), //read|write
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 78, 77), //close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 6, 77, 76), //fstat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 32, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 21, 74, 73), //lseek|mmap|mprotect|munmap|brk|rt_sigaction|rt_sigprocmask|rt_sigreturn|ioctl|pread64|pwrite64|readv|writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 29, 73, 72), //sched_yield|mremap|msync|mincore|madvise
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 72, 71), //dup
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 38, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 37, 68, 67), //nanosleep|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 43, 67, 66), //setitimer|getpid|sendfile|socket|connect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 66, 65), //sendto|recvfrom|sendmsg|recvmsg|shutdown|bind|listen|getsockname|getpeername|socketpair|setsockopt|getsockopt|clone
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 72, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 64, 64, 63), //vfork|execve|exit|wait4|kill|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 78, 63, 62), //fcntl|flock|fsync|fdatasync|truncate|ftruncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 91, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 82, 58, 57), //getcwd|chdir|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 92, 57, 56), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 56, 55), //fchown
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 135, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 112, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 111, 53, 52), //umask|gettimeofday|getrlimit|getrusage|sysinfo|times|ptrace|getuid|syslog|getgid|setuid|setgid|geteuid|getegid|setpgid|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 132, 52, 51), //setsid|setreuid|setregid|getgroups|setgroups|setresuid|getresuid|setresgid|getresgid|getpgid|setfsuid|setfsgid|getsid|capget|capset|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|sigaltstack
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 51, 50), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 157, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 155, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 139, 47, 46), //statfs|fstatfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 153, 46, 45), //getpriority|setpriority|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|mlock|munlock|mlockall|munlockall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 156, 45, 44), //pivot_root
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 43, 42), //prctl|arch_prctl|adjtimex|setrlimit|chroot|sync|acct|settimeofday|mount|umount2|swapon
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 42, 41), //reboot|sethostname|setdomainname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 262, 21, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 233, 11, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 202, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 186, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 179, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 177, 36, 35), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 180, 35, 34), //quotactl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 201, 34, 33), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 221, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 217, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 205, 31, 30), //futex|sched_setaffinity|sched_getaffinity
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 220, 30, 29), //getdents64|set_tid_address|restart_syscall
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 232, 29, 28), //fadvise64|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 250, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 247, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 235, 25, 24), //epoll_ctl|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 249, 24, 23), //waitid|add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 23, 22), //keyctl|ioprio_set|ioprio_get
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 257, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 21, 20), //inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 261, 20, 19), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 302, 9, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 283, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 280, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 275, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 15, 14), //newfstatat|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 279, 14, 13), //splice|tee|sync_file_range|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 282, 13, 12), //utimensat|epoll_pwait
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 11, 10), //timerfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 10, 9), //fallocate|timerfd_settime|timerfd_gettime|accept4|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open|recvmmsg
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 5, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 313, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 305, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 303, 6, 5), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 312, 5, 4), //clock_adjtime|syncfs|sendmmsg|setns|getcpu|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 320, 4, 3), //finit_module|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 325, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 323, 2, 1), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 329, 1, 0), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t x86_64_global_filter_size = sizeof(x86_64_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/seccomp/x86_global_policy.cpp b/libc/seccomp/x86_global_policy.cpp
new file mode 100644
index 0000000..36f4884
--- /dev/null
+++ b/libc/seccomp/x86_global_policy.cpp
@@ -0,0 +1,129 @@
+// Autogenerated file - edit at your peril!!
+
+#include <linux/filter.h>
+#include <errno.h>
+
+#include "seccomp_bpfs.h"
+const sock_filter x86_global_filter[] = {
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 0, 0, 118),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 136, 59, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 66, 29, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 41, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 24, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 10, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 8, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 7, 111, 110), //restart_syscall|exit|fork|read|write|open|close
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 9, 110, 109), //creat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 19, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 13, 108, 107), //unlink|execve|chdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 22, 107, 106), //lseek|getpid|mount
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 33, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 26, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 25, 104, 103), //getuid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 27, 103, 102), //ptrace
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 36, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 34, 101, 100), //access
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 40, 100, 99), //sync|kill|rename|mkdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 57, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 51, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 45, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 44, 96, 95), //dup|pipe|times
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 46, 95, 94), //brk
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 54, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 53, 93, 92), //acct|umount2
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 56, 92, 91), //ioctl|fcntl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 63, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 60, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 58, 89, 88), //setpgid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 62, 88, 87), //umask|chroot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 65, 87, 86), //dup2|getppid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 102, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 87, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 77, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 74, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 68, 82, 81), //setsid|sigaction
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 76, 81, 80), //sethostname|setrlimit
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 85, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 80, 79, 78), //getrusage|gettimeofday|settimeofday
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 86, 78, 77), //readlink
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 94, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 90, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 89, 75, 74), //swapon|reboot
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 93, 74, 73), //mmap|munmap|truncate
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 96, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 95, 72, 71), //fchmod
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 98, 71, 70), //getpriority|setpriority
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 124, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 116, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 114, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 106, 67, 66), //socketcall|syslog|setitimer|getitimer
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 115, 66, 65), //wait4
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 118, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 117, 64, 63), //sysinfo
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 123, 63, 62), //fsync|sigreturn|clone|setdomainname|uname
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 131, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 128, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 126, 60, 59), //adjtimex|mprotect
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 130, 59, 58), //init_module|delete_module
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 134, 58, 57), //quotactl|getpgid|fchdir
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 286, 29, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 213, 15, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 172, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 150, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 138, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 137, 52, 51), //personality
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 149, 51, 50), //setfsuid|setfsgid|_llseek|getdents|_newselect|flock|msync|readv|writev|getsid|fdatasync
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 168, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 164, 49, 48), //mlock|munlock|mlockall|munlockall|sched_setparam|sched_getparam|sched_setscheduler|sched_getscheduler|sched_yield|sched_get_priority_max|sched_get_priority_min|sched_rr_get_interval|nanosleep|mremap
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 169, 48, 47), //poll
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 190, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 183, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 182, 45, 44), //prctl|rt_sigreturn|rt_sigaction|rt_sigprocmask|rt_sigpending|rt_sigtimedwait|rt_sigqueueinfo|rt_sigsuspend|pread64|pwrite64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 188, 44, 43), //getcwd|capget|capset|sigaltstack|sendfile
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 199, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 198, 42, 41), //vfork|ugetrlimit|mmap2|truncate64|ftruncate64|stat64|lstat64|fstat64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 212, 41, 40), //getuid32|getgid32|geteuid32|getegid32|setreuid32|setregid32|getgroups32|setgroups32|fchown32|setresuid32|getresuid32|setresgid32|getresgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 254, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 224, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 218, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 215, 37, 36), //setuid32|setgid32
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 222, 36, 35), //mincore|madvise|getdents64|fcntl64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 252, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 244, 34, 33), //gettid|readahead|setxattr|lsetxattr|fsetxattr|getxattr|lgetxattr|fgetxattr|listxattr|llistxattr|flistxattr|removexattr|lremovexattr|fremovexattr|tkill|sendfile64|futex|sched_setaffinity|sched_getaffinity|set_thread_area
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 253, 33, 32), //exit_group
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 284, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 271, 30, 29), //epoll_create|epoll_ctl|epoll_wait|remap_file_pages|set_tid_address|timer_create|timer_settime|timer_gettime|timer_getoverrun|timer_delete|clock_settime|clock_gettime|clock_getres|clock_nanosleep|statfs64|fstatfs64|tgkill
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 273, 29, 28), //fadvise64_64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 285, 28, 27), //waitid
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 322, 13, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 300, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 291, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 288, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 287, 23, 22), //add_key
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 289, 22, 21), //keyctl
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 295, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 294, 20, 19), //inotify_init|inotify_add_watch|inotify_rm_watch
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 299, 19, 18), //openat|mkdirat|mknodat|fchownat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 318, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 313, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 311, 16, 15), //fstatat64|unlinkat|renameat|linkat|symlinkat|readlinkat|fchmodat|faccessat|pselect6|ppoll|unshare
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 317, 15, 14), //splice|sync_file_range|tee|vmsplice
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 321, 14, 13), //getcpu|epoll_pwait|utimensat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 350, 7, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 343, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 340, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 337, 10, 9), //timerfd_create|eventfd|fallocate|timerfd_settime|timerfd_gettime|signalfd4|eventfd2|epoll_create1|dup3|pipe2|inotify_init1|preadv|pwritev|rt_tgsigqueueinfo|perf_event_open
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 341, 9, 8), //prlimit64
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 346, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 345, 7, 6), //clock_adjtime|syncfs
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 349, 6, 5), //setns|process_vm_readv|process_vm_writev
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 376, 3, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 358, 1, 0),
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 357, 3, 2), //finit_module|sched_setattr|sched_getattr|renameat2|seccomp|getrandom|memfd_create
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 359, 2, 1), //execveat
+BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 380, 1, 0), //mlock2|copy_file_range|preadv2|pwritev2
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+};
+
+const size_t x86_global_filter_size = sizeof(x86_global_filter) / sizeof(struct sock_filter);
diff --git a/libc/stdio/fmemopen.cpp b/libc/stdio/fmemopen.cpp
new file mode 100644
index 0000000..9d8c41f
--- /dev/null
+++ b/libc/stdio/fmemopen.cpp
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "local.h"
+
+// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fmemopen.html
+// and http://man7.org/linux/man-pages/man3/fmemopen.3.html for documentation.
+
+struct fmemopen_cookie {
+  char* buf;
+  char* allocation;
+  size_t capacity;
+  size_t size;
+  size_t offset;
+  bool append;
+};
+
+static int fmemopen_read(void* cookie, char* buf, int n) {
+  fmemopen_cookie* ck = static_cast<fmemopen_cookie*>(cookie);
+
+  if (static_cast<size_t>(n) > ck->size - ck->offset) n = ck->size - ck->offset;
+
+  if (n > 0) {
+    memmove(buf, ck->buf + ck->offset, n);
+    ck->offset += n;
+  }
+  return n;
+}
+
+static int fmemopen_write(void* cookie, const char* buf, int n) {
+  fmemopen_cookie* ck = static_cast<fmemopen_cookie*>(cookie);
+
+  // We don't need to add the trailing NUL if there's already a trailing NUL
+  // in the data we're writing.
+  size_t space_for_null = (n > 0 && buf[n - 1] != '\0') ? 1 : 0;
+
+  // Undo any seeking/reading on an append-only stream.
+  if (ck->append) ck->offset = ck->size;
+
+  // How much can we actually fit?
+  if (static_cast<size_t>(n) + space_for_null > ck->capacity - ck->offset) {
+    n = ck->capacity - ck->offset - space_for_null;
+    // Give up if we don't even have room for one byte of userdata.
+    if (n <= 0) {
+      errno = ENOSPC;
+      return -1;
+    }
+  }
+
+  if (n > 0) {
+    memmove(ck->buf + ck->offset, buf, n);
+    ck->offset += n;
+    // Is this the furthest we've ever been?
+    if (ck->offset >= ck->size) {
+      if (buf[n - 1] != '\0') ck->buf[ck->offset] = '\0';
+      ck->size = ck->offset;
+    }
+  }
+  return n;
+}
+
+static fpos_t fmemopen_seek(void* cookie, fpos_t offset, int whence) {
+  fmemopen_cookie* ck = static_cast<fmemopen_cookie*>(cookie);
+
+  if (whence == SEEK_SET && (offset >= 0 && static_cast<size_t>(offset) <= ck->capacity)) {
+    return (ck->offset = offset);
+  } else if (whence == SEEK_CUR && (ck->offset + offset <= ck->capacity)) {
+    return (ck->offset += offset);
+  } else if (whence == SEEK_END && (offset <= 0 && static_cast<size_t>(-offset) <= ck->size)) {
+    return (ck->offset = ck->size + offset);
+  }
+  errno = EINVAL;
+  return -1;
+}
+
+static int fmemopen_close(void* cookie) {
+  fmemopen_cookie* ck = static_cast<fmemopen_cookie*>(cookie);
+  free(ck->allocation);
+  free(ck);
+  return 0;
+}
+
+FILE* fmemopen(void* buf, size_t capacity, const char* mode) {
+  int flags;
+  if (__sflags(mode, &flags) == 0) {
+    errno = EINVAL;
+    return nullptr;
+  }
+
+  fmemopen_cookie* ck = static_cast<fmemopen_cookie*>(calloc(sizeof(fmemopen_cookie), 1));
+  if (ck == nullptr) return nullptr;
+
+  ck->buf = static_cast<char*>(buf);
+  ck->capacity = capacity;
+
+  if (ck->buf == nullptr) ck->buf = ck->allocation = static_cast<char*>(calloc(capacity, 1));
+  if (ck->buf == nullptr) {
+    free(ck);
+    return nullptr;
+  }
+
+  FILE* fp = funopen(ck,
+                     (flags & O_WRONLY) ? nullptr : fmemopen_read,
+                     (flags & O_RDONLY) ? nullptr : fmemopen_write,
+                     fmemopen_seek,
+                     fmemopen_close);
+  if (fp == nullptr) {
+    fmemopen_close(ck);
+    return nullptr;
+  }
+
+  if (mode[0] == 'a') {
+    ck->size = strnlen(ck->buf, ck->capacity);
+    ck->offset = ck->size;
+    ck->append = true;
+  } else if (mode[0] == 'r') {
+    ck->size = capacity;
+    ck->offset = 0;
+  } else if (mode[0] == 'w') {
+    ck->size = 0;
+    ck->offset = 0;
+    ck->buf[0] = '\0';
+  }
+
+  return fp;
+}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 575a428..afb02ca 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -134,7 +134,7 @@
 #define __SEOF 0x0020  // Found EOF.
 #define __SERR 0x0040  // Found error.
 #define __SMBF 0x0080  // `_buf` is from malloc.
-#define __SAPP 0x0100  // fdopen()ed in append mode.
+// #define __SAPP 0x0100 --- historical (fdopen()ed in append mode).
 #define __SSTR 0x0200  // This is an sprintf/snprintf string.
 // #define __SOPT 0x0400 --- historical (do fseek() optimization).
 // #define __SNPT 0x0800 --- historical (do not do fseek() optimization).
@@ -143,7 +143,7 @@
 #define __SALC 0x4000  // Allocate string space dynamically.
 #define __SIGN 0x8000  // Ignore this file in _fwalk.
 
-// TODO: remove remaining references to these obsolete flags.
+// TODO: remove remaining references to these obsolete flags (see above).
 #define __SNPT 0
 #define __SOPT 0
 
@@ -224,15 +224,6 @@
 	_UB(fp)._base = NULL; \
 }
 
-/*
- * test for an fgetln() buffer.
- */
-#define	HASLB(fp) ((fp)->_lb._base != NULL)
-#define	FREELB(fp) { \
-	free((char *)(fp)->_lb._base); \
-	(fp)->_lb._base = NULL; \
-}
-
 #define FLOCKFILE(fp)   if (!_EXT(fp)->_caller_handles_locking) flockfile(fp)
 #define FUNLOCKFILE(fp) if (!_EXT(fp)->_caller_handles_locking) funlockfile(fp)
 
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index b0f5c60..4d6438b 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -68,14 +68,8 @@
 
 _THREAD_PRIVATE_MUTEX(__sfp_mutex);
 
-// TODO: when we no longer have to support both clang and GCC, we can simplify all this.
-#define SBUF_INIT {0,0}
-#if defined(__LP64__)
-#define MBSTATE_T_INIT {{0},{0}}
-#else
-#define MBSTATE_T_INIT {{0}}
-#endif
-#define WCHAR_IO_DATA_INIT {MBSTATE_T_INIT,MBSTATE_T_INIT,{0},0,0}
+#define SBUF_INIT {}
+#define WCHAR_IO_DATA_INIT {}
 
 static struct __sfileext __sFext[3] = {
   { SBUF_INIT, WCHAR_IO_DATA_INIT, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, false, __sseek64 },
@@ -132,6 +126,13 @@
   return g;
 }
 
+static inline void free_fgetln_buffer(FILE* fp) {
+  if (__predict_false(fp->_lb._base != nullptr)) {
+    free(fp->_lb._base);
+    fp->_lb._base = nullptr;
+  }
+}
+
 /*
  * Find a free FILE for fopen et al.
  */
@@ -205,11 +206,11 @@
 }
 
 FILE* fopen(const char* file, const char* mode) {
-  int oflags;
-  int flags = __sflags(mode, &oflags);
+  int mode_flags;
+  int flags = __sflags(mode, &mode_flags);
   if (flags == 0) return nullptr;
 
-  int fd = open(file, oflags, DEFFILEMODE);
+  int fd = open(file, mode_flags, DEFFILEMODE);
   if (fd == -1) {
     return nullptr;
   }
@@ -221,41 +222,34 @@
     return nullptr;
   }
 
-  // When opening in append mode, even though we use O_APPEND,
-  // we need to seek to the end so that ftell() gets the right
-  // answer.  If the user then alters the seek pointer, or
-  // the file extends, this will fail, but there is not much
-  // we can do about this.  (We could set __SAPP and check in
-  // fseek and ftell.)
-  // TODO: check in __sseek instead.
-  if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
-
+  // For append mode, even though we use O_APPEND, we need to seek to the end now.
+  if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
   return fp;
 }
 __strong_alias(fopen64, fopen);
 
 FILE* fdopen(int fd, const char* mode) {
-  int oflags;
-  int flags = __sflags(mode, &oflags);
+  int mode_flags;
+  int flags = __sflags(mode, &mode_flags);
   if (flags == 0) return nullptr;
 
   // Make sure the mode the user wants is a subset of the actual mode.
-  int fdflags = fcntl(fd, F_GETFL, 0);
-  if (fdflags < 0) return nullptr;
-  int tmp = fdflags & O_ACCMODE;
-  if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
+  int fd_flags = fcntl(fd, F_GETFL, 0);
+  if (fd_flags == -1) return nullptr;
+  int tmp = fd_flags & O_ACCMODE;
+  if (tmp != O_RDWR && (tmp != (mode_flags & O_ACCMODE))) {
     errno = EINVAL;
     return nullptr;
   }
 
-  // If opened for appending, but underlying descriptor does not have
-  // O_APPEND bit set, assert __SAPP so that __swrite() will lseek to
-  // end before each write.
-  // TODO: use fcntl(2) to set O_APPEND instead.
-  if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) flags |= __SAPP;
+  // Make sure O_APPEND is set on the underlying fd if our mode has 'a'.
+  // POSIX says we just take the current offset of the underlying fd.
+  if ((mode_flags & O_APPEND) && !(fd_flags & O_APPEND)) {
+    if (fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) return nullptr;
+  }
 
-  // If close-on-exec was requested, then turn it on if not already.
-  if ((oflags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
+  // Make sure O_CLOEXEC is set on the underlying fd if our mode has 'x'.
+  if ((mode_flags & O_CLOEXEC) && !((tmp = fcntl(fd, F_GETFD)) & FD_CLOEXEC)) {
     fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
   }
 
@@ -267,8 +261,8 @@
 // all possible, no matter what.
 // TODO: rewrite this mess completely.
 FILE* freopen(const char* file, const char* mode, FILE* fp) {
-  int oflags;
-  int flags = __sflags(mode, &oflags);
+  int mode_flags;
+  int flags = __sflags(mode, &mode_flags);
   if (flags == 0) {
     fclose(fp);
     return nullptr;
@@ -300,13 +294,13 @@
   }
 
   // Get a new descriptor to refer to the new file.
-  int fd = open(file, oflags, DEFFILEMODE);
+  int fd = open(file, mode_flags, DEFFILEMODE);
   if (fd < 0 && isopen) {
     // If out of fd's close the old one and try again.
     if (errno == ENFILE || errno == EMFILE) {
       (*fp->_close)(fp->_cookie);
       isopen = 0;
-      fd = open(file, oflags, DEFFILEMODE);
+      fd = open(file, mode_flags, DEFFILEMODE);
     }
   }
 
@@ -326,7 +320,7 @@
   if (HASUB(fp)) FREEUB(fp);
   _UB(fp)._size = 0;
   WCIO_FREE(fp);
-  if (HASLB(fp)) FREELB(fp);
+  free_fgetln_buffer(fp);
   fp->_lb._size = 0;
 
   if (fd < 0) { // Did not get it after all.
@@ -339,7 +333,7 @@
   // to maintain the descriptor.  Various C library routines (perror)
   // assume stderr is always fd STDERR_FILENO, even if being freopen'd.
   if (wantfd >= 0 && fd != wantfd) {
-    if (dup3(fd, wantfd, oflags & O_CLOEXEC) >= 0) {
+    if (dup3(fd, wantfd, mode_flags & O_CLOEXEC) >= 0) {
       close(fd);
       fd = wantfd;
     }
@@ -360,13 +354,8 @@
   fp->_close = __sclose;
   _EXT(fp)->_seek64 = __sseek64;
 
-  // When opening in append mode, even though we use O_APPEND,
-  // we need to seek to the end so that ftell() gets the right
-  // answer.  If the user then alters the seek pointer, or
-  // the file extends, this will fail, but there is not much
-  // we can do about this.  (We could set __SAPP and check in
-  // fseek and ftell.)
-  if (oflags & O_APPEND) __sseek64(fp, 0, SEEK_END);
+  // For append mode, even though we use O_APPEND, we need to seek to the end now.
+  if ((mode_flags & O_APPEND) != 0) __sseek64(fp, 0, SEEK_END);
   return fp;
 }
 __strong_alias(freopen64, freopen);
@@ -386,7 +375,7 @@
   }
   if (fp->_flags & __SMBF) free(fp->_bf._base);
   if (HASUB(fp)) FREEUB(fp);
-  if (HASLB(fp)) FREELB(fp);
+  free_fgetln_buffer(fp);
 
   // Poison this FILE so accesses after fclose will be obvious.
   fp->_file = -1;
@@ -445,12 +434,6 @@
 
 int __swrite(void* cookie, const char* buf, int n) {
   FILE* fp = reinterpret_cast<FILE*>(cookie);
-  if (fp->_flags & __SAPP) {
-    // The FILE* is in append mode, but the underlying fd doesn't have O_APPEND set.
-    // We need to seek manually.
-    // TODO: use fcntl(2) to set O_APPEND in fdopen(3) instead?
-    TEMP_FAILURE_RETRY(lseek64(fp->_file, 0, SEEK_END));
-  }
   return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
 }
 
@@ -489,6 +472,7 @@
 static off64_t __ftello64_unlocked(FILE* fp) {
   // Find offset of underlying I/O object, then adjust for buffered bytes.
   __sflush(fp);  // May adjust seek offset on append stream.
+
   off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
   if (result == -1) {
     return -1;
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 6573644..d40891c 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -14,17 +14,33 @@
 import tarfile
 import tempfile
 
-def IsUninteresting(path):
-    path = path.lower()
-    if path.endswith(".mk") or path.endswith(".py") or path.endswith(".pyc") or path.endswith(".txt") or path.endswith(".3") or path.endswith(".swp"):
-        return True
-    if path.endswith("/notice") or path.endswith("/readme") or path.endswith("/caveats"):
-        return True
-    if path.endswith("/tzdata") or path.endswith("/zoneinfo/generate"):
-        return True
-    return False
+VERBOSE = False
 
-def IsAutoGenerated(content):
+def warn(s):
+    sys.stderr.write("warning: %s\n" % s)
+
+def warn_verbose(s):
+    if VERBOSE:
+        warn(s)
+
+def is_interesting(path):
+    path = path.lower()
+    uninteresting_extensions = [
+        ".bp",
+        ".map",
+        ".mk",
+        ".py",
+        ".pyc",
+        ".swp",
+        ".txt",
+    ]
+    if os.path.splitext(path)[1] in uninteresting_extensions:
+        return False
+    if path.endswith("/notice") or path.endswith("/readme"):
+        return False
+    return True
+
+def is_auto_generated(content):
     if "Generated by gensyscalls.py" in content or "generated by genserv.py" in content:
         return True
     if "This header was automatically generated from a Linux kernel header" in content:
@@ -33,7 +49,7 @@
 
 copyrights = set()
 
-def ExtractCopyrightAt(lines, i):
+def extract_copyright_at(lines, i):
     hash = lines[i].startswith("#")
 
     # Do we need to back up to find the start of the copyright header?
@@ -100,13 +116,42 @@
 
     return i
 
-args = sys.argv[1:]
-if len(args) == 0:
-    args = [ "." ]
 
-for arg in args:
-    sys.stderr.write('Searching for source files in "%s"...\n' % arg)
+def do_file(path):
+    with open(path, "r") as the_file:
+        try:
+            content = open(path, "r").read().decode("utf-8")
+        except UnicodeDecodeError:
+            warn("bad UTF-8 in %s" % path)
+            content = open(path, "r").read().decode("iso-8859-1")
 
+    lines = content.split("\n")
+
+    if len(lines) <= 4:
+        warn_verbose("ignoring short file %s" % path)
+        return
+
+    if is_auto_generated(content):
+        warn_verbose("ignoring auto-generated file %s" % path)
+        return
+
+    if not "Copyright" in content:
+        if "public domain" in content.lower():
+            warn("ignoring public domain file %s" % path)
+            return
+        warn('no copyright notice found in "%s" (%d lines)' % (path, len(lines)))
+        return
+
+    # Manually iterate because extract_copyright_at tells us how many lines to skip.
+    i = 0
+    while i < len(lines):
+        if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
+            i = extract_copyright_at(lines, i)
+        else:
+            i += 1
+
+
+def do_dir(path):
     for directory, sub_directories, filenames in os.walk(arg):
         if ".git" in sub_directories:
             sub_directories.remove(".git")
@@ -114,45 +159,24 @@
 
         for filename in sorted(filenames):
             path = os.path.join(directory, filename)
-            if IsUninteresting(path):
-                #print "ignoring uninteresting file %s" % path
-                continue
+            if is_interesting(path):
+                do_file(path)
 
-            try:
-                content = open(path, 'r').read().decode('utf-8')
-            except:
-                sys.stderr.write('warning: bad UTF-8 in %s\n' % path)
-                content = open(path, 'r').read().decode('iso-8859-1')
 
-            lines = content.split("\n")
+args = sys.argv[1:]
+if len(args) == 0:
+    args = [ "." ]
 
-            if len(lines) <= 4:
-                #print "ignoring short file %s" % path
-                continue
-
-            if IsAutoGenerated(content):
-                #print "ignoring auto-generated file %s" % path
-                continue
-
-            if not "Copyright" in content:
-                if "public domain" in content.lower():
-                    #print "ignoring public domain file %s" % path
-                    continue
-                sys.stderr.write('warning: no copyright notice found in "%s" (%d lines)\n' % (path, len(lines)))
-                continue
-
-            i = 0
-            while i < len(lines):
-                if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
-                    i = ExtractCopyrightAt(lines, i)
-                i += 1
-
-            #print path
+for arg in args:
+    if os.path.isdir(arg):
+        do_dir(arg)
+    else:
+        do_file(arg)
 
 for copyright in sorted(copyrights):
-    print copyright.encode('utf-8')
+    print copyright.encode("utf-8")
     print
-    print '-------------------------------------------------------------------'
+    print "-------------------------------------------------------------------"
     print
 
 sys.exit(0)
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index 79968ae..f3a232e 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -26,7 +26,7 @@
     self.names.append(name)
 
 
-def get_names(syscall_files, architecture):
+def get_names(syscall_files, architecture, global_policy):
   syscall_lists = []
   for syscall_file in syscall_files:
     parser = SysCallsTxtParser()
@@ -34,6 +34,11 @@
     syscall_lists.append(parser.syscalls)
 
   bionic, whitelist, blacklist = syscall_lists[0], syscall_lists[1], syscall_lists[2]
+  if global_policy:
+    global_whitelist = syscall_lists[-1]
+  else:
+    global_whitelist = []
+
   for x in blacklist:
     if not x in bionic:
       raise RuntimeError("Blacklist item not in bionic - aborting " + str(x))
@@ -42,7 +47,7 @@
       raise RuntimeError("Blacklist item in whitelist - aborting " + str(x))
 
   bionic_minus_blacklist = [x for x in bionic if x not in blacklist]
-  syscalls = bionic_minus_blacklist + whitelist
+  syscalls = bionic_minus_blacklist + whitelist + global_whitelist
 
   # Select only elements matching required architecture
   syscalls = [x for x in syscalls if architecture in x and x[architecture]]
@@ -170,7 +175,8 @@
   return bpf
 
 
-def convert_bpf_to_output(bpf, architecture):
+def convert_bpf_to_output(bpf, architecture, global_policy):
+  suffix = "global_" if global_policy else ""
   header = textwrap.dedent("""\
     // Autogenerated file - edit at your peril!!
 
@@ -178,24 +184,25 @@
     #include <errno.h>
 
     #include "seccomp_bpfs.h"
-    const sock_filter {architecture}_filter[] = {{
-    """).format(architecture=architecture)
+    const sock_filter {architecture}_{suffix}filter[] = {{
+    """).format(architecture=architecture,suffix=suffix)
 
   footer = textwrap.dedent("""\
 
     }};
 
-    const size_t {architecture}_filter_size = sizeof({architecture}_filter) / sizeof(struct sock_filter);
-    """).format(architecture=architecture)
+    const size_t {architecture}_{suffix}filter_size = sizeof({architecture}_{suffix}filter) / sizeof(struct sock_filter);
+    """).format(architecture=architecture,suffix=suffix)
   return header + "\n".join(bpf) + footer
 
 
-def construct_bpf(syscall_files, architecture, header_dir, extra_switches):
-  names = get_names(syscall_files, architecture)
+def construct_bpf(syscall_files, architecture, header_dir, extra_switches,
+                  global_policy):
+  names = get_names(syscall_files, architecture, global_policy)
   syscalls = convert_names_to_NRs(names, header_dir, extra_switches)
   ranges = convert_NRs_to_ranges(syscalls)
   bpf = convert_ranges_to_bpf(ranges)
-  return convert_bpf_to_output(bpf, architecture)
+  return convert_bpf_to_output(bpf, architecture, global_policy)
 
 
 ANDROID_SYSCALL_FILES = ["SYSCALLS.TXT",
@@ -216,15 +223,18 @@
   os.chdir(os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc"))
 
 
-def main():
-  set_dir()
+def gen_policy(global_policy):
+  if global_policy:
+    ANDROID_SYSCALL_FILES.append("SECCOMP_WHITELIST_GLOBAL.TXT")
+
   for arch, header_path, switches in POLICY_CONFIGS:
     files = [open(filename) for filename in ANDROID_SYSCALL_FILES]
-    output = construct_bpf(files, arch, header_path, switches)
+    output = construct_bpf(files, arch, header_path, switches, global_policy)
 
     # And output policy
     existing = ""
-    output_path = "seccomp/{}_policy.cpp".format(arch)
+    global_string = "_global" if global_policy else ""
+    output_path = "seccomp/{}{}_policy.cpp".format(arch, global_string)
     if os.path.isfile(output_path):
       existing = open(output_path).read()
     if output == existing:
@@ -234,5 +244,11 @@
         output_file.write(output)
       print "Generated file " + output_path
 
+
+def main():
+  set_dir()
+  gen_policy(False)
+  gen_policy(True)
+
 if __name__ == "__main__":
   main()
diff --git a/libc/upstream-openbsd/lib/libc/compat-43/killpg.c b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
similarity index 65%
rename from libc/upstream-openbsd/lib/libc/compat-43/killpg.c
rename to libc/upstream-freebsd/lib/libc/string/wcsstr.c
index 75b1ad9..ce598a6 100644
--- a/libc/upstream-openbsd/lib/libc/compat-43/killpg.c
+++ b/libc/upstream-freebsd/lib/libc/string/wcsstr.c
@@ -1,6 +1,9 @@
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,19 +30,34 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
 
 /*
- * Backwards-compatible killpg().
+ * Find the first occurrence of find in s.
  */
-int
-killpg(pid_t pgid, int sig)
+wchar_t *
+wcsstr(const wchar_t * __restrict s, const wchar_t * __restrict find)
 {
-	if (pgid == 1) {
-		errno = ESRCH;
-		return (-1);
+	wchar_t c, sc;
+	size_t len;
+
+	if ((c = *find++) != L'\0') {
+		len = wcslen(find);
+		do {
+			do {
+				if ((sc = *s++) == L'\0')
+					return (NULL);
+			} while (sc != c);
+		} while (wcsncmp(s, find, len) != 0);
+		s--;
 	}
-	return (kill(-pgid, sig));
+	return ((wchar_t *)s);
 }
diff --git a/libc/upstream-openbsd/lib/libc/string/wmemcpy.c b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
similarity index 84%
rename from libc/upstream-openbsd/lib/libc/string/wmemcpy.c
rename to libc/upstream-freebsd/lib/libc/string/wmemcpy.c
index 9bbd836..c10770c 100644
--- a/libc/upstream-openbsd/lib/libc/string/wmemcpy.c
+++ b/libc/upstream-freebsd/lib/libc/string/wmemcpy.c
@@ -1,6 +1,3 @@
-/*	$OpenBSD: wmemcpy.c,v 1.3 2005/08/08 08:05:37 espie Exp $	*/
-/*	$NetBSD: wmemcpy.c,v 1.2 2001/01/03 14:29:37 lukem Exp $	*/
-
 /*-
  * Copyright (c)1999 Citrus Project,
  * All rights reserved.
@@ -29,12 +26,19 @@
  *	citrus Id: wmemcpy.c,v 1.2 2000/12/20 14:08:31 itojun Exp
  */
 
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemcpy.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
 #include <string.h>
 #include <wchar.h>
 
 wchar_t *
-wmemcpy(wchar_t *d, const wchar_t *s, size_t n)
+wmemcpy(wchar_t * __restrict d, const wchar_t * __restrict s, size_t n)
 {
-
 	return (wchar_t *)memcpy(d, s, n * sizeof(wchar_t));
 }
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index bec860b..baf5057 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -22,6 +22,11 @@
 #include <sys/cdefs.h>
 #include <stddef.h> // For size_t.
 
+#define __BEGIN_HIDDEN_DECLS _Pragma("GCC visibility push(hidden)")
+#define __END_HIDDEN_DECLS _Pragma("GCC visibility pop")
+
+extern const char* __progname;
+
 /* Redirect internal C library calls to the public function. */
 #define _err err
 #define _errx errx
@@ -35,6 +40,7 @@
 /* Ignore all DEF_STRONG/DEF_WEAK in OpenBSD. */
 #define DEF_STRONG(sym)
 #define DEF_WEAK(sym)
+#define __weak_alias __strong_alias
 
 /* Ignore all __warn_references in OpenBSD. */
 #define __warn_references(sym,msg)
diff --git a/libc/upstream-openbsd/lib/libc/crypt/arc4random.c b/libc/upstream-openbsd/lib/libc/crypt/arc4random.c
index 64248b6..8a4ecc9 100644
--- a/libc/upstream-openbsd/lib/libc/crypt/arc4random.c
+++ b/libc/upstream-openbsd/lib/libc/crypt/arc4random.c
@@ -1,9 +1,10 @@
-/*	$OpenBSD: arc4random.c,v 1.50 2014/07/21 18:13:12 deraadt Exp $	*/
+/*	$OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $	*/
 
 /*
  * Copyright (c) 1996, David Mazieres <dm@uun.org>
  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
  * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -30,18 +31,18 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
-#include <sys/param.h>
 #include <sys/time.h>
 
 #define KEYSTREAM_ONLY
 #include "chacha_private.h"
 
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#ifdef __GNUC__
+#define minimum(a, b) ((a) < (b) ? (a) : (b))
+
+#if defined(__GNUC__) || defined(_MSC_VER)
 #define inline __inline
-#else				/* !__GNUC__ */
+#else				/* __GNUC__ || _MSC_VER */
 #define inline
-#endif				/* !__GNUC__ */
+#endif				/* !__GNUC__ && !_MSC_VER */
 
 #define KEYSZ	32
 #define IVSZ	8
@@ -127,7 +128,7 @@
 	if (dat) {
 		size_t i, m;
 
-		m = min(datlen, KEYSZ + IVSZ);
+		m = minimum(datlen, KEYSZ + IVSZ);
 		for (i = 0; i < m; i++)
 			rsx->rs_buf[i] ^= dat[i];
 	}
@@ -147,7 +148,7 @@
 	_rs_stir_if_needed(n);
 	while (n > 0) {
 		if (rs->rs_have > 0) {
-			m = min(n, rs->rs_have);
+			m = minimum(n, rs->rs_have);
 			keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
 			    - rs->rs_have;
 			memcpy(buf, keystream, m);
@@ -185,6 +186,7 @@
 	_ARC4_UNLOCK();
 	return val;
 }
+DEF_WEAK(arc4random);
 
 void
 arc4random_buf(void *buf, size_t n)
@@ -193,3 +195,4 @@
 	_rs_random_buf(buf, n);
 	_ARC4_UNLOCK();
 }
+DEF_WEAK(arc4random_buf);
diff --git a/libc/upstream-openbsd/lib/libc/crypt/arc4random_uniform.c b/libc/upstream-openbsd/lib/libc/crypt/arc4random_uniform.c
index 1aa9a62..23a15e3 100644
--- a/libc/upstream-openbsd/lib/libc/crypt/arc4random_uniform.c
+++ b/libc/upstream-openbsd/lib/libc/crypt/arc4random_uniform.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: arc4random_uniform.c,v 1.1 2014/07/12 13:24:54 deraadt Exp $	*/
+/*	$OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $	*/
 
 /*
  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
@@ -54,3 +54,4 @@
 
 	return r % upper_bound;
 }
+DEF_WEAK(arc4random_uniform);
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/dmisc.c b/libc/upstream-openbsd/lib/libc/gdtoa/dmisc.c
index a5795cf..f3d8ea7 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/dmisc.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/dmisc.c
@@ -104,6 +104,7 @@
 		dtoa_result = 0;
 #endif
 	}
+DEF_STRONG(freedtoa);
 
  int
 quorem
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/dtoa.c b/libc/upstream-openbsd/lib/libc/gdtoa/dtoa.c
index 668f7b5..c1c8724 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/dtoa.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/dtoa.c
@@ -837,3 +837,4 @@
 		*rve = s;
 	return s0;
 	}
+DEF_STRONG(dtoa);
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.c b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.c
index fd11de5..feae5af 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoa.c
@@ -827,3 +827,4 @@
 	*kindp |= inex;
 	return s0;
 	}
+DEF_STRONG(gdtoa);
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
index 7a36967..0f3de12 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/gdtoaimp.h
@@ -590,7 +590,7 @@
 			int *decpt, int *sign, char **rve));
  extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
  extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
- extern void hexdig_init_D2A(Void);
+ extern void __hexdig_init_D2A(Void);
  extern int hexnan ANSI((CONST char**, FPI*, ULong*));
  extern int hi0bits_D2A ANSI((ULong));
  extern Bigint *i2b ANSI((int));
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/gethex.c b/libc/upstream-openbsd/lib/libc/gdtoa/gethex.c
index 7ace0fa..f521f15 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/gethex.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/gethex.c
@@ -67,7 +67,7 @@
 #endif
 
 	if (!hexdig['0'])
-		hexdig_init_D2A();
+		__hexdig_init_D2A();
 	*bp = 0;
 	havedig = 0;
 	s0 = *(CONST unsigned char **)sp + 2;
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/hd_init.c b/libc/upstream-openbsd/lib/libc/gdtoa/hd_init.c
index fa6e18d..2227640 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/hd_init.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/hd_init.c
@@ -46,7 +46,7 @@
 	}
 
  void
-hexdig_init_D2A(Void)
+__hexdig_init_D2A(Void)
 {
 #define USC (unsigned char *)
 	htinit(hexdig, USC "0123456789", 0x10);
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/hdtoa.c b/libc/upstream-openbsd/lib/libc/gdtoa/hdtoa.c
index c62f6d5..45caef4 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/hdtoa.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/hdtoa.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: hdtoa.c,v 1.2 2009/10/16 12:15:03 martynas Exp $	*/
+/*	$OpenBSD: hdtoa.c,v 1.3 2015/09/14 12:49:33 guenther Exp $	*/
 /*-
  * Copyright (c) 2004, 2005 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
@@ -210,6 +210,7 @@
 
 	return (s0);
 }
+DEF_STRONG(__hdtoa);
 
 #if (LDBL_MANT_DIG > DBL_MANT_DIG)
 
@@ -319,6 +320,7 @@
 
 	return (s0);
 }
+DEF_STRONG(__hldtoa);
 
 #else	/* (LDBL_MANT_DIG == DBL_MANT_DIG) */
 
@@ -328,5 +330,6 @@
 {
 	return (__hdtoa((double)e, xdigs, ndigits, decpt, sign, rve));
 }
+DEF_STRONG(__hldtoa);
 
 #endif	/* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/hexnan.c b/libc/upstream-openbsd/lib/libc/gdtoa/hexnan.c
index a443721..b47d499 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/hexnan.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/hexnan.c
@@ -62,7 +62,7 @@
 	int havedig, hd0, i, nbits;
 
 	if (!hexdig['0'])
-		hexdig_init_D2A();
+		__hexdig_init_D2A();
 	nbits = fpi->nbits;
 	x = x0 + (nbits >> kshift);
 	if (nbits & kmask)
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/ldtoa.c b/libc/upstream-openbsd/lib/libc/gdtoa/ldtoa.c
index 16f6f9c..7282e7a 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/ldtoa.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/ldtoa.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ldtoa.c,v 1.2 2014/08/10 02:15:18 guenther Exp $	*/
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
 /*-
  * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
  * All rights reserved.
@@ -26,9 +26,7 @@
  */
 
 #include <sys/types.h>
-#ifndef __vax__
 #include <machine/ieee.h>
-#endif /* !__vax__ */
 #include <float.h>
 #include <stdint.h>
 #include <limits.h>
@@ -106,6 +104,7 @@
 		*decpt = INT_MAX;
 	return ret;
 }
+DEF_STRONG(__ldtoa);
 
 #else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
 
@@ -120,5 +119,6 @@
 		*decpt = INT_MAX;
 	return ret;
 }
+DEF_STRONG(__ldtoa);
 
 #endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/misc.c b/libc/upstream-openbsd/lib/libc/gdtoa/misc.c
index 6ad706b..b149f07 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/misc.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/misc.c
@@ -98,9 +98,9 @@
 	if (v) {
 		if (v->k > Kmax)
 #ifdef FREE
-			FREE((void*)v);
+			FREE(v);
 #else
-			free((void*)v);
+			free(v);
 #endif
 		else {
 			ACQUIRE_DTOA_LOCK(0);
@@ -876,6 +876,8 @@
 #endif
 		};
 
+#ifdef NO_STRING_H
+
  char *
 #ifdef KR_headers
 strcp_D2A(a, b) char *a; char *b;
@@ -888,8 +890,6 @@
 	return a;
 	}
 
-#ifdef NO_STRING_H
-
  Char *
 #ifdef KR_headers
 memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/strtod.c b/libc/upstream-openbsd/lib/libc/gdtoa/strtod.c
index ded47d8..ac2283c 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/strtod.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/strtod.c
@@ -1102,4 +1102,4 @@
 		*se = (char *)s;
 	return sign ? -dval(&rv) : dval(&rv);
 	}
-
+DEF_STRONG(strtod);
diff --git a/libc/upstream-openbsd/lib/libc/gdtoa/strtof.c b/libc/upstream-openbsd/lib/libc/gdtoa/strtof.c
index 224491b..914e218 100644
--- a/libc/upstream-openbsd/lib/libc/gdtoa/strtof.c
+++ b/libc/upstream-openbsd/lib/libc/gdtoa/strtof.c
@@ -79,3 +79,4 @@
 		u.L[0] |= 0x80000000L;
 	return u.f;
 	}
+DEF_STRONG(strtof);
diff --git a/libc/upstream-openbsd/lib/libc/gen/alarm.c b/libc/upstream-openbsd/lib/libc/gen/alarm.c
index 2af847a..8bca23a 100644
--- a/libc/upstream-openbsd/lib/libc/gen/alarm.c
+++ b/libc/upstream-openbsd/lib/libc/gen/alarm.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: alarm.c,v 1.7 2005/08/08 08:05:33 espie Exp $ */
+/*	$OpenBSD: alarm.c,v 1.8 2016/01/28 16:40:54 schwarze Exp $ */
 /*
  * Copyright (c) 1983, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -28,9 +28,6 @@
  * SUCH DAMAGE.
  */
 
-/*
- * Backwards compatible alarm.
- */
 #include <sys/time.h>
 #include <unistd.h>
 
diff --git a/libc/upstream-openbsd/lib/libc/gen/ctype_.c b/libc/upstream-openbsd/lib/libc/gen/ctype_.c
index 89c8257..8972244 100644
--- a/libc/upstream-openbsd/lib/libc/gen/ctype_.c
+++ b/libc/upstream-openbsd/lib/libc/gen/ctype_.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ctype_.c,v 1.10 2011/09/22 09:06:10 stsp Exp $ */
+/*	$OpenBSD: ctype_.c,v 1.12 2015/09/19 04:02:21 guenther Exp $ */
 /*
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
@@ -74,3 +74,6 @@
 };
 
 const char *_ctype_ = _C_ctype_;
+#if 0
+DEF_STRONG(_ctype_);
+#endif
diff --git a/libc/upstream-openbsd/lib/libc/gen/ftok.c b/libc/upstream-openbsd/lib/libc/gen/ftok.c
index f9d6621..387b80f 100644
--- a/libc/upstream-openbsd/lib/libc/gen/ftok.c
+++ b/libc/upstream-openbsd/lib/libc/gen/ftok.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ftok.c,v 1.7 2005/08/08 08:05:34 espie Exp $ */
+/*	$OpenBSD: ftok.c,v 1.8 2014/11/15 22:38:47 guenther Exp $ */
 /*
  * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
  * All rights reserved.
@@ -26,7 +26,6 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ipc.h>
 
diff --git a/libc/upstream-openbsd/lib/libc/gen/getprogname.c b/libc/upstream-openbsd/lib/libc/gen/getprogname.c
index 17046ab..a020830 100644
--- a/libc/upstream-openbsd/lib/libc/gen/getprogname.c
+++ b/libc/upstream-openbsd/lib/libc/gen/getprogname.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: getprogname.c,v 1.3 2013/11/12 06:09:48 deraadt Exp $ */
+/* $OpenBSD: getprogname.c,v 1.4 2016/03/13 18:34:20 guenther Exp $ */
 /*
  * Copyright (c) 2013 Antoine Jacoutot <ajacoutot@openbsd.org>
  *
@@ -17,8 +17,6 @@
 
 #include <stdlib.h>
 
-extern const char *__progname;
-
 const char *
 getprogname(void)
 {
diff --git a/libc/upstream-openbsd/lib/libc/gen/isctype.c b/libc/upstream-openbsd/lib/libc/gen/isctype.c
index 970b5e2..a4e944c 100644
--- a/libc/upstream-openbsd/lib/libc/gen/isctype.c
+++ b/libc/upstream-openbsd/lib/libc/gen/isctype.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: isctype.c,v 1.11 2005/08/08 08:05:34 espie Exp $ */
+/*	$OpenBSD: isctype.c,v 1.12 2015/09/13 11:38:08 guenther Exp $ */
 /*
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
@@ -43,6 +43,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & (_U|_L|_N)));
 }
+DEF_STRONG(isalnum);
 
 #undef isalpha
 int
@@ -50,6 +51,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & (_U|_L)));
 }
+DEF_STRONG(isalpha);
 
 #undef isblank
 int
@@ -57,6 +59,7 @@
 {
 	return (c == ' ' || c == '\t');
 }
+DEF_STRONG(isblank);
 
 #undef iscntrl
 int
@@ -64,6 +67,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _C));
 }
+DEF_STRONG(iscntrl);
 
 #undef isdigit
 int
@@ -71,6 +75,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _N));
 }
+DEF_STRONG(isdigit);
 
 #undef isgraph
 int
@@ -78,6 +83,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & (_P|_U|_L|_N)));
 }
+DEF_STRONG(isgraph);
 
 #undef islower
 int
@@ -85,6 +91,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _L));
 }
+DEF_STRONG(islower);
 
 #undef isprint
 int
@@ -92,6 +99,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & (_P|_U|_L|_N|_B)));
 }
+DEF_STRONG(isprint);
 
 #undef ispunct
 int
@@ -99,6 +107,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _P));
 }
+DEF_STRONG(ispunct);
 
 #undef isspace
 int
@@ -106,6 +115,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _S));
 }
+DEF_STRONG(isspace);
 
 #undef isupper
 int
@@ -113,6 +123,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & _U));
 }
+DEF_STRONG(isupper);
 
 #undef isxdigit
 int
@@ -120,6 +131,7 @@
 {
 	return (c == EOF ? 0 : ((_ctype_ + 1)[(unsigned char)c] & (_N|_X)));
 }
+DEF_STRONG(isxdigit);
 
 #undef isascii
 int
@@ -127,6 +139,7 @@
 {
 	return ((unsigned int)c <= 0177);
 }
+DEF_WEAK(isascii);
 
 #undef toascii
 int
diff --git a/libc/upstream-openbsd/lib/libc/gen/setprogname.c b/libc/upstream-openbsd/lib/libc/gen/setprogname.c
index 089a15a..ec3189f 100644
--- a/libc/upstream-openbsd/lib/libc/gen/setprogname.c
+++ b/libc/upstream-openbsd/lib/libc/gen/setprogname.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: setprogname.c,v 1.4 2013/11/12 06:09:48 deraadt Exp $ */
+/* $OpenBSD: setprogname.c,v 1.5 2016/03/13 18:34:20 guenther Exp $ */
 /*
  * Copyright (c) 2013 Antoine Jacoutot <ajacoutot@openbsd.org>
  *
@@ -18,8 +18,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-extern const char *__progname;
-
 void
 setprogname(const char *progname)
 {
diff --git a/libc/upstream-openbsd/lib/libc/gen/tolower_.c b/libc/upstream-openbsd/lib/libc/gen/tolower_.c
index 50dcc7b..2402c42 100644
--- a/libc/upstream-openbsd/lib/libc/gen/tolower_.c
+++ b/libc/upstream-openbsd/lib/libc/gen/tolower_.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tolower_.c,v 1.9 2005/08/08 08:05:34 espie Exp $ */
+/*	$OpenBSD: tolower_.c,v 1.11 2015/09/19 04:02:21 guenther Exp $ */
 /*
  * Written by J.T. Conklin <jtc@netbsd.org>.
  * Public domain.
@@ -46,6 +46,9 @@
 };
 
 const short *_tolower_tab_ = _C_tolower_;
+#if 0
+DEF_STRONG(_tolower_tab_);
+#endif
 
 #undef tolower
 int
@@ -55,3 +58,4 @@
 		return(c);
 	return((_tolower_tab_ + 1)[c]);
 }
+DEF_STRONG(tolower);
diff --git a/libc/upstream-openbsd/lib/libc/gen/toupper_.c b/libc/upstream-openbsd/lib/libc/gen/toupper_.c
index 4093199..8408f9e 100644
--- a/libc/upstream-openbsd/lib/libc/gen/toupper_.c
+++ b/libc/upstream-openbsd/lib/libc/gen/toupper_.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: toupper_.c,v 1.10 2005/08/09 08:36:48 kevlo Exp $ */
+/*	$OpenBSD: toupper_.c,v 1.12 2015/09/19 04:02:21 guenther Exp $ */
 /*
  * Written by J.T. Conklin <jtc@netbsd.org>.
  * Public domain.
@@ -47,6 +47,9 @@
 };
 
 const short *_toupper_tab_ = _C_toupper_;
+#if 0
+DEF_STRONG(_toupper_tab_);
+#endif
 
 #undef toupper
 int
@@ -56,3 +59,4 @@
 		return(c);
 	return((_toupper_tab_ + 1)[c]);
 }
+DEF_STRONG(toupper);
diff --git a/libc/upstream-openbsd/lib/libc/gen/verr.c b/libc/upstream-openbsd/lib/libc/gen/verr.c
index 8f4722b..b27b9ca 100644
--- a/libc/upstream-openbsd/lib/libc/gen/verr.c
+++ b/libc/upstream-openbsd/lib/libc/gen/verr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: verr.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
+/*	$OpenBSD: verr.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -35,8 +35,6 @@
 #include <string.h>
 #include <stdarg.h>
 
-extern char *__progname;		/* Program name, from crt0. */
-
 __dead void
 verr(int eval, const char *fmt, va_list ap)
 {
diff --git a/libc/upstream-openbsd/lib/libc/gen/verrx.c b/libc/upstream-openbsd/lib/libc/gen/verrx.c
index f0186b6..0c9308f 100644
--- a/libc/upstream-openbsd/lib/libc/gen/verrx.c
+++ b/libc/upstream-openbsd/lib/libc/gen/verrx.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: verrx.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
+/*	$OpenBSD: verrx.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -33,8 +33,6 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
-extern char *__progname;		/* Program name, from crt0. */
-
 __dead void
 verrx(int eval, const char *fmt, va_list ap)
 {
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarn.c b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
index 44d8be4..457d619 100644
--- a/libc/upstream-openbsd/lib/libc/gen/vwarn.c
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarn.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vwarn.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
+/*	$OpenBSD: vwarn.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -31,11 +31,10 @@
 #include <err.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 
-extern char *__progname;		/* Program name, from crt0. */
-
 void
 vwarn(const char *fmt, va_list ap)
 {
diff --git a/libc/upstream-openbsd/lib/libc/gen/vwarnx.c b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
index 67d8f5b..146e267 100644
--- a/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
+++ b/libc/upstream-openbsd/lib/libc/gen/vwarnx.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vwarnx.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
+/*	$OpenBSD: vwarnx.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,10 +30,9 @@
 
 #include <err.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <stdarg.h>
 
-extern char *__progname;		/* Program name, from crt0. */
-
 void
 vwarnx(const char *fmt, va_list ap)
 {
diff --git a/libc/upstream-openbsd/lib/libc/include/ctype_private.h b/libc/upstream-openbsd/lib/libc/include/ctype_private.h
index 39cc792..cbe1b20 100644
--- a/libc/upstream-openbsd/lib/libc/include/ctype_private.h
+++ b/libc/upstream-openbsd/lib/libc/include/ctype_private.h
@@ -1,7 +1,9 @@
-/* $OpenBSD: ctype_private.h,v 1.1 2005/08/08 05:53:00 espie Exp $ */
+/* $OpenBSD: ctype_private.h,v 1.2 2015/08/27 04:37:09 guenther Exp $ */
 /* Written by Marc Espie, public domain */
 #define CTYPE_NUM_CHARS       256
+
+__BEGIN_HIDDEN_DECLS
 extern const char _C_ctype_[];
 extern const short _C_toupper_[];
 extern const short _C_tolower_[];
-
+__END_HIDDEN_DECLS
diff --git a/libc/upstream-openbsd/lib/libc/locale/_wcstol.h b/libc/upstream-openbsd/lib/libc/locale/_wcstol.h
index 7b49bbf..1b60a3a 100644
--- a/libc/upstream-openbsd/lib/libc/locale/_wcstol.h
+++ b/libc/upstream-openbsd/lib/libc/locale/_wcstol.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: _wcstol.h,v 1.1 2005/07/01 08:59:27 espie Exp $	*/
+/*	$OpenBSD: _wcstol.h,v 1.3 2015/10/01 02:32:07 guenther Exp $	*/
 /* $NetBSD: _wcstol.h,v 1.2 2003/08/07 16:43:03 agc Exp $ */
 
 /*-
@@ -130,7 +130,7 @@
 		}
 	}
 	if (endptr != 0)
-		/* LINTED interface specification */
 		*endptr = (wchar_t *)(any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(FUNCNAME);
diff --git a/libc/upstream-openbsd/lib/libc/locale/_wcstoul.h b/libc/upstream-openbsd/lib/libc/locale/_wcstoul.h
index 736b38f..159b22b 100644
--- a/libc/upstream-openbsd/lib/libc/locale/_wcstoul.h
+++ b/libc/upstream-openbsd/lib/libc/locale/_wcstoul.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: _wcstoul.h,v 1.1 2005/07/01 08:59:27 espie Exp $	*/
+/*	$OpenBSD: _wcstoul.h,v 1.3 2015/10/01 02:32:07 guenther Exp $	*/
 /* $NetBSD: _wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp $ */
 
 /*
@@ -110,7 +110,7 @@
 	if (neg && any > 0)
 		acc = -acc;
 	if (endptr != 0)
-		/* LINTED interface specification */
 		*endptr = (wchar_t *)(any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(FUNCNAME);
diff --git a/libc/upstream-openbsd/lib/libc/locale/btowc.c b/libc/upstream-openbsd/lib/libc/locale/btowc.c
index 9627340..455b346 100644
--- a/libc/upstream-openbsd/lib/libc/locale/btowc.c
+++ b/libc/upstream-openbsd/lib/libc/locale/btowc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: btowc.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
+/*	$OpenBSD: btowc.c,v 1.3 2015/09/12 16:23:14 guenther Exp $ */
 
 /*-
  * Copyright (c) 2002, 2003 Tim J. Robbins.
@@ -50,3 +50,4 @@
 		return (WEOF);
 	return (wc);
 }
+DEF_STRONG(btowc);
diff --git a/libc/upstream-openbsd/lib/libc/locale/mbrlen.c b/libc/upstream-openbsd/lib/libc/locale/mbrlen.c
index 0f05bd0..52df61a 100644
--- a/libc/upstream-openbsd/lib/libc/locale/mbrlen.c
+++ b/libc/upstream-openbsd/lib/libc/locale/mbrlen.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: mbrlen.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
+/*	$OpenBSD: mbrlen.c,v 1.3 2015/09/12 16:23:14 guenther Exp $ */
 
 /*-
  * Copyright (c) 2002-2004 Tim J. Robbins.
@@ -37,3 +37,4 @@
 		ps = &mbs;
 	return (mbrtowc(NULL, s, n, ps));
 }
+DEF_STRONG(mbrlen);
diff --git a/libc/upstream-openbsd/lib/libc/locale/wctob.c b/libc/upstream-openbsd/lib/libc/locale/wctob.c
index ea1f40c..51ac355 100644
--- a/libc/upstream-openbsd/lib/libc/locale/wctob.c
+++ b/libc/upstream-openbsd/lib/libc/locale/wctob.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: wctob.c,v 1.2 2012/12/05 23:20:00 deraadt Exp $ */
+/*	$OpenBSD: wctob.c,v 1.3 2015/09/12 16:23:14 guenther Exp $ */
 /*-
  * Copyright (c) 2002-2004 Tim J. Robbins.
  * All rights reserved.
@@ -41,3 +41,4 @@
 		return (EOF);
 	return ((unsigned char)*buf);
 }
+DEF_STRONG(wctob);
diff --git a/libc/upstream-openbsd/lib/libc/locale/wctoint.h b/libc/upstream-openbsd/lib/libc/locale/wctoint.h
index c9bf084..ea50c5a 100644
--- a/libc/upstream-openbsd/lib/libc/locale/wctoint.h
+++ b/libc/upstream-openbsd/lib/libc/locale/wctoint.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: wctoint.h,v 1.1 2005/07/01 08:59:27 espie Exp $	*/
+/*	$OpenBSD: wctoint.h,v 1.2 2015/09/13 11:38:08 guenther Exp $	*/
 /* $NetBSD: __wctoint.h,v 1.1 2001/09/28 11:25:37 yamt Exp $ */
 
 /*-
@@ -30,7 +30,7 @@
  */
 
 
-__inline static int
+inline static int
 wctoint(wchar_t wc)
 {
 	int n;
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_lnaof.c b/libc/upstream-openbsd/lib/libc/net/inet_lnaof.c
index b1a58cd..9284538 100644
--- a/libc/upstream-openbsd/lib/libc/net/inet_lnaof.c
+++ b/libc/upstream-openbsd/lib/libc/net/inet_lnaof.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: inet_lnaof.c,v 1.6 2005/08/06 20:30:03 espie Exp $ */
+/*	$OpenBSD: inet_lnaof.c,v 1.7 2015/01/16 16:48:51 deraadt Exp $ */
 /*
  * Copyright (c) 1983, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -28,7 +28,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_makeaddr.c b/libc/upstream-openbsd/lib/libc/net/inet_makeaddr.c
index 87d9325..88ddd28 100644
--- a/libc/upstream-openbsd/lib/libc/net/inet_makeaddr.c
+++ b/libc/upstream-openbsd/lib/libc/net/inet_makeaddr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: inet_makeaddr.c,v 1.6 2005/08/06 20:30:03 espie Exp $ */
+/*	$OpenBSD: inet_makeaddr.c,v 1.7 2015/01/16 16:48:51 deraadt Exp $ */
 /*
  * Copyright (c) 1983, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -28,7 +28,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_netof.c b/libc/upstream-openbsd/lib/libc/net/inet_netof.c
index 2f468c3..4efceed 100644
--- a/libc/upstream-openbsd/lib/libc/net/inet_netof.c
+++ b/libc/upstream-openbsd/lib/libc/net/inet_netof.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: inet_netof.c,v 1.6 2005/08/06 20:30:03 espie Exp $ */
+/*	$OpenBSD: inet_netof.c,v 1.7 2015/01/16 16:48:51 deraadt Exp $ */
 /*
  * Copyright (c) 1983, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -28,7 +28,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_ntop.c b/libc/upstream-openbsd/lib/libc/net/inet_ntop.c
index f991a07..2bb11c2 100644
--- a/libc/upstream-openbsd/lib/libc/net/inet_ntop.c
+++ b/libc/upstream-openbsd/lib/libc/net/inet_ntop.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: inet_ntop.c,v 1.10 2014/05/17 18:16:14 tedu Exp $	*/
+/*	$OpenBSD: inet_ntop.c,v 1.13 2016/09/21 04:38:56 guenther Exp $	*/
 
 /* Copyright (c) 1996 by Internet Software Consortium.
  *
@@ -16,7 +16,6 @@
  * SOFTWARE.
  */
 
-#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -47,15 +46,16 @@
 {
 	switch (af) {
 	case AF_INET:
-		return (inet_ntop4(src, dst, (size_t)size));
+		return (inet_ntop4(src, dst, size));
 	case AF_INET6:
-		return (inet_ntop6(src, dst, (size_t)size));
+		return (inet_ntop6(src, dst, size));
 	default:
 		errno = EAFNOSUPPORT;
 		return (NULL);
 	}
 	/* NOTREACHED */
 }
+DEF_WEAK(inet_ntop);
 
 /* const char *
  * inet_ntop4(src, dst, size)
@@ -167,7 +167,7 @@
 		/* Is this address an encapsulated IPv4? */
 		if (i == 6 && best.base == 0 &&
 		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
-			if (!inet_ntop4(src+12, tp, (size_t)(ep - tp)))
+			if (!inet_ntop4(src+12, tp, ep - tp))
 				return (NULL);
 			tp += strlen(tp);
 			break;
diff --git a/libc/upstream-openbsd/lib/libc/net/inet_pton.c b/libc/upstream-openbsd/lib/libc/net/inet_pton.c
index 7e521c3..5d7148e 100644
--- a/libc/upstream-openbsd/lib/libc/net/inet_pton.c
+++ b/libc/upstream-openbsd/lib/libc/net/inet_pton.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: inet_pton.c,v 1.8 2010/05/06 15:47:14 claudio Exp $	*/
+/*	$OpenBSD: inet_pton.c,v 1.10 2015/09/13 21:36:08 guenther Exp $	*/
 
 /* Copyright (c) 1996 by Internet Software Consortium.
  *
@@ -16,7 +16,6 @@
  * SOFTWARE.
  */
 
-#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -58,6 +57,7 @@
 	}
 	/* NOTREACHED */
 }
+DEF_WEAK(inet_pton);
 
 /* int
  * inet_pton4(src, dst)
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fflush.c b/libc/upstream-openbsd/lib/libc/stdio/fflush.c
index 3e30f10..fd1a4b3 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fflush.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fflush.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fflush.c,v 1.8 2009/11/09 00:18:27 kurt Exp $ */
+/*	$OpenBSD: fflush.c,v 1.9 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -52,6 +52,7 @@
 	FUNLOCKFILE(fp);
 	return (r);
 }
+DEF_STRONG(fflush);
 
 int
 __sflush(FILE *fp)
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fgets.c b/libc/upstream-openbsd/lib/libc/stdio/fgets.c
index 345884a..3cea8f7 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fgets.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fgets.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fgets.c,v 1.14 2009/11/09 00:18:27 kurt Exp $ */
+/*	$OpenBSD: fgets.c,v 1.16 2016/09/21 04:38:56 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -83,19 +83,19 @@
 		 */
 		if (len > n)
 			len = n;
-		t = memchr((void *)p, '\n', len);
+		t = memchr(p, '\n', len);
 		if (t != NULL) {
 			len = ++t - p;
 			fp->_r -= len;
 			fp->_p = t;
-			(void)memcpy((void *)s, (void *)p, len);
+			(void)memcpy(s, p, len);
 			s[len] = '\0';
 			FUNLOCKFILE(fp);
 			return (buf);
 		}
 		fp->_r -= len;
 		fp->_p += len;
-		(void)memcpy((void *)s, (void *)p, len);
+		(void)memcpy(s, p, len);
 		s += len;
 		n -= len;
 	}
@@ -103,3 +103,4 @@
 	FUNLOCKFILE(fp);
 	return (buf);
 }
+DEF_STRONG(fgets);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c b/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
deleted file mode 100644
index 8cda047..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/fmemopen.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*	$OpenBSD: fmemopen.c,v 1.2 2013/03/27 15:06:25 mpi Exp $	*/
-
-/*
- * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
- * Copyright (c) 2009 Ted Unangst
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "local.h"
-
-struct state {
-	char		*string;	/* actual stream */
-	size_t		 pos;		/* current position */
-	size_t		 size;		/* allocated size */
-	size_t		 len;		/* length of the data */
-	int		 update;	/* open for update */
-};
-
-static int
-fmemopen_read(void *v, char *b, int l)
-{
-	struct state	*st = v;
-	int		 i;
-
-	for (i = 0; i < l && i + st->pos < st->len; i++)
-		b[i] = st->string[st->pos + i];
-	st->pos += i;
-
-	return (i);
-}
-
-static int
-fmemopen_write(void *v, const char *b, int l)
-{
-	struct state	*st = v;
-	int		i;
-
-	for (i = 0; i < l && i + st->pos < st->size; i++)
-		st->string[st->pos + i] = b[i];
-	st->pos += i;
-
-	if (st->pos >= st->len) {
-		st->len = st->pos;
-
-		if (st->len < st->size)
-			st->string[st->len] = '\0';
-		else if (!st->update)
-			st->string[st->size - 1] = '\0';
-	}
-
-	return (i);
-}
-
-static fpos_t
-fmemopen_seek(void *v, fpos_t off, int whence)
-{
-	struct state	*st = v;
-	ssize_t		 base = 0;
-
-	switch (whence) {
-	case SEEK_SET:
-		break;
-	case SEEK_CUR:
-		base = st->pos;
-		break;
-	case SEEK_END:
-		base = st->len;
-		break;
-	}
-
-	if (off > st->size - base || off < -base) {
-		errno = EOVERFLOW;
-		return (-1);
-	}
-
-	st->pos = base + off;
-
-	return (st->pos);
-}
-
-static int
-fmemopen_close(void *v)
-{
-	free(v);
-
-	return (0);
-}
-
-static int
-fmemopen_close_free(void *v)
-{
-	struct state	*st = v;
-
-	free(st->string);
-	free(st);
-
-	return (0);
-}
-
-FILE *
-fmemopen(void *buf, size_t size, const char *mode)
-{
-	struct state	*st;
-	FILE		*fp;
-	int		 flags, oflags;
-
-	if (size == 0) {
-		errno = EINVAL;
-		return (NULL);
-	}
-
-	if ((flags = __sflags(mode, &oflags)) == 0) {
-		errno = EINVAL;
-		return (NULL);
-	}
-
-	if (buf == NULL && ((oflags & O_RDWR) == 0)) {
-		errno = EINVAL;
-		return (NULL);
-	}
-
-	if ((st = malloc(sizeof(*st))) == NULL)
-		return (NULL);
-
-	if ((fp = __sfp()) == NULL) {
-		free(st);
-		return (NULL);
-	}
-
-	st->pos = 0;
-	st->len = (oflags & O_WRONLY) ? 0 : size;
-	st->size = size;
-	st->update = oflags & O_RDWR;
-
-	if (buf == NULL) {
-		if ((st->string = malloc(size)) == NULL) {
-			free(st);
-			fp->_flags = 0;
-			return (NULL);
-		}
-		*st->string = '\0';
-	} else {
-		st->string = (char *)buf;
-
-		if (oflags & O_TRUNC)
-			*st->string = '\0';
-
-		if (oflags & O_APPEND) {
-			char	*p;
-
-			if ((p = memchr(st->string, '\0', size)) != NULL)
-				st->pos = st->len = (p - st->string);
-			else
-				st->pos = st->len = size;
-		}
-	}
-
-	fp->_flags = (short)flags;
-	fp->_file = -1;
-	fp->_cookie = (void *)st;
-	fp->_read = (flags & __SWR) ? NULL : fmemopen_read;
-	fp->_write = (flags & __SRD) ? NULL : fmemopen_write;
-	fp->_seek = fmemopen_seek;
-	fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close;
-
-	return (fp);
-}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fpurge.c b/libc/upstream-openbsd/lib/libc/stdio/fpurge.c
index 65bd749..8dd8a91 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fpurge.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fpurge.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fpurge.c,v 1.9 2009/11/09 00:18:27 kurt Exp $ */
+/*	$OpenBSD: fpurge.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -59,3 +59,4 @@
 	FUNLOCKFILE(fp);
 	return (0);
 }
+DEF_WEAK(fpurge);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fputs.c b/libc/upstream-openbsd/lib/libc/stdio/fputs.c
index ea8556a..05ead5c 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fputs.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fputs.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fputs.c,v 1.10 2009/11/09 00:18:27 kurt Exp $ */
+/*	$OpenBSD: fputs.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -56,3 +56,4 @@
 	FUNLOCKFILE(fp);
 	return (ret);
 }
+DEF_STRONG(fputs);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fputws.c b/libc/upstream-openbsd/lib/libc/stdio/fputws.c
index 108846e..8961571 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fputws.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fputws.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fputws.c,v 1.7 2013/11/12 07:04:35 deraadt Exp $	*/
+/*	$OpenBSD: fputws.c,v 1.8 2015/08/31 02:53:57 guenther Exp $	*/
 /* $NetBSD: fputws.c,v 1.1 2003/03/07 07:11:37 tshiozak Exp $ */
 
 /*-
@@ -55,3 +55,4 @@
 
 	return (0);
 }
+DEF_STRONG(fputws);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
index d3a309b..f04565b 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
+++ b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fvwrite.h,v 1.6 2013/11/12 07:04:35 deraadt Exp $	*/
+/*	$OpenBSD: fvwrite.h,v 1.7 2015/08/27 04:37:09 guenther Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -45,5 +45,7 @@
 	int	uio_resid;
 };
 
+__BEGIN_HIDDEN_DECLS
 extern int __sfvwrite(FILE *, struct __suio *);
 wint_t __fputwc_unlock(wchar_t wc, FILE *fp);
+__END_HIDDEN_DECLS
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwalk.c b/libc/upstream-openbsd/lib/libc/stdio/fwalk.c
index 8ac6628..4b1aa43 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fwalk.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fwalk.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fwalk.c,v 1.10 2009/11/09 00:18:27 kurt Exp $ */
+/*	$OpenBSD: fwalk.c,v 1.12 2016/05/23 00:21:48 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwide.c b/libc/upstream-openbsd/lib/libc/stdio/fwide.c
index 93cddc6..27ca0f8 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fwide.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fwide.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fwide.c,v 1.4 2009/11/09 00:18:27 kurt Exp $	*/
+/*	$OpenBSD: fwide.c,v 1.5 2015/08/31 02:53:57 guenther Exp $	*/
 /* $NetBSD: fwide.c,v 1.2 2003/01/18 11:29:54 thorpej Exp $ */
 
 /*-
@@ -62,3 +62,4 @@
 
 	return mode;
 }
+DEF_STRONG(fwide);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c b/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
index c72d968..f829398 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: fwrite.c,v 1.11 2014/05/01 16:40:36 deraadt Exp $ */
+/*	$OpenBSD: fwrite.c,v 1.12 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -86,3 +86,4 @@
 		return (count);
 	return ((n - uio.uio_resid) / size);
 }
+DEF_STRONG(fwrite);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/mktemp.c b/libc/upstream-openbsd/lib/libc/stdio/mktemp.c
index 956608c..4b81d5d 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/mktemp.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/mktemp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: mktemp.c,v 1.35 2014/10/31 15:54:14 millert Exp $ */
+/*	$OpenBSD: mktemp.c,v 1.38 2015/09/13 08:31:47 guenther Exp $ */
 /*
  * Copyright (c) 1996-1998, 2008 Theo de Raadt
  * Copyright (c) 1997, 2008-2009 Todd C. Miller
@@ -110,8 +110,6 @@
 	return(-1);
 }
 
-char *_mktemp(char *);
-
 char *
 _mktemp(char *path)
 {
@@ -140,12 +138,14 @@
 {
 	return(mktemp_internal(path, 0, MKTEMP_FILE, 0));
 }
+DEF_WEAK(mkstemp);
 
 int
 mkostemp(char *path, int flags)
 {
 	return(mktemp_internal(path, 0, MKTEMP_FILE, flags));
 }
+DEF_WEAK(mkostemp);
 
 int
 mkstemps(char *path, int slen)
diff --git a/libc/upstream-openbsd/lib/libc/stdio/perror.c b/libc/upstream-openbsd/lib/libc/stdio/perror.c
index 8728718..fdd6120 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/perror.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/perror.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: perror.c,v 1.8 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: perror.c,v 1.9 2015/08/31 02:53:57 guenther Exp $ */
 /*
  * Copyright (c) 1988, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -60,3 +60,4 @@
 	v->iov_len = 1;
 	(void)writev(STDERR_FILENO, iov, (v - iov) + 1);
 }
+DEF_STRONG(perror);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/puts.c b/libc/upstream-openbsd/lib/libc/stdio/puts.c
index 655aed7..57d4b78 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/puts.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/puts.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: puts.c,v 1.11 2009/11/21 09:53:44 guenther Exp $ */
+/*	$OpenBSD: puts.c,v 1.12 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -60,3 +60,4 @@
 	FUNLOCKFILE(stdout);
 	return (ret ? EOF : '\n');
 }
+DEF_STRONG(puts);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/rget.c b/libc/upstream-openbsd/lib/libc/stdio/rget.c
index 4cd97cb..368815b 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/rget.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/rget.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: rget.c,v 1.7 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: rget.c,v 1.8 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -49,3 +49,4 @@
 	}
 	return (EOF);
 }
+DEF_STRONG(__srget);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c b/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
index 9b2ab57..da68b90 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/setvbuf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: setvbuf.c,v 1.12 2015/01/13 07:18:21 guenther Exp $ */
+/*	$OpenBSD: setvbuf.c,v 1.14 2016/09/21 04:38:56 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -70,7 +70,7 @@
 	fp->_r = fp->_lbfsize = 0;
 	flags = fp->_flags;
 	if (flags & __SMBF)
-		free((void *)fp->_bf._base);
+		free(fp->_bf._base);
 	flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF);
 
 	/* If setting unbuffered mode, skip all the hard work. */
@@ -157,3 +157,4 @@
 
 	return (ret);
 }
+DEF_STRONG(setvbuf);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/tmpnam.c b/libc/upstream-openbsd/lib/libc/stdio/tmpnam.c
index 32e0a22..d6dc10e 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/tmpnam.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/tmpnam.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tmpnam.c,v 1.10 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: tmpnam.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -39,8 +39,6 @@
 __warn_references(tmpnam,
     "warning: tmpnam() possibly used unsafely; consider using mkstemp()");
 
-extern char *_mktemp(char *);
-
 char *
 tmpnam(char *s)
 {
diff --git a/libc/upstream-openbsd/lib/libc/stdio/ungetc.c b/libc/upstream-openbsd/lib/libc/stdio/ungetc.c
index ec98f26..4cd638b 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/ungetc.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/ungetc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ungetc.c,v 1.13 2014/10/11 04:05:10 deraadt Exp $ */
+/*	$OpenBSD: ungetc.c,v 1.15 2016/09/21 04:38:56 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -53,7 +53,7 @@
 		/*
 		 * Get a new buffer (rather than expanding the old one).
 		 */
-		if ((p = malloc((size_t)BUFSIZ)) == NULL)
+		if ((p = malloc(BUFSIZ)) == NULL)
 			return (EOF);
 		_UB(fp)._base = p;
 		_UB(fp)._size = BUFSIZ;
@@ -68,7 +68,7 @@
 	if (p == NULL)
 		return (EOF);
 	/* no overlap (hence can use memcpy) because we doubled the size */
-	(void)memcpy((void *)(p + i), (void *)p, (size_t)i);
+	(void)memcpy(p + i, p, i);
 	fp->_p = p + i;
 	_UB(fp)._base = p;
 	_UB(fp)._size = i * 2;
@@ -143,3 +143,4 @@
 	FUNLOCKFILE(fp);
 	return (c);
 }
+DEF_STRONG(ungetc);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c b/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c
index c0321e9..9b312df 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ungetwc.c,v 1.5 2011/10/16 13:20:51 stsp Exp $	*/
+/*	$OpenBSD: ungetwc.c,v 1.6 2015/08/31 02:53:57 guenther Exp $	*/
 /* $NetBSD: ungetwc.c,v 1.2 2003/01/18 11:29:59 thorpej Exp $ */
 
 /*-
@@ -75,3 +75,4 @@
 	FUNLOCKFILE(fp);
 	return (r);
 }
+DEF_STRONG(ungetwc);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vdprintf.c b/libc/upstream-openbsd/lib/libc/stdio/vdprintf.c
index 49c1969..e76fcd4 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vdprintf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vdprintf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vdprintf.c,v 1.1 2013/01/30 00:08:13 brad Exp $	*/
+/*	$OpenBSD: vdprintf.c,v 1.2 2015/08/31 02:53:57 guenther Exp $	*/
 /*	$FreeBSD: src/lib/libc/stdio/vdprintf.c,v 1.4 2012/11/17 01:49:40 svnexp Exp $ */
 
 /*-
@@ -71,3 +71,4 @@
 
 	return fflush(&f) ? EOF : ret;
 }
+DEF_WEAK(vdprintf);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vsscanf.c b/libc/upstream-openbsd/lib/libc/stdio/vsscanf.c
index 71eb752..86e0b4c 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vsscanf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vsscanf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: vsscanf.c,v 1.12 2011/11/08 18:30:42 guenther Exp $ */
+/*	$OpenBSD: vsscanf.c,v 1.13 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +35,6 @@
 #include <string.h>
 #include "local.h"
 
-/* ARGSUSED */
 static int
 eofread(void *cookie, char *buf, int len)
 {
@@ -57,3 +56,4 @@
 	f._lb._base = NULL;
 	return (__svfscanf(&f, fmt, ap));
 }
+DEF_STRONG(vsscanf);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c b/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c
index cbaa250..e87dfeb 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vswscanf.c,v 1.2 2012/12/05 23:20:01 deraadt Exp $ */
+/* $OpenBSD: vswscanf.c,v 1.3 2015/08/31 02:53:57 guenther Exp $ */
 
 /*-
  * Copyright (c) 1990, 1993
@@ -86,3 +86,4 @@
 
 	return (r);
 }
+DEF_STRONG(vswscanf);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/wbuf.c b/libc/upstream-openbsd/lib/libc/stdio/wbuf.c
index 6aa00e1..2d07750 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/wbuf.c
+++ b/libc/upstream-openbsd/lib/libc/stdio/wbuf.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: wbuf.c,v 1.12 2009/11/09 00:18:28 kurt Exp $ */
+/*	$OpenBSD: wbuf.c,v 1.13 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -82,3 +82,4 @@
 			return (EOF);
 	return (c);
 }
+DEF_STRONG(__swbuf);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/abs.c b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
index 5d2fbae..0e39cc5 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/abs.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/abs.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: abs.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: abs.c,v 1.6 2015/09/13 08:31:47 guenther Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -35,3 +35,4 @@
 {
 	return(j < 0 ? -j : j);
 }
+DEF_STRONG(abs);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/atoi.c b/libc/upstream-openbsd/lib/libc/stdlib/atoi.c
index b084267..7c9eb13 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/atoi.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/atoi.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: atoi.c,v 1.5 2005/08/08 08:05:36 espie Exp $ */
+/*	$OpenBSD: atoi.c,v 1.6 2015/09/13 08:31:47 guenther Exp $ */
 /*
  * Copyright (c) 1988 Regents of the University of California.
  * All rights reserved.
@@ -35,3 +35,4 @@
 {
 	return((int)strtol(str, (char **)NULL, 10));
 }
+DEF_STRONG(atoi);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c
index 2fc04e4..74e3556 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoimax.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtoimax.c,v 1.2 2014/09/13 20:10:12 schwarze Exp $	*/
+/*	$OpenBSD: strtoimax.c,v 1.4 2017/07/06 16:23:11 millert Exp $	*/
 /*
  * Copyright (c) 1992 The Regents of the University of California.
  * All rights reserved.
@@ -74,8 +74,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -148,3 +148,4 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtoimax);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtol.c b/libc/upstream-openbsd/lib/libc/stdlib/strtol.c
index 86cec35..599d235 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtol.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtol.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtol.c,v 1.10 2014/09/13 20:10:12 schwarze Exp $ */
+/*	$OpenBSD: strtol.c,v 1.12 2017/07/06 16:23:11 millert Exp $ */
 /*
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -75,8 +75,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -148,3 +148,4 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtol);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c
index cf82c8e..d21a249 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoll.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtoll.c,v 1.8 2014/09/13 20:10:12 schwarze Exp $ */
+/*	$OpenBSD: strtoll.c,v 1.10 2017/07/06 16:23:11 millert Exp $ */
 /*
  * Copyright (c) 1992 The Regents of the University of California.
  * All rights reserved.
@@ -77,8 +77,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -151,5 +151,6 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtoll);
 
-__strong_alias(strtoq, strtoll);
+__weak_alias(strtoq, strtoll);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c
index 2aa41b7..6667bea 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoul.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtoul.c,v 1.9 2014/09/13 20:10:12 schwarze Exp $ */
+/*	$OpenBSD: strtoul.c,v 1.11 2017/07/06 16:23:11 millert Exp $ */
 /*
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -69,8 +69,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -107,3 +107,4 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtoul);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c
index 8464176..d7733e40 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoull.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtoull.c,v 1.7 2014/09/13 20:10:12 schwarze Exp $ */
+/*	$OpenBSD: strtoull.c,v 1.9 2017/07/06 16:23:11 millert Exp $ */
 /*
  * Copyright (c) 1992 The Regents of the University of California.
  * All rights reserved.
@@ -71,8 +71,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -109,5 +109,6 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtoull);
 
-__strong_alias(strtouq, strtoull);
+__weak_alias(strtouq, strtoull);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c b/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c
index c73f7e5..348184c 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/strtoumax.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strtoumax.c,v 1.2 2014/09/13 20:10:12 schwarze Exp $	*/
+/*	$OpenBSD: strtoumax.c,v 1.4 2017/07/06 16:23:11 millert Exp $	*/
 /*
  * Copyright (c) 1992 The Regents of the University of California.
  * All rights reserved.
@@ -68,8 +68,8 @@
 		if (c == '+')
 			c = *s++;
 	}
-	if ((base == 0 || base == 16) &&
-	    c == '0' && (*s == 'x' || *s == 'X')) {
+	if ((base == 0 || base == 16) && c == '0' &&
+	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
 		c = s[1];
 		s += 2;
 		base = 16;
@@ -106,3 +106,4 @@
 		*endptr = (char *) (any ? s - 1 : nptr);
 	return (acc);
 }
+DEF_STRONG(strtoumax);
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/tfind.c b/libc/upstream-openbsd/lib/libc/stdlib/tfind.c
index 0d1d519..49f9dbc 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/tfind.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/tfind.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tfind.c,v 1.6 2014/03/16 18:38:30 guenther Exp $	*/
+/*	$OpenBSD: tfind.c,v 1.7 2015/09/26 16:03:48 guenther Exp $	*/
 
 /*
  * Tree search generalized from Knuth (6.2.2) Algorithm T just like
@@ -10,7 +10,6 @@
  *
  * Totally public domain.
  */
-/*LINTLIBRARY*/
 #include <search.h>
 
 typedef struct node_t
diff --git a/libc/upstream-openbsd/lib/libc/stdlib/tsearch.c b/libc/upstream-openbsd/lib/libc/stdlib/tsearch.c
index a141085..1dd3145 100644
--- a/libc/upstream-openbsd/lib/libc/stdlib/tsearch.c
+++ b/libc/upstream-openbsd/lib/libc/stdlib/tsearch.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tsearch.c,v 1.8 2014/03/16 18:38:30 guenther Exp $	*/
+/*	$OpenBSD: tsearch.c,v 1.10 2015/09/26 16:03:48 guenther Exp $	*/
 
 /*
  * Tree search generalized from Knuth (6.2.2) Algorithm T just like
@@ -10,7 +10,6 @@
  *
  * Totally public domain.
  */
-/*LINTLIBRARY*/
 
 #include <search.h>
 #include <stdlib.h>
@@ -40,7 +39,7 @@
 	    &(*rootp)->left :		/* T3: follow left branch */
 	    &(*rootp)->right;		/* T4: follow right branch */
     }
-    q = (node *) malloc(sizeof(node));	/* T5: key not found */
+    q = malloc(sizeof(node));	/* T5: key not found */
     if (q != (struct node_t *)0) {	/* make new node */
 	*rootp = q;			/* link new node to old */
 	q->key = key;			/* initialize new node */
diff --git a/libc/upstream-openbsd/lib/libc/string/memchr.c b/libc/upstream-openbsd/lib/libc/string/memchr.c
index 05a1197..976ed21 100644
--- a/libc/upstream-openbsd/lib/libc/string/memchr.c
+++ b/libc/upstream-openbsd/lib/libc/string/memchr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: memchr.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: memchr.c,v 1.8 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -34,7 +34,8 @@
 #include <string.h>
 
 void *
-memchr(const void *s, int c, size_t n) __overloadable {
+memchr(const void *s, int c, size_t n) __overloadable
+{
 	if (n != 0) {
 		const unsigned char *p = s;
 
@@ -45,3 +46,4 @@
 	}
 	return (NULL);
 }
+DEF_STRONG(memchr);
diff --git a/libc/upstream-openbsd/lib/libc/string/memmove.c b/libc/upstream-openbsd/lib/libc/string/memmove.c
index 910f48c..6b5db47 100644
--- a/libc/upstream-openbsd/lib/libc/string/memmove.c
+++ b/libc/upstream-openbsd/lib/libc/string/memmove.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: memmove.c,v 1.1 2014/11/30 19:43:56 deraadt Exp $ */
+/*	$OpenBSD: memmove.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -110,3 +110,4 @@
 done:
 	return (dst0);
 }
+DEF_STRONG(memmove);
diff --git a/libc/upstream-openbsd/lib/libc/string/memrchr.c b/libc/upstream-openbsd/lib/libc/string/memrchr.c
index 1cce809..4b67503 100644
--- a/libc/upstream-openbsd/lib/libc/string/memrchr.c
+++ b/libc/upstream-openbsd/lib/libc/string/memrchr.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: memrchr.c,v 1.2 2007/11/27 16:22:12 martynas Exp $	*/
+/*	$OpenBSD: memrchr.c,v 1.3 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*
  * Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -36,3 +36,4 @@
 	}
 	return(NULL);
 }
+DEF_WEAK(memrchr);
diff --git a/libc/upstream-openbsd/lib/libc/string/stpncpy.c b/libc/upstream-openbsd/lib/libc/string/stpncpy.c
index 661a4fd..f30bf15 100644
--- a/libc/upstream-openbsd/lib/libc/string/stpncpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/stpncpy.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: stpncpy.c,v 1.2 2012/07/11 10:44:59 naddy Exp $	*/
+/*	$OpenBSD: stpncpy.c,v 1.3 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -54,3 +54,4 @@
 	}
 	return (dst);
 }
+DEF_WEAK(stpncpy);
diff --git a/libc/upstream-openbsd/lib/libc/string/strcasecmp.c b/libc/upstream-openbsd/lib/libc/string/strcasecmp.c
index 2be0913..edbd638 100644
--- a/libc/upstream-openbsd/lib/libc/string/strcasecmp.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcasecmp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strcasecmp.c,v 1.6 2005/08/08 08:05:37 espie Exp $	*/
+/*	$OpenBSD: strcasecmp.c,v 1.7 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*
  * Copyright (c) 1987, 1993
@@ -85,6 +85,7 @@
 			return (0);
 	return (cm[*us1] - cm[*--us2]);
 }
+DEF_WEAK(strcasecmp);
 
 int
 strncasecmp(const char *s1, const char *s2, size_t n)
@@ -103,3 +104,4 @@
 	}
 	return (0);
 }
+DEF_WEAK(strncasecmp);
diff --git a/libc/upstream-openbsd/lib/libc/string/strcmp.c b/libc/upstream-openbsd/lib/libc/string/strcmp.c
index d1b6c50..be17556 100644
--- a/libc/upstream-openbsd/lib/libc/string/strcmp.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcmp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strcmp.c,v 1.8 2014/06/10 04:17:37 deraadt Exp $	*/
+/*	$OpenBSD: strcmp.c,v 1.9 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -45,3 +45,4 @@
 			return (0);
 	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
 }
+DEF_STRONG(strcmp);
diff --git a/libc/upstream-openbsd/lib/libc/string/strcspn.c b/libc/upstream-openbsd/lib/libc/string/strcspn.c
index 1eb2336..3c1f5a4 100644
--- a/libc/upstream-openbsd/lib/libc/string/strcspn.c
+++ b/libc/upstream-openbsd/lib/libc/string/strcspn.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strcspn.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: strcspn.c,v 1.6 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -56,3 +56,4 @@
 	}
 	/* NOTREACHED */
 }
+DEF_STRONG(strcspn);
diff --git a/libc/upstream-openbsd/lib/libc/string/strdup.c b/libc/upstream-openbsd/lib/libc/string/strdup.c
index a6aa1e0..9aebf39 100644
--- a/libc/upstream-openbsd/lib/libc/string/strdup.c
+++ b/libc/upstream-openbsd/lib/libc/string/strdup.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strdup.c,v 1.6 2005/08/08 08:05:37 espie Exp $	*/
+/*	$OpenBSD: strdup.c,v 1.7 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*
  * Copyright (c) 1988, 1993
@@ -47,3 +47,4 @@
 	(void)memcpy(copy, str, siz);
 	return(copy);
 }
+DEF_WEAK(strdup);
diff --git a/libc/upstream-openbsd/lib/libc/string/strlcat.c b/libc/upstream-openbsd/lib/libc/string/strlcat.c
index 7bf98aa..8a950f5 100644
--- a/libc/upstream-openbsd/lib/libc/string/strlcat.c
+++ b/libc/upstream-openbsd/lib/libc/string/strlcat.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strlcat.c,v 1.16 2015/08/31 02:53:57 guenther Exp $	*/
+/*	$OpenBSD: strlcat.c,v 1.18 2016/10/16 17:37:39 dtucker Exp $	*/
 
 /*
  * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
diff --git a/libc/upstream-openbsd/lib/libc/string/strlcpy.c b/libc/upstream-openbsd/lib/libc/string/strlcpy.c
index a5343b8..647b18b 100644
--- a/libc/upstream-openbsd/lib/libc/string/strlcpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/strlcpy.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strlcpy.c,v 1.13 2015/08/31 02:53:57 guenther Exp $	*/
+/*	$OpenBSD: strlcpy.c,v 1.15 2016/10/16 17:37:39 dtucker Exp $	*/
 
 /*
  * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
diff --git a/libc/upstream-openbsd/lib/libc/string/strncat.c b/libc/upstream-openbsd/lib/libc/string/strncat.c
index 32334b3..5b07749 100644
--- a/libc/upstream-openbsd/lib/libc/string/strncat.c
+++ b/libc/upstream-openbsd/lib/libc/string/strncat.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strncat.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: strncat.c,v 1.6 2015/08/31 02:53:57 guenther Exp $ */
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
  * All rights reserved.
@@ -55,3 +55,4 @@
 	}
 	return (dst);
 }
+DEF_STRONG(strncat);
diff --git a/libc/upstream-openbsd/lib/libc/string/strncmp.c b/libc/upstream-openbsd/lib/libc/string/strncmp.c
index 0a4ddc1..535d2a6 100644
--- a/libc/upstream-openbsd/lib/libc/string/strncmp.c
+++ b/libc/upstream-openbsd/lib/libc/string/strncmp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strncmp.c,v 1.8 2014/06/10 04:17:37 deraadt Exp $	*/
+/*	$OpenBSD: strncmp.c,v 1.9 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*
  * Copyright (c) 1989 The Regents of the University of California.
@@ -45,3 +45,4 @@
 	} while (--n != 0);
 	return (0);
 }
+DEF_STRONG(strncmp);
diff --git a/libc/upstream-openbsd/lib/libc/string/strncpy.c b/libc/upstream-openbsd/lib/libc/string/strncpy.c
index e83c7e5..ad9dc84 100644
--- a/libc/upstream-openbsd/lib/libc/string/strncpy.c
+++ b/libc/upstream-openbsd/lib/libc/string/strncpy.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strncpy.c,v 1.7 2014/06/10 04:17:37 deraadt Exp $	*/
+/*	$OpenBSD: strncpy.c,v 1.8 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -56,3 +56,4 @@
 	}
 	return (dst);
 }
+DEF_STRONG(strncpy);
diff --git a/libc/upstream-openbsd/lib/libc/string/strndup.c b/libc/upstream-openbsd/lib/libc/string/strndup.c
index 27701ac..a6e5bff 100644
--- a/libc/upstream-openbsd/lib/libc/string/strndup.c
+++ b/libc/upstream-openbsd/lib/libc/string/strndup.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strndup.c,v 1.1 2010/05/18 22:24:55 tedu Exp $	*/
+/*	$OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*
  * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -37,3 +37,4 @@
 
 	return copy;
 }
+DEF_WEAK(strndup);
diff --git a/libc/upstream-openbsd/lib/libc/string/strpbrk.c b/libc/upstream-openbsd/lib/libc/string/strpbrk.c
index cd3b71c..336c22d 100644
--- a/libc/upstream-openbsd/lib/libc/string/strpbrk.c
+++ b/libc/upstream-openbsd/lib/libc/string/strpbrk.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strpbrk.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: strpbrk.c,v 1.6 2015/08/31 02:53:57 guenther Exp $ */
 /*
  * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.
@@ -46,3 +46,4 @@
 	}
 	return (NULL);
 }
+DEF_STRONG(strpbrk);
diff --git a/libc/upstream-openbsd/lib/libc/string/strsep.c b/libc/upstream-openbsd/lib/libc/string/strsep.c
index 2ffc4b4..97c3cbf 100644
--- a/libc/upstream-openbsd/lib/libc/string/strsep.c
+++ b/libc/upstream-openbsd/lib/libc/string/strsep.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strsep.c,v 1.7 2014/02/05 20:42:32 stsp Exp $	*/
+/*	$OpenBSD: strsep.c,v 1.8 2015/08/31 02:53:57 guenther Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -68,3 +68,4 @@
 	}
 	/* NOTREACHED */
 }
+DEF_WEAK(strsep);
diff --git a/libc/upstream-openbsd/lib/libc/string/strspn.c b/libc/upstream-openbsd/lib/libc/string/strspn.c
index 385649c..0ce41cb 100644
--- a/libc/upstream-openbsd/lib/libc/string/strspn.c
+++ b/libc/upstream-openbsd/lib/libc/string/strspn.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: strspn.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
+/*	$OpenBSD: strspn.c,v 1.6 2015/08/31 02:53:57 guenther Exp $ */
 /*
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
@@ -49,3 +49,4 @@
 			goto cont;
 	return (p - 1 - s1);
 }
+DEF_STRONG(strspn);
diff --git a/libc/upstream-openbsd/lib/libc/string/wcsstr.c b/libc/upstream-openbsd/lib/libc/string/wcsstr.c
deleted file mode 100644
index 669e340..0000000
--- a/libc/upstream-openbsd/lib/libc/string/wcsstr.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*	$OpenBSD: wcsstr.c,v 1.3 2005/08/08 08:05:37 espie Exp $	*/
-/*	$NetBSD: wcsstr.c,v 1.3 2003/03/05 20:18:17 tshiozak Exp $	*/
-
-/*-
- * Copyright (c)1999 Citrus 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- *	citrus Id: wcsstr.c,v 1.2 2000/12/21 05:07:25 itojun Exp
- */
-
-#include <wchar.h>
-
-wchar_t *
-#ifdef WCSWCS
-wcswcs(const wchar_t *big, const wchar_t *little)
-#else
-wcsstr(const wchar_t *big, const wchar_t *little)
-#endif
-{
-	const wchar_t *p;
-	const wchar_t *q;
-	const wchar_t *r;
-
-	if (!*little) {
-		/* LINTED interface specification */
-		return (wchar_t *)big;
-	}
-	if (wcslen(big) < wcslen(little))
-		return NULL;
-
-	p = big;
-	q = little;
-	while (*p) {
-		q = little;
-		r = p;
-		while (*q) {
-			if (*r != *q)
-				break;
-			q++;
-			r++;
-		}
-		if (!*q) {
-			/* LINTED interface specification */
-			return (wchar_t *)p;
-		}
-		p++;
-	}
-	return NULL;
-}
diff --git a/libc/upstream-openbsd/lib/libc/string/wcswidth.c b/libc/upstream-openbsd/lib/libc/string/wcswidth.c
index 8ea1bdf..9f003f9 100644
--- a/libc/upstream-openbsd/lib/libc/string/wcswidth.c
+++ b/libc/upstream-openbsd/lib/libc/string/wcswidth.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: wcswidth.c,v 1.4 2011/04/04 18:16:24 stsp Exp $	*/
+/*	$OpenBSD: wcswidth.c,v 1.5 2015/09/12 16:23:14 guenther Exp $	*/
 /*	$NetBSD: wcswidth.c,v 1.2 2001/01/03 14:29:37 lukem Exp $	*/
 
 /*-
@@ -48,3 +48,4 @@
 
 	return w;
 }
+DEF_WEAK(wcswidth);
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 668f008..292bd97 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -34,11 +34,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -48,4 +52,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index a4c6483..408d4dc 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libm/Android.bp b/libm/Android.bp
index 8947f4d..75e8957 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -63,7 +63,6 @@
         "upstream-freebsd/lib/msun/src/e_sinhf.c",
         "upstream-freebsd/lib/msun/src/e_sqrt.c",
         "upstream-freebsd/lib/msun/src/e_sqrtf.c",
-        "upstream-freebsd/lib/msun/src/imprecise.c",
         "upstream-freebsd/lib/msun/src/k_cos.c",
         "upstream-freebsd/lib/msun/src/k_cosf.c",
         "upstream-freebsd/lib/msun/src/k_exp.c",
@@ -209,6 +208,7 @@
         // Functionality not in the BSDs.
         "significandl.c",
         "sincos.c",
+        "fake_long_double.c",
 
         // Modified versions of BSD code.
         "signbit.c",
@@ -218,10 +218,6 @@
     ],
 
     multilib: {
-        lib32: {
-            srcs: ["fake_long_double.c"],
-        },
-
         lib64: {
             srcs: [
                 "upstream-freebsd/lib/msun/src/e_acosl.c",
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index 20148a3..fd983ed 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -17,12 +17,11 @@
 #include <float.h>
 #include <math.h>
 
-#ifndef __LP64__
-/*
- * The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
- * Android works around those cases by replacing the broken functions with our own trivial stubs
- * that call the regular "double" function.
- */
+#if !defined(__LP64__)
+
+// The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
+// Android works around those cases by replacing the broken functions with our own trivial stubs
+// that call the regular "double" function.
 
 long double copysignl(long double a1, long double a2) { return copysign(a1, a2); }
 long double fmaxl(long double a1, long double a2) { return fmax(a1, a2); }
@@ -40,3 +39,7 @@
 long double roundl(long double a1) { return round(a1); }
 
 #endif // __LP64__
+
+// FreeBSD doesn't have ld128 implementations of powl or tgammal, so both LP32 and LP64 need these.
+long double powl(long double x, long double y) { return pow(x, y); }
+long double tgammal(long double x) { return tgamma(x); }
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index a4dd6c2..ee41e45 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -28,7 +28,15 @@
 
 #define __warn_references(sym,msg) /* ignored */
 
-/* digittoint is in BSD's <ctype.h>. */
+// digittoint is in BSD's <ctype.h>, but not ours, so we have a secret
+// implementation in libm. We reuse parts of libm in the NDK's
+// libandroid_support, where it's a static library, so we want all our
+// "hidden" functions start with a double underscore --- being HIDDEN
+// in the ELF sense is not sufficient.
+#define digittoint __libm_digittoint
 int digittoint(char ch);
 
+// Similarly rename _scan_nan.
+#define _scan_nan __libm_scan_nan
+
 #endif
diff --git a/libm/upstream-freebsd/lib/msun/src/imprecise.c b/libm/upstream-freebsd/lib/msun/src/imprecise.c
deleted file mode 100644
index 08cd239..0000000
--- a/libm/upstream-freebsd/lib/msun/src/imprecise.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 2013 David Chisnall
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#include <float.h>
-#include <math.h>
-
-/*
- * If long double is not the same size as double, then these will lose
- * precision and we should emit a warning whenever something links against
- * them.
- */
-#if (LDBL_MANT_DIG > 53)
-#define WARN_IMPRECISE(x) \
-	__warn_references(x, # x " has lower than advertised precision");
-#else
-#define WARN_IMPRECISE(x)
-#endif
-/*
- * Declare the functions as weak variants so that other libraries providing
- * real versions can override them.
- */
-#define	DECLARE_WEAK(x)\
-	__weak_reference(imprecise_## x, x);\
-	WARN_IMPRECISE(x)
-
-long double
-imprecise_powl(long double x, long double y)
-{
-
-	return pow(x, y);
-}
-DECLARE_WEAK(powl);
-
-#define DECLARE_IMPRECISE(f) \
-	long double imprecise_ ## f ## l(long double v) { return f(v); }\
-	DECLARE_WEAK(f ## l)
-
-DECLARE_IMPRECISE(tgamma);
diff --git a/tests/Android.bp b/tests/Android.bp
index d4027b3..8f1c11f 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -527,7 +527,6 @@
     static_libs: [
         "libm",
         "libc",
-        "libc++_static",
         "libdl",
         "libtinyxml2",
         "liblog",
@@ -537,12 +536,6 @@
 
     static_executable: true,
     stl: "libc++_static",
-
-    // libc and libc++ both define std::nothrow. libc's is a private symbol, but this
-    // still causes issues when linking libc.a and libc++.a, since private isn't
-    // effective until it has been linked. To fix this, just allow multiple symbol
-    // definitions for the static tests.
-    ldflags: ["-Wl,--allow-multiple-definition"],
 }
 
 // -----------------------------------------------------------------------------
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 227b6d1..9dcc000 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -148,12 +148,16 @@
 
   const std::string& GetName() const { return name_; }
 
-  void SetResult(TestResult result) { result_ = result; }
+  void SetResult(TestResult result) {
+    // Native xfails are inherently likely to actually be relying on undefined
+    // behavior/uninitialized memory, and thus likely to pass from time to time
+    // on CTS. Avoid that unpleasantness by just rewriting all xfail failures
+    // as successes. You'll still see the actual failure details.
+    if (GetName().find("xfail") == 0) result = TEST_SUCCESS;
+    result_ = result;
+  }
 
   TestResult GetResult() const { return result_; }
-  TestResult GetExpectedResult() const {
-    return GetName().find("xfail") == 0 ? TEST_FAILED : TEST_SUCCESS;
-  }
 
   void SetTestTime(int64_t elapsed_time_ns) { elapsed_time_ns_ = elapsed_time_ns; }
 
@@ -208,13 +212,8 @@
     return test_list_[test_id].GetResult();
   }
 
-  TestResult GetExpectedTestResult(size_t test_id) const {
-    VerifyTestId(test_id);
-    return test_list_[test_id].GetExpectedResult();
-  }
-
   bool GetTestSuccess(size_t test_id) const {
-    return GetTestResult(test_id) == GetExpectedTestResult(test_id);
+    return GetTestResult(test_id) == TEST_SUCCESS;
   }
 
   void SetTestTime(size_t test_id, int64_t elapsed_time_ns) {
@@ -349,7 +348,7 @@
   printf("%s", test_output.c_str());
 
   TestResult result = testcase.GetTestResult(test_id);
-  if (result == testcase.GetExpectedTestResult(test_id)) {
+  if (result == TEST_SUCCESS) {
     ColoredPrintf(COLOR_GREEN, "[       OK ] ");
   } else {
     ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
@@ -366,19 +365,10 @@
 
 static void OnTestEndPrint(const TestCase& testcase, size_t test_id) {
   TestResult result = testcase.GetTestResult(test_id);
-  TestResult expected = testcase.GetExpectedTestResult(test_id);
   if (result == TEST_SUCCESS) {
-    if (expected == TEST_SUCCESS) {
-      ColoredPrintf(COLOR_GREEN, "[    OK    ] ");
-    } else if (expected == TEST_FAILED) {
-      ColoredPrintf(COLOR_RED, "[  XPASS   ] ");
-    }
+    ColoredPrintf(COLOR_GREEN, "[    OK    ] ");
   } else if (result == TEST_FAILED) {
-    if (expected == TEST_SUCCESS) {
-      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
-    } else if (expected == TEST_FAILED) {
-      ColoredPrintf(COLOR_YELLOW, "[  XFAIL   ] ");
-    }
+    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
   } else if (result == TEST_TIMEOUT) {
     ColoredPrintf(COLOR_RED, "[ TIMEOUT  ] ");
   }
@@ -400,7 +390,6 @@
                                     int64_t elapsed_time_ns) {
 
   std::vector<std::string> fail_test_name_list;
-  std::vector<std::string> xpass_test_name_list;
   std::vector<std::pair<std::string, int64_t>> timeout_test_list;
 
   // For tests that were slow but didn't time out.
@@ -414,22 +403,14 @@
     test_count += testcase.TestCount();
     for (size_t i = 0; i < testcase.TestCount(); ++i) {
       TestResult result = testcase.GetTestResult(i);
-      TestResult expected = testcase.GetExpectedTestResult(i);
       if (result == TEST_TIMEOUT) {
         timeout_test_list.push_back(
             std::make_pair(testcase.GetTestName(i), testcase.GetTestTime(i)));
-      } else if (result == expected) {
-        if (result == TEST_SUCCESS) {
-          ++success_test_count;
-        } else {
-          ++expected_failure_count;
-        }
-      } else {
-        if (result == TEST_FAILED) {
+      } else if (result == TEST_SUCCESS) {
+        ++success_test_count;
+        if (testcase.GetTestName(i).find(".xfail_") != std::string::npos) ++expected_failure_count;
+      } else if (result == TEST_FAILED) {
           fail_test_name_list.push_back(testcase.GetTestName(i));
-        } else {
-          xpass_test_name_list.push_back(testcase.GetTestName(i));
-        }
       }
       if (result != TEST_TIMEOUT &&
           testcase.GetTestTime(i) / 1000000 >= GetSlowThresholdMs(testcase.GetTestName(i))) {
@@ -450,7 +431,7 @@
   ColoredPrintf(COLOR_GREEN,  "[   PASS   ] ");
   printf("%zu %s.", success_test_count, (success_test_count == 1) ? "test" : "tests");
   if (expected_failure_count > 0) {
-    printf(" (%zu expected failure%s)", expected_failure_count,
+    printf(" (%zu expected failure%s.)", expected_failure_count,
            (expected_failure_count == 1) ? "" : "s");
   }
   printf("\n");
@@ -490,18 +471,7 @@
     }
   }
 
-  // Print tests that should have failed.
-  size_t xpass_test_count = xpass_test_name_list.size();
-  if (xpass_test_count > 0) {
-    ColoredPrintf(COLOR_RED,  "[  XPASS   ] ");
-    printf("%zu %s, listed below:\n", xpass_test_count, (xpass_test_count == 1) ? "test" : "tests");
-    for (const auto& name : xpass_test_name_list) {
-      ColoredPrintf(COLOR_RED, "[  XPASS   ] ");
-      printf("%s\n", name.c_str());
-    }
-  }
-
-  if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0 || xpass_test_count > 0) {
+  if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0) {
     printf("\n");
   }
 
@@ -514,9 +484,6 @@
   if (fail_test_count > 0) {
     printf("%2zu FAILED %s\n", fail_test_count, (fail_test_count == 1) ? "TEST" : "TESTS");
   }
-  if (xpass_test_count > 0) {
-    printf("%2zu SHOULD HAVE FAILED %s\n", xpass_test_count, (xpass_test_count == 1) ? "TEST" : "TESTS");
-  }
 
   fflush(stdout);
 }
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 36ac690..207c156 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -527,3 +527,11 @@
   ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
   EXPECT_TRUE(sigismember(&set, SIGALRM));
 }
+
+TEST(signal, killpg_EINVAL) {
+  // POSIX leaves pgrp <= 1 undefined, but glibc fails with EINVAL for < 0
+  // and passes 0 through to kill(2).
+  errno = 0;
+  ASSERT_EQ(-1, killpg(-1, SIGKILL));
+  ASSERT_EQ(EINVAL, errno);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index da70d21..dac7056 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -27,6 +27,7 @@
 #include <wchar.h>
 #include <locale.h>
 
+#include <string>
 #include <vector>
 
 #include "BionicDeathTest.h"
@@ -41,9 +42,29 @@
 #define STDIO_DEATHTEST stdio_DeathTest
 #endif
 
+using namespace std::string_literals;
+
 class stdio_DeathTest : public BionicDeathTest {};
 class stdio_nofortify_DeathTest : public BionicDeathTest {};
 
+static void SetFileTo(const char* path, const char* content) {
+  FILE* fp;
+  ASSERT_NE(nullptr, fp = fopen(path, "w"));
+  ASSERT_NE(EOF, fputs(content, fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+static void AssertFileIs(const char* path, const char* expected) {
+  FILE* fp;
+  ASSERT_NE(nullptr, fp = fopen(path, "r"));
+  char* line = nullptr;
+  size_t length;
+  ASSERT_NE(EOF, getline(&line, &length, fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_STREQ(expected, line);
+  free(line);
+}
+
 static void AssertFileIs(FILE* fp, const char* expected, bool is_fmemopen = false) {
   rewind(fp);
 
@@ -923,7 +944,7 @@
   ASSERT_EQ(WEOF, fgetwc(fp));
   ASSERT_EQ(EILSEQ, errno);
 
-  fclose(fp);
+  ASSERT_EQ(0, fclose(fp));
 }
 
 TEST(STDIO_TEST, fmemopen) {
@@ -934,32 +955,410 @@
   ASSERT_NE(EOF, fputs("abc>\n", fp));
   fflush(fp);
 
+  // We wrote to the buffer...
   ASSERT_STREQ("<abc>\n", buf);
 
+  // And can read back from the file.
   AssertFileIs(fp, "<abc>\n", true);
-  fclose(fp);
+  ASSERT_EQ(0, fclose(fp));
 }
 
-TEST(STDIO_TEST, KNOWN_FAILURE_ON_BIONIC(fmemopen_NULL)) {
+TEST(STDIO_TEST, fmemopen_nullptr) {
   FILE* fp = fmemopen(nullptr, 128, "r+");
   ASSERT_NE(EOF, fputs("xyz\n", fp));
 
   AssertFileIs(fp, "xyz\n", true);
-  fclose(fp);
+  ASSERT_EQ(0, fclose(fp));
 }
 
-TEST(STDIO_TEST, fmemopen_EINVAL) {
+TEST(STDIO_TEST, fmemopen_trailing_NUL_byte) {
+  FILE* fp;
+  char buf[8];
+
+  // POSIX: "When a stream open for writing is flushed or closed, a null byte
+  // shall be written at the current position or at the end of the buffer,
+  // depending on the size of the contents."
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "w"));
+  // Even with nothing written (and not in truncate mode), we'll flush a NUL...
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ("\0xxxxxxx"s, std::string(buf, buf + sizeof(buf)));
+  // Now write and check that the NUL moves along with our writes...
+  ASSERT_NE(EOF, fputs("hello", fp));
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ("hello\0xx"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_NE(EOF, fputs("wo", fp));
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ("hellowo\0"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
+
+  // "If a stream open for update is flushed or closed and the last write has
+  // advanced the current buffer size, a null byte shall be written at the end
+  // of the buffer if it fits."
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "r+"));
+  // Nothing written yet, so no advance...
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ("xxxxxxxx"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_NE(EOF, fputs("hello", fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_size) {
+  FILE* fp;
   char buf[16];
+  memset(buf, 'x', sizeof(buf));
 
-  // Invalid size.
-  errno = 0;
-  ASSERT_EQ(nullptr, fmemopen(buf, 0, "r+"));
-  ASSERT_EQ(EINVAL, errno);
+  // POSIX: "The stream shall also maintain the size of the current buffer
+  // contents; use of fseek() or fseeko() on the stream with SEEK_END shall
+  // seek relative to this size."
 
-  // No '+' with NULL buffer.
+  // "For modes r and r+ the size shall be set to the value given by the size
+  // argument."
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "r"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "r+"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+
+  // "For modes w and w+ the initial size shall be zero..."
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "w"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "w+"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+
+  // "...and for modes a and a+ the initial size shall be:
+  // 1. Zero, if buf is a null pointer
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "a"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "a+"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  EXPECT_EQ(0, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+
+  // 2. The position of the first null byte in the buffer, if one is found
+  memset(buf, 'x', sizeof(buf));
+  buf[3] = '\0';
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "a"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(3, ftell(fp));
+  EXPECT_EQ(3, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(3, ftell(fp));
+  EXPECT_EQ(3, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+  memset(buf, 'x', sizeof(buf));
+  buf[3] = '\0';
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "a+"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(3, ftell(fp));
+  EXPECT_EQ(3, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(3, ftell(fp));
+  EXPECT_EQ(3, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+
+  // 3. The value of the size argument, if buf is not a null pointer and no
+  // null byte is found.
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "a"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 16, "a+"));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fseeko(fp, 0, SEEK_END));
+  EXPECT_EQ(16, ftell(fp));
+  EXPECT_EQ(16, ftello(fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_SEEK_END) {
+  // fseek SEEK_END is relative to the current string length, not the buffer size.
+  FILE* fp;
+  char buf[8];
+  memset(buf, 'x', sizeof(buf));
+  strcpy(buf, "str");
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "w+"));
+  ASSERT_NE(EOF, fputs("string", fp));
+  EXPECT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(static_cast<long>(strlen("string")), ftell(fp));
+  EXPECT_EQ(static_cast<off_t>(strlen("string")), ftello(fp));
+  EXPECT_EQ(0, fclose(fp));
+
+  // glibc < 2.22 interpreted SEEK_END the wrong way round (subtracting rather
+  // than adding).
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "w+"));
+  ASSERT_NE(EOF, fputs("54321", fp));
+  EXPECT_EQ(0, fseek(fp, -2, SEEK_END));
+  EXPECT_EQ('2', fgetc(fp));
+  EXPECT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_seek_invalid) {
+  char buf[8];
+  memset(buf, 'x', sizeof(buf));
+  FILE* fp = fmemopen(buf, sizeof(buf), "w");
+  ASSERT_TRUE(fp != nullptr);
+
+  // POSIX: "An attempt to seek ... to a negative position or to a position
+  // larger than the buffer size given in the size argument shall fail."
+  // (There's no mention of what errno should be set to, and glibc doesn't
+  // set errno in any of these cases.)
+  EXPECT_EQ(-1, fseek(fp, -2, SEEK_SET));
+  EXPECT_EQ(-1, fseeko(fp, -2, SEEK_SET));
+  EXPECT_EQ(-1, fseek(fp, sizeof(buf) + 1, SEEK_SET));
+  EXPECT_EQ(-1, fseeko(fp, sizeof(buf) + 1, SEEK_SET));
+}
+
+TEST(STDIO_TEST, fmemopen_read_EOF) {
+  // POSIX: "A read operation on the stream shall not advance the current
+  // buffer position beyond the current buffer size."
+  char buf[8];
+  memset(buf, 'x', sizeof(buf));
+  FILE* fp = fmemopen(buf, sizeof(buf), "r");
+  ASSERT_TRUE(fp != nullptr);
+  char buf2[BUFSIZ];
+  ASSERT_EQ(8U, fread(buf2, 1, sizeof(buf2), fp));
+  // POSIX: "Reaching the buffer size in a read operation shall count as
+  // end-of-file.
+  ASSERT_TRUE(feof(fp));
+  ASSERT_EQ(EOF, fgetc(fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_read_null_bytes) {
+  // POSIX: "Null bytes in the buffer shall have no special meaning for reads."
+  char buf[] = "h\0e\0l\0l\0o";
+  FILE* fp = fmemopen(buf, sizeof(buf), "r");
+  ASSERT_TRUE(fp != nullptr);
+  ASSERT_EQ('h', fgetc(fp));
+  ASSERT_EQ(0, fgetc(fp));
+  ASSERT_EQ('e', fgetc(fp));
+  ASSERT_EQ(0, fgetc(fp));
+  ASSERT_EQ('l', fgetc(fp));
+  ASSERT_EQ(0, fgetc(fp));
+  // POSIX: "The read operation shall start at the current buffer position of
+  // the stream."
+  char buf2[8];
+  memset(buf2, 'x', sizeof(buf2));
+  ASSERT_EQ(4U, fread(buf2, 1, sizeof(buf2), fp));
+  ASSERT_EQ('l', buf2[0]);
+  ASSERT_EQ(0, buf2[1]);
+  ASSERT_EQ('o', buf2[2]);
+  ASSERT_EQ(0, buf2[3]);
+  for (size_t i = 4; i < sizeof(buf2); ++i) ASSERT_EQ('x', buf2[i]) << i;
+  ASSERT_TRUE(feof(fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_write) {
+  FILE* fp;
+  char buf[8];
+
+  // POSIX: "A write operation shall start either at the current position of
+  // the stream (if mode has not specified 'a' as the first character)..."
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "r+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+  ASSERT_EQ(' ', fputc(' ', fp));
+  EXPECT_EQ("xx xxxxx", std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
+
+  // "...or at the current size of the stream (if mode had 'a' as the first
+  // character)." (See the fmemopen_size test for what "size" means, but for
+  // mode "a", it's the first NUL byte.)
+  memset(buf, 'x', sizeof(buf));
+  buf[3] = '\0';
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "a+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(' ', fputc(' ', fp));
+  EXPECT_EQ("xxx \0xxx"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
+
+  // "If the current position at the end of the write is larger than the
+  // current buffer size, the current buffer size shall be set to the current
+  // position." (See the fmemopen_size test for what "size" means, but to
+  // query it we SEEK_END with offset 0, and then ftell.)
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "w+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(0, ftell(fp));
+  ASSERT_EQ(' ', fputc(' ', fp));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(1, ftell(fp));
+  ASSERT_NE(EOF, fputs("123", fp));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(4, ftell(fp));
+  EXPECT_EQ(" 123\0xxx"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_write_EOF) {
+  // POSIX: "A write operation on the stream shall not advance the current
+  // buffer size beyond the size given in the size argument."
+  FILE* fp;
+
+  // Scalar writes...
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 4, "w"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ('x', fputc('x', fp));
+  ASSERT_EQ('x', fputc('x', fp));
+  ASSERT_EQ('x', fputc('x', fp));
+  ASSERT_EQ(EOF, fputc('x', fp)); // Only 3 fit because of the implicit NUL.
+  ASSERT_EQ(0, fclose(fp));
+
+  // Vector writes...
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 4, "w"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(3U, fwrite("xxxx", 1, 4, fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_initial_position) {
+  // POSIX: "The ... current position in the buffer ... shall be initially
+  // set to either the beginning of the buffer (for r and w modes) ..."
+  char buf[] = "hello\0world";
+  FILE* fp;
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "r"));
+  EXPECT_EQ(0L, ftell(fp));
+  EXPECT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "w"));
+  EXPECT_EQ(0L, ftell(fp));
+  EXPECT_EQ(0, fclose(fp));
+  buf[0] = 'h'; // (Undo the effects of the above.)
+
+  // POSIX: "...or to the first null byte in the buffer (for a modes)."
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "a"));
+  EXPECT_EQ(5L, ftell(fp));
+  EXPECT_EQ(0, fclose(fp));
+
+  // POSIX: "If no null byte is found in append mode, the initial position
+  // shall be set to one byte after the end of the buffer."
+  memset(buf, 'x', sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "a"));
+  EXPECT_EQ(static_cast<long>(sizeof(buf)), ftell(fp));
+  EXPECT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_initial_position_allocated) {
+  // POSIX: "If buf is a null pointer, the initial position shall always be
+  // set to the beginning of the buffer."
+  FILE* fp = fmemopen(nullptr, 128, "a+");
+  ASSERT_TRUE(fp != nullptr);
+  EXPECT_EQ(0L, ftell(fp));
+  EXPECT_EQ(0L, fseek(fp, 0, SEEK_SET));
+  EXPECT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_zero_length) {
+  // POSIX says it's up to the implementation whether or not you can have a
+  // zero-length buffer (but "A future version of this standard may require
+  // support of zero-length buffer streams explicitly"). BSD and glibc < 2.22
+  // agreed that you couldn't, but glibc >= 2.22 allows it for consistency.
+  FILE* fp;
+  char buf[16];
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 0, "r+"));
+  ASSERT_EQ(EOF, fgetc(fp));
+  ASSERT_TRUE(feof(fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 0, "r+"));
+  ASSERT_EQ(EOF, fgetc(fp));
+  ASSERT_TRUE(feof(fp));
+  ASSERT_EQ(0, fclose(fp));
+
+  ASSERT_NE(nullptr, fp = fmemopen(buf, 0, "w+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(EOF, fputc('x', fp));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 0, "w+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(EOF, fputc('x', fp));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_write_only_allocated) {
+  // POSIX says fmemopen "may fail if the mode argument does not include a '+'".
+  // BSD fails, glibc doesn't. We side with the more lenient.
+  FILE* fp;
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "r"));
+  ASSERT_EQ(0, fclose(fp));
+  ASSERT_NE(nullptr, fp = fmemopen(nullptr, 16, "w"));
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_fileno) {
+  // There's no fd backing an fmemopen FILE*.
+  FILE* fp = fmemopen(nullptr, 16, "r");
+  ASSERT_TRUE(fp != nullptr);
   errno = 0;
-  ASSERT_EQ(nullptr, fmemopen(nullptr, 0, "r"));
-  ASSERT_EQ(EINVAL, errno);
+  ASSERT_EQ(-1, fileno(fp));
+  ASSERT_EQ(EBADF, errno);
+  ASSERT_EQ(0, fclose(fp));
+}
+
+TEST(STDIO_TEST, fmemopen_append_after_seek) {
+  // In BSD and glibc < 2.22, append mode didn't force writes to append if
+  // there had been an intervening seek.
+
+  FILE* fp;
+  char buf[] = "hello\0world";
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "a"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_SET));
+  ASSERT_NE(EOF, fputc('!', fp));
+  EXPECT_EQ("hello!\0orld\0"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
+
+  memcpy(buf, "hello\0world", sizeof(buf));
+  ASSERT_NE(nullptr, fp = fmemopen(buf, sizeof(buf), "a+"));
+  setbuf(fp, nullptr); // Turn off buffering so we can see what's happening as it happens.
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_SET));
+  ASSERT_NE(EOF, fputc('!', fp));
+  EXPECT_EQ("hello!\0orld\0"s, std::string(buf, buf + sizeof(buf)));
+  ASSERT_EQ(0, fclose(fp));
 }
 
 TEST(STDIO_TEST, open_memstream) {
@@ -1465,3 +1864,57 @@
   sprintf(&buf[0], "hello");
   ASSERT_EQ(buf, "hello");
 }
+
+TEST(STDIO_TEST, fopen_append_mode_and_ftell) {
+  TemporaryFile tf;
+  SetFileTo(tf.filename, "0123456789");
+  FILE* fp = fopen(tf.filename, "a");
+  EXPECT_EQ(10, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+  EXPECT_EQ(2, ftell(fp));
+  ASSERT_NE(EOF, fputs("xxx", fp));
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fclose(fp));
+  AssertFileIs(tf.filename, "0123456789xxx");
+}
+
+TEST(STDIO_TEST, fdopen_append_mode_and_ftell) {
+  TemporaryFile tf;
+  SetFileTo(tf.filename, "0123456789");
+  int fd = open(tf.filename, O_RDWR);
+  ASSERT_NE(-1, fd);
+  // POSIX: "The file position indicator associated with the new stream is set to the position
+  // indicated by the file offset associated with the file descriptor."
+  ASSERT_EQ(4, lseek(fd, 4, SEEK_SET));
+  FILE* fp = fdopen(fd, "a");
+  EXPECT_EQ(4, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+  EXPECT_EQ(2, ftell(fp));
+  ASSERT_NE(EOF, fputs("xxx", fp));
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fclose(fp));
+  AssertFileIs(tf.filename, "0123456789xxx");
+}
+
+TEST(STDIO_TEST, freopen_append_mode_and_ftell) {
+  TemporaryFile tf;
+  SetFileTo(tf.filename, "0123456789");
+  FILE* other_fp = fopen("/proc/version", "r");
+  FILE* fp = freopen(tf.filename, "a", other_fp);
+  EXPECT_EQ(10, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 2, SEEK_SET));
+  EXPECT_EQ(2, ftell(fp));
+  ASSERT_NE(EOF, fputs("xxx", fp));
+  ASSERT_EQ(0, fflush(fp));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
+  EXPECT_EQ(13, ftell(fp));
+  ASSERT_EQ(0, fclose(fp));
+  AssertFileIs(tf.filename, "0123456789xxx");
+}
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 4c4c102..c724f74 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -555,54 +555,6 @@
   close(fd);
 }
 
-TEST(stdlib, strtol_EINVAL) {
-  errno = 0;
-  strtol("123", NULL, -1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtol("123", NULL, 1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtol("123", NULL, 37);
-  ASSERT_EQ(EINVAL, errno);
-}
-
-TEST(stdlib, strtoll_EINVAL) {
-  errno = 0;
-  strtoll("123", NULL, -1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoll("123", NULL, 1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoll("123", NULL, 37);
-  ASSERT_EQ(EINVAL, errno);
-}
-
-TEST(stdlib, strtoul_EINVAL) {
-  errno = 0;
-  strtoul("123", NULL, -1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoul("123", NULL, 1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoul("123", NULL, 37);
-  ASSERT_EQ(EINVAL, errno);
-}
-
-TEST(stdlib, strtoull_EINVAL) {
-  errno = 0;
-  strtoull("123", NULL, -1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoull("123", NULL, 1);
-  ASSERT_EQ(EINVAL, errno);
-  errno = 0;
-  strtoull("123", NULL, 37);
-  ASSERT_EQ(EINVAL, errno);
-}
-
 TEST(stdlib, getsubopt) {
   char* const tokens[] = {
     const_cast<char*>("a"),
@@ -648,3 +600,51 @@
   // "mblen() shall ... return 0 (if s points to the null byte)".
   EXPECT_EQ(0, mblen("", 1));
 }
+
+template <typename T>
+static void CheckStrToInt(T fn(const char* s, char** end, int base)) {
+  char* end_p;
+
+  // Negative base => invalid.
+  errno = 0;
+  ASSERT_EQ(T(0), fn("123", &end_p, -1));
+  ASSERT_EQ(EINVAL, errno);
+
+  // Base 1 => invalid (base 0 means "please guess").
+  errno = 0;
+  ASSERT_EQ(T(0), fn("123", &end_p, 1));
+  ASSERT_EQ(EINVAL, errno);
+
+  // Base > 36 => invalid.
+  errno = 0;
+  ASSERT_EQ(T(0), fn("123", &end_p, 37));
+  ASSERT_EQ(EINVAL, errno);
+
+  // If we see "0x" *not* followed by a hex digit, we shouldn't swallow the 'x'.
+  ASSERT_EQ(T(0), fn("0xy", &end_p, 16));
+  ASSERT_EQ('x', *end_p);
+}
+
+TEST(stdlib, strtol_smoke) {
+  CheckStrToInt(strtol);
+}
+
+TEST(stdlib, strtoll_smoke) {
+  CheckStrToInt(strtoll);
+}
+
+TEST(stdlib, strtoul_smoke) {
+  CheckStrToInt(strtoul);
+}
+
+TEST(stdlib, strtoull_smoke) {
+  CheckStrToInt(strtoull);
+}
+
+TEST(stdlib, strtoimax_smoke) {
+  CheckStrToInt(strtoimax);
+}
+
+TEST(stdlib, strtoumax_smoke) {
+  CheckStrToInt(strtoumax);
+}
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index 00322ec..78fcf2b 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -66,14 +66,28 @@
   long result = ptrace(PTRACE_GETHBPREGS, child, 0, &capabilities);
   if (result == -1) {
     EXPECT_EQ(EIO, errno);
+    GTEST_LOG_(INFO) << "Hardware debug support disabled at kernel configuration time.";
     return false;
   }
-  switch (feature) {
-    case HwFeature::Watchpoint:
-      return ((capabilities >> 8) & 0xff) > 0;
-    case HwFeature::Breakpoint:
-      return (capabilities & 0xff) > 0;
+  uint8_t hb_count = capabilities & 0xff;
+  capabilities >>= 8;
+  uint8_t wp_count = capabilities & 0xff;
+  capabilities >>= 8;
+  uint8_t max_wp_size = capabilities & 0xff;
+  if (max_wp_size == 0) {
+    GTEST_LOG_(INFO)
+        << "Kernel reports zero maximum watchpoint size. Hardware debug support missing.";
+    return false;
   }
+  if (feature == HwFeature::Watchpoint && wp_count == 0) {
+    GTEST_LOG_(INFO) << "Kernel reports zero hardware watchpoints";
+    return false;
+  }
+  if (feature == HwFeature::Breakpoint && hb_count == 0) {
+    GTEST_LOG_(INFO) << "Kernel reports zero hardware breakpoints";
+    return false;
+  }
+  return true;
 #elif defined(__aarch64__)
   user_hwdebug_state dreg_state;
   iovec iov;
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index c887f8a..8b29667 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -280,7 +280,10 @@
 
   char bytes[MB_LEN_MAX];
 
+  memset(bytes, 1, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'\0', NULL));
+  EXPECT_EQ('\0', bytes[0]);
+  EXPECT_EQ('\x01', bytes[1]);
 
   memset(bytes, 0, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'h', NULL));
@@ -408,4 +411,3 @@
   GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
 #endif
 }
-
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 109b92c..9b811ed 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -759,6 +759,7 @@
   EXPECT_GT(_POSIX_TZNAME_MAX, 0);
   EXPECT_NE(-1, _POSIX_VDISABLE);
 
+  EXPECT_EQ(_POSIX_VERSION, _POSIX2_VERSION);
   EXPECT_GT(_POSIX2_BC_BASE_MAX, 0);
   EXPECT_GT(_POSIX2_BC_DIM_MAX, 0);
   EXPECT_GT(_POSIX2_BC_SCALE_MAX, 0);
@@ -784,7 +785,6 @@
   EXPECT_EQ(-1, _POSIX_SPAWN);
   EXPECT_EQ(-1, _POSIX_THREAD_ROBUST_PRIO_INHERIT);
 
-  EXPECT_EQ(-1, _POSIX2_VERSION);
   EXPECT_EQ(-1, _POSIX2_CHAR_TERM);
   EXPECT_EQ(-1, _POSIX2_C_DEV);
   EXPECT_EQ(-1, _POSIX2_LOCALEDEF);
@@ -837,6 +837,7 @@
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_FORT_DEV);
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_FORT_RUN);
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_UPE);
+  VERIFY_SYSCONF_POSIX_VERSION(_SC_2_VERSION);
   VERIFY_SYSCONF_POSITIVE(_SC_JOB_CONTROL);
   VERIFY_SYSCONF_POSITIVE(_SC_SAVED_IDS);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_VERSION);
@@ -952,7 +953,6 @@
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_CHAR_TERM);
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_LOCALEDEF);
   VERIFY_SYSCONF_UNSUPPORTED(_SC_2_SW_DEV);
-  VERIFY_SYSCONF_UNSUPPORTED(_SC_2_VERSION);
 
   VERIFY_SYSCONF_UNSUPPORTED(_SC_XOPEN_CRYPT);
   VERIFY_SYSCONF_UNSUPPORTED(_SC_XOPEN_ENH_I18N);
@@ -1372,3 +1372,10 @@
   ASSERT_EXIT(execve("/system/bin/run-as", args, envs), testing::ExitedWithCode(1),
               "<unknown>: usage: run-as");
 }
+
+TEST(UNISTD_TEST, getlogin_r) {
+  char buf[LOGIN_NAME_MAX] = {};
+  EXPECT_EQ(ERANGE, getlogin_r(buf, 0));
+  EXPECT_EQ(0, getlogin_r(buf, sizeof(buf)));
+  EXPECT_STREQ(getlogin(), buf);
+}
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 830eb70..a795d2c 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -445,6 +445,18 @@
   ASSERT_EQ(L'e', dst[1]);
   ASSERT_EQ(L'l', dst[2]);
   ASSERT_EQ(&s[3], src);
+
+  memset(dst, 0, sizeof(dst));
+  const char* incomplete = "\xc2"; // Incomplete UTF-8 sequence.
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(dst, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
+
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(nullptr, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
 }
 
 TEST(wchar, wcsftime) {
@@ -742,3 +754,80 @@
 TEST(wchar, wcstold) {
   CheckWcsToFloat(wcstold);
 }
+
+static void AssertWcwidthRange(wchar_t begin, wchar_t end, int expected) {
+  for (wchar_t i = begin; i < end; ++i) {
+    EXPECT_EQ(expected, wcwidth(i)) << static_cast<int>(i);
+  }
+}
+
+TEST(wchar, wcwidth_NUL) {
+  // NUL is defined to return 0 rather than -1, despite being a C0 control.
+  EXPECT_EQ(0, wcwidth(0));
+}
+
+TEST(wchar, wcwidth_ascii) {
+  AssertWcwidthRange(0x20, 0x7f, 1); // Non-C0 non-DEL ASCII.
+}
+
+TEST(wchar, wcwidth_controls) {
+  AssertWcwidthRange(0x01, 0x20, -1); // C0 controls.
+  EXPECT_EQ(-1, wcwidth(0x7f)); // DEL.
+  AssertWcwidthRange(0x80, 0xa0, -1); // C1 controls.
+}
+
+TEST(wchar, wcwidth_non_spacing_and_enclosing_marks_and_format) {
+  EXPECT_EQ(0, wcwidth(0x0300)); // Combining grave.
+  EXPECT_EQ(0, wcwidth(0x20dd)); // Combining enclosing circle.
+  EXPECT_EQ(0, wcwidth(0x00ad)); // Soft hyphen (SHY).
+  EXPECT_EQ(0, wcwidth(0x200b)); // Zero width space.
+}
+
+TEST(wchar, wcwidth_cjk) {
+  EXPECT_EQ(2, wcwidth(0x4e00)); // Start of CJK unified block.
+  EXPECT_EQ(2, wcwidth(0x9fff)); // End of CJK unified block.
+  EXPECT_EQ(2, wcwidth(0x3400)); // Start of CJK extension A block.
+  EXPECT_EQ(2, wcwidth(0x4dbf)); // End of CJK extension A block.
+  EXPECT_EQ(2, wcwidth(0x20000)); // Start of CJK extension B block.
+  EXPECT_EQ(2, wcwidth(0x2a6df)); // End of CJK extension B block.
+}
+
+TEST(wchar, wcwidth_korean_combining_jamo) {
+  AssertWcwidthRange(0x1160, 0x1200, 0); // Original range.
+  EXPECT_EQ(0, wcwidth(0xd7b0)); // Newer.
+  EXPECT_EQ(0, wcwidth(0xd7cb));
+}
+
+TEST(wchar, wcwidth_korean_jeongeul_syllables) {
+  EXPECT_EQ(2, wcwidth(0xac00)); // Start of block.
+  EXPECT_EQ(2, wcwidth(0xd7a3)); // End of defined code points in Unicode 7.
+  // Undefined characters at the end of the block have width 1.
+}
+
+TEST(wchar, wcwidth_kana) {
+  // Hiragana (most, not undefined).
+  AssertWcwidthRange(0x3041, 0x3097, 2);
+  // Katakana.
+  AssertWcwidthRange(0x30a0, 0x3100, 2);
+}
+
+TEST(wchar, wcwidth_circled_two_digit_cjk) {
+  // Circled two-digit CJK "speed sign" numbers are wide,
+  // though EastAsianWidth is ambiguous.
+  AssertWcwidthRange(0x3248, 0x3250, 2);
+}
+
+TEST(wchar, wcwidth_hexagrams) {
+  // Hexagrams are wide, though EastAsianWidth is neutral.
+  AssertWcwidthRange(0x4dc0, 0x4e00, 2);
+}
+
+TEST(wchar, wcwidth_default_ignorables) {
+  AssertWcwidthRange(0xfff0, 0xfff8, 0); // Unassigned by default ignorable.
+  EXPECT_EQ(0, wcwidth(0xe0000)); // ...through 0xe0fff.
+}
+
+TEST(wchar, wcwidth_korean_common_non_syllables) {
+  EXPECT_EQ(2, wcwidth(L'ㅜ')); // Korean "crying" emoticon.
+  EXPECT_EQ(2, wcwidth(L'ㅋ')); // Korean "laughing" emoticon.
+}
diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc
index 96e6efd..275e486 100644
--- a/tools/relocation_packer/src/elf_file.cc
+++ b/tools/relocation_packer/src/elf_file.cc
@@ -234,24 +234,22 @@
   }
 
   // Loading failed if we did not find the required special sections.
-  if (!found_relocations_section) {
-    LOG(ERROR) << "Missing or empty .rel.dyn or .rela.dyn section";
-    return false;
-  }
   if (!found_dynamic_section) {
     LOG(ERROR) << "Missing .dynamic section";
     return false;
   }
 
-  // Loading failed if we could not identify the relocations type.
-  if (!has_rel_relocations && !has_rela_relocations) {
-    LOG(ERROR) << "No relocations sections found";
-    return false;
-  }
-  if (has_rel_relocations && has_rela_relocations) {
-    LOG(ERROR) << "Multiple relocations sections with different types found, "
-               << "not currently supported";
-    return false;
+  if (found_relocations_section != nullptr) {
+    // Loading failed if we could not identify the relocations type.
+    if (!has_rel_relocations && !has_rela_relocations) {
+      LOG(ERROR) << "No relocations sections found";
+      return false;
+    }
+    if (has_rel_relocations && has_rela_relocations) {
+      LOG(ERROR) << "Multiple relocations sections with different types found, "
+                 << "not currently supported";
+      return false;
+    }
   }
 
   elf_ = elf;
@@ -682,6 +680,11 @@
     return false;
   }
 
+  if (relocations_section_ == nullptr) {
+    // There is nothing to do
+    return true;
+  }
+
   // Retrieve the current dynamic relocations section data.
   Elf_Data* data = GetSectionData(relocations_section_);
   // we always pack rela, because packed format is pretty much the same
@@ -831,6 +834,11 @@
     return false;
   }
 
+  if (relocations_section_ == nullptr) {
+    // There is nothing to do
+    return true;
+  }
+
   typename ELF::Shdr* section_header = ELF::getshdr(relocations_section_);
   // Retrieve the current packed android relocations section data.
   Elf_Data* data = GetSectionData(relocations_section_);