Merge remote-tracking branch 'aosp/upstream-master'

* aosp/upstream-master: (34 commits)
  syslog: revert LOG_FAC/LOG_FACMASK changes
  siglongjmp: document why this function just calls longjmp
  inet_ntop: fix the IPv6 leading zero sequence compression
  dynlink: avoid copying to temp buffer in get_lfs64
  sys/epoll.h: add epoll ioctls
  getusershell: skip blank lines and comments
  dynlink: fix get_lfs64() with posix_fallocate64
  syslog: fix incorrect LOG_MAKEPRI and LOG_FAC[MASK] macros
  add renameat2 linux syscall wrapper
  fix mismatched type in posix_getdents definition
  aarch64 crti.o: fix alignment of _init/_fini
  fix typo that broke sys/reg.h and sys/user.h
  implement posix_getdents adopted for next issue of POSIX
  stdint.h: derive limits from __LONG_MAX, use common fast16 types
  sys/user.h: derive __WORDSIZE from __LONG_MAX
  sys/reg.h: derive __WORDSIZE from __LONG_MAX
  unistd.h: derive ILP32/LP64 macros from __LONG_MAX instead of arch bits
  unify bits/stat.h for all archs sharing a common definition
  align aarch64, riscv64, loongarch64 stat structure padding type
  ldso: fix non-functional fix to early dynamic PAGE_SIZE access
  ...

