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); +}