Test: builds
Bug: 366560307
Change-Id: Idb2e014d70aeea578abcf5bf75b56352bb11bf89
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..49f66dd
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,816 @@
+// Build musl libc from source to eventually use as the libc for host modules in the platform build.
+// The list of sources to compile for each library is loaded from sources.bp, which is generated
+// by generate_bp.py.
+
+package {
+    default_visibility: ["//visibility:private"],
+    default_applicable_licenses: ["musl_license"],
+}
+
+license {
+    name: "musl_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-MIT",
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: ["COPYRIGHT"],
+}
+
+cc_library_headers {
+    name: "libc_musl_arch_headers",
+    host_supported: true,
+    device_supported: false,
+    system_shared_libs: [],
+    generated_headers: [
+        "libc_musl_alltypes.h",
+        "libc_musl_syscall.h",
+    ],
+    export_generated_headers: [
+        "libc_musl_alltypes.h",
+        "libc_musl_syscall.h",
+    ],
+    export_include_dirs: [
+        "arch/generic",
+    ],
+    arch: {
+        arm: {
+            export_include_dirs: ["arch/arm"],
+        },
+        arm64: {
+            export_include_dirs: ["arch/aarch64"],
+        },
+        x86: {
+            export_include_dirs: ["arch/i386"],
+        },
+        x86_64: {
+            export_include_dirs: ["arch/x86_64"],
+        },
+    },
+}
+
+cc_library_headers {
+    name: "libc_musl_private_headers",
+    host_supported: true,
+    device_supported: false,
+    system_shared_libs: [],
+    generated_headers: [
+        "libc_musl_version.h",
+    ],
+    export_generated_headers: [
+        "libc_musl_version.h",
+    ],
+    export_include_dirs: [
+        "src/include",
+        "src/internal",
+    ],
+}
+
+cc_library_headers {
+    name: "libc_musl_public_headers",
+    host_supported: true,
+    device_supported: false,
+    system_shared_libs: [],
+    export_system_include_dirs: [
+        "android/include",
+        "include",
+    ],
+}
+
+cc_defaults {
+    name: "libc_musl_base_defaults",
+    host_supported: true,
+    device_supported: false,
+    system_shared_libs: [],
+    cflags: [
+        // CFLAGS_C99FSE
+        "-nostdinc",
+        "-ffreestanding",
+        "-Wa,--noexecstack",
+
+        // CFLAGS_AUTO
+        "-Os",
+        "-pipe",
+        "-fomit-frame-pointer",
+        "-fno-unwind-tables",
+        "-fno-asynchronous-unwind-tables",
+        "-ffunction-sections",
+        "-fdata-sections",
+        //"-w",
+        "-Wno-pointer-to-int-cast",
+        "-Werror=implicit-function-declaration",
+        "-Werror=implicit-int",
+        "-Werror=pointer-sign",
+        "-Werror=pointer-arith",
+        "-Werror=int-conversion",
+        "-Werror=incompatible-pointer-types",
+        "-Qunused-arguments",
+        "-Waddress",
+        "-Warray-bounds",
+        "-Wchar-subscripts",
+        "-Wduplicate-decl-specifier",
+        "-Winit-self",
+        "-Wreturn-type",
+        "-Wsequence-point",
+        "-Wstrict-aliasing",
+        "-Wunused-function",
+        "-Wunused-label",
+        "-Wunused-variable",
+
+        // CFLAGS_ALL
+        "-D_XOPEN_SOURCE=700",
+
+        // undefine NDEBUG from global flags, musl defines it locally
+        "-UNDEBUG",
+
+        // disable warnings:
+        "-Wno-bitwise-op-parentheses",
+        "-Wno-dangling-else",
+        "-Wno-ignored-attributes",
+        "-Wno-logical-op-parentheses",
+        "-Wno-missing-braces",
+        "-Wno-missing-field-initializers",
+        "-Wno-parentheses",
+        "-Wno-shift-op-parentheses",
+        "-Wno-string-plus-int",
+        "-Wno-unused-parameter",
+    ],
+
+    arch: {
+        x86: {
+            cflags: ["-frounding-math"],
+        },
+        x86_64: {
+            cflags: ["-frounding-math"],
+        },
+        arm: {
+            cflags: ["-Wno-ignored-pragmas"],
+        },
+        arm64: {
+            cflags: ["-Wno-ignored-pragmas"],
+        },
+    },
+
+    ldflags: [
+        "-Wl,--sort-section,alignment",
+        "-Wl,--sort-common",
+        "-Wl,--gc-sections",
+        "-Wl,--hash-style=both",
+        "-Wl,--no-undefined",
+        // Can't use --exclude-libs=ALL, that excludes the static libraries
+        // used for building subparts of libc_musl.
+        //"-Wl,--exclude-libs=ALL",
+        "-Wl,--exclude-libs=libgcc.a",
+        "-Wl,--exclude-libs=libgcc_stripped.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+    ],
+
+    asflags: ["-Wno-unused-command-line-argument"],
+
+    stl: "none",
+    c_std: "c99",
+    sanitize: {
+        never: true,
+    },
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        bionic: {
+            enabled: false,
+        },
+        glibc: {
+            enabled: false,
+        },
+    },
+    lto: {
+        never: true,
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_defaults",
+    defaults: ["libc_musl_base_defaults"],
+    header_libs: [
+        // The order here is very important, private headers like src/include/features.h override
+        // public headers like include/features.h, and arch headers like arch/x86_64/ksigaction.h
+        // override private headers like src/internal/ksigaction.h.
+        "libc_musl_arch_headers",
+        "libc_musl_private_headers",
+        "libc_musl_public_headers",
+    ],
+}
+
+cc_library_headers {
+    name: "libc_musl_headers",
+    visibility: ["//bionic/libc"],
+    host_supported: true,
+    device_supported: false,
+    system_shared_libs: [],
+    export_header_lib_headers: [
+        "libc_musl_arch_headers",
+        "libc_musl_public_headers",
+        "libc_uapi_headers",
+    ],
+    header_libs: [
+        "libc_musl_arch_headers",
+        "libc_musl_public_headers",
+        "libc_uapi_headers",
+    ],
+}
+
+//
+// The main musl libc library
+//
+
+cc_library {
+    name: "libc_musl",
+    visibility: ["//visibility:public"],
+    defaults: ["libc_musl_defaults"],
+    whole_static_libs: ["libc_musl_static"],
+    shared: {
+        whole_static_libs: ["libc_musl_ldso"],
+    },
+    ldflags: [
+        "-Wl,-e,_dlstart",
+        "-nostdlib",
+    ],
+    dynamic_list: "dynamic.list",
+    export_header_lib_headers: [
+        "libc_musl_arch_headers",
+        "libc_musl_public_headers",
+        "libc_uapi_headers",
+    ],
+    header_libs: [
+        "libc_uapi_headers",
+    ],
+}
+
+// All the static parts of the main musl libc.  Don't use this directly, use
+// the version exported through libc_musl instead.
+cc_library_static {
+    name: "libc_musl_static",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_sources",
+    ],
+    whole_static_libs: [
+        "libc_musl_opt",
+        "libc_musl_opt_nossp",
+        "libc_musl_nossp",
+        "libexecinfo",
+        "libb64",
+        "libunwind",
+    ],
+    multilib: {
+        lib32: {
+            whole_static_libs: ["libc_musl_compat32"],
+        },
+    },
+    export_header_lib_headers: [
+        "libc_musl_arch_headers",
+        "libc_musl_public_headers",
+        "libc_uapi_headers",
+    ],
+    header_libs: [
+        "libc_uapi_headers",
+    ],
+}
+
+// Musl sources that are compiled with -O3
+cc_library_static {
+    name: "libc_musl_opt",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_opt_sources",
+    ],
+    cflags: ["-O3"],
+}
+
+// Musl sources that are compiled with -O3 and -fno-stack-protector
+cc_library_static {
+    name: "libc_musl_opt_nossp",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_opt_nossp_sources",
+    ],
+    cflags: [
+        "-O3",
+        "-fno-stack-protector",
+    ],
+}
+
+// Musl sources that are compiled with -fno-stack-protector
+cc_library_static {
+    name: "libc_musl_nossp",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_nossp_sources",
+    ],
+    cflags: ["-fno-stack-protector"],
+}
+
+// Musl sources for 32-bit architectures
+cc_library_static {
+    name: "libc_musl_compat32",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_compat32_sources",
+    ],
+}
+
+// Musl sources for the dynamic linker.
+cc_library_static {
+    name: "libc_musl_ldso",
+    defaults: [
+        "libc_musl_defaults",
+        "libc_musl_ldso_sources",
+    ],
+    cflags: [
+        "-fno-stack-protector",
+        "-DLIBC_SONAME=libc_musl.so",
+    ],
+}
+
+// An attempt to compile the dynamic linker as a standalone library separate from libc_musl.so.
+// Not used yet.
+cc_library_shared {
+    name: "musl_linker",
+    defaults: [
+        "libc_musl_defaults",
+    ],
+    nocrt: true,
+    static_libs: [
+        "libc_musl_ldso",
+        "libc_musl",
+    ],
+    ldflags: [
+        "-Wl,-e,_dlstart",
+        "-nostdlib",
+        "-Wl,--exclude-libs=libc_musl.a",
+    ],
+}
+
+//
+// The musl CRT objects
+//
+
+cc_defaults {
+    name: "libc_musl_crt_defaults",
+    defaults: ["libc_musl_base_defaults"],
+    cflags: [
+        // These are required to make sure the C code in crt/*.c
+        // doesn't have any dependencies on libc.
+        "-fno-stack-protector",
+        "-ftrivial-auto-var-init=uninitialized",
+    ],
+    ldflags: [
+        "-Wl,--no-gc-sections",
+    ],
+
+    // The headers below are the same as the header_libs in
+    // libc_musl_defaults, but bazel considers the crt depending
+    // on a header lib to be a circular dependency (toolchain ->
+    // crt objects -> header lib -> toolchain).
+    // TODO(b/263407827): go back to using header_libs once bazel
+    // supports it without introducing a dependency on the toolchain.
+    arch: {
+        arm: {
+            local_include_dirs: ["arch/arm"],
+        },
+        arm64: {
+            local_include_dirs: ["arch/aarch64"],
+        },
+        x86: {
+            local_include_dirs: ["arch/i386"],
+        },
+        x86_64: {
+            local_include_dirs: ["arch/x86_64"],
+        },
+    },
+    generated_headers: [
+        "libc_musl_alltypes.h",
+        "libc_musl_syscall.h",
+        "libc_musl_version.h",
+    ],
+    local_include_dirs: [
+        "arch/generic",
+        "src/include",
+        "src/internal",
+        "android/include",
+        "include",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crt1",
+    defaults: [
+        "libc_musl_crt_defaults",
+        "libc_musl_crt1_sources",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crti",
+    defaults: [
+        "libc_musl_crt_defaults",
+        "libc_musl_crti_sources",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crtn",
+    defaults: [
+        "libc_musl_crt_defaults",
+        "libc_musl_crtn_sources",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_rcrt1",
+    defaults: [
+        "libc_musl_crt_defaults",
+        "libc_musl_rcrt1_sources",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_Scrt1",
+    defaults: [
+        "libc_musl_crt_defaults",
+        "libc_musl_Scrt1_sources",
+    ],
+}
+
+//
+// The custom CRT objects for use in the platform build.
+// Embeds the linker into crtbegin_dynamic.
+//
+
+cc_object {
+    name: "libc_musl_crtbegin_dynamic",
+    defaults: ["libc_musl_crt_defaults"],
+    visibility: ["//visibility:public"],
+    objs: [
+        "libc_musl_crti",
+        "clang_rt.crtbegin",
+    ],
+    srcs: [
+        "android/relinterp.c",
+    ],
+    cflags: ["-DLOADER_PATH=\"libc_musl.so\""],
+}
+
+cc_object {
+    name: "libc_musl_crtbegin_static",
+    defaults: ["libc_musl_crt_defaults"],
+    visibility: ["//visibility:public"],
+    objs: [
+        "libc_musl_Scrt1",
+        "libc_musl_crti",
+        "clang_rt.crtbegin",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crtend",
+    defaults: ["libc_musl_crt_defaults"],
+    visibility: ["//visibility:public"],
+    objs: [
+        "clang_rt.crtend",
+        "libc_musl_crtn",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crtbegin_so",
+    defaults: ["libc_musl_crt_defaults"],
+    visibility: ["//visibility:public"],
+    objs: [
+        "libc_musl_crti",
+        "clang_rt.crtbegin",
+    ],
+}
+
+cc_object {
+    name: "libc_musl_crtend_so",
+    defaults: ["libc_musl_crt_defaults"],
+    visibility: ["//visibility:public"],
+    objs: [
+        "clang_rt.crtend",
+        "libc_musl_crtn",
+    ],
+}
+
+//
+// Tests for the embedded linker trampoline
+//
+
+cc_test_host {
+    name: "libc_musl_ldso_trampoline_test",
+    srcs: ["android/ldso_trampoline_test.cpp"],
+    stl: "libc++",
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+//
+// Generated headers
+//
+
+genrule {
+    name: "libc_musl_version.h",
+    srcs: ["VERSION"],
+    out: ["version.h"],
+    cmd: "printf '#define VERSION \"%s\"\n' \"$$(cat $(location VERSION))\" > $(out)",
+}
+
+// libc_musl_arch_alltypes.h is split out of libc_musl_alltypes.h to ensure the arch-specific
+// alltypes.h.in ends up before the generic alltypes.h.in in the output.
+cc_genrule {
+    name: "libc_musl_arch_alltypes.h",
+    host_supported: true,
+    device_supported: false,
+    arch: {
+        arm: {
+            srcs: ["arch/arm/bits/alltypes.h.in"],
+        },
+        arm64: {
+            srcs: ["arch/aarch64/bits/alltypes.h.in"],
+        },
+        x86: {
+            srcs: ["arch/i386/bits/alltypes.h.in"],
+        },
+        x86_64: {
+            srcs: ["arch/x86_64/bits/alltypes.h.in"],
+        },
+    },
+    tool_files: ["tools/mkalltypes.sed"],
+    out: ["bits/arch/alltypes.h"],
+    cmd: "sed -f $(location tools/mkalltypes.sed) $(in) > $(out)",
+}
+
+cc_genrule {
+    name: "libc_musl_alltypes.h",
+    host_supported: true,
+    device_supported: false,
+    srcs: [
+        "include/alltypes.h.in",
+        ":libc_musl_arch_alltypes.h",
+    ],
+    tool_files: ["tools/mkalltypes.sed"],
+    out: ["bits/alltypes.h"],
+    cmd: "( " +
+        "cat $(location :libc_musl_arch_alltypes.h) && " +
+        "sed -f $(location tools/mkalltypes.sed) $(location include/alltypes.h.in) " +
+        ") > $(out)",
+}
+
+cc_genrule {
+    name: "libc_musl_syscall.h",
+    host_supported: true,
+    device_supported: false,
+    arch: {
+        arm: {
+            srcs: ["arch/arm/bits/syscall.h.in"],
+        },
+        arm64: {
+            srcs: ["arch/aarch64/bits/syscall.h.in"],
+        },
+        x86: {
+            srcs: ["arch/i386/bits/syscall.h.in"],
+        },
+        x86_64: {
+            srcs: ["arch/x86_64/bits/syscall.h.in"],
+        },
+    },
+    out: ["bits/syscall.h"],
+    cmd: "cp $(in) $(out) && sed -n -e s/__NR_/SYS_/p < $(in) >> $(out)",
+}
+
+//
+// Rules to generate a sysroot.  This isn't used during the build, but can be convenient to run
+// configure scripts from external projects to generate necessary files to build against musl.
+//
+
+
+// An empty static library that will be copied to libdl.a, etc. in the sysroot.
+// Shouldn't be used by anything else besides the sysroot cc_genrule.
+cc_library_static {
+    name: "libc_musl_sysroot_static_empty",
+    defaults: [
+        "libc_musl_defaults",
+    ],
+}
+
+// The linker and trampoline compiled as a .o file to use as part of the sysroot
+// crt.
+cc_object {
+    name: "libc_musl_linker_object",
+    defaults: ["libc_musl_crt_defaults"],
+    srcs: [
+        "android/relinterp.c",
+    ],
+    cflags: ["-DLOADER_PATH=\"libc_musl.so\""],
+}
+
+// The architecture-specific bits have to be handled separately because the label varies based
+// on architecture, which prevents using $(locations) to find them and requires using $(in)
+// instead, which would mix in all the other files if this were part of the main libc_musl_sysroot
+// genrule.
+cc_genrule {
+    name: "libc_musl_sysroot_bits",
+    host_supported: true,
+    device_supported: false,
+    arch: {
+        arm: {
+            srcs: ["arch/arm/bits/*.h"],
+        },
+        arm64: {
+            srcs: ["arch/aarch64/bits/*.h"],
+        },
+        x86: {
+            srcs: ["arch/i386/bits/*.h"],
+        },
+        x86_64: {
+            srcs: ["arch/x86_64/bits/*.h"],
+        },
+    },
+    out: ["libc_musl_sysroot_bits.zip"],
+    tools: ["soong_zip"],
+    cmd: "includes=($(in)) && $(location soong_zip) -o $(out) -P include/bits -j -D $$(dirname $${includes[0]})",
+}
+
+genrule {
+    name: "libc_musl_clang_wrapper",
+    srcs: ["tools/musl-clang.in"],
+    out: ["musl-clang"],
+    cmd: "sed -e 's`@CC@`clang`' -e 's`@PREFIX@`$$(dirname \"$$0\")/..`' -e 's`@INCDIR@`$${libc}/include`' -e 's`@LIBDIR@`$${libc}/lib`' $(in) > $(out) && " +
+        "chmod a+x $(out)",
+}
+
+genrule {
+    name: "libc_musl_ld_wrapper",
+    srcs: ["tools/ld.musl-clang.in"],
+    out: ["ld.musl-clang"],
+    cmd: "sed -e 's`@CC@`clang`' -e 's`@LIBDIR@`$$(dirname \"$$0\")/../lib`' -e 's`@LDSO@`$$(dirname \"$$0\")/../lib/ld-musl.so.1`' $(in) > $(out) && " +
+        "chmod a+x $(out)",
+}
+
+cc_library_host_static {
+    name: "libz_static_for_sysroot",
+    whole_static_libs: ["libz"],
+}
+
+cc_genrule {
+    name: "libc_musl_sysroot",
+    host_supported: true,
+    device_supported: false,
+    enabled: false,
+    target: {
+        musl: {
+            enabled: true,
+        },
+    },
+    srcs: [
+        "LICENSE",
+        "COPYRIGHT",
+
+        // Headers
+        "include/**/*.h",
+        "arch/generic/bits/*.h",
+        "android/include/bits/*.h",
+        "android/include/sys/cdefs.h",
+        ":libc_musl_syscall.h",
+        ":libc_musl_alltypes.h",
+        ":libc_musl_sysroot_bits",
+
+        // Bionic kernel uapi headers
+        ":libc_musl_sysroot_bionic_headers",
+
+        ":libc_musl_sysroot_zlib_headers",
+
+        // Libraries
+        ":libc_musl",
+        ":libc_musl_static",
+        ":libz_static_for_sysroot",
+
+        // Objects
+        ":libc_musl_crti",
+        ":libc_musl_crtn",
+        ":libc_musl_crt1",
+        ":libc_musl_rcrt1",
+        ":libc_musl_Scrt1",
+        ":clang_rt.crtbegin",
+        ":clang_rt.crtend",
+
+        // Embedded linker objects and linker scripts
+        ":libc_musl_linker_object",
+        "android/relinterp.script",
+
+        // Wrapper scripts
+        ":libc_musl_clang_wrapper",
+        ":libc_musl_ld_wrapper",
+
+        // Empty static libraries
+        ":libc_musl_sysroot_static_empty",
+    ],
+    out: ["libc_musl_sysroot.zip"],
+    tools: [
+        "soong_zip",
+        "merge_zips",
+        "zip2zip",
+    ],
+    cmd: "includes=($(locations include/**/*.h)) && " +
+        "bits=($(locations arch/generic/bits/*.h)) && " +
+        "android_bits=($(locations android/include/bits/*.h)) && " +
+        "ln -s libc_musl.so $(genDir)/ld-musl.so.1 && " +
+        "echo -e 'GROUP ( libc_musl_linker_object.o )\nINCLUDE relinterp.script' > $(genDir)/Scrt1.ld && " +
+        "echo -e 'GROUP ( libc_musl.so )' > $(genDir)/libc.so && " +
+        "$(location soong_zip) -o $(genDir)/sysroot.zip " +
+        " -j " +
+        "  -f $(location LICENSE) " +
+        "  -f $(location COPYRIGHT) " +
+        // headers
+        " -P include " +
+        "  -C $$(dirname $${includes[0]}) " +
+        "  -D $$(dirname $${includes[0]}) " +
+        " -P include/bits -j " +
+        "  -f $(location :libc_musl_syscall.h) " +
+        "  -f $(location :libc_musl_alltypes.h) " +
+        "  -D $$(dirname $${bits[0]}) " +
+        "  -D $$(dirname $${android_bits[0]}) " +
+        " -P include/sys -j " +
+        "  -f $(location android/include/sys/cdefs.h) " +
+        // embedded linker crt objects
+        " -P lib -j " +
+        "  -f $(location android/relinterp.script) " +
+        "  -f $(location :libc_musl_linker_object) " +
+        // libs
+        "  -f $(location :libc_musl) " +
+        "  -f $(genDir)/ld-musl.so.1 " +
+        "  -f $(genDir)/libc.so " +
+        // clang wrappers
+        " -P bin -j " +
+        "  -f $(location :libc_musl_clang_wrapper) " +
+        "  -f $(location :libc_musl_ld_wrapper) " +
+        " && " +
+        // libs in a separate zip so they can be renamed
+        "$(location soong_zip) -o $(genDir)/libs.zip " +
+        " -P lib -j " +
+        "  -f $(location :libc_musl_static) " +
+        "  -f $(location :libc_musl_sysroot_static_empty) " +
+        "  -f $(genDir)/Scrt1.ld " +
+        "  -f $(location :libc_musl_crti) " +
+        "  -f $(location :libc_musl_crtn) " +
+        "  -f $(location :libc_musl_crt1) " +
+        "  -f $(location :libc_musl_rcrt1) " +
+        "  -f $(location :libc_musl_Scrt1) " +
+        "  -f $(location :clang_rt.crtbegin) " +
+        "  -f $(location :clang_rt.crtend) " +
+        "  -f $(location :libz_static_for_sysroot) " +
+        " && " +
+        "$(location zip2zip) -i $(genDir)/libs.zip -o $(genDir)/libs_renamed.zip " +
+        // rename libs from module names to desired names in sysroot
+        " lib/libc_musl_static.a:lib/libc.a " +
+        // Swap in linker script for Scrt1.o
+        " lib/Scrt1.o:lib/Scrt1-real.o " +
+        " lib/Scrt1.ld:lib/Scrt1.o " +
+        // copy empty static libs
+        " lib/libc_musl_sysroot_static_empty.a:lib/libcrypt.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libdl.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libm.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libpthread.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libresolv.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/librt.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libutil.a " +
+        " lib/libc_musl_sysroot_static_empty.a:lib/libxnet.a " +
+        // rename clang crt objects to gcc names
+        " lib/clang_rt.crtbegin.o:lib/crtbegin.o " +
+        " lib/clang_rt.crtbegin.o:lib/crtbeginS.o " +
+        " lib/clang_rt.crtbegin.o:lib/crtbeginT.o " +
+        " lib/clang_rt.crtend.o:lib/crtend.o " +
+        " lib/clang_rt.crtend.o:lib/crtendS.o " +
+        // rename crt objects
+        " lib/libc_musl_crti.o:lib/crti.o " +
+        " lib/libc_musl_crtn.o:lib/crtn.o " +
+        " lib/libc_musl_crt1.o:lib/crt1.o " +
+        " lib/libc_musl_rcrt1.o:lib/rcrt1.o " +
+        // rename static libz
+        " lib/libz_static_for_sysroot.a:lib/libz.a " +
+        " && " +
+        "$(location merge_zips) -ignore-duplicates $(out) " +
+        " $(location :libc_musl_sysroot_bionic_headers) " +
+        " $(location :libc_musl_sysroot_zlib_headers) " +
+        " $(location :libc_musl_sysroot_bits) " +
+        " $(genDir)/sysroot.zip " +
+        " $(genDir)/libs_renamed.zip",
+}
+
+build=["sources.bp"]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..cf3af40
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+COPYRIGHT
\ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..113252e
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/musl
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
+name: "musl"
+description: "musl is an implementation of the C standard library built on top of the Linux system call API, including interfaces defined in the base language standard, POSIX, and widely agreed-upon extensions. musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety.  "
+third_party {
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2024
+    month: 3
+    day: 4
+  }
+  homepage: "https://musl.libc.org/"
+  identifier {
+    type: "Git"
+    value: "git://git.musl-libc.org/musl"
+    version: "v1.2.5"
+  }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..1db06a6
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+ccross@google.com
+enh@google.com
diff --git a/android/.clang-format b/android/.clang-format
new file mode 120000
index 0000000..f7e9891
--- /dev/null
+++ b/android/.clang-format
@@ -0,0 +1 @@
+../../../system/core/.clang-format-2
\ No newline at end of file
diff --git a/android/generate_bp.py b/android/generate_bp.py
new file mode 100755
index 0000000..45cbbcc
--- /dev/null
+++ b/android/generate_bp.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python3
+
+# This replicates the logic in Makefile to produce lists of generic
+# and architecture specific sources, then writes them into sources.bp
+# as cc_defaults modules for use by the Android.bp file.
+
+import copy
+import glob
+import os.path
+
+BP_TO_MUSL_ARCHES = {
+  'arm': 'arm',
+  'arm64': 'aarch64',
+  'x86': 'i386',
+  'x86_64': 'x86_64',
+}
+
+SRC_DIRS = (
+  'src/*',
+  'src/malloc/mallocng',
+)
+COMPAT32_SRC_DIRS = (
+  'compat/time32',
+)
+OPT_DIRS = (
+  'src/internal',
+  'src/malloc',
+  'src/string',
+)
+NOSSP_SRCS = (
+  'src/env/__libc_start_main.c',
+  'src/env/__init_tls.c',
+  'src/env/__stack_chk_fail.c',
+  'src/thread/__set_thread_area.c',
+  'src/string/memset.c',
+  'src/string/memcpy.c',
+)
+LDSO_SRC_DIRS = (
+  'ldso',
+)
+CRT_SRCS = (
+  'crt/crt1.c',
+  'crt/crti.c',
+  'crt/crtn.c',
+  'crt/rcrt1.c',
+  'crt/Scrt1.c',
+)
+
+def overridden_base_src(arch, src):
+  src = src.replace('/'+arch+'/','/')
+  if src.endswith('.s') or src.endswith('.S'):
+    src = src[:-2]+'.c'
+  return src
+
+def overridden_base_srcs(arch, srcs):
+  return [overridden_base_src(arch, src) for src in srcs]
+
+def glob_dirs(*args):
+  """glob_dirs takes a list of parts of glob patterns, some of which may be
+  lists or tuples, expands the lists and tuples into every combination
+  of patterns, and returns the glob expansion of the patterns."""
+  ret = []
+  for i, arg in enumerate(args):
+    if type(arg) is list or type(arg) is tuple:
+      for entry in arg:
+        new_args = list(args)
+        new_args[i] = entry
+        ret += glob_dirs(*new_args)
+      return ret
+  return sorted(glob.glob('/'.join(args)))
+
+def force_exists(files):
+  """force_exists raises an exception if any of the input files are missing
+  and returns the sorted list of inputs files"""
+  files = sorted(files)
+  glob_files = glob_dirs(files)
+  if glob_files != files:
+    raise(Exception('failed to find sources: %s' % ', '.join(['"'+x+'"' for x in list(set(files) - set(glob_files))])))
+  return files
+
+def files_to_arch_files(base_files, arch):
+  files=[]
+  for f in base_files:
+    base, ext = os.path.splitext(os.path.basename(f))
+    pattern = os.path.join(os.path.dirname(f), arch, base+'.[csS]')
+    glob_files = glob.glob(pattern)
+    if len(glob_files) > 1:
+      raise(Exception('expected at most one file for %s, found %s' % (pattern, glob_files)))
+    elif glob_files:
+      files.append(glob_files[0])
+
+  return files
+
+class SourceSet(object):
+  def __init__(self, *, dirs=[], files=[]):
+    self.srcs = self._srcs(dirs, files)
+    self.arch_srcs, self.arch_exclude_srcs = self._arch_srcs(dirs, files)
+
+  def _srcs(self, dirs, files):
+    return glob_dirs(dirs, '*.c') + force_exists(files)
+
+  def _arch_srcs(self, dirs, files):
+    srcs = {}
+    exclude_srcs = {}
+    for bp_arch, musl_arch in BP_TO_MUSL_ARCHES.items():
+      arch_srcs = glob_dirs(dirs, musl_arch, '*.[csS]')
+      arch_srcs += files_to_arch_files(files, musl_arch)
+      arch_exclude_srcs = overridden_base_srcs(musl_arch, arch_srcs)
+      if arch_srcs:
+        srcs[bp_arch] = arch_srcs
+      if arch_exclude_srcs:
+        exclude_srcs[bp_arch] = arch_exclude_srcs
+    return srcs, exclude_srcs
+
+  def intersect(self, other):
+    diff = self.subtract(other)
+    return self.subtract(diff)
+
+  def subtract(self, other):
+    ret = copy.deepcopy(self)
+    ret.srcs = sorted(list(set(ret.srcs) - set(other.srcs)))
+    for bp_arch in BP_TO_MUSL_ARCHES:
+      ret.arch_srcs[bp_arch] = sorted(list(set(ret.arch_srcs[bp_arch]) - set(other.arch_srcs[bp_arch])))
+      ret.arch_exclude_srcs[bp_arch] = sorted(list(set(ret.arch_exclude_srcs[bp_arch]) - set(other.arch_exclude_srcs[bp_arch])))
+    return ret
+
+  def union(self, other):
+    ret = copy.deepcopy(self)
+    ret.srcs = sorted(ret.srcs + other.srcs)
+    for bp_arch in BP_TO_MUSL_ARCHES:
+      ret.arch_srcs[bp_arch] = sorted(ret.arch_srcs[bp_arch] + other.arch_srcs[bp_arch])
+      ret.arch_exclude_srcs[bp_arch] = sorted(ret.arch_exclude_srcs[bp_arch] + other.arch_exclude_srcs[bp_arch])
+    return self
+
+class Blueprint(object):
+  def __init__(self, out):
+    self.out = out
+
+  def PrintHeader(self):
+    self.out.write(
+"""// Copyright (C) 2021 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.
+
+// This file is created by generate_bp.py. Do not edit manually.
+""")
+
+  def PrintDefaults(self, name, srcs):
+    """Print a cc_defaults section from a list of source files, architecture
+    specific source files, and source files replaced by architecture specific
+    source files"""
+    self.out.write('\n')
+    self.out.write('cc_defaults {\n')
+    self.out.write('    name: "%s",\n' % name)
+    self.out.write('    srcs: [\n')
+    for f in srcs.srcs:
+      self.out.write('        "%s",\n' % f)
+    self.out.write('    ],\n')
+
+    if srcs.arch_srcs or srcs.arch_exclude_srcs:
+      self.out.write('    arch: {\n')
+      for arch in BP_TO_MUSL_ARCHES.keys():
+        if srcs.arch_srcs[arch] or srcs.arch_exclude_srcs[arch]:
+          self.out.write('        %s: {\n' % arch)
+          if srcs.arch_srcs[arch]:
+            self.out.write('            srcs: [\n')
+            for f in srcs.arch_srcs[arch]:
+              self.out.write('                "%s",\n' % f)
+            self.out.write('            ],\n')
+          if srcs.arch_exclude_srcs[arch]:
+            self.out.write('            exclude_srcs: [\n')
+            for f in srcs.arch_exclude_srcs[arch]:
+              self.out.write('                "%s",\n' % f)
+            self.out.write('            ],\n')
+          self.out.write('        },\n')
+      self.out.write('    },\n')
+
+    self.out.write('}\n')
+
+
+libc = SourceSet(dirs=SRC_DIRS)
+compat32 = SourceSet(dirs=COMPAT32_SRC_DIRS)
+opt = SourceSet(dirs=OPT_DIRS)
+nossp = SourceSet(files=NOSSP_SRCS)
+ldso = SourceSet(dirs=LDSO_SRC_DIRS)
+
+crts = {}
+for crt in CRT_SRCS:
+  srcs = SourceSet(files=[crt])
+  name = os.path.splitext(os.path.basename(crt))[0]
+  crts[name] = srcs
+
+libc = libc.subtract(opt).subtract(nossp)
+opt_nossp = opt.intersect(nossp)
+opt = opt.subtract(opt_nossp)
+nossp = nossp.subtract(opt_nossp)
+
+dir_name = os.path.dirname(os.path.realpath(__file__))
+
+with open(os.path.join(dir_name, '..', 'sources.bp'), 'w+') as out:
+  bp = Blueprint(out)
+  bp.PrintHeader()
+  bp.PrintDefaults('libc_musl_sources', libc)
+  bp.PrintDefaults('libc_musl_compat32_sources', compat32)
+  bp.PrintDefaults('libc_musl_opt_sources', opt)
+  bp.PrintDefaults('libc_musl_opt_nossp_sources', opt_nossp)
+  bp.PrintDefaults('libc_musl_nossp_sources', nossp)
+  bp.PrintDefaults('libc_musl_ldso_sources', ldso)
+  for crt in sorted(crts.keys()):
+    bp.PrintDefaults('libc_musl_%s_sources' % crt, crts[crt])
diff --git a/android/include/bits/in_addr.h b/android/include/bits/in_addr.h
new file mode 100644
index 0000000..07313e5
--- /dev/null
+++ b/android/include/bits/in_addr.h
@@ -0,0 +1,4 @@
+#pragma once
+
+// musl defines in_addr in netinet/in.h
+#include <netinet/in.h>
diff --git a/android/include/bits/ip_mreq_source.h b/android/include/bits/ip_mreq_source.h
new file mode 100644
index 0000000..b8aeb8c
--- /dev/null
+++ b/android/include/bits/ip_mreq_source.h
@@ -0,0 +1,4 @@
+#pragma once
+
+// musl defines ip_mreq_source in netinet/in.h
+#include <netinet/in.h>
diff --git a/android/include/bits/ip_msfilter.h b/android/include/bits/ip_msfilter.h
new file mode 100644
index 0000000..262a294
--- /dev/null
+++ b/android/include/bits/ip_msfilter.h
@@ -0,0 +1,4 @@
+#pragma once
+
+// musl defines ip_msfilter in netinet/in.h
+#include <netinet/in.h>
diff --git a/android/include/bits/sockaddr_storage.h b/android/include/bits/sockaddr_storage.h
new file mode 100644
index 0000000..0de9de1
--- /dev/null
+++ b/android/include/bits/sockaddr_storage.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <features.h>
+
+#define __NEED_sa_family_t
+#include <bits/alltypes.h>
+
+struct sockaddr_storage {
+	sa_family_t ss_family;
+	char __ss_padding[128-sizeof(long)-sizeof(sa_family_t)];
+	unsigned long __ss_align;
+};
diff --git a/android/include/bits/tcphdr.h b/android/include/bits/tcphdr.h
new file mode 100644
index 0000000..174e400
--- /dev/null
+++ b/android/include/bits/tcphdr.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <features.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+struct tcphdr {
+#ifdef _GNU_SOURCE
+#ifdef __GNUC__
+	__extension__
+#endif
+	union { struct {
+
+	uint16_t source;
+	uint16_t dest;
+	uint32_t seq;
+	uint32_t ack_seq;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	uint16_t res1:4;
+	uint16_t doff:4;
+	uint16_t fin:1;
+	uint16_t syn:1;
+	uint16_t rst:1;
+	uint16_t psh:1;
+	uint16_t ack:1;
+	uint16_t urg:1;
+	uint16_t res2:2;
+#else
+	uint16_t doff:4;
+	uint16_t res1:4;
+	uint16_t res2:2;
+	uint16_t urg:1;
+	uint16_t ack:1;
+	uint16_t psh:1;
+	uint16_t rst:1;
+	uint16_t syn:1;
+	uint16_t fin:1;
+#endif
+	uint16_t window;
+	uint16_t check;
+	uint16_t urg_ptr;
+
+	}; struct {
+#endif
+
+	uint16_t th_sport;
+	uint16_t th_dport;
+	uint32_t th_seq;
+	uint32_t th_ack;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	uint8_t th_x2:4;
+	uint8_t th_off:4;
+#else
+	uint8_t th_off:4;
+	uint8_t th_x2:4;
+#endif
+	uint8_t th_flags;
+	uint16_t th_win;
+	uint16_t th_sum;
+	uint16_t th_urp;
+
+#ifdef _GNU_SOURCE
+	}; };
+#endif
+};
+
+#endif
diff --git a/android/include/features.h b/android/include/features.h
new file mode 100644
index 0000000..7865504
--- /dev/null
+++ b/android/include/features.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+
+/*
+ * Globally enable _LARGEFILE64_SOURCE in Android builds when _GNU_SOURCE is
+ * set.  Using a global build flag is difficult because some code uses
+ * #define _LARGEFILE64_SOURCE and other code uses #define _LARGEFILE64_SOURCE 1
+ * leading to redefinition errors when either value is used as a global flag.
+ */
+#if defined(_GNU_SOURCE)
+#if !defined(_LARGEFILE64_SOURCE)
+#define _LARGEFILE64_SOURCE
+#endif
+#endif
+
+
+#include_next <features.h>
diff --git a/android/include/math.h b/android/include/math.h
new file mode 100644
index 0000000..dbc80be
--- /dev/null
+++ b/android/include/math.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+/* GNU extensions not in musl. */
+
+#if defined(_GNU_SOURCE)
+#define M_El            2.718281828459045235360287471352662498L /* e */
+#define M_LOG2El        1.442695040888963407359924681001892137L /* log 2e */
+#define M_LOG10El       0.434294481903251827651128918916605082L /* log 10e */
+#define M_LN2l          0.693147180559945309417232121458176568L /* log e2 */
+#define M_LN10l         2.302585092994045684017991454684364208L /* log e10 */
+#define M_PIl           3.141592653589793238462643383279502884L /* pi */
+#define M_PI_2l         1.570796326794896619231321691639751442L /* pi/2 */
+#define M_PI_4l         0.785398163397448309615660845819875721L /* pi/4 */
+#define M_1_PIl         0.318309886183790671537767526745028724L /* 1/pi */
+#define M_2_PIl         0.636619772367581343075535053490057448L /* 2/pi */
+#define M_2_SQRTPIl     1.128379167095512573896158903121545172L /* 2/sqrt(pi) */
+#define M_SQRT2l        1.414213562373095048801688724209698079L /* sqrt(2) */
+#define M_SQRT1_2l      0.707106781186547524400844362104849039L /* 1/sqrt(2) */
+#endif
+
+#include_next <math.h>
diff --git a/android/include/resolv.h b/android/include/resolv.h
new file mode 100644
index 0000000..41dfb9a
--- /dev/null
+++ b/android/include/resolv.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include_next <resolv.h>
+#include <bionic/b64.h>
diff --git a/android/include/sys/capability.h b/android/include/sys/capability.h
new file mode 100644
index 0000000..85096b4
--- /dev/null
+++ b/android/include/sys/capability.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+/**
+ * @file sys/capability.h
+ * @brief Capabilities.
+ */
+
+#include <sys/cdefs.h>
+#include <linux/capability.h>
+
+__BEGIN_DECLS
+
+/**
+ * [capget(2)](http://man7.org/linux/man-pages/man2/capget.2.html) gets the calling
+ * thread's capabilities.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ */
+int capget(cap_user_header_t __hdr_ptr, cap_user_data_t __data_ptr);
+
+/**
+ * [capset(2)](http://man7.org/linux/man-pages/man2/capset.2.html) sets the calling
+ * thread's capabilities.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ */
+int capset(cap_user_header_t __hdr_ptr, const cap_user_data_t __data_ptr);
+
+__END_DECLS
diff --git a/android/include/sys/cdefs.h b/android/include/sys/cdefs.h
new file mode 100644
index 0000000..03302bd
--- /dev/null
+++ b/android/include/sys/cdefs.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS }
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
diff --git a/android/include/unistd.h b/android/include/unistd.h
new file mode 100644
index 0000000..8089b8d
--- /dev/null
+++ b/android/include/unistd.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+
+/* Used to retry syscalls that can return EINTR. */
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    __typeof__(exp) _rc;                   \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#include_next <unistd.h>
diff --git a/android/ldso_trampoline.cpp b/android/ldso_trampoline.cpp
new file mode 100644
index 0000000..72b550c
--- /dev/null
+++ b/android/ldso_trampoline.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define START "__dlwrap__start"
+
+#include "crt_arch.h"
+
+#include <elf.h>
+#include <link.h>
+#include "reloc.h"
+
+#define AUX_CNT 32
+
+#include "ldso_trampoline_phdr.h"
+
+// The location of the embedded linker in the executable.
+// Hidden visibility is used to get a pc-relative reference instead
+// of a GOT reference, which isn't available when this code runs.
+__attribute__((visibility("hidden"))) extern const char __dlwrap_linker;
+__attribute__((visibility("hidden"))) extern const char __dlwrap_linker_end;
+
+// The real entry point of the binary to use after linker bootstrapping.
+__attribute__((visibility("hidden"))) extern "C" void _start();
+
+// Allocate some R/W memory to store a copy of the program headers.
+static ElfW(Phdr) phdr_copy[64];
+
+static size_t get_auxv(size_t* auxv, size_t entry) {
+  for (size_t i = 0; auxv[i]; i += 2)
+    if (auxv[i] == entry) return auxv[i + 1];
+  return 0;
+}
+
+static void set_auxv(size_t* auxv, size_t entry, size_t value) {
+  for (size_t i = 0; auxv[i]; i += 2) {
+    if (auxv[i] == entry) {
+      auxv[i + 1] = value;
+      return;
+    }
+  }
+  __builtin_trap();
+}
+
+/*
+ * This is the entry point for the linker wrapper, which finds
+ * the real linker, then bootstraps into it.
+ */
+extern "C" void __dlwrap__start_c(size_t* sp) {
+  size_t i, aux[AUX_CNT];
+
+  int argc = *sp;
+  char** argv = reinterpret_cast<char**>(sp + 1);
+
+  for (i = argc + 1; argv[i]; i++)
+    ;
+  size_t* auxv = reinterpret_cast<size_t*>(argv + i + 1);
+
+  for (i = 0; i < AUX_CNT; i++) aux[i] = 0;
+  for (i = 0; auxv[i]; i += 2)
+    if (auxv[i] < AUX_CNT) aux[auxv[i]] = auxv[i + 1];
+
+  ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(get_auxv(auxv, AT_PHDR));
+  size_t phdr_count = get_auxv(auxv, AT_PHNUM);
+  ElfW(Addr) load_bias = get_elf_load_bias_from_phdr(phdr, phdr_count);
+
+  ElfW(Addr) linker_addr = reinterpret_cast<ElfW(Addr)>(&__dlwrap_linker);
+  ElfW(Addr) linker_size = static_cast<ElfW(Addr)>(&__dlwrap_linker_end - &__dlwrap_linker);
+  ElfW(Addr) linker_vaddr = linker_addr - load_bias;
+  ElfW(Addr) linker_entry_offset = reinterpret_cast<ElfW(Ehdr)*>(linker_addr)->e_entry;
+
+  // Make a copy of the ELF program headers that does not contain the load
+  // segments for the embedded linker.  The embedded linker contains its
+  // own copy of its load segments, which causes problems if musl uses
+  // both sets of load segments when donating unused space to the heap.
+  if (phdr_count > sizeof(phdr_copy) / sizeof(phdr_copy[0])) __builtin_trap();
+  copy_phdr(phdr, phdr_copy, phdr_count, load_bias);
+  phdr_trim_embedded_linker(phdr_copy, phdr_count, linker_vaddr, linker_vaddr + linker_size);
+
+  // Set AT_BASE to the embedded linker
+  set_auxv(auxv, AT_BASE, linker_addr);
+  // Set AT_ENTRY to the proper entry point
+  set_auxv(auxv, AT_ENTRY, reinterpret_cast<ElfW(Addr)>(&_start));
+  // Set AT_PHDR to the copied program headers
+  set_auxv(auxv, AT_PHDR, reinterpret_cast<ElfW(Addr)>(&phdr_copy));
+
+  // Jump to linker entry point
+  CRTJMP(linker_addr + linker_entry_offset, sp);
+}
diff --git a/android/ldso_trampoline_phdr.h b/android/ldso_trampoline_phdr.h
new file mode 100644
index 0000000..f41b2c8
--- /dev/null
+++ b/android/ldso_trampoline_phdr.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+/* Find the load bias (difference between address and p_vaddr) of an
+ * executable or shared object loaded by the kernel. The ELF file's
+ * PHDR table must have a PT_PHDR entry.  A VDSO doesn't have a PT_PHDR
+ * entry in its PHDR table.
+ */
+static inline ElfW(Addr)
+    get_elf_load_bias_from_phdr(const ElfW(Phdr) * phdr_table, size_t phdr_count) {
+  for (size_t i = 0; i < phdr_count; ++i) {
+    if (phdr_table[i].p_type == PT_PHDR) {
+      return reinterpret_cast<ElfW(Addr)>(phdr_table) - phdr_table[i].p_vaddr;
+    }
+  }
+  return 0;
+}
+
+/* Copy the phdr to a new location.  Update the PT_PHDR section to point to the
+ * new location.
+ */
+static inline void copy_phdr(ElfW(Phdr) * phdr_from, ElfW(Phdr) * phdr_to, size_t count,
+                             ElfW(Addr) load_bias) {
+  ElfW(Phdr)* pt_phdr = nullptr;       // The phdr entry with type PT_PHDR.
+  ElfW(Phdr)* phdr_to_phdr = nullptr;  // The phdr entry for the load segment that contains phdr_to.
+  ElfW(Phdr)* p = phdr_to;
+
+  // The ELF vaddr of phdr_to.
+  ElfW(Addr) phdr_to_vaddr = reinterpret_cast<ElfW(Addr)>(phdr_to) - load_bias;
+
+  for (size_t i = 0; i < count; ++i, ++p) {
+    // Assign each member to avoid the struct assignment being turned into a memcpy.
+    p->p_type = phdr_from[i].p_type;
+    p->p_offset = phdr_from[i].p_offset;
+    p->p_vaddr = phdr_from[i].p_vaddr;
+    p->p_paddr = phdr_from[i].p_paddr;
+    p->p_filesz = phdr_from[i].p_filesz;
+    p->p_memsz = phdr_from[i].p_memsz;
+    p->p_flags = phdr_from[i].p_flags;
+    p->p_align = phdr_from[i].p_align;
+
+    if (p->p_type == PT_PHDR) pt_phdr = p;
+    if (p->p_vaddr <= phdr_to_vaddr && p->p_vaddr + p->p_memsz > phdr_to_vaddr) phdr_to_phdr = p;
+  }
+
+  if (pt_phdr != nullptr && phdr_to_phdr != nullptr) {
+    pt_phdr->p_vaddr = reinterpret_cast<ElfW(Addr)>(phdr_to) - load_bias;
+    pt_phdr->p_paddr = pt_phdr->p_vaddr;
+    pt_phdr->p_offset = phdr_to_phdr->p_offset + (pt_phdr->p_vaddr - phdr_to_phdr->p_vaddr);
+  }
+}
+
+/* Trim a section to the given start and end.
+ */
+static inline void phdr_trim_segment(ElfW(Phdr) * phdr, ElfW(Addr) start, ElfW(Addr) end) {
+  const ElfW(Addr) shift = start - phdr->p_vaddr;
+  phdr->p_vaddr = start;
+  phdr->p_paddr = start;
+  phdr->p_memsz = end - start;
+  if (shift > 0) {
+    phdr->p_offset += shift;
+    phdr->p_filesz = (shift > phdr->p_filesz) ? 0 : (phdr->p_filesz - shift);
+  }
+  if (phdr->p_filesz > end - start) {
+    phdr->p_filesz = end - start;
+  }
+}
+
+/* Trim load sections that overlap with the embedded linker, and replace load sections
+ * that are entirely contained within the embedded linker with PT_NULL.
+ */
+static inline void phdr_trim_embedded_linker(ElfW(Phdr) * phdr, size_t phdr_count,
+                                             ElfW(Off) linker_start, ElfW(Off) linker_end) {
+  for (size_t i = 0; i < phdr_count; ++i, ++phdr) {
+    if (phdr->p_type != PT_LOAD) continue;
+
+    ElfW(Addr) start = phdr->p_vaddr;
+    ElfW(Addr) end = phdr->p_vaddr + phdr->p_memsz;
+
+    // A segment that surrounds an embedded linker segment is not supported;
+    if (start < linker_start && end > linker_end) __builtin_trap();
+
+    // Handle a segment that overlaps the beginning of the embedded linker;
+    if (start < linker_start && end > linker_start) end = linker_start;
+
+    // Handle a segment that overlaps the end of the embedded linker;
+    if (start < linker_end && end > linker_end) start = linker_end;
+
+    if (start < end && (start < linker_start || end > linker_end)) {
+      // The segment is still needed, trim it.
+      phdr_trim_segment(phdr, start, end);
+    } else {
+      // The segment is not needed, replace it with PT_NULL to avoid having
+      // to move the following segments in the phdr.
+      phdr->p_type = PT_NULL;
+    }
+  }
+}
diff --git a/android/ldso_trampoline_test.cpp b/android/ldso_trampoline_test.cpp
new file mode 100644
index 0000000..e3f3501
--- /dev/null
+++ b/android/ldso_trampoline_test.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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 <gtest/gtest.h>
+
+#include <link.h>
+
+#include "ldso_trampoline_phdr.h"
+
+struct PhdrTrimSegmentTestParameters {
+  std::string name;
+  size_t in_vaddr, in_filesz, in_memsz;
+  size_t out_vaddr, out_filesz, out_memsz;
+  size_t trim_start, trim_end;
+};
+
+class PhdrTrimSegmentTests : public ::testing::TestWithParam<PhdrTrimSegmentTestParameters> {
+ protected:
+};
+
+TEST_P(PhdrTrimSegmentTests, Tests) {
+  auto params = GetParam();
+  ElfW(Phdr) phdr{};
+  phdr.p_vaddr = params.in_vaddr;
+  phdr.p_paddr = params.in_vaddr;
+  phdr.p_filesz = params.in_filesz;
+  phdr.p_memsz = params.in_memsz;
+  phdr_trim_segment(&phdr, params.trim_start, params.trim_end);
+  ASSERT_EQ(phdr.p_vaddr, params.out_vaddr);
+  ASSERT_EQ(phdr.p_paddr, params.out_vaddr);
+  ASSERT_EQ(phdr.p_filesz, params.out_filesz);
+  ASSERT_EQ(phdr.p_memsz, params.out_memsz);
+}
+
+INSTANTIATE_TEST_CASE_P(ldso_trampoline, PhdrTrimSegmentTests,
+                        ::testing::Values(
+                            PhdrTrimSegmentTestParameters{
+                                .name = "noop",
+                                .in_vaddr = 1,
+                                .in_filesz = 2,
+                                .in_memsz = 2,
+                                .trim_start = 1,
+                                .trim_end = 3,
+                                .out_vaddr = 1,
+                                .out_filesz = 2,
+                                .out_memsz = 2,
+                            },
+                            PhdrTrimSegmentTestParameters{
+                                .name = "trim_beginning",
+                                .in_vaddr = 1,
+                                .in_filesz = 2,
+                                .in_memsz = 2,
+                                .trim_start = 2,
+                                .trim_end = 3,
+                                .out_vaddr = 2,
+                                .out_filesz = 1,
+                                .out_memsz = 1,
+                            },
+                            PhdrTrimSegmentTestParameters{
+                                .name = "trim_end",
+                                .in_vaddr = 1,
+                                .in_filesz = 2,
+                                .in_memsz = 2,
+                                .trim_start = 1,
+                                .trim_end = 2,
+                                .out_vaddr = 1,
+                                .out_filesz = 1,
+                                .out_memsz = 1,
+                            },
+                            PhdrTrimSegmentTestParameters{
+                                .name = "trim_data_bss",
+                                .in_vaddr = 1,
+                                .in_filesz = 2,
+                                .in_memsz = 3,
+                                .trim_start = 2,
+                                .trim_end = 4,
+                                .out_vaddr = 2,
+                                .out_filesz = 1,
+                                .out_memsz = 2,
+                            }),
+                        [](const testing::TestParamInfo<PhdrTrimSegmentTestParameters>& info) {
+                          return info.param.name;
+                        });
diff --git a/android/relinterp.c b/android/relinterp.c
new file mode 100644
index 0000000..c900e79
--- /dev/null
+++ b/android/relinterp.c
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define SYSCALL_NO_TLS 1
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
+#include <stdalign.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+#include "reloc.h"
+#include "syscall.h"
+
+typedef void EntryFunc(void);
+
+// arm64 doesn't have a constant page size and has to use the value from AT_PAGESZ.
+#ifndef PAGE_SIZE
+#define PAGE_SIZE g_page_size
+#endif
+
+#define PAGE_START(x) ((x) & (~(PAGE_SIZE-1)))
+#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
+
+#define START "_start"
+#include "crt_arch.h"
+
+int main();
+weak void _init();
+weak void _fini();
+int __libc_start_main(int (*)(), int, char **,
+  void (*)(), void(*)(), void(*)());
+
+static ElfW(Phdr) replacement_phdr_table[64];
+static char replacement_interp[PATH_MAX];
+
+static bool g_debug = false;
+static const char* g_prog_name = NULL;
+static uintptr_t g_page_size = 0;
+static int g_errno = 0;
+
+__attribute__((visibility("hidden"))) extern ElfW(Dyn) _DYNAMIC[];
+
+__attribute__((used))
+static long ri_set_errno(unsigned long val) {
+  if (val > -4096UL) {
+    g_errno = -val;
+    return -1;
+  }
+  return val;
+}
+
+#define ri_syscall(...) ri_set_errno(__syscall(__VA_ARGS__))
+
+static ssize_t ri_write(int fd, const void* buf, size_t amt) {
+  return ri_syscall(SYS_write, fd, buf, amt);
+}
+
+__attribute__((noreturn))
+static void ri_exit(int status) {
+  ri_syscall(SYS_exit, status);
+  __builtin_unreachable();
+}
+
+static int ri_open(const char* path, int flags, mode_t mode) {
+  return ri_syscall(SYS_openat, AT_FDCWD, path, flags, mode);
+}
+
+static int ri_close(int fd) {
+  return ri_syscall(SYS_close, fd);
+}
+
+static off_t ri_lseek(int fd, off_t offset, int whence) {
+  return ri_syscall(SYS_lseek, fd, offset, whence);
+}
+
+static ssize_t ri_readlink(const char* path, char* buf, size_t size) {
+  return ri_syscall(SYS_readlinkat, AT_FDCWD, path, buf, size);
+}
+
+static void* ri_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) {
+#ifdef SYS_mmap2
+  return (void*)ri_syscall(SYS_mmap2, addr, length, prot, flags, fd, offset/SYSCALL_MMAP2_UNIT);
+#else
+  return (void*)ri_syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
+#endif
+}
+
+static void* ri_munmap(void* addr, size_t length) {
+  return (void*)ri_syscall(SYS_munmap, addr, length);
+}
+
+static int ri_mprotect(void* addr, size_t len, int prot) {
+  return ri_syscall(SYS_mprotect, addr, len, prot);
+}
+
+static ssize_t ri_pread(int fd, void* buf, size_t size, off_t ofs) {
+  return ri_syscall(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs));
+}
+
+static size_t ri_strlen(const char* src) {
+  for (size_t len = 0;; ++len) {
+    if (src[len] == '\0') return len;
+  }
+}
+
+static char* ri_strcpy(char* dst, const char* src) {
+  char* result = dst;
+  while ((*dst = *src) != '\0') {
+    ++dst;
+    ++src;
+  }
+  return result;
+}
+
+static char* ri_strcat(char* dst, const char* src) {
+  ri_strcpy(dst + ri_strlen(dst), src);
+  return dst;
+}
+
+static void* ri_memset(void* dst, int val, size_t len) {
+  for (size_t i = 0; i < len; ++i) {
+    ((char*)dst)[i] = val;
+  }
+  return dst;
+}
+
+__attribute__ ((unused))
+static void* ri_memcpy(void* dst, const void* src, size_t len) {
+  for (size_t i = 0; i < len; ++i) {
+    ((char*)dst)[i] = ((char*)src)[i];
+  }
+  return dst;
+}
+
+static int ri_strncmp(const char* x, const char *y, size_t maxlen) {
+  for (size_t i = 0;; ++i) {
+    if (i == maxlen) return 0;
+    int result = (unsigned char)x[i] - (unsigned char)y[i];
+    if (result != 0) return result;
+    if (x[i] == '\0') return 0;
+  }
+}
+
+static int ri_strcmp(const char* x, const char *y) {
+  return ri_strncmp(x, y, SIZE_MAX);
+}
+
+static char* ri_strrchr(const char* str, int ch) {
+  char* result = NULL;
+  while (true) {
+    if (*str == ch) result = (char*)str;
+    if (*str == '\0') break;
+    ++str;
+  }
+  return result;
+}
+
+static char* ri_strchr(const char* str, int ch) {
+  while (*str) {
+    if (*str == ch) return (char*)str;
+    ++str;
+  }
+  return NULL;
+}
+
+static void ri_dirname(char* path) {
+  char* last_slash = ri_strrchr(path, '/');
+  if (last_slash == NULL) {
+    path[0] = '.';   // returns "."
+    path[1] = '\0';
+  } else if (last_slash == path) {
+    path[1] = '\0';  // returns "/"
+  } else {
+    *last_slash = '\0';
+  }
+}
+
+static void out_str_n(const char* str, size_t n) {
+  ri_write(STDERR_FILENO, str, n);
+}
+
+static void out_str(const char* str) {
+  out_str_n(str, ri_strlen(str));
+}
+
+static char* ul_to_str(unsigned long i, char* out, unsigned char base) {
+  char buf[65];
+  char* cur = &buf[65];
+  *--cur = '\0';
+  do {
+    *--cur = "0123456789abcdef"[i % base];
+    i /= base;
+  } while (i > 0);
+  return ri_strcpy(out, cur);
+}
+
+static char* l_to_str(long i, char* out, unsigned char base) {
+  if (i < 0) {
+    *out = '-';
+    ul_to_str(-(unsigned long)i, out + 1, base);
+    return out;
+  } else {
+    return ul_to_str(i, out, base);
+  }
+}
+
+static const char* ri_strerror(int err) {
+  switch (err) {
+    case EPERM: return "Operation not permitted";
+    case ENOENT: return "No such file or directory";
+    case EIO: return "I/O error";
+    case ENXIO: return "No such device or address";
+    case EAGAIN: return "Try again";
+    case ENOMEM: return "Out of memory";
+    case EACCES: return "Permission denied";
+    case ENODEV: return "No such device";
+    case ENOTDIR: return "Not a directory";
+    case EINVAL: return "Invalid argument";
+    case ENFILE: return "File table overflow";
+    case EMFILE: return "Too many open files";
+    case ESPIPE: return "Illegal seek";
+    case ENAMETOOLONG: return "File name too long";
+    case ELOOP: return "Too many symbolic links encountered";
+  }
+  static char buf[64];
+  ri_strcpy(buf, "Unknown error ");
+  l_to_str(err, buf + ri_strlen(buf), 10);
+  return buf;
+}
+
+static void outv(const char *fmt, va_list ap) {
+  char buf[65];
+  while (true) {
+    if (fmt[0] == '\0') break;
+
+#define NUM_FMT(num_fmt, type, func, base)                  \
+    if (!ri_strncmp(fmt, num_fmt, sizeof(num_fmt) - 1)) {   \
+      out_str(func(va_arg(ap, type), buf, base));           \
+      fmt += sizeof(num_fmt) - 1;                           \
+      continue;                                             \
+    }
+    NUM_FMT("%d",  int,           l_to_str,  10);
+    NUM_FMT("%ld", long,          l_to_str,  10);
+    NUM_FMT("%u",  unsigned int,  ul_to_str, 10);
+    NUM_FMT("%lu", unsigned long, ul_to_str, 10);
+    NUM_FMT("%zu", size_t,        ul_to_str, 10);
+    NUM_FMT("%x",  unsigned int,  ul_to_str, 16);
+    NUM_FMT("%lx", unsigned long, ul_to_str, 16);
+    NUM_FMT("%zx", size_t,        ul_to_str, 16);
+#undef NUM_FMT
+
+    if (!ri_strncmp(fmt, "%p", 2)) {
+      out_str(ul_to_str((unsigned long)va_arg(ap, void*), buf, 16));
+      fmt += 2;
+    } else if (!ri_strncmp(fmt, "%s", 2)) {
+      const char* arg = va_arg(ap, const char*);
+      out_str(arg ? arg : "(null)");
+      fmt += 2;
+    } else if (!ri_strncmp(fmt, "%%", 2)) {
+      out_str("%");
+      fmt += 2;
+    } else if (fmt[0] == '%') {
+      buf[0] = fmt[1];
+      buf[1] = '\0';
+      out_str("relinterp error: unrecognized output specifier: '%");
+      out_str(buf);
+      out_str("'\n");
+      ri_exit(1);
+    } else {
+      size_t len = 0;
+      while (fmt[len] != '\0' && fmt[len] != '%') ++len;
+      out_str_n(fmt, len);
+      fmt += len;
+    }
+  }
+}
+
+__attribute__((format(printf, 1, 2)))
+static void debug(const char* fmt, ...) {
+  if (!g_debug) return;
+  out_str("relinterp: ");
+
+  va_list ap;
+  va_start(ap, fmt);
+  outv(fmt, ap);
+  va_end(ap);
+  out_str("\n");
+}
+
+__attribute__((format(printf, 1, 2), noreturn))
+static void fatal(const char* fmt, ...) {
+  out_str("relinterp: ");
+  if (g_prog_name) {
+    out_str(g_prog_name);
+    out_str(": ");
+  }
+  out_str("fatal error: ");
+
+  va_list ap;
+  va_start(ap, fmt);
+  outv(fmt, ap);
+  va_end(ap);
+  out_str("\n");
+  ri_exit(1);
+}
+
+static void* optimizer_barrier(void* val) {
+  __asm__ volatile ("nop" :: "r"(&val) : "memory");
+  return val;
+}
+
+typedef struct {
+  unsigned long key;
+  unsigned long value;
+} AuxEntry;
+
+typedef struct {
+  int argc;
+  char **argv;
+  char **envp;
+  size_t envp_count;
+  AuxEntry* auxv;
+  size_t auxv_count;
+} KernelArguments;
+
+static KernelArguments read_args(void* raw_args) {
+  KernelArguments result;
+  result.argc = *(long*)raw_args;
+  result.argv = (char**)((void**)raw_args + 1);
+  result.envp = result.argv + result.argc + 1;
+
+  char** envp = result.envp;
+  while (*envp != NULL) ++envp;
+  result.envp_count = envp - result.envp;
+  ++envp;
+
+  result.auxv = (AuxEntry*)envp;
+  size_t count = 0;
+  while (result.auxv[count].key != 0) {
+    ++count;
+  }
+  result.auxv_count = count;
+  return result;
+}
+
+static void dump_auxv(const KernelArguments* args) {
+  for (size_t i = 0; i < args->auxv_count; ++i) {
+    const char* name = "";
+    switch (args->auxv[i].key) {
+      case AT_BASE: name = " [AT_BASE]"; break;
+      case AT_EGID: name = " [AT_EGID]"; break;
+      case AT_ENTRY: name = " [AT_ENTRY]"; break;
+      case AT_EUID: name = " [AT_EUID]"; break;
+      case AT_GID: name = " [AT_GID]"; break;
+      case AT_PAGESZ: name = " [AT_PAGESZ]"; break;
+      case AT_PHDR: name = " [AT_PHDR]"; break;
+      case AT_PHENT: name = " [AT_PHENT]"; break;
+      case AT_PHNUM: name = " [AT_PHNUM]"; break;
+      case AT_SECURE: name = " [AT_SECURE]"; break;
+      case AT_SYSINFO: name = " [AT_SYSINFO]"; break;
+      case AT_SYSINFO_EHDR: name = " [AT_SYSINFO_EHDR]"; break;
+      case AT_UID: name = " [AT_UID]"; break;
+    }
+    debug("  %lu => 0x%lx%s", args->auxv[i].key, args->auxv[i].value, name);
+  }
+}
+
+static unsigned long ri_getauxval(const KernelArguments* args, unsigned long kind,
+                                  bool allow_missing) {
+  for (size_t i = 0; i < args->auxv_count; ++i) {
+    if (args->auxv[i].key == kind) return args->auxv[i].value;
+  }
+  if (!allow_missing) fatal("could not find aux vector entry %lu", kind);
+  return 0;
+}
+
+static int elf_flags_to_prot(int flags) {
+  int result = 0;
+  if (flags & PF_R) result |= PROT_READ;
+  if (flags & PF_W) result |= PROT_WRITE;
+  if (flags & PF_X) result |= PROT_EXEC;
+  return result;
+}
+
+typedef struct {
+  int fd;
+  char path[PATH_MAX];
+} OpenedLoader;
+
+typedef struct {
+  void* base_addr;
+  EntryFunc* entry;
+} LoadedInterp;
+
+static LoadedInterp load_interp(const OpenedLoader *loader, ElfW(Ehdr)* hdr) {
+  ElfW(Phdr)* phdr = (ElfW(Phdr)*)((char*)hdr + hdr->e_phoff);
+  size_t phdr_count = hdr->e_phnum;
+
+  size_t max_vaddr = 0;
+
+  // Find the virtual address extent.
+  for (size_t i = 0; i < phdr_count; ++i) {
+    if (phdr[i].p_type == PT_LOAD) {
+      max_vaddr = PAGE_END(MAX(max_vaddr, phdr[i].p_vaddr + phdr[i].p_memsz));
+    }
+  }
+
+  // Map an area to fit the loader.
+  void* loader_vaddr = ri_mmap(NULL, max_vaddr, PROT_READ | PROT_WRITE,
+                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (loader_vaddr == (void*)MAP_FAILED) {
+    fatal("reservation mmap of 0x%zx bytes for %s failed: %s", max_vaddr, loader->path,
+          ri_strerror(g_errno));
+  }
+
+  // Map each PT_LOAD.
+  for (size_t i = 0; i < phdr_count; ++i) {
+    if (phdr[i].p_type == PT_LOAD) {
+      size_t start = PAGE_START(phdr[i].p_vaddr);
+      const size_t end = PAGE_END(phdr[i].p_vaddr + phdr[i].p_memsz);
+      if (phdr[i].p_filesz > 0) {
+        const size_t file_end = phdr[i].p_vaddr + phdr[i].p_filesz;
+        void* tmp = ri_mmap((char*)loader_vaddr + start,
+                            file_end - start,
+                            elf_flags_to_prot(phdr[i].p_flags),
+                            MAP_PRIVATE | MAP_FIXED, loader->fd, PAGE_START(phdr[i].p_offset));
+        if (tmp == (void*)MAP_FAILED) {
+          fatal("PT_LOAD mmap failed (%s segment #%zu): %s", loader->path, i,
+                ri_strerror(g_errno));
+        }
+        start = file_end;
+        if (phdr[i].p_flags & PF_W) {
+          // The bytes between p_filesz and PAGE_END(p_filesz) currently come from the file mapping,
+          // but they need to be zeroed. (Apparently this zeroing isn't necessary if the segment isn't
+          // writable, and zeroing a non-writable page would be inconvenient.)
+          ri_memset((char*)loader_vaddr + start, '\0', PAGE_END(start) - start);
+        }
+        start = PAGE_END(start);
+      }
+      if (start < end) {
+        // The memory is already zeroed, because it comes from an anonymous file mapping. Just set
+        // the protections correctly.
+        int result = ri_mprotect((char*)loader_vaddr + start, end - start,
+                                 elf_flags_to_prot(phdr[i].p_flags));
+        if (result != 0) {
+          fatal("mprotect of PT_LOAD failed (%s segment #%zu): %s", loader->path, i,
+                ri_strerror(g_errno));
+        }
+      }
+    }
+  }
+
+  return (LoadedInterp) {
+    .base_addr = loader_vaddr,
+    .entry = (EntryFunc*)((uintptr_t)loader_vaddr + hdr->e_entry),
+  };
+}
+
+typedef struct {
+  ElfW(Phdr)* phdr;
+  size_t phdr_count;
+  uintptr_t load_bias;
+  uintptr_t page_size;
+  char* search_paths;
+  ElfW(Ehdr)* ehdr;
+  ElfW(Phdr)* first_load;
+  bool secure;
+} ExeInfo;
+
+static ExeInfo get_exe_info(const KernelArguments* args) {
+  ExeInfo result = { 0 };
+  result.phdr = (ElfW(Phdr)*)ri_getauxval(args, AT_PHDR, false);
+  result.phdr_count = ri_getauxval(args, AT_PHNUM, false);
+  result.page_size = ri_getauxval(args, AT_PAGESZ, false);
+
+  unsigned long uid = ri_getauxval(args, AT_UID, false);
+  unsigned long euid = ri_getauxval(args, AT_EUID, false);
+  unsigned long gid = ri_getauxval(args, AT_GID, false);
+  unsigned long egid = ri_getauxval(args, AT_EGID, false);
+  unsigned long secure = ri_getauxval(args, AT_SECURE, true);
+  result.secure = uid != euid || gid != egid || secure;
+
+  debug("orig phdr     = %p", (void*)result.phdr);
+  debug("orig phnum    = %zu", result.phdr_count);
+
+  for (size_t i = 0; i < result.phdr_count; ++i) {
+    if (result.phdr[i].p_type == PT_DYNAMIC) {
+      result.load_bias = (uintptr_t)&_DYNAMIC - result.phdr[i].p_vaddr;
+    }
+  }
+  debug("load_bias     = 0x%lx", (unsigned long)result.load_bias);
+
+  for (size_t i = 0; i < result.phdr_count; ++i) {
+    ElfW(Phdr)* phdr = &result.phdr[i];
+    if (phdr->p_type != PT_LOAD) continue;
+    result.first_load = phdr;
+    if (phdr->p_offset != 0) {
+      fatal("expected zero p_offset for first PT_LOAD, found 0x%zx instead",
+            (size_t)phdr->p_offset);
+    }
+    result.ehdr = (ElfW(Ehdr)*)(phdr->p_vaddr + result.load_bias);
+    break;
+  }
+  debug("ehdr          = %p", (void*)result.ehdr);
+
+  ElfW(Word) runpath_offset = -1;
+  char* strtab = NULL;
+  for (ElfW(Dyn)* dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++) {
+    switch (dyn->d_tag) {
+    case DT_RUNPATH:
+      runpath_offset = dyn->d_un.d_val;
+      break;
+    case DT_RPATH:
+      if (runpath_offset == -1) runpath_offset = dyn->d_un.d_val;
+      break;
+    case DT_STRTAB:
+      strtab = (char*)(dyn->d_un.d_ptr + result.load_bias);
+      break;
+    }
+  }
+
+  if (strtab && runpath_offset != -1) {
+    result.search_paths = strtab + runpath_offset;
+    debug("dt_runpath    = %s", result.search_paths);
+  }
+  return result;
+}
+
+// Loaders typically read the PT_INTERP of the executable, e.g. to set a pathname on the loader.
+// glibc insists on the executable having PT_INTERP, and aborts if it's missing.  Musl passes it
+// to debuggers to find symbols for the loader, which includes all the libc symbols.
+//
+// Make a copy of the phdr table and insert PT_INTERP into the copy.
+//
+static void insert_pt_interp_into_phdr_table(const KernelArguments* args, const ExeInfo* exe,
+                                             const char* loader_realpath) {
+  // Reserve extra space for the inserted PT_PHDR and PT_INTERP segments and a null terminator.
+  if (exe->phdr_count + 3 > sizeof(replacement_phdr_table) / sizeof(replacement_phdr_table[0])) {
+    fatal("too many phdr table entries in executable");
+  }
+
+  ElfW(Phdr) newPhdr = {
+    .p_type = PT_PHDR,
+    // The replacement phdr is in the BSS section, which has no file location.
+    // Use 0 for the offset.  If this causes a problem the replacement phdr could
+    // be moved to the data section and the correct p_offset calculated.
+    .p_offset = 0,
+    .p_vaddr = (uintptr_t)&replacement_phdr_table - exe->load_bias,
+    .p_paddr = (uintptr_t)&replacement_phdr_table - exe->load_bias,
+    .p_memsz = (exe->phdr_count + 1) * sizeof(ElfW(Phdr)),
+    .p_filesz = (exe->phdr_count + 1) * sizeof(ElfW(Phdr)),
+    .p_flags = PF_R,
+    .p_align = alignof(ElfW(Phdr)),
+  };
+
+  ElfW(Phdr*) cur = replacement_phdr_table;
+  if (exe->phdr[0].p_type != PT_PHDR) {
+    // ld.bfd does not insert a PT_PHDR if there is no PT_INTERP, fake one.
+    // It has to be first.  We're adding an entry so increase memsz and filesz.
+    newPhdr.p_memsz += sizeof(ElfW(Phdr));
+    newPhdr.p_filesz += sizeof(ElfW(Phdr));
+    *cur = newPhdr;
+    ++cur;
+  }
+
+  for (size_t i = 0; i < exe->phdr_count; ++i) {
+    switch (exe->phdr[i].p_type) {
+    case 0:
+      fatal("unexpected null phdr entry at index %zu", i);
+      break;
+    case PT_PHDR:
+      *cur = newPhdr;
+      break;
+    default:
+      *cur = exe->phdr[i];
+    }
+    ++cur;
+  }
+
+  // Insert PT_INTERP at the end.
+  cur->p_type = PT_INTERP;
+  cur->p_offset = 0;
+  cur->p_vaddr = (uintptr_t)&replacement_interp - exe->load_bias;
+  cur->p_paddr = cur->p_vaddr;
+  cur->p_filesz = ri_strlen(replacement_interp) + 1;
+  cur->p_memsz = ri_strlen(replacement_interp) + 1;
+  cur->p_flags = PF_R;
+  cur->p_align = 1;
+  ++cur;
+
+  ri_strcpy(replacement_interp, loader_realpath);
+
+  debug("new phdr      = %p", (void*)&replacement_phdr_table);
+  debug("new phnum     = %zu", cur - replacement_phdr_table);
+
+  // Update the aux vector with the new phdr+phnum.
+  for (size_t i = 0; i < args->auxv_count; ++i) {
+    if (args->auxv[i].key == AT_PHDR) {
+      args->auxv[i].value = (unsigned long)&replacement_phdr_table;
+    } else if (args->auxv[i].key == AT_PHNUM) {
+      args->auxv[i].value = cur - replacement_phdr_table;
+    }
+  }
+
+  // AT_PHDR and AT_PHNUM are now updated to point to the replacement program
+  // headers, but the e_phoff and e_phnum in the ELF headers still point to the
+  // original program headers.  dynlink.c doesn't use e_phoff value from the
+  // main application's program headers.  The e_phoff and e_phnum values could
+  // be updated, but that would require using mprotect to allow modifications
+  // to the read-only first page.
+}
+
+static void realpath_fd(int fd, const char* orig_path, char* out, size_t len) {
+  char path[64];
+  ri_strcpy(path, "/proc/self/fd/");
+  ul_to_str(fd, path + ri_strlen(path), 10);
+  ssize_t result = ri_readlink(path, out, len);
+  if (result == -1) fatal("could not get realpath of %s: %s", orig_path, ri_strerror(g_errno));
+  if ((size_t)result >= len) fatal("realpath of %s too long", orig_path);
+}
+
+static int open_loader(const ExeInfo* exe, const char* path, OpenedLoader* loader) {
+  debug("trying to open '%s'", path);
+  loader->fd = ri_open(path, O_RDONLY, 0);
+  if (loader->fd < 0) {
+    debug("could not open loader %s: %s", path, ri_strerror(g_errno));
+    return -1;
+  }
+
+  ElfW(Ehdr) hdr;
+  ssize_t l = ri_pread(loader->fd, &hdr, sizeof(hdr), 0);
+  if (l < 0) {
+    debug("reading elf header from %s failed: %s", path, ri_strerror(g_errno));
+    return -1;
+  }
+  if (l != sizeof(hdr)) {
+    debug("file %s too short to contain elf header", path);
+    return -1;
+  }
+
+  if (hdr.e_ident[0] != ELFMAG0 ||
+      hdr.e_ident[1] != ELFMAG1 ||
+      hdr.e_ident[2] != ELFMAG2 ||
+      hdr.e_ident[3] != ELFMAG3) {
+    debug("file %s is not an elf file", path);
+    return -1;
+  }
+
+  if (hdr.e_machine != exe->ehdr->e_machine) {
+    debug("incorrect elf machine for loader %s, expected %d got %d",
+          path, exe->ehdr->e_machine, hdr.e_machine);
+    return -1;
+  }
+
+  if (hdr.e_ident[EI_CLASS] != exe->ehdr->e_ident[EI_CLASS]) {
+    debug("incorrect elf class for loader %s, expected %d got %d",
+          path, exe->ehdr->e_ident[EI_CLASS], hdr.e_ident[EI_CLASS]);
+    return -1;
+  }
+
+  realpath_fd(loader->fd, path, loader->path, sizeof(loader->path));
+
+  return 0;
+}
+
+static int open_rel_loader(const ExeInfo* exe, const char* dir, const char* rel, OpenedLoader* loader) {
+  char buf[PATH_MAX];
+
+  size_t dir_len = ri_strlen(dir);
+
+  if (dir_len + (dir_len == 0 ? 1 : 0) + ri_strlen(rel) + 2 > sizeof(buf)) {
+    debug("path to loader exceeds PATH_MAX: %s/%s", dir, rel);
+    return 1;
+  }
+
+  if (dir_len == 0) {
+    ri_strcpy(buf, ".");
+  } else {
+    ri_strcpy(buf, dir);
+    if (dir[dir_len-1] != '/') {
+      ri_strcat(buf, "/");
+    }
+  }
+  ri_strcat(buf, rel);
+
+  return open_loader(exe, buf, loader);
+}
+
+static void get_origin(char* buf, size_t buf_len) {
+  ssize_t len = ri_readlink("/proc/self/exe", buf, buf_len);
+  if (len <= 0 || (size_t)len >= buf_len) {
+    fatal("could not readlink /proc/self/exe: %s", ri_strerror(g_errno));
+  }
+  buf[len] = '\0';
+
+  ri_dirname(buf);
+}
+
+static int search_path_list_for_loader(const ExeInfo* exe, const char* loader_rel_path, const char* search_path,
+                                       const char* search_path_name, bool expand_origin, OpenedLoader *loader) {
+  char origin_buf[PATH_MAX];
+  char* origin = NULL;
+
+  const char* p = search_path;
+  while (p && p[0]) {
+    const char* start = p;
+    const char* end = ri_strchr(p, ':');
+    if (end == NULL) {
+      end = start + ri_strlen(p);
+      p = NULL;
+    } else {
+      p = end + 1;
+    }
+    size_t n = end - start;
+    char search_path_entry[PATH_MAX];
+    if (n >= sizeof(search_path_entry)) {
+      // Too long, skip.
+      debug("%s entry too long: %s", search_path_name, start);
+      continue;
+    }
+
+    ri_memcpy(search_path_entry, start, n);
+    search_path_entry[n] = '\0';
+
+    char buf[PATH_MAX];
+    char* d = NULL;
+    if (expand_origin) {
+      d = ri_strchr(search_path_entry, '$');
+    }
+    if (d && (!ri_strncmp(d, "$ORIGIN", 7) || !ri_strncmp(d, "${ORIGIN}", 9))) {
+      if (!origin) {
+        get_origin(origin_buf, sizeof(origin_buf));
+        origin = origin_buf;
+      }
+
+      size_t s = 7;
+      if (d[1] == '{') {
+        s += 2;
+      }
+      ri_memcpy(buf, search_path_entry, d - search_path_entry);
+      buf[d - search_path_entry] = '\0';
+      if (ri_strlen(buf) + ri_strlen(origin) + ri_strlen(d+s) >= sizeof(buf)) {
+        debug("path to loader %s%s%s too long", buf, origin, d+s);
+        continue;
+      }
+
+      ri_strcat(buf, origin);
+      ri_strcat(buf, d+s);
+    } else {
+      ri_strcpy(buf, search_path_entry);
+    }
+    debug("trying loader %s at %s", loader_rel_path, buf);
+    if (!open_rel_loader(exe, buf, loader_rel_path, loader)) {
+      debug("opened loader %s at %s", loader_rel_path, buf);
+      return 0;
+    }
+  }
+
+  return -1;
+}
+
+static int find_and_open_loader(const ExeInfo* exe, const char* ld_library_path, OpenedLoader* loader) {
+  const char* loader_rel_path = LOADER_PATH;
+
+  if (loader_rel_path[0] == '/') {
+    return open_loader(exe, loader_rel_path, loader);
+  }
+
+  if (exe->secure) {
+    fatal("relinterp not supported for secure executables");
+  }
+
+  if (!search_path_list_for_loader(exe, loader_rel_path, ld_library_path, "LD_LIBRARY_PATH", false, loader)) {
+    return 0;
+  }
+
+  if (!exe->search_paths || ri_strlen(exe->search_paths) == 0) {
+    // If no DT_RUNPATH search relative to the exe.
+    char origin[PATH_MAX];
+    get_origin(origin, sizeof(origin));
+    return open_rel_loader(exe, origin, loader_rel_path, loader);
+  }
+
+  if (!search_path_list_for_loader(exe, loader_rel_path, exe->search_paths, "rpath", true, loader)) {
+    return 0;
+  }
+
+  fatal("unable to find loader %s in rpath %s", loader_rel_path, exe->search_paths);
+}
+
+// Use a trick to determine whether the executable has been relocated yet. This variable points to
+// a variable in libc. It will be NULL if and only if the program hasn't been linked yet. This
+// should accommodate these situations:
+//  - The program was actually statically-linked instead.
+//  - Either a PIE or non-PIE dynamic executable.
+//  - Any situation where the loader calls the executable's _start:
+//     - In normal operation, the kernel calls the executable's _start, _start jumps to the loader's
+//       entry point, which jumps to _start again after linking it.
+//     - The executable actually has its PT_INTERP set after all.
+//     - The user runs the loader, passing it the path of the executable.
+// This C file must always be compiled as PIC, or else the linker will use a COPY relocation and
+// duplicate "environ" into the executable.
+static bool is_exe_relocated(void) {
+  // Use the GOT to get the address of environ.
+  extern char** environ;
+  void* read_environ = optimizer_barrier(&environ);
+  debug("read_environ = %p", read_environ);
+  return read_environ != NULL;
+}
+
+void _start_c(long* raw_args) {
+  const KernelArguments args = read_args(raw_args);
+  const char* ld_library_path = NULL;
+
+  for (size_t i = 0; i < args.envp_count; ++i) {
+    if (!ri_strcmp(args.envp[i], "RELINTERP_DEBUG=1")) {
+      g_debug = true;
+    }
+    if (!ri_strncmp(args.envp[i], "LD_LIBRARY_PATH=", 16)) {
+      ld_library_path = args.envp[i] + 16;
+    }
+  }
+  if (args.argc >= 1) {
+    g_prog_name = args.argv[0];
+  }
+
+  if (is_exe_relocated()) {
+    debug("exe is already relocated, starting main executable");
+    int argc = raw_args[0];
+    char **argv = (void *)(raw_args+1);
+    __libc_start_main(main, argc, argv, _init, _fini, 0);
+  }
+
+  debug("entering relinterp");
+
+  const ExeInfo exe = get_exe_info(&args);
+  g_page_size = exe.page_size;
+
+  OpenedLoader loader;
+  if (find_and_open_loader(&exe, ld_library_path, &loader)) {
+    fatal("failed to open loader");
+  }
+  off_t len = ri_lseek(loader.fd, 0, SEEK_END);
+  if (len == (off_t)-1) fatal("lseek on %s failed: %s", loader.path, ri_strerror(g_errno));
+
+  void* loader_data = ri_mmap(NULL, len, PROT_READ, MAP_PRIVATE, loader.fd, 0);
+  if (loader_data == (void*)MAP_FAILED) {
+    fatal("could not mmap %s: %s", loader.path, ri_strerror(g_errno));
+  }
+
+  LoadedInterp interp = load_interp(&loader, (ElfW(Ehdr)*)loader_data);
+  if (ri_munmap(loader_data, len) != 0) fatal("munmap failed: %s", ri_strerror(g_errno));
+
+  debug("original auxv:");
+  dump_auxv(&args);
+
+  // Create a virtual phdr table that includes PT_INTERP, for the benefit of loaders that read the
+  // executable PT_INTERP.
+  insert_pt_interp_into_phdr_table(&args, &exe, loader.path);
+  ri_close(loader.fd);
+
+  // TODO: /proc/pid/auxv isn't updated with the new auxv vector. Is it possible to update it?
+  // XXX: If we try to update it, we'd use prctl(PR_SET_MM, PR_SET_MM_AUXV, &vec, size, 0)
+  // Maybe updating it would be useful as a way to communicate the loader's base to a debugger.
+  // e.g. lldb uses AT_BASE in the aux vector, but it caches the values at process startup, so
+  // it wouldn't currently notice a changed value.
+
+  // The loader uses AT_BASE to locate itself, so search for the entry and update it. Even though
+  // its value is always zero, the kernel still includes the entry[0]. If this changes (or we want
+  // to make weaker assumptions about the kernel's behavior), then we can copy the kernel arguments
+  // onto the stack (e.g. using alloca) before jumping to the loader's entry point.
+  // [0] https://github.com/torvalds/linux/blob/v5.13/fs/binfmt_elf.c#L263
+  for (size_t i = 0; i < args.auxv_count; ++i) {
+    if (args.auxv[i].key == AT_BASE) {
+      args.auxv[i].value = (unsigned long)interp.base_addr;
+      debug("new auxv:");
+      dump_auxv(&args);
+      debug("transferring to real loader");
+      CRTJMP(interp.entry, raw_args);
+    }
+  }
+  fatal("AT_BASE not found in aux vector");
+}
+
+
+// Normally gdb and lldb look for a symbol named "_dl_debug_state" in the
+// interpreter to get notified when the dynamic loader has modified the
+// list of shared libraries.  When using relinterp, the debugger is not
+// aware of the interpreter (PT_INTERP is unset and auxv AT_BASE is 0) so it
+// doesn't know where to look for the symbol.  It falls back to looking in the
+// executable, so provide a symbol for it to find.  The dynamic loader will
+// need to forward its calls to its own _dl_debug_state symbol to this one.
+//
+// This has to be defined in a .c file because lldb looks for a symbol with
+// DWARF language type DW_LANG_C.
+extern void _dl_debug_state() {
+}
diff --git a/android/relinterp.script b/android/relinterp.script
new file mode 100644
index 0000000..9085231
--- /dev/null
+++ b/android/relinterp.script
@@ -0,0 +1,4 @@
+SECTIONS {
+  /DISCARD/ : { *(.interp) }
+}
+INSERT BEFORE .text;
diff --git a/dynamic.list b/dynamic.list
index ee0d363..84d13c5 100644
--- a/dynamic.list
+++ b/dynamic.list
@@ -14,6 +14,7 @@
 posix_memalign;
 aligned_alloc;
 malloc_usable_size;
+mallinfo;
 
 timezone;
 daylight;
diff --git a/include/malloc.h b/include/malloc.h
index 35f8b19..98ba010 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -18,6 +18,36 @@
 
 size_t malloc_usable_size(void *);
 
+struct mallinfo {
+  int arena;
+  int ordblks;
+  int smblks;
+  int hblks;
+  int hblkhd;
+  int usmblks;
+  int fsmblks;
+  int uordblks;
+  int fordblks;
+  int keepcost;
+};
+
+struct mallinfo mallinfo(void);
+
+struct mallinfo2 {
+  size_t arena;
+  size_t ordblks;
+  size_t smblks;
+  size_t hblks;
+  size_t hblkhd;
+  size_t usmblks;
+  size_t fsmblks;
+  size_t uordblks;
+  size_t fordblks;
+  size_t keepcost;
+};
+
+struct mallinfo2 mallinfo2(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/netinet/tcp.h b/include/netinet/tcp.h
index fad1d84..7ac938b 100644
--- a/include/netinet/tcp.h
+++ b/include/netinet/tcp.h
@@ -112,65 +112,7 @@
 #define TH_ACK 0x10
 #define TH_URG 0x20
 
-struct tcphdr {
-#ifdef _GNU_SOURCE
-#ifdef __GNUC__
-	__extension__
-#endif
-	union { struct {
-
-	uint16_t source;
-	uint16_t dest;
-	uint32_t seq;
-	uint32_t ack_seq;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-	uint16_t res1:4;
-	uint16_t doff:4;
-	uint16_t fin:1;
-	uint16_t syn:1;
-	uint16_t rst:1;
-	uint16_t psh:1;
-	uint16_t ack:1;
-	uint16_t urg:1;
-	uint16_t res2:2;
-#else
-	uint16_t doff:4;
-	uint16_t res1:4;
-	uint16_t res2:2;
-	uint16_t urg:1;
-	uint16_t ack:1;
-	uint16_t psh:1;
-	uint16_t rst:1;
-	uint16_t syn:1;
-	uint16_t fin:1;
-#endif
-	uint16_t window;
-	uint16_t check;
-	uint16_t urg_ptr;
-
-	}; struct {
-#endif
-
-	uint16_t th_sport;
-	uint16_t th_dport;
-	uint32_t th_seq;
-	uint32_t th_ack;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-	uint8_t th_x2:4;
-	uint8_t th_off:4;
-#else
-	uint8_t th_off:4;
-	uint8_t th_x2:4;
-#endif
-	uint8_t th_flags;
-	uint16_t th_win;
-	uint16_t th_sum;
-	uint16_t th_urp;
-
-#ifdef _GNU_SOURCE
-	}; };
-#endif
-};
+#include <bits/tcphdr.h>
 #endif
 
 #ifdef _GNU_SOURCE
diff --git a/include/sys/socket.h b/include/sys/socket.h
index 6dc1e40..acbe63c 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -355,7 +355,7 @@
 
 #define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1))
 #define CMSG_NXTHDR(mhdr, cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) || \
-	__CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= __MHDR_END(mhdr) - (unsigned char *)(cmsg) \
+	__CMSG_LEN(cmsg) + sizeof(struct cmsghdr) >= (size_t)(__MHDR_END(mhdr) - (unsigned char *)(cmsg)) \
 	? 0 : (struct cmsghdr *)__CMSG_NEXT(cmsg))
 #define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0)
 
@@ -371,11 +371,7 @@
 	char sa_data[14];
 };
 
-struct sockaddr_storage {
-	sa_family_t ss_family;
-	char __ss_padding[128-sizeof(long)-sizeof(sa_family_t)];
-	unsigned long __ss_align;
-};
+#include <bits/sockaddr_storage.h>
 
 int socket (int, int, int);
 int socketpair (int, int, int, int [2]);
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 3b57c07..5b5363c 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -32,6 +32,9 @@
 #define PAGE_SIZE ldso_page_size
 #endif
 
+#define STRINGIFY(x) __STRINGIFY(x)
+#define __STRINGIFY(x) #x
+
 #define malloc __libc_malloc
 #define calloc __libc_calloc
 #define realloc __libc_realloc
@@ -70,6 +73,8 @@
 	size_t *dynv;
 	struct dso *next, *prev;
 
+	int elfmachine;
+	int elfclass;
 	Phdr *phdr;
 	int phnum;
 	size_t phentsize;
@@ -158,6 +163,7 @@
 static struct fdpic_dummy_loadmap app_dummy_loadmap;
 
 struct debug *_dl_debug_addr = &debug;
+static void (*exe_dl_debug_state)(void) = 0;
 
 extern weak hidden char __ehdr_start[];
 
@@ -454,7 +460,7 @@
 		tls_val = def.sym ? def.sym->st_value : 0;
 
 		if ((type == REL_TPOFF || type == REL_TPOFF_NEG)
-		    && def.dso->tls_id > static_tls_cnt) {
+		    && def.dso && def.dso->tls_id > static_tls_cnt) {
 			error("Error relocating %s: %s: initial-exec TLS "
 				"resolves to dynamic definition in %s",
 				dso->name, name, def.dso->name);
@@ -503,14 +509,14 @@
 			break;
 #ifdef TLS_ABOVE_TP
 		case REL_TPOFF:
-			*reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend;
+			*reloc_addr = (def.dso ? tls_val + def.dso->tls.offset + TPOFF_K : 0) + addend;
 			break;
 #else
 		case REL_TPOFF:
-			*reloc_addr = tls_val - def.dso->tls.offset + addend;
+			*reloc_addr = (def.dso ? tls_val - def.dso->tls.offset : 0) + addend;
 			break;
 		case REL_TPOFF_NEG:
-			*reloc_addr = def.dso->tls.offset - tls_val + addend;
+			*reloc_addr = (def.dso ? def.dso->tls.offset - tls_val : 0) + addend;
 			break;
 #endif
 		case REL_TLSDESC:
@@ -681,6 +687,19 @@
 	}
 }
 
+static int verify_elf_magic(const Ehdr* eh) {
+	return eh->e_ident[0] == ELFMAG0 &&
+		eh->e_ident[1] == ELFMAG1 &&
+		eh->e_ident[2] == ELFMAG2 &&
+		eh->e_ident[3] == ELFMAG3;
+}
+
+/* Verifies that an elf header's machine and class match the loader */
+static int verify_elf_arch(const Ehdr* eh) {
+	return eh->e_machine == ldso.elfmachine &&
+		eh->e_ident[EI_CLASS] == ldso.elfclass;
+}
+
 static void *map_library(int fd, struct dso *dso)
 {
 	Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
@@ -703,6 +722,10 @@
 	if (l<0) return 0;
 	if (l<sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC))
 		goto noexec;
+	if (!verify_elf_magic(eh)) goto noexec;
+	if (!verify_elf_arch(eh)) goto noexec;
+	dso->elfmachine = eh->e_machine;
+	dso->elfclass = eh->e_ident[EI_CLASS];
 	phsize = eh->e_phentsize * eh->e_phnum;
 	if (phsize > sizeof buf - sizeof *eh) {
 		allocated_buf = malloc(phsize);
@@ -867,29 +890,53 @@
 	return 0;
 }
 
-static int path_open(const char *name, const char *s, char *buf, size_t buf_size)
+static int path_open_library(const char *name, const char *s, char *buf, size_t buf_size)
 {
 	size_t l;
 	int fd;
+	const char *p;
 	for (;;) {
 		s += strspn(s, ":\n");
+		p = s;
 		l = strcspn(s, ":\n");
 		if (l-1 >= INT_MAX) return -1;
-		if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) {
-			if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd;
+		s += l;
+		if (snprintf(buf, buf_size, "%.*s/%s", (int)l, p, name) < buf_size) {
+			fd = open(buf, O_RDONLY|O_CLOEXEC);
+			if (fd < 0) {
 			switch (errno) {
 			case ENOENT:
 			case ENOTDIR:
 			case EACCES:
 			case ENAMETOOLONG:
-				break;
+					/* Keep searching in path list. */
+					continue;
 			default:
-				/* Any negative value but -1 will inhibit
-				 * futher path search. */
+					/* Any negative value but -1 will
+					 * inhibit further path search in
+					 * load_library. */
 				return -2;
 			}
 		}
-		s += l;
+			Ehdr eh;
+			ssize_t n = pread(fd, &eh, sizeof eh, 0);
+			/* If the elf file is invalid return -2 to inhibit
+			 * further path search in load_library. */
+			if (n < 0 ||
+			    n != sizeof eh ||
+			    !verify_elf_magic(&eh)) {
+				close(fd);
+				return -2;
+			}
+			/* If the elf file has a valid header but is for the
+			 * wrong architecture ignore it and keep searching the
+			 * path list. */
+			if (!verify_elf_arch(&eh)) {
+				close(fd);
+				continue;
+			}
+			return fd;
+		}
 	}
 }
 
@@ -1069,7 +1116,7 @@
 	/* Catch and block attempts to reload the implementation itself */
 	if (name[0]=='l' && name[1]=='i' && name[2]=='b') {
 		static const char reserved[] =
-			"c.pthread.rt.m.dl.util.xnet.";
+			"c.c_musl.pthread.rt.m.dl.util.xnet.";
 		const char *rp, *next;
 		for (rp=reserved; *rp; rp=next) {
 			next = strchr(rp, '.') + 1;
@@ -1113,12 +1160,12 @@
 		}
 		if (strlen(name) > NAME_MAX) return 0;
 		fd = -1;
-		if (env_path) fd = path_open(name, env_path, buf, sizeof buf);
+		if (env_path) fd = path_open_library(name, env_path, buf, sizeof buf);
 		for (p=needed_by; fd == -1 && p; p=p->needed_by) {
 			if (fixup_rpath(p, buf, sizeof buf) < 0)
 				fd = -2; /* Inhibit further search. */
 			if (p->rpath)
-				fd = path_open(name, p->rpath, buf, sizeof buf);
+				fd = path_open_library(name, p->rpath, buf, sizeof buf);
 		}
 		if (fd == -1) {
 			if (!sys_path) {
@@ -1157,7 +1204,7 @@
 				}
 			}
 			if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib";
-			fd = path_open(name, sys_path, buf, sizeof buf);
+			fd = path_open_library(name, sys_path, buf, sizeof buf);
 		}
 		pathname = buf;
 	}
@@ -1189,7 +1236,7 @@
 	if (find_sym(&temp_dso, "__libc_start_main", 1).sym &&
 	    find_sym(&temp_dso, "stdin", 1).sym) {
 		unmap_library(&temp_dso);
-		return load_library("libc.so", needed_by);
+		return load_library(STRINGIFY(LIBC_SONAME), needed_by);
 	}
 	/* Past this point, if we haven't reached runtime yet, ldso has
 	 * committed either to use the mapped library or to abort execution.
@@ -1623,6 +1670,8 @@
 
 static void dl_debug_state(void)
 {
+	if (exe_dl_debug_state)
+		exe_dl_debug_state();
 }
 
 weak_alias(dl_debug_state, _dl_debug_state);
@@ -1725,10 +1774,12 @@
 		ldso.base = base;
 	}
 	Ehdr *ehdr = __ehdr_start ? (void *)__ehdr_start : (void *)ldso.base;
-	ldso.name = ldso.shortname = "libc.so";
+	ldso.name = ldso.shortname = STRINGIFY(LIBC_SONAME);
 	ldso.phnum = ehdr->e_phnum;
 	ldso.phdr = laddr(&ldso, ehdr->e_phoff);
 	ldso.phentsize = ehdr->e_phentsize;
+	ldso.elfmachine = ehdr->e_machine;
+	ldso.elfclass = ehdr->e_ident[EI_CLASS];
 	search_vec(auxv, &ldso_page_size, AT_PAGESZ);
 	kernel_mapped_dso(&ldso);
 	decode_dyn(&ldso);
@@ -2053,6 +2104,12 @@
 	if (find_sym(head, "aligned_alloc", 1).dso != &ldso)
 		__aligned_alloc_replaced = 1;
 
+	/* Determine if another DSO is providing the _dl_debug_state symbol
+	 * and forward calls to it. */
+	struct symdef debug_sym = find_sym(head, "_dl_debug_state", 1);
+	if (debug_sym.dso != &ldso)
+		exe_dl_debug_state = (void (*)(void))laddr(debug_sym.dso, debug_sym.sym->st_value);
+
 	/* Switch to runtime mode: any further failures in the dynamic
 	 * linker are a reportable failure rather than a fatal startup
 	 * error. */
diff --git a/sources.bp b/sources.bp
new file mode 100644
index 0000000..873b2a7
--- /dev/null
+++ b/sources.bp
@@ -0,0 +1,2085 @@
+// Copyright (C) 2021 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.
+
+// This file is created by generate_bp.py. Do not edit manually.
+
+cc_defaults {
+    name: "libc_musl_sources",
+    srcs: [
+        "src/aio/aio.c",
+        "src/aio/aio_suspend.c",
+        "src/aio/lio_listio.c",
+        "src/complex/__cexp.c",
+        "src/complex/__cexpf.c",
+        "src/complex/cabs.c",
+        "src/complex/cabsf.c",
+        "src/complex/cabsl.c",
+        "src/complex/cacos.c",
+        "src/complex/cacosf.c",
+        "src/complex/cacosh.c",
+        "src/complex/cacoshf.c",
+        "src/complex/cacoshl.c",
+        "src/complex/cacosl.c",
+        "src/complex/carg.c",
+        "src/complex/cargf.c",
+        "src/complex/cargl.c",
+        "src/complex/casin.c",
+        "src/complex/casinf.c",
+        "src/complex/casinh.c",
+        "src/complex/casinhf.c",
+        "src/complex/casinhl.c",
+        "src/complex/casinl.c",
+        "src/complex/catan.c",
+        "src/complex/catanf.c",
+        "src/complex/catanh.c",
+        "src/complex/catanhf.c",
+        "src/complex/catanhl.c",
+        "src/complex/catanl.c",
+        "src/complex/ccos.c",
+        "src/complex/ccosf.c",
+        "src/complex/ccosh.c",
+        "src/complex/ccoshf.c",
+        "src/complex/ccoshl.c",
+        "src/complex/ccosl.c",
+        "src/complex/cexp.c",
+        "src/complex/cexpf.c",
+        "src/complex/cexpl.c",
+        "src/complex/cimag.c",
+        "src/complex/cimagf.c",
+        "src/complex/cimagl.c",
+        "src/complex/clog.c",
+        "src/complex/clogf.c",
+        "src/complex/clogl.c",
+        "src/complex/conj.c",
+        "src/complex/conjf.c",
+        "src/complex/conjl.c",
+        "src/complex/cpow.c",
+        "src/complex/cpowf.c",
+        "src/complex/cpowl.c",
+        "src/complex/cproj.c",
+        "src/complex/cprojf.c",
+        "src/complex/cprojl.c",
+        "src/complex/creal.c",
+        "src/complex/crealf.c",
+        "src/complex/creall.c",
+        "src/complex/csin.c",
+        "src/complex/csinf.c",
+        "src/complex/csinh.c",
+        "src/complex/csinhf.c",
+        "src/complex/csinhl.c",
+        "src/complex/csinl.c",
+        "src/complex/csqrt.c",
+        "src/complex/csqrtf.c",
+        "src/complex/csqrtl.c",
+        "src/complex/ctan.c",
+        "src/complex/ctanf.c",
+        "src/complex/ctanh.c",
+        "src/complex/ctanhf.c",
+        "src/complex/ctanhl.c",
+        "src/complex/ctanl.c",
+        "src/conf/confstr.c",
+        "src/conf/fpathconf.c",
+        "src/conf/legacy.c",
+        "src/conf/pathconf.c",
+        "src/conf/sysconf.c",
+        "src/crypt/crypt.c",
+        "src/crypt/crypt_blowfish.c",
+        "src/crypt/crypt_des.c",
+        "src/crypt/crypt_md5.c",
+        "src/crypt/crypt_r.c",
+        "src/crypt/crypt_sha256.c",
+        "src/crypt/crypt_sha512.c",
+        "src/crypt/encrypt.c",
+        "src/ctype/__ctype_b_loc.c",
+        "src/ctype/__ctype_get_mb_cur_max.c",
+        "src/ctype/__ctype_tolower_loc.c",
+        "src/ctype/__ctype_toupper_loc.c",
+        "src/ctype/isalnum.c",
+        "src/ctype/isalpha.c",
+        "src/ctype/isascii.c",
+        "src/ctype/isblank.c",
+        "src/ctype/iscntrl.c",
+        "src/ctype/isdigit.c",
+        "src/ctype/isgraph.c",
+        "src/ctype/islower.c",
+        "src/ctype/isprint.c",
+        "src/ctype/ispunct.c",
+        "src/ctype/isspace.c",
+        "src/ctype/isupper.c",
+        "src/ctype/iswalnum.c",
+        "src/ctype/iswalpha.c",
+        "src/ctype/iswblank.c",
+        "src/ctype/iswcntrl.c",
+        "src/ctype/iswctype.c",
+        "src/ctype/iswdigit.c",
+        "src/ctype/iswgraph.c",
+        "src/ctype/iswlower.c",
+        "src/ctype/iswprint.c",
+        "src/ctype/iswpunct.c",
+        "src/ctype/iswspace.c",
+        "src/ctype/iswupper.c",
+        "src/ctype/iswxdigit.c",
+        "src/ctype/isxdigit.c",
+        "src/ctype/toascii.c",
+        "src/ctype/tolower.c",
+        "src/ctype/toupper.c",
+        "src/ctype/towctrans.c",
+        "src/ctype/wcswidth.c",
+        "src/ctype/wctrans.c",
+        "src/ctype/wcwidth.c",
+        "src/dirent/alphasort.c",
+        "src/dirent/closedir.c",
+        "src/dirent/dirfd.c",
+        "src/dirent/fdopendir.c",
+        "src/dirent/opendir.c",
+        "src/dirent/posix_getdents.c",
+        "src/dirent/readdir.c",
+        "src/dirent/readdir_r.c",
+        "src/dirent/rewinddir.c",
+        "src/dirent/scandir.c",
+        "src/dirent/seekdir.c",
+        "src/dirent/telldir.c",
+        "src/dirent/versionsort.c",
+        "src/env/__environ.c",
+        "src/env/__reset_tls.c",
+        "src/env/clearenv.c",
+        "src/env/getenv.c",
+        "src/env/putenv.c",
+        "src/env/secure_getenv.c",
+        "src/env/setenv.c",
+        "src/env/unsetenv.c",
+        "src/errno/__errno_location.c",
+        "src/errno/strerror.c",
+        "src/exit/_Exit.c",
+        "src/exit/abort.c",
+        "src/exit/abort_lock.c",
+        "src/exit/assert.c",
+        "src/exit/at_quick_exit.c",
+        "src/exit/atexit.c",
+        "src/exit/exit.c",
+        "src/exit/quick_exit.c",
+        "src/fcntl/creat.c",
+        "src/fcntl/fcntl.c",
+        "src/fcntl/open.c",
+        "src/fcntl/openat.c",
+        "src/fcntl/posix_fadvise.c",
+        "src/fcntl/posix_fallocate.c",
+        "src/fenv/__flt_rounds.c",
+        "src/fenv/fegetexceptflag.c",
+        "src/fenv/feholdexcept.c",
+        "src/fenv/fenv.c",
+        "src/fenv/fesetexceptflag.c",
+        "src/fenv/fesetround.c",
+        "src/fenv/feupdateenv.c",
+        "src/ipc/ftok.c",
+        "src/ipc/msgctl.c",
+        "src/ipc/msgget.c",
+        "src/ipc/msgrcv.c",
+        "src/ipc/msgsnd.c",
+        "src/ipc/semctl.c",
+        "src/ipc/semget.c",
+        "src/ipc/semop.c",
+        "src/ipc/semtimedop.c",
+        "src/ipc/shmat.c",
+        "src/ipc/shmctl.c",
+        "src/ipc/shmdt.c",
+        "src/ipc/shmget.c",
+        "src/ldso/__dlsym.c",
+        "src/ldso/dl_iterate_phdr.c",
+        "src/ldso/dladdr.c",
+        "src/ldso/dlclose.c",
+        "src/ldso/dlerror.c",
+        "src/ldso/dlinfo.c",
+        "src/ldso/dlopen.c",
+        "src/ldso/dlsym.c",
+        "src/ldso/tlsdesc.c",
+        "src/legacy/cuserid.c",
+        "src/legacy/daemon.c",
+        "src/legacy/err.c",
+        "src/legacy/euidaccess.c",
+        "src/legacy/ftw.c",
+        "src/legacy/futimes.c",
+        "src/legacy/getdtablesize.c",
+        "src/legacy/getloadavg.c",
+        "src/legacy/getpagesize.c",
+        "src/legacy/getpass.c",
+        "src/legacy/getusershell.c",
+        "src/legacy/isastream.c",
+        "src/legacy/lutimes.c",
+        "src/legacy/ulimit.c",
+        "src/legacy/utmpx.c",
+        "src/legacy/valloc.c",
+        "src/linux/adjtime.c",
+        "src/linux/adjtimex.c",
+        "src/linux/arch_prctl.c",
+        "src/linux/brk.c",
+        "src/linux/cache.c",
+        "src/linux/cap.c",
+        "src/linux/chroot.c",
+        "src/linux/clock_adjtime.c",
+        "src/linux/clone.c",
+        "src/linux/copy_file_range.c",
+        "src/linux/epoll.c",
+        "src/linux/eventfd.c",
+        "src/linux/fallocate.c",
+        "src/linux/fanotify.c",
+        "src/linux/flock.c",
+        "src/linux/getdents.c",
+        "src/linux/getrandom.c",
+        "src/linux/gettid.c",
+        "src/linux/inotify.c",
+        "src/linux/ioperm.c",
+        "src/linux/iopl.c",
+        "src/linux/klogctl.c",
+        "src/linux/membarrier.c",
+        "src/linux/memfd_create.c",
+        "src/linux/mlock2.c",
+        "src/linux/module.c",
+        "src/linux/mount.c",
+        "src/linux/name_to_handle_at.c",
+        "src/linux/open_by_handle_at.c",
+        "src/linux/personality.c",
+        "src/linux/pivot_root.c",
+        "src/linux/prctl.c",
+        "src/linux/preadv2.c",
+        "src/linux/prlimit.c",
+        "src/linux/process_vm.c",
+        "src/linux/ptrace.c",
+        "src/linux/pwritev2.c",
+        "src/linux/quotactl.c",
+        "src/linux/readahead.c",
+        "src/linux/reboot.c",
+        "src/linux/remap_file_pages.c",
+        "src/linux/renameat2.c",
+        "src/linux/sbrk.c",
+        "src/linux/sendfile.c",
+        "src/linux/setfsgid.c",
+        "src/linux/setfsuid.c",
+        "src/linux/setgroups.c",
+        "src/linux/sethostname.c",
+        "src/linux/setns.c",
+        "src/linux/settimeofday.c",
+        "src/linux/signalfd.c",
+        "src/linux/splice.c",
+        "src/linux/statx.c",
+        "src/linux/stime.c",
+        "src/linux/swap.c",
+        "src/linux/sync_file_range.c",
+        "src/linux/syncfs.c",
+        "src/linux/sysinfo.c",
+        "src/linux/tee.c",
+        "src/linux/timerfd.c",
+        "src/linux/unshare.c",
+        "src/linux/utimes.c",
+        "src/linux/vhangup.c",
+        "src/linux/vmsplice.c",
+        "src/linux/wait3.c",
+        "src/linux/wait4.c",
+        "src/linux/xattr.c",
+        "src/locale/__lctrans.c",
+        "src/locale/__mo_lookup.c",
+        "src/locale/bind_textdomain_codeset.c",
+        "src/locale/c_locale.c",
+        "src/locale/catclose.c",
+        "src/locale/catgets.c",
+        "src/locale/catopen.c",
+        "src/locale/dcngettext.c",
+        "src/locale/duplocale.c",
+        "src/locale/freelocale.c",
+        "src/locale/iconv.c",
+        "src/locale/iconv_close.c",
+        "src/locale/langinfo.c",
+        "src/locale/locale_map.c",
+        "src/locale/localeconv.c",
+        "src/locale/newlocale.c",
+        "src/locale/pleval.c",
+        "src/locale/setlocale.c",
+        "src/locale/strcoll.c",
+        "src/locale/strfmon.c",
+        "src/locale/strtod_l.c",
+        "src/locale/strxfrm.c",
+        "src/locale/textdomain.c",
+        "src/locale/uselocale.c",
+        "src/locale/wcscoll.c",
+        "src/locale/wcsxfrm.c",
+        "src/malloc/mallocng/aligned_alloc.c",
+        "src/malloc/mallocng/donate.c",
+        "src/malloc/mallocng/free.c",
+        "src/malloc/mallocng/mallinfo.c",
+        "src/malloc/mallocng/malloc.c",
+        "src/malloc/mallocng/malloc_usable_size.c",
+        "src/malloc/mallocng/realloc.c",
+        "src/math/__cos.c",
+        "src/math/__cosdf.c",
+        "src/math/__cosl.c",
+        "src/math/__expo2.c",
+        "src/math/__expo2f.c",
+        "src/math/__fpclassify.c",
+        "src/math/__fpclassifyf.c",
+        "src/math/__fpclassifyl.c",
+        "src/math/__invtrigl.c",
+        "src/math/__math_divzero.c",
+        "src/math/__math_divzerof.c",
+        "src/math/__math_invalid.c",
+        "src/math/__math_invalidf.c",
+        "src/math/__math_invalidl.c",
+        "src/math/__math_oflow.c",
+        "src/math/__math_oflowf.c",
+        "src/math/__math_uflow.c",
+        "src/math/__math_uflowf.c",
+        "src/math/__math_xflow.c",
+        "src/math/__math_xflowf.c",
+        "src/math/__polevll.c",
+        "src/math/__rem_pio2.c",
+        "src/math/__rem_pio2_large.c",
+        "src/math/__rem_pio2f.c",
+        "src/math/__rem_pio2l.c",
+        "src/math/__signbit.c",
+        "src/math/__signbitf.c",
+        "src/math/__signbitl.c",
+        "src/math/__sin.c",
+        "src/math/__sindf.c",
+        "src/math/__sinl.c",
+        "src/math/__tan.c",
+        "src/math/__tandf.c",
+        "src/math/__tanl.c",
+        "src/math/acos.c",
+        "src/math/acosf.c",
+        "src/math/acosh.c",
+        "src/math/acoshf.c",
+        "src/math/acoshl.c",
+        "src/math/acosl.c",
+        "src/math/asin.c",
+        "src/math/asinf.c",
+        "src/math/asinh.c",
+        "src/math/asinhf.c",
+        "src/math/asinhl.c",
+        "src/math/asinl.c",
+        "src/math/atan.c",
+        "src/math/atan2.c",
+        "src/math/atan2f.c",
+        "src/math/atan2l.c",
+        "src/math/atanf.c",
+        "src/math/atanh.c",
+        "src/math/atanhf.c",
+        "src/math/atanhl.c",
+        "src/math/atanl.c",
+        "src/math/cbrt.c",
+        "src/math/cbrtf.c",
+        "src/math/cbrtl.c",
+        "src/math/ceil.c",
+        "src/math/ceilf.c",
+        "src/math/ceill.c",
+        "src/math/copysign.c",
+        "src/math/copysignf.c",
+        "src/math/copysignl.c",
+        "src/math/cos.c",
+        "src/math/cosf.c",
+        "src/math/cosh.c",
+        "src/math/coshf.c",
+        "src/math/coshl.c",
+        "src/math/cosl.c",
+        "src/math/erf.c",
+        "src/math/erff.c",
+        "src/math/erfl.c",
+        "src/math/exp.c",
+        "src/math/exp10.c",
+        "src/math/exp10f.c",
+        "src/math/exp10l.c",
+        "src/math/exp2.c",
+        "src/math/exp2f.c",
+        "src/math/exp2f_data.c",
+        "src/math/exp2l.c",
+        "src/math/exp_data.c",
+        "src/math/expf.c",
+        "src/math/expl.c",
+        "src/math/expm1.c",
+        "src/math/expm1f.c",
+        "src/math/expm1l.c",
+        "src/math/fabs.c",
+        "src/math/fabsf.c",
+        "src/math/fabsl.c",
+        "src/math/fdim.c",
+        "src/math/fdimf.c",
+        "src/math/fdiml.c",
+        "src/math/finite.c",
+        "src/math/finitef.c",
+        "src/math/floor.c",
+        "src/math/floorf.c",
+        "src/math/floorl.c",
+        "src/math/fma.c",
+        "src/math/fmaf.c",
+        "src/math/fmal.c",
+        "src/math/fmax.c",
+        "src/math/fmaxf.c",
+        "src/math/fmaxl.c",
+        "src/math/fmin.c",
+        "src/math/fminf.c",
+        "src/math/fminl.c",
+        "src/math/fmod.c",
+        "src/math/fmodf.c",
+        "src/math/fmodl.c",
+        "src/math/frexp.c",
+        "src/math/frexpf.c",
+        "src/math/frexpl.c",
+        "src/math/hypot.c",
+        "src/math/hypotf.c",
+        "src/math/hypotl.c",
+        "src/math/ilogb.c",
+        "src/math/ilogbf.c",
+        "src/math/ilogbl.c",
+        "src/math/j0.c",
+        "src/math/j0f.c",
+        "src/math/j1.c",
+        "src/math/j1f.c",
+        "src/math/jn.c",
+        "src/math/jnf.c",
+        "src/math/ldexp.c",
+        "src/math/ldexpf.c",
+        "src/math/ldexpl.c",
+        "src/math/lgamma.c",
+        "src/math/lgamma_r.c",
+        "src/math/lgammaf.c",
+        "src/math/lgammaf_r.c",
+        "src/math/lgammal.c",
+        "src/math/llrint.c",
+        "src/math/llrintf.c",
+        "src/math/llrintl.c",
+        "src/math/llround.c",
+        "src/math/llroundf.c",
+        "src/math/llroundl.c",
+        "src/math/log.c",
+        "src/math/log10.c",
+        "src/math/log10f.c",
+        "src/math/log10l.c",
+        "src/math/log1p.c",
+        "src/math/log1pf.c",
+        "src/math/log1pl.c",
+        "src/math/log2.c",
+        "src/math/log2_data.c",
+        "src/math/log2f.c",
+        "src/math/log2f_data.c",
+        "src/math/log2l.c",
+        "src/math/log_data.c",
+        "src/math/logb.c",
+        "src/math/logbf.c",
+        "src/math/logbl.c",
+        "src/math/logf.c",
+        "src/math/logf_data.c",
+        "src/math/logl.c",
+        "src/math/lrint.c",
+        "src/math/lrintf.c",
+        "src/math/lrintl.c",
+        "src/math/lround.c",
+        "src/math/lroundf.c",
+        "src/math/lroundl.c",
+        "src/math/modf.c",
+        "src/math/modff.c",
+        "src/math/modfl.c",
+        "src/math/nan.c",
+        "src/math/nanf.c",
+        "src/math/nanl.c",
+        "src/math/nearbyint.c",
+        "src/math/nearbyintf.c",
+        "src/math/nearbyintl.c",
+        "src/math/nextafter.c",
+        "src/math/nextafterf.c",
+        "src/math/nextafterl.c",
+        "src/math/nexttoward.c",
+        "src/math/nexttowardf.c",
+        "src/math/nexttowardl.c",
+        "src/math/pow.c",
+        "src/math/pow_data.c",
+        "src/math/powf.c",
+        "src/math/powf_data.c",
+        "src/math/powl.c",
+        "src/math/remainder.c",
+        "src/math/remainderf.c",
+        "src/math/remainderl.c",
+        "src/math/remquo.c",
+        "src/math/remquof.c",
+        "src/math/remquol.c",
+        "src/math/rint.c",
+        "src/math/rintf.c",
+        "src/math/rintl.c",
+        "src/math/round.c",
+        "src/math/roundf.c",
+        "src/math/roundl.c",
+        "src/math/scalb.c",
+        "src/math/scalbf.c",
+        "src/math/scalbln.c",
+        "src/math/scalblnf.c",
+        "src/math/scalblnl.c",
+        "src/math/scalbn.c",
+        "src/math/scalbnf.c",
+        "src/math/scalbnl.c",
+        "src/math/signgam.c",
+        "src/math/significand.c",
+        "src/math/significandf.c",
+        "src/math/sin.c",
+        "src/math/sincos.c",
+        "src/math/sincosf.c",
+        "src/math/sincosl.c",
+        "src/math/sinf.c",
+        "src/math/sinh.c",
+        "src/math/sinhf.c",
+        "src/math/sinhl.c",
+        "src/math/sinl.c",
+        "src/math/sqrt.c",
+        "src/math/sqrt_data.c",
+        "src/math/sqrtf.c",
+        "src/math/sqrtl.c",
+        "src/math/tan.c",
+        "src/math/tanf.c",
+        "src/math/tanh.c",
+        "src/math/tanhf.c",
+        "src/math/tanhl.c",
+        "src/math/tanl.c",
+        "src/math/tgamma.c",
+        "src/math/tgammaf.c",
+        "src/math/tgammal.c",
+        "src/math/trunc.c",
+        "src/math/truncf.c",
+        "src/math/truncl.c",
+        "src/misc/a64l.c",
+        "src/misc/basename.c",
+        "src/misc/dirname.c",
+        "src/misc/ffs.c",
+        "src/misc/ffsl.c",
+        "src/misc/ffsll.c",
+        "src/misc/fmtmsg.c",
+        "src/misc/forkpty.c",
+        "src/misc/get_current_dir_name.c",
+        "src/misc/getauxval.c",
+        "src/misc/getdomainname.c",
+        "src/misc/getentropy.c",
+        "src/misc/gethostid.c",
+        "src/misc/getopt.c",
+        "src/misc/getopt_long.c",
+        "src/misc/getpriority.c",
+        "src/misc/getresgid.c",
+        "src/misc/getresuid.c",
+        "src/misc/getrlimit.c",
+        "src/misc/getrusage.c",
+        "src/misc/getsubopt.c",
+        "src/misc/initgroups.c",
+        "src/misc/ioctl.c",
+        "src/misc/issetugid.c",
+        "src/misc/lockf.c",
+        "src/misc/login_tty.c",
+        "src/misc/mntent.c",
+        "src/misc/nftw.c",
+        "src/misc/openpty.c",
+        "src/misc/ptsname.c",
+        "src/misc/pty.c",
+        "src/misc/realpath.c",
+        "src/misc/setdomainname.c",
+        "src/misc/setpriority.c",
+        "src/misc/setrlimit.c",
+        "src/misc/syscall.c",
+        "src/misc/syslog.c",
+        "src/misc/uname.c",
+        "src/misc/wordexp.c",
+        "src/mman/madvise.c",
+        "src/mman/mincore.c",
+        "src/mman/mlock.c",
+        "src/mman/mlockall.c",
+        "src/mman/mmap.c",
+        "src/mman/mprotect.c",
+        "src/mman/mremap.c",
+        "src/mman/msync.c",
+        "src/mman/munlock.c",
+        "src/mman/munlockall.c",
+        "src/mman/munmap.c",
+        "src/mman/posix_madvise.c",
+        "src/mman/shm_open.c",
+        "src/mq/mq_close.c",
+        "src/mq/mq_getattr.c",
+        "src/mq/mq_notify.c",
+        "src/mq/mq_open.c",
+        "src/mq/mq_receive.c",
+        "src/mq/mq_send.c",
+        "src/mq/mq_setattr.c",
+        "src/mq/mq_timedreceive.c",
+        "src/mq/mq_timedsend.c",
+        "src/mq/mq_unlink.c",
+        "src/multibyte/btowc.c",
+        "src/multibyte/c16rtomb.c",
+        "src/multibyte/c32rtomb.c",
+        "src/multibyte/internal.c",
+        "src/multibyte/mblen.c",
+        "src/multibyte/mbrlen.c",
+        "src/multibyte/mbrtoc16.c",
+        "src/multibyte/mbrtoc32.c",
+        "src/multibyte/mbrtowc.c",
+        "src/multibyte/mbsinit.c",
+        "src/multibyte/mbsnrtowcs.c",
+        "src/multibyte/mbsrtowcs.c",
+        "src/multibyte/mbstowcs.c",
+        "src/multibyte/mbtowc.c",
+        "src/multibyte/wcrtomb.c",
+        "src/multibyte/wcsnrtombs.c",
+        "src/multibyte/wcsrtombs.c",
+        "src/multibyte/wcstombs.c",
+        "src/multibyte/wctob.c",
+        "src/multibyte/wctomb.c",
+        "src/network/accept.c",
+        "src/network/accept4.c",
+        "src/network/bind.c",
+        "src/network/connect.c",
+        "src/network/dn_comp.c",
+        "src/network/dn_expand.c",
+        "src/network/dn_skipname.c",
+        "src/network/dns_parse.c",
+        "src/network/ent.c",
+        "src/network/ether.c",
+        "src/network/freeaddrinfo.c",
+        "src/network/gai_strerror.c",
+        "src/network/getaddrinfo.c",
+        "src/network/gethostbyaddr.c",
+        "src/network/gethostbyaddr_r.c",
+        "src/network/gethostbyname.c",
+        "src/network/gethostbyname2.c",
+        "src/network/gethostbyname2_r.c",
+        "src/network/gethostbyname_r.c",
+        "src/network/getifaddrs.c",
+        "src/network/getnameinfo.c",
+        "src/network/getpeername.c",
+        "src/network/getservbyname.c",
+        "src/network/getservbyname_r.c",
+        "src/network/getservbyport.c",
+        "src/network/getservbyport_r.c",
+        "src/network/getsockname.c",
+        "src/network/getsockopt.c",
+        "src/network/h_errno.c",
+        "src/network/herror.c",
+        "src/network/hstrerror.c",
+        "src/network/htonl.c",
+        "src/network/htons.c",
+        "src/network/if_freenameindex.c",
+        "src/network/if_indextoname.c",
+        "src/network/if_nameindex.c",
+        "src/network/if_nametoindex.c",
+        "src/network/in6addr_any.c",
+        "src/network/in6addr_loopback.c",
+        "src/network/inet_addr.c",
+        "src/network/inet_aton.c",
+        "src/network/inet_legacy.c",
+        "src/network/inet_ntoa.c",
+        "src/network/inet_ntop.c",
+        "src/network/inet_pton.c",
+        "src/network/listen.c",
+        "src/network/lookup_ipliteral.c",
+        "src/network/lookup_name.c",
+        "src/network/lookup_serv.c",
+        "src/network/netlink.c",
+        "src/network/netname.c",
+        "src/network/ns_parse.c",
+        "src/network/ntohl.c",
+        "src/network/ntohs.c",
+        "src/network/proto.c",
+        "src/network/recv.c",
+        "src/network/recvfrom.c",
+        "src/network/recvmmsg.c",
+        "src/network/recvmsg.c",
+        "src/network/res_init.c",
+        "src/network/res_mkquery.c",
+        "src/network/res_msend.c",
+        "src/network/res_query.c",
+        "src/network/res_querydomain.c",
+        "src/network/res_send.c",
+        "src/network/res_state.c",
+        "src/network/resolvconf.c",
+        "src/network/send.c",
+        "src/network/sendmmsg.c",
+        "src/network/sendmsg.c",
+        "src/network/sendto.c",
+        "src/network/serv.c",
+        "src/network/setsockopt.c",
+        "src/network/shutdown.c",
+        "src/network/sockatmark.c",
+        "src/network/socket.c",
+        "src/network/socketpair.c",
+        "src/passwd/fgetgrent.c",
+        "src/passwd/fgetpwent.c",
+        "src/passwd/fgetspent.c",
+        "src/passwd/getgr_a.c",
+        "src/passwd/getgr_r.c",
+        "src/passwd/getgrent.c",
+        "src/passwd/getgrent_a.c",
+        "src/passwd/getgrouplist.c",
+        "src/passwd/getpw_a.c",
+        "src/passwd/getpw_r.c",
+        "src/passwd/getpwent.c",
+        "src/passwd/getpwent_a.c",
+        "src/passwd/getspent.c",
+        "src/passwd/getspnam.c",
+        "src/passwd/getspnam_r.c",
+        "src/passwd/lckpwdf.c",
+        "src/passwd/nscd_query.c",
+        "src/passwd/putgrent.c",
+        "src/passwd/putpwent.c",
+        "src/passwd/putspent.c",
+        "src/prng/__rand48_step.c",
+        "src/prng/__seed48.c",
+        "src/prng/drand48.c",
+        "src/prng/lcong48.c",
+        "src/prng/lrand48.c",
+        "src/prng/mrand48.c",
+        "src/prng/rand.c",
+        "src/prng/rand_r.c",
+        "src/prng/random.c",
+        "src/prng/seed48.c",
+        "src/prng/srand48.c",
+        "src/process/_Fork.c",
+        "src/process/execl.c",
+        "src/process/execle.c",
+        "src/process/execlp.c",
+        "src/process/execv.c",
+        "src/process/execve.c",
+        "src/process/execvp.c",
+        "src/process/fexecve.c",
+        "src/process/fork.c",
+        "src/process/posix_spawn.c",
+        "src/process/posix_spawn_file_actions_addchdir.c",
+        "src/process/posix_spawn_file_actions_addclose.c",
+        "src/process/posix_spawn_file_actions_adddup2.c",
+        "src/process/posix_spawn_file_actions_addfchdir.c",
+        "src/process/posix_spawn_file_actions_addopen.c",
+        "src/process/posix_spawn_file_actions_destroy.c",
+        "src/process/posix_spawn_file_actions_init.c",
+        "src/process/posix_spawnattr_destroy.c",
+        "src/process/posix_spawnattr_getflags.c",
+        "src/process/posix_spawnattr_getpgroup.c",
+        "src/process/posix_spawnattr_getsigdefault.c",
+        "src/process/posix_spawnattr_getsigmask.c",
+        "src/process/posix_spawnattr_init.c",
+        "src/process/posix_spawnattr_sched.c",
+        "src/process/posix_spawnattr_setflags.c",
+        "src/process/posix_spawnattr_setpgroup.c",
+        "src/process/posix_spawnattr_setsigdefault.c",
+        "src/process/posix_spawnattr_setsigmask.c",
+        "src/process/posix_spawnp.c",
+        "src/process/system.c",
+        "src/process/vfork.c",
+        "src/process/wait.c",
+        "src/process/waitid.c",
+        "src/process/waitpid.c",
+        "src/regex/fnmatch.c",
+        "src/regex/glob.c",
+        "src/regex/regcomp.c",
+        "src/regex/regerror.c",
+        "src/regex/regexec.c",
+        "src/regex/tre-mem.c",
+        "src/sched/affinity.c",
+        "src/sched/sched_cpucount.c",
+        "src/sched/sched_get_priority_max.c",
+        "src/sched/sched_getcpu.c",
+        "src/sched/sched_getparam.c",
+        "src/sched/sched_getscheduler.c",
+        "src/sched/sched_rr_get_interval.c",
+        "src/sched/sched_setparam.c",
+        "src/sched/sched_setscheduler.c",
+        "src/sched/sched_yield.c",
+        "src/search/hsearch.c",
+        "src/search/insque.c",
+        "src/search/lsearch.c",
+        "src/search/tdelete.c",
+        "src/search/tdestroy.c",
+        "src/search/tfind.c",
+        "src/search/tsearch.c",
+        "src/search/twalk.c",
+        "src/select/poll.c",
+        "src/select/ppoll.c",
+        "src/select/pselect.c",
+        "src/select/select.c",
+        "src/setjmp/longjmp.c",
+        "src/setjmp/setjmp.c",
+        "src/signal/block.c",
+        "src/signal/getitimer.c",
+        "src/signal/kill.c",
+        "src/signal/killpg.c",
+        "src/signal/psiginfo.c",
+        "src/signal/psignal.c",
+        "src/signal/raise.c",
+        "src/signal/restore.c",
+        "src/signal/setitimer.c",
+        "src/signal/sigaction.c",
+        "src/signal/sigaddset.c",
+        "src/signal/sigaltstack.c",
+        "src/signal/sigandset.c",
+        "src/signal/sigdelset.c",
+        "src/signal/sigemptyset.c",
+        "src/signal/sigfillset.c",
+        "src/signal/sighold.c",
+        "src/signal/sigignore.c",
+        "src/signal/siginterrupt.c",
+        "src/signal/sigisemptyset.c",
+        "src/signal/sigismember.c",
+        "src/signal/siglongjmp.c",
+        "src/signal/signal.c",
+        "src/signal/sigorset.c",
+        "src/signal/sigpause.c",
+        "src/signal/sigpending.c",
+        "src/signal/sigprocmask.c",
+        "src/signal/sigqueue.c",
+        "src/signal/sigrelse.c",
+        "src/signal/sigrtmax.c",
+        "src/signal/sigrtmin.c",
+        "src/signal/sigset.c",
+        "src/signal/sigsetjmp.c",
+        "src/signal/sigsetjmp_tail.c",
+        "src/signal/sigsuspend.c",
+        "src/signal/sigtimedwait.c",
+        "src/signal/sigwait.c",
+        "src/signal/sigwaitinfo.c",
+        "src/stat/__xstat.c",
+        "src/stat/chmod.c",
+        "src/stat/fchmod.c",
+        "src/stat/fchmodat.c",
+        "src/stat/fstat.c",
+        "src/stat/fstatat.c",
+        "src/stat/futimens.c",
+        "src/stat/futimesat.c",
+        "src/stat/lchmod.c",
+        "src/stat/lstat.c",
+        "src/stat/mkdir.c",
+        "src/stat/mkdirat.c",
+        "src/stat/mkfifo.c",
+        "src/stat/mkfifoat.c",
+        "src/stat/mknod.c",
+        "src/stat/mknodat.c",
+        "src/stat/stat.c",
+        "src/stat/statvfs.c",
+        "src/stat/umask.c",
+        "src/stat/utimensat.c",
+        "src/stdio/__fclose_ca.c",
+        "src/stdio/__fdopen.c",
+        "src/stdio/__fmodeflags.c",
+        "src/stdio/__fopen_rb_ca.c",
+        "src/stdio/__lockfile.c",
+        "src/stdio/__overflow.c",
+        "src/stdio/__stdio_close.c",
+        "src/stdio/__stdio_exit.c",
+        "src/stdio/__stdio_read.c",
+        "src/stdio/__stdio_seek.c",
+        "src/stdio/__stdio_write.c",
+        "src/stdio/__stdout_write.c",
+        "src/stdio/__toread.c",
+        "src/stdio/__towrite.c",
+        "src/stdio/__uflow.c",
+        "src/stdio/asprintf.c",
+        "src/stdio/clearerr.c",
+        "src/stdio/dprintf.c",
+        "src/stdio/ext.c",
+        "src/stdio/ext2.c",
+        "src/stdio/fclose.c",
+        "src/stdio/feof.c",
+        "src/stdio/ferror.c",
+        "src/stdio/fflush.c",
+        "src/stdio/fgetc.c",
+        "src/stdio/fgetln.c",
+        "src/stdio/fgetpos.c",
+        "src/stdio/fgets.c",
+        "src/stdio/fgetwc.c",
+        "src/stdio/fgetws.c",
+        "src/stdio/fileno.c",
+        "src/stdio/flockfile.c",
+        "src/stdio/fmemopen.c",
+        "src/stdio/fopen.c",
+        "src/stdio/fopencookie.c",
+        "src/stdio/fprintf.c",
+        "src/stdio/fputc.c",
+        "src/stdio/fputs.c",
+        "src/stdio/fputwc.c",
+        "src/stdio/fputws.c",
+        "src/stdio/fread.c",
+        "src/stdio/freopen.c",
+        "src/stdio/fscanf.c",
+        "src/stdio/fseek.c",
+        "src/stdio/fsetpos.c",
+        "src/stdio/ftell.c",
+        "src/stdio/ftrylockfile.c",
+        "src/stdio/funlockfile.c",
+        "src/stdio/fwide.c",
+        "src/stdio/fwprintf.c",
+        "src/stdio/fwrite.c",
+        "src/stdio/fwscanf.c",
+        "src/stdio/getc.c",
+        "src/stdio/getc_unlocked.c",
+        "src/stdio/getchar.c",
+        "src/stdio/getchar_unlocked.c",
+        "src/stdio/getdelim.c",
+        "src/stdio/getline.c",
+        "src/stdio/gets.c",
+        "src/stdio/getw.c",
+        "src/stdio/getwc.c",
+        "src/stdio/getwchar.c",
+        "src/stdio/ofl.c",
+        "src/stdio/ofl_add.c",
+        "src/stdio/open_memstream.c",
+        "src/stdio/open_wmemstream.c",
+        "src/stdio/pclose.c",
+        "src/stdio/perror.c",
+        "src/stdio/popen.c",
+        "src/stdio/printf.c",
+        "src/stdio/putc.c",
+        "src/stdio/putc_unlocked.c",
+        "src/stdio/putchar.c",
+        "src/stdio/putchar_unlocked.c",
+        "src/stdio/puts.c",
+        "src/stdio/putw.c",
+        "src/stdio/putwc.c",
+        "src/stdio/putwchar.c",
+        "src/stdio/remove.c",
+        "src/stdio/rename.c",
+        "src/stdio/rewind.c",
+        "src/stdio/scanf.c",
+        "src/stdio/setbuf.c",
+        "src/stdio/setbuffer.c",
+        "src/stdio/setlinebuf.c",
+        "src/stdio/setvbuf.c",
+        "src/stdio/snprintf.c",
+        "src/stdio/sprintf.c",
+        "src/stdio/sscanf.c",
+        "src/stdio/stderr.c",
+        "src/stdio/stdin.c",
+        "src/stdio/stdout.c",
+        "src/stdio/swprintf.c",
+        "src/stdio/swscanf.c",
+        "src/stdio/tempnam.c",
+        "src/stdio/tmpfile.c",
+        "src/stdio/tmpnam.c",
+        "src/stdio/ungetc.c",
+        "src/stdio/ungetwc.c",
+        "src/stdio/vasprintf.c",
+        "src/stdio/vdprintf.c",
+        "src/stdio/vfprintf.c",
+        "src/stdio/vfscanf.c",
+        "src/stdio/vfwprintf.c",
+        "src/stdio/vfwscanf.c",
+        "src/stdio/vprintf.c",
+        "src/stdio/vscanf.c",
+        "src/stdio/vsnprintf.c",
+        "src/stdio/vsprintf.c",
+        "src/stdio/vsscanf.c",
+        "src/stdio/vswprintf.c",
+        "src/stdio/vswscanf.c",
+        "src/stdio/vwprintf.c",
+        "src/stdio/vwscanf.c",
+        "src/stdio/wprintf.c",
+        "src/stdio/wscanf.c",
+        "src/stdlib/abs.c",
+        "src/stdlib/atof.c",
+        "src/stdlib/atoi.c",
+        "src/stdlib/atol.c",
+        "src/stdlib/atoll.c",
+        "src/stdlib/bsearch.c",
+        "src/stdlib/div.c",
+        "src/stdlib/ecvt.c",
+        "src/stdlib/fcvt.c",
+        "src/stdlib/gcvt.c",
+        "src/stdlib/imaxabs.c",
+        "src/stdlib/imaxdiv.c",
+        "src/stdlib/labs.c",
+        "src/stdlib/ldiv.c",
+        "src/stdlib/llabs.c",
+        "src/stdlib/lldiv.c",
+        "src/stdlib/qsort.c",
+        "src/stdlib/qsort_nr.c",
+        "src/stdlib/strtod.c",
+        "src/stdlib/strtol.c",
+        "src/stdlib/wcstod.c",
+        "src/stdlib/wcstol.c",
+        "src/temp/__randname.c",
+        "src/temp/mkdtemp.c",
+        "src/temp/mkostemp.c",
+        "src/temp/mkostemps.c",
+        "src/temp/mkstemp.c",
+        "src/temp/mkstemps.c",
+        "src/temp/mktemp.c",
+        "src/termios/cfgetospeed.c",
+        "src/termios/cfmakeraw.c",
+        "src/termios/cfsetospeed.c",
+        "src/termios/tcdrain.c",
+        "src/termios/tcflow.c",
+        "src/termios/tcflush.c",
+        "src/termios/tcgetattr.c",
+        "src/termios/tcgetsid.c",
+        "src/termios/tcgetwinsize.c",
+        "src/termios/tcsendbreak.c",
+        "src/termios/tcsetattr.c",
+        "src/termios/tcsetwinsize.c",
+        "src/thread/__lock.c",
+        "src/thread/__syscall_cp.c",
+        "src/thread/__timedwait.c",
+        "src/thread/__tls_get_addr.c",
+        "src/thread/__unmapself.c",
+        "src/thread/__wait.c",
+        "src/thread/call_once.c",
+        "src/thread/clone.c",
+        "src/thread/cnd_broadcast.c",
+        "src/thread/cnd_destroy.c",
+        "src/thread/cnd_init.c",
+        "src/thread/cnd_signal.c",
+        "src/thread/cnd_timedwait.c",
+        "src/thread/cnd_wait.c",
+        "src/thread/default_attr.c",
+        "src/thread/lock_ptc.c",
+        "src/thread/mtx_destroy.c",
+        "src/thread/mtx_init.c",
+        "src/thread/mtx_lock.c",
+        "src/thread/mtx_timedlock.c",
+        "src/thread/mtx_trylock.c",
+        "src/thread/mtx_unlock.c",
+        "src/thread/pthread_atfork.c",
+        "src/thread/pthread_attr_destroy.c",
+        "src/thread/pthread_attr_get.c",
+        "src/thread/pthread_attr_init.c",
+        "src/thread/pthread_attr_setdetachstate.c",
+        "src/thread/pthread_attr_setguardsize.c",
+        "src/thread/pthread_attr_setinheritsched.c",
+        "src/thread/pthread_attr_setschedparam.c",
+        "src/thread/pthread_attr_setschedpolicy.c",
+        "src/thread/pthread_attr_setscope.c",
+        "src/thread/pthread_attr_setstack.c",
+        "src/thread/pthread_attr_setstacksize.c",
+        "src/thread/pthread_barrier_destroy.c",
+        "src/thread/pthread_barrier_init.c",
+        "src/thread/pthread_barrier_wait.c",
+        "src/thread/pthread_barrierattr_destroy.c",
+        "src/thread/pthread_barrierattr_init.c",
+        "src/thread/pthread_barrierattr_setpshared.c",
+        "src/thread/pthread_cancel.c",
+        "src/thread/pthread_cleanup_push.c",
+        "src/thread/pthread_cond_broadcast.c",
+        "src/thread/pthread_cond_destroy.c",
+        "src/thread/pthread_cond_init.c",
+        "src/thread/pthread_cond_signal.c",
+        "src/thread/pthread_cond_timedwait.c",
+        "src/thread/pthread_cond_wait.c",
+        "src/thread/pthread_condattr_destroy.c",
+        "src/thread/pthread_condattr_init.c",
+        "src/thread/pthread_condattr_setclock.c",
+        "src/thread/pthread_condattr_setpshared.c",
+        "src/thread/pthread_create.c",
+        "src/thread/pthread_detach.c",
+        "src/thread/pthread_equal.c",
+        "src/thread/pthread_getattr_np.c",
+        "src/thread/pthread_getconcurrency.c",
+        "src/thread/pthread_getcpuclockid.c",
+        "src/thread/pthread_getname_np.c",
+        "src/thread/pthread_getschedparam.c",
+        "src/thread/pthread_getspecific.c",
+        "src/thread/pthread_join.c",
+        "src/thread/pthread_key_create.c",
+        "src/thread/pthread_kill.c",
+        "src/thread/pthread_mutex_consistent.c",
+        "src/thread/pthread_mutex_destroy.c",
+        "src/thread/pthread_mutex_getprioceiling.c",
+        "src/thread/pthread_mutex_init.c",
+        "src/thread/pthread_mutex_lock.c",
+        "src/thread/pthread_mutex_setprioceiling.c",
+        "src/thread/pthread_mutex_timedlock.c",
+        "src/thread/pthread_mutex_trylock.c",
+        "src/thread/pthread_mutex_unlock.c",
+        "src/thread/pthread_mutexattr_destroy.c",
+        "src/thread/pthread_mutexattr_init.c",
+        "src/thread/pthread_mutexattr_setprotocol.c",
+        "src/thread/pthread_mutexattr_setpshared.c",
+        "src/thread/pthread_mutexattr_setrobust.c",
+        "src/thread/pthread_mutexattr_settype.c",
+        "src/thread/pthread_once.c",
+        "src/thread/pthread_rwlock_destroy.c",
+        "src/thread/pthread_rwlock_init.c",
+        "src/thread/pthread_rwlock_rdlock.c",
+        "src/thread/pthread_rwlock_timedrdlock.c",
+        "src/thread/pthread_rwlock_timedwrlock.c",
+        "src/thread/pthread_rwlock_tryrdlock.c",
+        "src/thread/pthread_rwlock_trywrlock.c",
+        "src/thread/pthread_rwlock_unlock.c",
+        "src/thread/pthread_rwlock_wrlock.c",
+        "src/thread/pthread_rwlockattr_destroy.c",
+        "src/thread/pthread_rwlockattr_init.c",
+        "src/thread/pthread_rwlockattr_setpshared.c",
+        "src/thread/pthread_self.c",
+        "src/thread/pthread_setattr_default_np.c",
+        "src/thread/pthread_setcancelstate.c",
+        "src/thread/pthread_setcanceltype.c",
+        "src/thread/pthread_setconcurrency.c",
+        "src/thread/pthread_setname_np.c",
+        "src/thread/pthread_setschedparam.c",
+        "src/thread/pthread_setschedprio.c",
+        "src/thread/pthread_setspecific.c",
+        "src/thread/pthread_sigmask.c",
+        "src/thread/pthread_spin_destroy.c",
+        "src/thread/pthread_spin_init.c",
+        "src/thread/pthread_spin_lock.c",
+        "src/thread/pthread_spin_trylock.c",
+        "src/thread/pthread_spin_unlock.c",
+        "src/thread/pthread_testcancel.c",
+        "src/thread/sem_destroy.c",
+        "src/thread/sem_getvalue.c",
+        "src/thread/sem_init.c",
+        "src/thread/sem_open.c",
+        "src/thread/sem_post.c",
+        "src/thread/sem_timedwait.c",
+        "src/thread/sem_trywait.c",
+        "src/thread/sem_unlink.c",
+        "src/thread/sem_wait.c",
+        "src/thread/synccall.c",
+        "src/thread/syscall_cp.c",
+        "src/thread/thrd_create.c",
+        "src/thread/thrd_exit.c",
+        "src/thread/thrd_join.c",
+        "src/thread/thrd_sleep.c",
+        "src/thread/thrd_yield.c",
+        "src/thread/tls.c",
+        "src/thread/tss_create.c",
+        "src/thread/tss_delete.c",
+        "src/thread/tss_set.c",
+        "src/thread/vmlock.c",
+        "src/time/__map_file.c",
+        "src/time/__month_to_secs.c",
+        "src/time/__secs_to_tm.c",
+        "src/time/__tm_to_secs.c",
+        "src/time/__tz.c",
+        "src/time/__year_to_secs.c",
+        "src/time/asctime.c",
+        "src/time/asctime_r.c",
+        "src/time/clock.c",
+        "src/time/clock_getcpuclockid.c",
+        "src/time/clock_getres.c",
+        "src/time/clock_gettime.c",
+        "src/time/clock_nanosleep.c",
+        "src/time/clock_settime.c",
+        "src/time/ctime.c",
+        "src/time/ctime_r.c",
+        "src/time/difftime.c",
+        "src/time/ftime.c",
+        "src/time/getdate.c",
+        "src/time/gettimeofday.c",
+        "src/time/gmtime.c",
+        "src/time/gmtime_r.c",
+        "src/time/localtime.c",
+        "src/time/localtime_r.c",
+        "src/time/mktime.c",
+        "src/time/nanosleep.c",
+        "src/time/strftime.c",
+        "src/time/strptime.c",
+        "src/time/time.c",
+        "src/time/timegm.c",
+        "src/time/timer_create.c",
+        "src/time/timer_delete.c",
+        "src/time/timer_getoverrun.c",
+        "src/time/timer_gettime.c",
+        "src/time/timer_settime.c",
+        "src/time/times.c",
+        "src/time/timespec_get.c",
+        "src/time/utime.c",
+        "src/time/wcsftime.c",
+        "src/unistd/_exit.c",
+        "src/unistd/access.c",
+        "src/unistd/acct.c",
+        "src/unistd/alarm.c",
+        "src/unistd/chdir.c",
+        "src/unistd/chown.c",
+        "src/unistd/close.c",
+        "src/unistd/ctermid.c",
+        "src/unistd/dup.c",
+        "src/unistd/dup2.c",
+        "src/unistd/dup3.c",
+        "src/unistd/faccessat.c",
+        "src/unistd/fchdir.c",
+        "src/unistd/fchown.c",
+        "src/unistd/fchownat.c",
+        "src/unistd/fdatasync.c",
+        "src/unistd/fsync.c",
+        "src/unistd/ftruncate.c",
+        "src/unistd/getcwd.c",
+        "src/unistd/getegid.c",
+        "src/unistd/geteuid.c",
+        "src/unistd/getgid.c",
+        "src/unistd/getgroups.c",
+        "src/unistd/gethostname.c",
+        "src/unistd/getlogin.c",
+        "src/unistd/getlogin_r.c",
+        "src/unistd/getpgid.c",
+        "src/unistd/getpgrp.c",
+        "src/unistd/getpid.c",
+        "src/unistd/getppid.c",
+        "src/unistd/getsid.c",
+        "src/unistd/getuid.c",
+        "src/unistd/isatty.c",
+        "src/unistd/lchown.c",
+        "src/unistd/link.c",
+        "src/unistd/linkat.c",
+        "src/unistd/lseek.c",
+        "src/unistd/nice.c",
+        "src/unistd/pause.c",
+        "src/unistd/pipe.c",
+        "src/unistd/pipe2.c",
+        "src/unistd/posix_close.c",
+        "src/unistd/pread.c",
+        "src/unistd/preadv.c",
+        "src/unistd/pwrite.c",
+        "src/unistd/pwritev.c",
+        "src/unistd/read.c",
+        "src/unistd/readlink.c",
+        "src/unistd/readlinkat.c",
+        "src/unistd/readv.c",
+        "src/unistd/renameat.c",
+        "src/unistd/rmdir.c",
+        "src/unistd/setegid.c",
+        "src/unistd/seteuid.c",
+        "src/unistd/setgid.c",
+        "src/unistd/setpgid.c",
+        "src/unistd/setpgrp.c",
+        "src/unistd/setregid.c",
+        "src/unistd/setresgid.c",
+        "src/unistd/setresuid.c",
+        "src/unistd/setreuid.c",
+        "src/unistd/setsid.c",
+        "src/unistd/setuid.c",
+        "src/unistd/setxid.c",
+        "src/unistd/sleep.c",
+        "src/unistd/symlink.c",
+        "src/unistd/symlinkat.c",
+        "src/unistd/sync.c",
+        "src/unistd/tcgetpgrp.c",
+        "src/unistd/tcsetpgrp.c",
+        "src/unistd/truncate.c",
+        "src/unistd/ttyname.c",
+        "src/unistd/ttyname_r.c",
+        "src/unistd/ualarm.c",
+        "src/unistd/unlink.c",
+        "src/unistd/unlinkat.c",
+        "src/unistd/usleep.c",
+        "src/unistd/write.c",
+        "src/unistd/writev.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "src/exit/arm/__aeabi_atexit.c",
+                "src/fenv/arm/fenv-hf.S",
+                "src/fenv/arm/fenv.c",
+                "src/ldso/arm/dlsym.s",
+                "src/ldso/arm/dlsym_time64.S",
+                "src/ldso/arm/find_exidx.c",
+                "src/ldso/arm/tlsdesc.S",
+                "src/math/arm/fabs.c",
+                "src/math/arm/fabsf.c",
+                "src/math/arm/fma.c",
+                "src/math/arm/fmaf.c",
+                "src/math/arm/sqrt.c",
+                "src/math/arm/sqrtf.c",
+                "src/process/arm/vfork.s",
+                "src/setjmp/arm/longjmp.S",
+                "src/setjmp/arm/setjmp.S",
+                "src/signal/arm/restore.s",
+                "src/signal/arm/sigsetjmp.s",
+                "src/thread/arm/__aeabi_read_tp.s",
+                "src/thread/arm/__unmapself.s",
+                "src/thread/arm/atomics.s",
+                "src/thread/arm/clone.s",
+                "src/thread/arm/syscall_cp.s",
+            ],
+            exclude_srcs: [
+                "src/exit/__aeabi_atexit.c",
+                "src/fenv/fenv-hf.c",
+                "src/fenv/fenv.c",
+                "src/ldso/dlsym.c",
+                "src/ldso/dlsym_time64.c",
+                "src/ldso/find_exidx.c",
+                "src/ldso/tlsdesc.c",
+                "src/math/fabs.c",
+                "src/math/fabsf.c",
+                "src/math/fma.c",
+                "src/math/fmaf.c",
+                "src/math/sqrt.c",
+                "src/math/sqrtf.c",
+                "src/process/vfork.c",
+                "src/setjmp/longjmp.c",
+                "src/setjmp/setjmp.c",
+                "src/signal/restore.c",
+                "src/signal/sigsetjmp.c",
+                "src/thread/__aeabi_read_tp.c",
+                "src/thread/__unmapself.c",
+                "src/thread/atomics.c",
+                "src/thread/clone.c",
+                "src/thread/syscall_cp.c",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "src/fenv/aarch64/fenv.s",
+                "src/ldso/aarch64/dlsym.s",
+                "src/ldso/aarch64/tlsdesc.s",
+                "src/math/aarch64/ceil.c",
+                "src/math/aarch64/ceilf.c",
+                "src/math/aarch64/fabs.c",
+                "src/math/aarch64/fabsf.c",
+                "src/math/aarch64/floor.c",
+                "src/math/aarch64/floorf.c",
+                "src/math/aarch64/fma.c",
+                "src/math/aarch64/fmaf.c",
+                "src/math/aarch64/fmax.c",
+                "src/math/aarch64/fmaxf.c",
+                "src/math/aarch64/fmin.c",
+                "src/math/aarch64/fminf.c",
+                "src/math/aarch64/llrint.c",
+                "src/math/aarch64/llrintf.c",
+                "src/math/aarch64/llround.c",
+                "src/math/aarch64/llroundf.c",
+                "src/math/aarch64/lrint.c",
+                "src/math/aarch64/lrintf.c",
+                "src/math/aarch64/lround.c",
+                "src/math/aarch64/lroundf.c",
+                "src/math/aarch64/nearbyint.c",
+                "src/math/aarch64/nearbyintf.c",
+                "src/math/aarch64/rint.c",
+                "src/math/aarch64/rintf.c",
+                "src/math/aarch64/round.c",
+                "src/math/aarch64/roundf.c",
+                "src/math/aarch64/sqrt.c",
+                "src/math/aarch64/sqrtf.c",
+                "src/math/aarch64/trunc.c",
+                "src/math/aarch64/truncf.c",
+                "src/process/aarch64/vfork.s",
+                "src/setjmp/aarch64/longjmp.s",
+                "src/setjmp/aarch64/setjmp.s",
+                "src/signal/aarch64/restore.s",
+                "src/signal/aarch64/sigsetjmp.s",
+                "src/thread/aarch64/__unmapself.s",
+                "src/thread/aarch64/clone.s",
+                "src/thread/aarch64/syscall_cp.s",
+            ],
+            exclude_srcs: [
+                "src/fenv/fenv.c",
+                "src/ldso/dlsym.c",
+                "src/ldso/tlsdesc.c",
+                "src/math/ceil.c",
+                "src/math/ceilf.c",
+                "src/math/fabs.c",
+                "src/math/fabsf.c",
+                "src/math/floor.c",
+                "src/math/floorf.c",
+                "src/math/fma.c",
+                "src/math/fmaf.c",
+                "src/math/fmax.c",
+                "src/math/fmaxf.c",
+                "src/math/fmin.c",
+                "src/math/fminf.c",
+                "src/math/llrint.c",
+                "src/math/llrintf.c",
+                "src/math/llround.c",
+                "src/math/llroundf.c",
+                "src/math/lrint.c",
+                "src/math/lrintf.c",
+                "src/math/lround.c",
+                "src/math/lroundf.c",
+                "src/math/nearbyint.c",
+                "src/math/nearbyintf.c",
+                "src/math/rint.c",
+                "src/math/rintf.c",
+                "src/math/round.c",
+                "src/math/roundf.c",
+                "src/math/sqrt.c",
+                "src/math/sqrtf.c",
+                "src/math/trunc.c",
+                "src/math/truncf.c",
+                "src/process/vfork.c",
+                "src/setjmp/longjmp.c",
+                "src/setjmp/setjmp.c",
+                "src/signal/restore.c",
+                "src/signal/sigsetjmp.c",
+                "src/thread/__unmapself.c",
+                "src/thread/clone.c",
+                "src/thread/syscall_cp.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "src/fenv/i386/fenv.s",
+                "src/ldso/i386/dlsym.s",
+                "src/ldso/i386/dlsym_time64.S",
+                "src/ldso/i386/tlsdesc.s",
+                "src/math/i386/__invtrigl.s",
+                "src/math/i386/acos.s",
+                "src/math/i386/acosf.s",
+                "src/math/i386/acosl.s",
+                "src/math/i386/asin.s",
+                "src/math/i386/asinf.s",
+                "src/math/i386/asinl.s",
+                "src/math/i386/atan.s",
+                "src/math/i386/atan2.s",
+                "src/math/i386/atan2f.s",
+                "src/math/i386/atan2l.s",
+                "src/math/i386/atanf.s",
+                "src/math/i386/atanl.s",
+                "src/math/i386/ceil.s",
+                "src/math/i386/ceilf.s",
+                "src/math/i386/ceill.s",
+                "src/math/i386/exp2l.s",
+                "src/math/i386/exp_ld.s",
+                "src/math/i386/expl.s",
+                "src/math/i386/expm1l.s",
+                "src/math/i386/fabs.c",
+                "src/math/i386/fabsf.c",
+                "src/math/i386/fabsl.c",
+                "src/math/i386/floor.s",
+                "src/math/i386/floorf.s",
+                "src/math/i386/floorl.s",
+                "src/math/i386/fmod.c",
+                "src/math/i386/fmodf.c",
+                "src/math/i386/fmodl.c",
+                "src/math/i386/hypot.s",
+                "src/math/i386/hypotf.s",
+                "src/math/i386/ldexp.s",
+                "src/math/i386/ldexpf.s",
+                "src/math/i386/ldexpl.s",
+                "src/math/i386/llrint.c",
+                "src/math/i386/llrintf.c",
+                "src/math/i386/llrintl.c",
+                "src/math/i386/log.s",
+                "src/math/i386/log10.s",
+                "src/math/i386/log10f.s",
+                "src/math/i386/log10l.s",
+                "src/math/i386/log1p.s",
+                "src/math/i386/log1pf.s",
+                "src/math/i386/log1pl.s",
+                "src/math/i386/log2.s",
+                "src/math/i386/log2f.s",
+                "src/math/i386/log2l.s",
+                "src/math/i386/logf.s",
+                "src/math/i386/logl.s",
+                "src/math/i386/lrint.c",
+                "src/math/i386/lrintf.c",
+                "src/math/i386/lrintl.c",
+                "src/math/i386/remainder.c",
+                "src/math/i386/remainderf.c",
+                "src/math/i386/remainderl.c",
+                "src/math/i386/remquo.s",
+                "src/math/i386/remquof.s",
+                "src/math/i386/remquol.s",
+                "src/math/i386/rint.c",
+                "src/math/i386/rintf.c",
+                "src/math/i386/rintl.c",
+                "src/math/i386/scalbln.s",
+                "src/math/i386/scalblnf.s",
+                "src/math/i386/scalblnl.s",
+                "src/math/i386/scalbn.s",
+                "src/math/i386/scalbnf.s",
+                "src/math/i386/scalbnl.s",
+                "src/math/i386/sqrt.c",
+                "src/math/i386/sqrtf.c",
+                "src/math/i386/sqrtl.c",
+                "src/math/i386/trunc.s",
+                "src/math/i386/truncf.s",
+                "src/math/i386/truncl.s",
+                "src/process/i386/vfork.s",
+                "src/setjmp/i386/longjmp.s",
+                "src/setjmp/i386/setjmp.s",
+                "src/signal/i386/restore.s",
+                "src/signal/i386/sigsetjmp.s",
+                "src/thread/i386/__unmapself.s",
+                "src/thread/i386/clone.s",
+                "src/thread/i386/syscall_cp.s",
+                "src/thread/i386/tls.s",
+            ],
+            exclude_srcs: [
+                "src/fenv/fenv.c",
+                "src/ldso/dlsym.c",
+                "src/ldso/dlsym_time64.c",
+                "src/ldso/tlsdesc.c",
+                "src/math/__invtrigl.c",
+                "src/math/acos.c",
+                "src/math/acosf.c",
+                "src/math/acosl.c",
+                "src/math/asin.c",
+                "src/math/asinf.c",
+                "src/math/asinl.c",
+                "src/math/atan.c",
+                "src/math/atan2.c",
+                "src/math/atan2f.c",
+                "src/math/atan2l.c",
+                "src/math/atanf.c",
+                "src/math/atanl.c",
+                "src/math/ceil.c",
+                "src/math/ceilf.c",
+                "src/math/ceill.c",
+                "src/math/exp2l.c",
+                "src/math/exp_ld.c",
+                "src/math/expl.c",
+                "src/math/expm1l.c",
+                "src/math/fabs.c",
+                "src/math/fabsf.c",
+                "src/math/fabsl.c",
+                "src/math/floor.c",
+                "src/math/floorf.c",
+                "src/math/floorl.c",
+                "src/math/fmod.c",
+                "src/math/fmodf.c",
+                "src/math/fmodl.c",
+                "src/math/hypot.c",
+                "src/math/hypotf.c",
+                "src/math/ldexp.c",
+                "src/math/ldexpf.c",
+                "src/math/ldexpl.c",
+                "src/math/llrint.c",
+                "src/math/llrintf.c",
+                "src/math/llrintl.c",
+                "src/math/log.c",
+                "src/math/log10.c",
+                "src/math/log10f.c",
+                "src/math/log10l.c",
+                "src/math/log1p.c",
+                "src/math/log1pf.c",
+                "src/math/log1pl.c",
+                "src/math/log2.c",
+                "src/math/log2f.c",
+                "src/math/log2l.c",
+                "src/math/logf.c",
+                "src/math/logl.c",
+                "src/math/lrint.c",
+                "src/math/lrintf.c",
+                "src/math/lrintl.c",
+                "src/math/remainder.c",
+                "src/math/remainderf.c",
+                "src/math/remainderl.c",
+                "src/math/remquo.c",
+                "src/math/remquof.c",
+                "src/math/remquol.c",
+                "src/math/rint.c",
+                "src/math/rintf.c",
+                "src/math/rintl.c",
+                "src/math/scalbln.c",
+                "src/math/scalblnf.c",
+                "src/math/scalblnl.c",
+                "src/math/scalbn.c",
+                "src/math/scalbnf.c",
+                "src/math/scalbnl.c",
+                "src/math/sqrt.c",
+                "src/math/sqrtf.c",
+                "src/math/sqrtl.c",
+                "src/math/trunc.c",
+                "src/math/truncf.c",
+                "src/math/truncl.c",
+                "src/process/vfork.c",
+                "src/setjmp/longjmp.c",
+                "src/setjmp/setjmp.c",
+                "src/signal/restore.c",
+                "src/signal/sigsetjmp.c",
+                "src/thread/__unmapself.c",
+                "src/thread/clone.c",
+                "src/thread/syscall_cp.c",
+                "src/thread/tls.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "src/fenv/x86_64/fenv.s",
+                "src/ldso/x86_64/dlsym.s",
+                "src/ldso/x86_64/tlsdesc.s",
+                "src/math/x86_64/__invtrigl.s",
+                "src/math/x86_64/acosl.s",
+                "src/math/x86_64/asinl.s",
+                "src/math/x86_64/atan2l.s",
+                "src/math/x86_64/atanl.s",
+                "src/math/x86_64/ceill.s",
+                "src/math/x86_64/exp2l.s",
+                "src/math/x86_64/expl.s",
+                "src/math/x86_64/expm1l.s",
+                "src/math/x86_64/fabs.c",
+                "src/math/x86_64/fabsf.c",
+                "src/math/x86_64/fabsl.c",
+                "src/math/x86_64/floorl.s",
+                "src/math/x86_64/fma.c",
+                "src/math/x86_64/fmaf.c",
+                "src/math/x86_64/fmodl.c",
+                "src/math/x86_64/llrint.c",
+                "src/math/x86_64/llrintf.c",
+                "src/math/x86_64/llrintl.c",
+                "src/math/x86_64/log10l.s",
+                "src/math/x86_64/log1pl.s",
+                "src/math/x86_64/log2l.s",
+                "src/math/x86_64/logl.s",
+                "src/math/x86_64/lrint.c",
+                "src/math/x86_64/lrintf.c",
+                "src/math/x86_64/lrintl.c",
+                "src/math/x86_64/remainderl.c",
+                "src/math/x86_64/remquol.c",
+                "src/math/x86_64/rintl.c",
+                "src/math/x86_64/sqrt.c",
+                "src/math/x86_64/sqrtf.c",
+                "src/math/x86_64/sqrtl.c",
+                "src/math/x86_64/truncl.s",
+                "src/process/x86_64/vfork.s",
+                "src/setjmp/x86_64/longjmp.s",
+                "src/setjmp/x86_64/setjmp.s",
+                "src/signal/x86_64/restore.s",
+                "src/signal/x86_64/sigsetjmp.s",
+                "src/thread/x86_64/__unmapself.s",
+                "src/thread/x86_64/clone.s",
+                "src/thread/x86_64/syscall_cp.s",
+            ],
+            exclude_srcs: [
+                "src/fenv/fenv.c",
+                "src/ldso/dlsym.c",
+                "src/ldso/tlsdesc.c",
+                "src/math/__invtrigl.c",
+                "src/math/acosl.c",
+                "src/math/asinl.c",
+                "src/math/atan2l.c",
+                "src/math/atanl.c",
+                "src/math/ceill.c",
+                "src/math/exp2l.c",
+                "src/math/expl.c",
+                "src/math/expm1l.c",
+                "src/math/fabs.c",
+                "src/math/fabsf.c",
+                "src/math/fabsl.c",
+                "src/math/floorl.c",
+                "src/math/fma.c",
+                "src/math/fmaf.c",
+                "src/math/fmodl.c",
+                "src/math/llrint.c",
+                "src/math/llrintf.c",
+                "src/math/llrintl.c",
+                "src/math/log10l.c",
+                "src/math/log1pl.c",
+                "src/math/log2l.c",
+                "src/math/logl.c",
+                "src/math/lrint.c",
+                "src/math/lrintf.c",
+                "src/math/lrintl.c",
+                "src/math/remainderl.c",
+                "src/math/remquol.c",
+                "src/math/rintl.c",
+                "src/math/sqrt.c",
+                "src/math/sqrtf.c",
+                "src/math/sqrtl.c",
+                "src/math/truncl.c",
+                "src/process/vfork.c",
+                "src/setjmp/longjmp.c",
+                "src/setjmp/setjmp.c",
+                "src/signal/restore.c",
+                "src/signal/sigsetjmp.c",
+                "src/thread/__unmapself.c",
+                "src/thread/clone.c",
+                "src/thread/syscall_cp.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_compat32_sources",
+    srcs: [
+        "compat/time32/__xstat.c",
+        "compat/time32/adjtime32.c",
+        "compat/time32/adjtimex_time32.c",
+        "compat/time32/aio_suspend_time32.c",
+        "compat/time32/clock_adjtime32.c",
+        "compat/time32/clock_getres_time32.c",
+        "compat/time32/clock_gettime32.c",
+        "compat/time32/clock_nanosleep_time32.c",
+        "compat/time32/clock_settime32.c",
+        "compat/time32/cnd_timedwait_time32.c",
+        "compat/time32/ctime32.c",
+        "compat/time32/ctime32_r.c",
+        "compat/time32/difftime32.c",
+        "compat/time32/fstat_time32.c",
+        "compat/time32/fstatat_time32.c",
+        "compat/time32/ftime32.c",
+        "compat/time32/futimens_time32.c",
+        "compat/time32/futimes_time32.c",
+        "compat/time32/futimesat_time32.c",
+        "compat/time32/getitimer_time32.c",
+        "compat/time32/getrusage_time32.c",
+        "compat/time32/gettimeofday_time32.c",
+        "compat/time32/gmtime32.c",
+        "compat/time32/gmtime32_r.c",
+        "compat/time32/localtime32.c",
+        "compat/time32/localtime32_r.c",
+        "compat/time32/lstat_time32.c",
+        "compat/time32/lutimes_time32.c",
+        "compat/time32/mktime32.c",
+        "compat/time32/mq_timedreceive_time32.c",
+        "compat/time32/mq_timedsend_time32.c",
+        "compat/time32/mtx_timedlock_time32.c",
+        "compat/time32/nanosleep_time32.c",
+        "compat/time32/ppoll_time32.c",
+        "compat/time32/pselect_time32.c",
+        "compat/time32/pthread_cond_timedwait_time32.c",
+        "compat/time32/pthread_mutex_timedlock_time32.c",
+        "compat/time32/pthread_rwlock_timedrdlock_time32.c",
+        "compat/time32/pthread_rwlock_timedwrlock_time32.c",
+        "compat/time32/pthread_timedjoin_np_time32.c",
+        "compat/time32/recvmmsg_time32.c",
+        "compat/time32/sched_rr_get_interval_time32.c",
+        "compat/time32/select_time32.c",
+        "compat/time32/sem_timedwait_time32.c",
+        "compat/time32/semtimedop_time32.c",
+        "compat/time32/setitimer_time32.c",
+        "compat/time32/settimeofday_time32.c",
+        "compat/time32/sigtimedwait_time32.c",
+        "compat/time32/stat_time32.c",
+        "compat/time32/stime32.c",
+        "compat/time32/thrd_sleep_time32.c",
+        "compat/time32/time32.c",
+        "compat/time32/time32gm.c",
+        "compat/time32/timer_gettime32.c",
+        "compat/time32/timer_settime32.c",
+        "compat/time32/timerfd_gettime32.c",
+        "compat/time32/timerfd_settime32.c",
+        "compat/time32/timespec_get_time32.c",
+        "compat/time32/utime_time32.c",
+        "compat/time32/utimensat_time32.c",
+        "compat/time32/utimes_time32.c",
+        "compat/time32/wait3_time32.c",
+        "compat/time32/wait4_time32.c",
+    ],
+}
+
+cc_defaults {
+    name: "libc_musl_opt_sources",
+    srcs: [
+        "src/internal/defsysinfo.c",
+        "src/internal/emulate_wait4.c",
+        "src/internal/floatscan.c",
+        "src/internal/intscan.c",
+        "src/internal/libc.c",
+        "src/internal/procfdname.c",
+        "src/internal/shgetc.c",
+        "src/internal/syscall_ret.c",
+        "src/internal/vdso.c",
+        "src/internal/version.c",
+        "src/malloc/calloc.c",
+        "src/malloc/free.c",
+        "src/malloc/libc_calloc.c",
+        "src/malloc/lite_malloc.c",
+        "src/malloc/memalign.c",
+        "src/malloc/posix_memalign.c",
+        "src/malloc/realloc.c",
+        "src/malloc/reallocarray.c",
+        "src/malloc/replaced.c",
+        "src/string/bcmp.c",
+        "src/string/bcopy.c",
+        "src/string/bzero.c",
+        "src/string/explicit_bzero.c",
+        "src/string/index.c",
+        "src/string/memccpy.c",
+        "src/string/memchr.c",
+        "src/string/memcmp.c",
+        "src/string/memmem.c",
+        "src/string/memmove.c",
+        "src/string/mempcpy.c",
+        "src/string/memrchr.c",
+        "src/string/rindex.c",
+        "src/string/stpcpy.c",
+        "src/string/stpncpy.c",
+        "src/string/strcasecmp.c",
+        "src/string/strcasestr.c",
+        "src/string/strcat.c",
+        "src/string/strchr.c",
+        "src/string/strchrnul.c",
+        "src/string/strcmp.c",
+        "src/string/strcpy.c",
+        "src/string/strcspn.c",
+        "src/string/strdup.c",
+        "src/string/strerror_r.c",
+        "src/string/strlcat.c",
+        "src/string/strlcpy.c",
+        "src/string/strlen.c",
+        "src/string/strncasecmp.c",
+        "src/string/strncat.c",
+        "src/string/strncmp.c",
+        "src/string/strncpy.c",
+        "src/string/strndup.c",
+        "src/string/strnlen.c",
+        "src/string/strpbrk.c",
+        "src/string/strrchr.c",
+        "src/string/strsep.c",
+        "src/string/strsignal.c",
+        "src/string/strspn.c",
+        "src/string/strstr.c",
+        "src/string/strtok.c",
+        "src/string/strtok_r.c",
+        "src/string/strverscmp.c",
+        "src/string/swab.c",
+        "src/string/wcpcpy.c",
+        "src/string/wcpncpy.c",
+        "src/string/wcscasecmp.c",
+        "src/string/wcscasecmp_l.c",
+        "src/string/wcscat.c",
+        "src/string/wcschr.c",
+        "src/string/wcscmp.c",
+        "src/string/wcscpy.c",
+        "src/string/wcscspn.c",
+        "src/string/wcsdup.c",
+        "src/string/wcslen.c",
+        "src/string/wcsncasecmp.c",
+        "src/string/wcsncasecmp_l.c",
+        "src/string/wcsncat.c",
+        "src/string/wcsncmp.c",
+        "src/string/wcsncpy.c",
+        "src/string/wcsnlen.c",
+        "src/string/wcspbrk.c",
+        "src/string/wcsrchr.c",
+        "src/string/wcsspn.c",
+        "src/string/wcsstr.c",
+        "src/string/wcstok.c",
+        "src/string/wcswcs.c",
+        "src/string/wmemchr.c",
+        "src/string/wmemcmp.c",
+        "src/string/wmemcpy.c",
+        "src/string/wmemmove.c",
+        "src/string/wmemset.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "src/string/arm/__aeabi_memcpy.s",
+                "src/string/arm/__aeabi_memset.s",
+            ],
+            exclude_srcs: [
+                "src/string/__aeabi_memcpy.c",
+                "src/string/__aeabi_memset.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "src/internal/i386/defsysinfo.s",
+                "src/string/i386/memmove.s",
+            ],
+            exclude_srcs: [
+                "src/internal/defsysinfo.c",
+                "src/string/memmove.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "src/string/x86_64/memmove.s",
+            ],
+            exclude_srcs: [
+                "src/string/memmove.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_opt_nossp_sources",
+    srcs: [
+        "src/string/memcpy.c",
+        "src/string/memset.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "src/string/arm/memcpy.S",
+            ],
+            exclude_srcs: [
+                "src/string/memcpy.c",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "src/string/aarch64/memcpy.S",
+                "src/string/aarch64/memset.S",
+            ],
+            exclude_srcs: [
+                "src/string/memcpy.c",
+                "src/string/memset.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "src/string/i386/memcpy.s",
+                "src/string/i386/memset.s",
+            ],
+            exclude_srcs: [
+                "src/string/memcpy.c",
+                "src/string/memset.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "src/string/x86_64/memcpy.s",
+                "src/string/x86_64/memset.s",
+            ],
+            exclude_srcs: [
+                "src/string/memcpy.c",
+                "src/string/memset.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_nossp_sources",
+    srcs: [
+        "src/env/__init_tls.c",
+        "src/env/__libc_start_main.c",
+        "src/env/__stack_chk_fail.c",
+        "src/thread/__set_thread_area.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "src/thread/arm/__set_thread_area.c",
+            ],
+            exclude_srcs: [
+                "src/thread/__set_thread_area.c",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "src/thread/aarch64/__set_thread_area.s",
+            ],
+            exclude_srcs: [
+                "src/thread/__set_thread_area.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "src/thread/i386/__set_thread_area.s",
+            ],
+            exclude_srcs: [
+                "src/thread/__set_thread_area.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "src/thread/x86_64/__set_thread_area.s",
+            ],
+            exclude_srcs: [
+                "src/thread/__set_thread_area.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_ldso_sources",
+    srcs: [
+        "ldso/dlstart.c",
+        "ldso/dynlink.c",
+    ],
+}
+
+cc_defaults {
+    name: "libc_musl_Scrt1_sources",
+    srcs: [
+        "crt/Scrt1.c",
+    ],
+}
+
+cc_defaults {
+    name: "libc_musl_crt1_sources",
+    srcs: [
+        "crt/crt1.c",
+    ],
+}
+
+cc_defaults {
+    name: "libc_musl_crti_sources",
+    srcs: [
+        "crt/crti.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "crt/arm/crti.s",
+            ],
+            exclude_srcs: [
+                "crt/crti.c",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "crt/aarch64/crti.s",
+            ],
+            exclude_srcs: [
+                "crt/crti.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "crt/i386/crti.s",
+            ],
+            exclude_srcs: [
+                "crt/crti.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "crt/x86_64/crti.s",
+            ],
+            exclude_srcs: [
+                "crt/crti.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_crtn_sources",
+    srcs: [
+        "crt/crtn.c",
+    ],
+    arch: {
+        arm: {
+            srcs: [
+                "crt/arm/crtn.s",
+            ],
+            exclude_srcs: [
+                "crt/crtn.c",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "crt/aarch64/crtn.s",
+            ],
+            exclude_srcs: [
+                "crt/crtn.c",
+            ],
+        },
+        x86: {
+            srcs: [
+                "crt/i386/crtn.s",
+            ],
+            exclude_srcs: [
+                "crt/crtn.c",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "crt/x86_64/crtn.s",
+            ],
+            exclude_srcs: [
+                "crt/crtn.c",
+            ],
+        },
+    },
+}
+
+cc_defaults {
+    name: "libc_musl_rcrt1_sources",
+    srcs: [
+        "crt/rcrt1.c",
+    ],
+}
diff --git a/src/internal/atomic.h b/src/internal/atomic.h
index 8f71c8c..a61b77b 100644
--- a/src/internal/atomic.h
+++ b/src/internal/atomic.h
@@ -330,4 +330,30 @@
 }
 #endif
 
+#if defined __has_builtin
+#if __has_builtin(__builtin_popcount)
+#define a_popcount_32 a_popcount_32
+static inline int a_popcount_32(uint32_t x)
+{
+	return __builtin_popcount(x);
+}
+#endif
+#endif
+
+#ifndef a_popcount_32
+#define a_popcount_32 a_popcount_32
+static inline int a_popcount_32(uint32_t x)
+{
+	const uint32_t m1 = 0x55555555;
+	const uint32_t m2 = 0x33333333;
+	const uint32_t m4 = 0x0f0f0f0f;
+	x -= (x >> 1) & m1;
+	x = (x & m2) + ((x >> 2) & m2);
+	x = (x + (x >> 4)) & m4;
+	x += x >> 8;
+	x += x >> 16;
+	return x & 0x3f;
+}
+#endif
+
 #endif
diff --git a/src/malloc/mallocng/mallinfo.c b/src/malloc/mallocng/mallinfo.c
new file mode 100644
index 0000000..365bc55
--- /dev/null
+++ b/src/malloc/mallocng/mallinfo.c
@@ -0,0 +1,87 @@
+#include <limits.h>
+#include <malloc.h>
+#include <stddef.h>
+
+#include "glue.h"
+#include "meta.h"
+
+static void accumulate_meta(struct mallinfo2 *mi, struct meta *g)
+{
+	int sc = g->sizeclass;
+	if (sc >= 48) {
+		// Large mmap allocation
+		mi->hblks++;
+		mi->uordblks += g->maplen*4096;
+		mi->hblkhd += g->maplen*4096;
+	} else {
+		if (g->freeable && !g->maplen) {
+			// Small size slots are embedded in a larger slot, avoid
+			// double counting by subtracting the size of the larger
+			// slot from the total used memory.
+			struct meta* outer_g = get_meta((void*)g->mem);
+			int outer_sc	= outer_g->sizeclass;
+			int outer_sz = size_classes[outer_sc]*UNIT;
+			mi->uordblks -= outer_sz;
+			mi->arena -= outer_sz;
+		}
+		int sz = size_classes[sc]*UNIT;
+		int mask = g->avail_mask | g->freed_mask;
+		int nr_unused = a_popcount_32(mask);
+
+		if (!g->last_idx) {
+			// Allocation groups with a single allocation may use a
+			// smaller maplen than normally used for the size class.
+			if (sz > g->maplen-IB-UNIT) {
+				sz = g->maplen-IB-UNIT;
+			}
+		}
+		mi->arena += sz*(g->last_idx+1);
+		mi->ordblks += nr_unused;
+		mi->uordblks += sz*(g->last_idx+1-nr_unused);
+		mi->fordblks += sz*nr_unused;
+	}
+}
+
+static void accumulate_meta_area(struct mallinfo2 *mi, struct meta_area *ma)
+{
+	for (int i=0; i<ma->nslots; i++) {
+		if (ma->slots[i].mem) {
+			accumulate_meta(mi, &ma->slots[i]);
+		}
+	}
+}
+
+struct mallinfo2 mallinfo2(void)
+{
+	struct mallinfo2 mi = {0};
+
+	rdlock();
+	struct meta_area *ma = ctx.meta_area_head;
+	while (ma) {
+		accumulate_meta_area(&mi, ma);
+		ma = ma->next;
+	}
+	unlock();
+
+	return mi;
+}
+
+#define cap(x) ((x > INT_MAX) ? INT_MAX : x)
+
+struct mallinfo mallinfo(void) {
+	struct mallinfo mi = {0};
+	struct mallinfo2 mi2 = mallinfo2();
+
+	mi.arena = cap(mi2.arena);
+	mi.ordblks = cap(mi2.ordblks);
+	mi.smblks = cap(mi2.smblks);
+	mi.hblks = cap(mi2.hblks);
+	mi.hblkhd = cap(mi2.hblkhd);
+	mi.usmblks = cap(mi2.usmblks);
+	mi.fsmblks = cap(mi2.fsmblks);
+	mi.uordblks = cap(mi2.uordblks);
+	mi.fordblks = cap(mi2.fordblks);
+	mi.keepcost = cap(mi2.keepcost);
+
+	return mi;
+}
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index b02b81c..fa66f0a 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -25,7 +25,7 @@
 	FUNLOCK(f);
 }
 
-int getopt(int argc, char * const argv[], const char *optstring)
+int __posix_getopt(int argc, char * const argv[], const char *optstring)
 {
 	int i;
 	wchar_t c, d;
@@ -102,5 +102,3 @@
 	}
 	return c;
 }
-
-weak_alias(getopt, __posix_getopt);
diff --git a/src/misc/getopt_long.c b/src/misc/getopt_long.c
index 6949ab1..117d1a1 100644
--- a/src/misc/getopt_long.c
+++ b/src/misc/getopt_long.c
@@ -9,6 +9,8 @@
 
 extern int __optpos, __optreset;
 
+int __posix_getopt(int argc, char * const argv[], const char *optstring);
+
 static void permute(char *const *argv, int dest, int src)
 {
 	char **av = (char **)argv;
@@ -134,7 +136,7 @@
 			return '?';
 		}
 	}
-	return getopt(argc, argv, optstring);
+	return __posix_getopt(argc, argv, optstring);
 }
 
 int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
@@ -146,3 +148,20 @@
 {
 	return __getopt_long(argc, argv, optstring, longopts, idx, 1);
 }
+
+/* ANDROID CHANGE: implement getopt via getopt_long to continue parsing options
+ * after the first non-option argument to match the user visible behavior of
+ * glibc.
+ */
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+	static int posixly_correct = -1;
+
+	if (posixly_correct == -1 || __optreset)
+		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+
+	if (posixly_correct)
+		return __posix_getopt(argc, argv, optstring);
+	else
+		return __getopt_long(argc, argv, optstring, NULL, NULL, 0);
+}