Merge "Update capability.h"
diff --git a/libc/Android.mk b/libc/Android.mk
index 2c1a3a6..273b73e 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -490,14 +490,11 @@
 # Define some common cflags
 # ========================================================
 libc_common_cflags := \
-    -DWITH_ERRLIST \
     -DANDROID_CHANGES \
     -D_LIBC=1 \
-    -DFLOATING_POINT \
     -DINET6 \
     -I$(LOCAL_PATH)/private \
     -DPOSIX_MISTAKE \
-    -DLOG_ON_HEAP_ERROR \
     -Wall -Wextra
 
 ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true)
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 88c980f..17b6141 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -1,326 +1,319 @@
-# This file is used to automatically generate bionic's the system calls stubs.
+# This file is used to automatically generate bionic's system call stubs.
 #
-# Each non comment line has the following format:
+# Each non-blank, non-comment line has the following format:
 #
-# return_type    func_name[:syscall_name[:call_id]]([parameter_list])  (1|-1|"stub")
+# return_type func_name[:syscall_name[:call_id]]([parameter_list]) arch_list
 #
-# Note that:
+# where:
+#       arch_list ::= "all" | "custom" | arch+
+#       arch      ::= "arm" | "mips" | "x86"
+#
+# Note:
 #      - syscall_name corresponds to the name of the syscall, which may differ from
 #        the exported function name (example: the exit syscall is implemented by the _exit()
 #        function, which is not the same as the standard C exit() function which calls it)
-#        The call_id parameter, given that func_name and syscall_name have
+#
+#      - The call_id parameter, given that func_name and syscall_name have
 #        been provided, allows the user to specify dispatch style syscalls.
 #        For example, socket() syscall on i386 actually becomes:
 #          socketcall(__NR_socket, 1, *(rest of args on stack)).
 #
-#      - each parameter type is assumed to be stored on 32 bits, there is no plan to support
-#        64-bit architectures at the moment
+#      - Each parameter type is assumed to be stored in 32 bits.
 #
-#      - the final field can be "1", meaning: generate a stub for each architecture,
-#        taking the constants from the kernel header files.
-#
-#      - the final field can be "stub" meaning: do not generate any stubs ---
-#        in this case, a hand-written custom stub must be provided.
-#        TODO: replace this with something like "custom" or "none", or remove
-#        it entirely.
-#
-#      - the final field can be a three-element list of 1s and -1 meaning:
-#        this system call is only available on some of the architectures (1),
-#        and no stub should be generated for those architectures marked with -1.
-#        the order is arm,x86,mips.
-#        TODO: replace this with something more readable like "-arm,-mips" (meaning x86 only).
+#      - The arch list can be the word "custom" meaning "do not generate any stubs".
+#        In this case, a hand-written custom stub must be provided.
 #
 # This file is processed by a python script named gensyscalls.py.
-#
 
 # process management
-void    _exit:exit_group (int)      1
-void    _exit_thread:exit (int)     1
-pid_t   __fork:fork (void)           1
-pid_t   _waitpid:waitpid (pid_t, int*, int, struct rusage*)   -1,1,1
-int     __waitid:waitid(int, pid_t, struct siginfo_t*, int,void*)          1
-pid_t   wait4(pid_t pid, int *status, int options, struct rusage *rusage)   1
+void    _exit:exit_group(int)      all
+void    _exit_thread:exit(int)     all
+pid_t   __fork:fork(void)           all
+pid_t   _waitpid:waitpid(pid_t, int*, int, struct rusage*)   mips,x86
+int     __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*)          all
+pid_t   wait4(pid_t pid, int* status, int options, struct rusage* rusage)   all
 
 # NOTE: this system call is never called directly, but we list it there
 #       to have __NR_clone properly defined.
-#
-pid_t   __sys_clone:clone (int, void*, int*, void*, int*) 1
+pid_t   __sys_clone:clone(int, void*, int*, void*, int*) all
 
-int     execve (const char*, char* const*, char* const*)  1
+int     execve(const char*, char* const*, char* const*)  all
 
-int     __setuid:setuid32 (uid_t)    1,1,-1
-int     __setuid:setuid (uid_t)   -1,-1,1
-uid_t   getuid:getuid32 ()         1,1,-1
-uid_t   getuid:getuid ()           -1,-1,1
-gid_t   getgid:getgid32 ()         1,1,-1
-gid_t   getgid:getgid ()           -1,-1,1
-uid_t   geteuid:geteuid32 ()       1,1,-1
-uid_t   geteuid:geteuid ()         -1,-1,1
-gid_t   getegid:getegid32 ()       1,1,-1
-gid_t   getegid:getegid ()         -1,-1,1
-uid_t   getresuid:getresuid32 (uid_t *ruid, uid_t *euid, uid_t *suid)   1,1,-1
-uid_t   getresuid:getresuid (uid_t *ruid, uid_t *euid, uid_t *suid)     -1,-1,1
-gid_t   getresgid:getresgid32 (gid_t *rgid, gid_t *egid, gid_t *sgid)   1,1,-1
-gid_t   getresgid:getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid)     -1,-1,1
-pid_t   gettid()                   1
-ssize_t readahead(int, off64_t, size_t)     1
-int     getgroups:getgroups32(int, gid_t *)    1,1,-1
-int     getgroups:getgroups(int, gid_t *)      -1,-1,1
-pid_t   getpgid(pid_t)             1
-pid_t   getppid()                  1
-pid_t   getsid(pid_t)              1
-pid_t   setsid()                   1
-int     setgid:setgid32(gid_t)     1,1,-1
-int     setgid:setgid(gid_t)       -1,-1,1
-int     seteuid:seteuid32(uid_t)   stub
-int     __setreuid:setreuid32(uid_t, uid_t)   1,1,-1
-int     __setreuid:setreuid(uid_t, uid_t)     -1,-1,1
-int     __setresuid:setresuid32(uid_t, uid_t, uid_t)   1,1,-1
-int     __setresuid:setresuid(uid_t, uid_t, uid_t)     -1,-1,1
-int     setresgid:setresgid32(gid_t, gid_t, gid_t)   1,1,-1
-int     setresgid:setresgid(gid_t, gid_t, gid_t)     -1,-1,1
-void*   __brk:brk(void*)           1
-# see comments in arch-arm/bionic/kill.S to understand why we don't generate an ARM stub for kill/tkill
-int     kill(pid_t, int)           -1,1,1
-int     tkill(pid_t tid, int sig)  -1,1,1
-int     tgkill(pid_t tgid, pid_t tid, int sig)  -1,1,1
-int     __ptrace:ptrace(int request, int pid, void* addr, void* data)  1
-int     __set_thread_area:set_thread_area(void*  user_desc)  -1,1,1
-int     __getpriority:getpriority(int, int)  1
-int     setpriority(int, int, int)   1
-int     setrlimit(int resource, const struct rlimit *rlp)  1
-int     getrlimit:ugetrlimit(int resource, struct rlimit *rlp)  1,1,-1
-int     getrlimit:getrlimit(int resource, struct rlimit *rlp)  -1,-1,1
-int     getrusage(int who, struct rusage*  r_usage)  1
-int     setgroups:setgroups32(int, const gid_t *)   1,1,-1
-int     setgroups:setgroups(int, const gid_t *)     -1,-1,1
-pid_t   getpgrp(void)  stub
-int     setpgid(pid_t, pid_t)  1
-pid_t   vfork(void)  1,-1,-1
-int     setregid:setregid32(gid_t, gid_t)  1,1,-1
-int     setregid:setregid(gid_t, gid_t)    -1,-1,1
-int     chroot(const char *)  1
-# IMPORTANT: Even though <sys/prctl.h> declares prctl(int,...), the syscall stub must take 6 arguments
+int     __setuid:setuid32(uid_t)  arm,x86
+int     __setuid:setuid(uid_t)    mips
+uid_t   getuid:getuid32()         arm,x86
+uid_t   getuid:getuid()           mips
+gid_t   getgid:getgid32()         arm,x86
+gid_t   getgid:getgid()           mips
+uid_t   geteuid:geteuid32()       arm,x86
+uid_t   geteuid:geteuid()         mips
+gid_t   getegid:getegid32()       arm,x86
+gid_t   getegid:getegid()         mips
+uid_t   getresuid:getresuid32(uid_t* ruid, uid_t* euid, uid_t* suid)   arm,x86
+uid_t   getresuid:getresuid(uid_t* ruid, uid_t* euid, uid_t* suid)     mips
+gid_t   getresgid:getresgid32(gid_t* rgid, gid_t* egid, gid_t* sgid)   arm,x86
+gid_t   getresgid:getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid)     mips
+pid_t   gettid()                   all
+ssize_t readahead(int, off64_t, size_t)     all
+int     getgroups:getgroups32(int, gid_t*)    arm,x86
+int     getgroups:getgroups(int, gid_t*)      mips
+pid_t   getpgid(pid_t)             all
+pid_t   getppid()                  all
+pid_t   getsid(pid_t)              all
+pid_t   setsid()                   all
+int     setgid:setgid32(gid_t)     arm,x86
+int     setgid:setgid(gid_t)       mips
+int     seteuid:seteuid32(uid_t)   custom
+int     __setreuid:setreuid32(uid_t, uid_t)   arm,x86
+int     __setreuid:setreuid(uid_t, uid_t)     mips
+int     __setresuid:setresuid32(uid_t, uid_t, uid_t)   arm,x86
+int     __setresuid:setresuid(uid_t, uid_t, uid_t)     mips
+int     setresgid:setresgid32(gid_t, gid_t, gid_t)   arm,x86
+int     setresgid:setresgid(gid_t, gid_t, gid_t)     mips
+void*   __brk:brk(void*)           all
+# See comments in kill.S to understand why we don't generate ARM stubs for kill/tkill/tgkill.
+int     kill(pid_t, int)           mips,x86
+int     tkill(pid_t tid, int sig)  mips,x86
+int     tgkill(pid_t tgid, pid_t tid, int sig)  mips,x86
+int     __ptrace:ptrace(int request, int pid, void* addr, void* data)  all
+int     __set_thread_area:set_thread_area(void*  user_desc)  mips,x86
+int     __getpriority:getpriority(int, int)  all
+int     setpriority(int, int, int)   all
+int     setrlimit(int resource, const struct rlimit* rlp)  all
+int     getrlimit:ugetrlimit(int resource, struct rlimit* rlp)  arm,x86
+int     getrlimit:getrlimit(int resource, struct rlimit* rlp)  mips
+int     getrusage(int who, struct rusage*  r_usage)  all
+int     setgroups:setgroups32(int, const gid_t*)   arm,x86
+int     setgroups:setgroups(int, const gid_t*)     mips
+pid_t   getpgrp(void)  custom
+int     setpgid(pid_t, pid_t)  all
+pid_t   vfork(void)  arm
+int     setregid:setregid32(gid_t, gid_t)  arm,x86
+int     setregid:setregid(gid_t, gid_t)    mips
+int     chroot(const char*)  all
+# IMPORTANT: Even though <sys/prctl.h> declares prctl(int, ...), the syscall stub must take 6 arguments
 #            to match the kernel implementation.
-int     prctl(int option, unsigned int arg2, unsigned int arg3, unsigned int arg4, unsigned int arg5) 1
-int     capget(cap_user_header_t header, cap_user_data_t data) 1
-int     capset(cap_user_header_t header, const cap_user_data_t data) 1
-int     sigaltstack(const stack_t*, stack_t*) 1
-int     acct(const char*  filepath)  1
+int     prctl(int option, unsigned int arg2, unsigned int arg3, unsigned int arg4, unsigned int arg5) all
+int     capget(cap_user_header_t header, cap_user_data_t data) all
+int     capset(cap_user_header_t header, const cap_user_data_t data) all
+int     sigaltstack(const stack_t*, stack_t*) all
+int     acct(const char*  filepath)  all
 
 # file descriptors
-ssize_t     read (int, void*, size_t)        1
-ssize_t     write (int, const void*, size_t)       1
-ssize_t     pread64 (int, void *, size_t, off64_t) 1
-ssize_t     pwrite64 (int, void *, size_t, off64_t) 1
-int         __open:open (const char*, int, mode_t)  1
-int         __openat:openat (int, const char*, int, mode_t) 1
-int         close (int)                      1
-int         creat(const char*, mode_t)       stub
-off_t       lseek(int, off_t, int)           1
-int         __llseek:_llseek (int, unsigned long, unsigned long, loff_t*, int)  1
-pid_t       getpid ()    1
-void *      mmap(void *, size_t, int, int, int, long)  stub
-void *      __mmap2:mmap2(void*, size_t, int, int, int, long)   1
-int         munmap(void *, size_t)  1
-void *      mremap(void *, size_t, size_t, unsigned long)  1
-int         msync(const void *, size_t, int)    1
-int         mprotect(const void *, size_t, int)  1
-int         madvise(const void *, size_t, int)  1
-int         mlock(const void *addr, size_t len)    1
-int         munlock(const void *addr, size_t len)   1
-int         mlockall(int flags)   1
-int         munlockall()   1
-int         mincore(void*  start, size_t  length, unsigned char*  vec)   1
-int         __ioctl:ioctl(int, int, void *)  1
-int         readv(int, const struct iovec *, int)   1
-int         writev(int, const struct iovec *, int)  1
-int         __fcntl:fcntl(int, int, void*)  1
-int         flock(int, int)   1
-int         fchmod(int, mode_t)  1
-int         dup(int)  1
-int         pipe(int *)  1,1,-1
-int         pipe2(int *, int) 1
-int         dup2(int, int)   1
-int         select:_newselect(int, struct fd_set *, struct fd_set *, struct fd_set *, struct timeval *)  1
-int         ftruncate(int, off_t)  1
-int         ftruncate64(int, off64_t) 1
-int         getdents:getdents64(unsigned int, struct dirent *, unsigned int)   1
-int         fsync(int)  1
-int         fdatasync(int) 1
-int         fchown:fchown32(int, uid_t, gid_t)  1,1,-1
-int         fchown:fchown(int, uid_t, gid_t)    -1,-1,1
-void        sync(void)  1
-int         __fcntl64:fcntl64(int, int, void *)  1
-int         __fstatfs64:fstatfs64(int, size_t, struct statfs *)  1
-ssize_t     sendfile(int out_fd, int in_fd, off_t *offset, size_t count)  1
-int         fstatat:fstatat64(int dirfd, const char *path, struct stat *buf, int flags)   1
-int         mkdirat(int dirfd, const char *pathname, mode_t mode)  1
-int         fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags)  1
-int         fchmodat(int dirfd, const char *path, mode_t mode, int flags)  1
-int         renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath)  1
-int         fsetxattr(int, const char *, const void *, size_t, int) 1
-ssize_t     fgetxattr(int, const char *, void *, size_t) 1
-ssize_t     flistxattr(int, char *, size_t) 1
-int         fremovexattr(int, const char *) 1
+ssize_t     read(int, void*, size_t)        all
+ssize_t     write(int, const void*, size_t)       all
+ssize_t     pread64(int, void*, size_t, off64_t) all
+ssize_t     pwrite64(int, void*, size_t, off64_t) all
+int         __open:open(const char*, int, mode_t)  all
+int         __openat:openat(int, const char*, int, mode_t) all
+int         close(int)                      all
+int         creat(const char*, mode_t)       custom
+off_t       lseek(int, off_t, int)           all
+int         __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int)  all
+pid_t       getpid()    all
+void*       mmap(void*, size_t, int, int, int, long)  custom
+void*       __mmap2:mmap2(void*, size_t, int, int, int, long)   all
+int         munmap(void*, size_t)  all
+void*       mremap(void*, size_t, size_t, unsigned long)  all
+int         msync(const void*, size_t, int)    all
+int         mprotect(const void*, size_t, int)  all
+int         madvise(const void*, size_t, int)  all
+int         mlock(const void* addr, size_t len)    all
+int         munlock(const void* addr, size_t len)   all
+int         mlockall(int flags)   all
+int         munlockall()   all
+int         mincore(void*  start, size_t  length, unsigned char*  vec)   all
+int         __ioctl:ioctl(int, int, void*)  all
+int         readv(int, const struct iovec*, int)   all
+int         writev(int, const struct iovec*, int)  all
+int         __fcntl:fcntl(int, int, void*)  all
+int         flock(int, int)   all
+int         fchmod(int, mode_t)  all
+int         dup(int)  all
+int         pipe(int*)  arm,x86
+int         pipe2(int*, int) all
+int         dup2(int, int)   all
+int         select:_newselect(int, struct fd_set*, struct fd_set*, struct fd_set*, struct timeval*)  all
+int         ftruncate(int, off_t)  all
+int         ftruncate64(int, off64_t) all
+int         getdents:getdents64(unsigned int, struct dirent*, unsigned int)   all
+int         fsync(int)  all
+int         fdatasync(int) all
+int         fchown:fchown32(int, uid_t, gid_t)  arm,x86
+int         fchown:fchown(int, uid_t, gid_t)    mips
+void        sync(void)  all
+int         __fcntl64:fcntl64(int, int, void*)  all
+int         __fstatfs64:fstatfs64(int, size_t, struct statfs*)  all
+ssize_t     sendfile(int out_fd, int in_fd, off_t* offset, size_t count)  all
+ssize_t     sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count)  all
+int         fstatat:fstatat64(int dirfd, const char* path, struct stat* buf, int flags)   all
+int         mkdirat(int dirfd, const char* pathname, mode_t mode)  all
+int         fchownat(int dirfd, const char* path, uid_t owner, gid_t group, int flags)  all
+int         fchmodat(int dirfd, const char* path, mode_t mode, int flags)  all
+int         renameat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath)  all
+int         fsetxattr(int, const char*, const void*, size_t, int) all
+ssize_t     fgetxattr(int, const char*, void*, size_t) all
+ssize_t     flistxattr(int, char*, size_t) all
+int         fremovexattr(int, const char*) all
 
 # file system
-int     link (const char*, const char*)  1
-int     unlink (const char*)             1
-int     unlinkat (int, const char *, int)   1
-int     chdir (const char*)              1
-int     mknod (const char*, mode_t, dev_t)  1
-int     chmod (const char*,mode_t)          1
-int     chown:chown32(const char *, uid_t, gid_t)  1,1,-1
-int     chown:chown(const char *, uid_t, gid_t)    -1,-1,1
-int     lchown:lchown32 (const char*, uid_t, gid_t)  1,1,-1
-int     lchown:lchown (const char*, uid_t, gid_t)  -1,-1,1
-int     mount (const char*, const char*, const char*, unsigned long, const void*)  1
-int     umount(const char*)  stub
-int     umount2 (const char*, int)  1
-int     fstat:fstat64(int, struct stat*)    1
-int     stat:stat64(const char *, struct stat *)  1
-int     lstat:lstat64(const char *, struct stat *)  1
-int     mkdir(const char *, mode_t) 1
-int     readlink(const char *, char *, size_t)  1
-int     rmdir(const char *)  1
-int     rename(const char *, const char *)  1
-int     __getcwd:getcwd(char * buf, size_t size)  1
-int     access(const char *, int)  1
-int     faccessat(int, const char *, int, int)  1
-int     symlink(const char *, const char *)  1
-int     fchdir(int)    1
-int     truncate(const char*, off_t)    1
-int     setxattr(const char *, const char *, const void *, size_t, int) 1
-int     lsetxattr(const char *, const char *, const void *, size_t, int) 1
-ssize_t getxattr(const char *, const char *, void *, size_t) 1
-ssize_t lgetxattr(const char *, const char *, void *, size_t) 1
-ssize_t listxattr(const char *, char *, size_t) 1
-ssize_t llistxattr(const char *, char *, size_t) 1
-int     removexattr(const char *, const char *) 1
-int     lremovexattr(const char *, const char *) 1
-int     __statfs64:statfs64(const char *, size_t, struct statfs *)  1
-long    unshare(unsigned long)  1
-int     swapon(const char *, int) 1
-int     swapoff(const char *) 1
+int     link(const char*, const char*)  all
+int     unlink(const char*)             all
+int     unlinkat(int, const char*, int)   all
+int     chdir(const char*)              all
+int     mknod(const char*, mode_t, dev_t)  all
+int     chmod(const char*, mode_t)          all
+int     chown:chown32(const char*, uid_t, gid_t)  arm,x86
+int     chown:chown(const char*, uid_t, gid_t)    mips
+int     lchown:lchown32(const char*, uid_t, gid_t)  arm,x86
+int     lchown:lchown(const char*, uid_t, gid_t)  mips
+int     mount(const char*, const char*, const char*, unsigned long, const void*)  all
+int     umount(const char*)  custom
+int     umount2(const char*, int)  all
+int     fstat:fstat64(int, struct stat*)    all
+int     stat:stat64(const char*, struct stat*)  all
+int     lstat:lstat64(const char*, struct stat*)  all
+int     mkdir(const char*, mode_t) all
+int     readlink(const char*, char*, size_t)  all
+int     rmdir(const char*)  all
+int     rename(const char*, const char*)  all
+int     __getcwd:getcwd(char* buf, size_t size)  all
+int     access(const char*, int)  all
+int     faccessat(int, const char*, int, int)  all
+int     symlink(const char*, const char*)  all
+int     fchdir(int)    all
+int     truncate(const char*, off_t)    all
+int     truncate64(const char*, off64_t)    all
+int     setxattr(const char*, const char*, const void*, size_t, int) all
+int     lsetxattr(const char*, const char*, const void*, size_t, int) all
+ssize_t getxattr(const char*, const char*, void*, size_t) all
+ssize_t lgetxattr(const char*, const char*, void*, size_t) all
+ssize_t listxattr(const char*, char*, size_t) all
+ssize_t llistxattr(const char*, char*, size_t) all
+int     removexattr(const char*, const char*) all
+int     lremovexattr(const char*, const char*) all
+int     __statfs64:statfs64(const char*, size_t, struct statfs*)  all
+long    unshare(unsigned long)  all
+int     swapon(const char*, int) all
+int     swapoff(const char*) all
 
 # time
-int           pause ()                       1
-int           gettimeofday(struct timeval*, struct timezone*)       1
-int           settimeofday(const struct timeval*, const struct timezone*)   1
-clock_t       times(struct tms *)       1
-int           nanosleep(const struct timespec *, struct timespec *)   1
-int           clock_gettime(clockid_t clk_id, struct timespec *tp)    1
-int           clock_settime(clockid_t clk_id, const struct timespec *tp)  1
-int           clock_getres(clockid_t clk_id, struct timespec *res)   1
-int           clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem)  1
-int           getitimer(int, const struct itimerval *)   1
-int           setitimer(int, const struct itimerval *, struct itimerval *)  1
-int           __timer_create:timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)    1
-int           __timer_settime:timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*) 1
-int           __timer_gettime:timer_gettime(timer_t, struct itimerspec*)                                1
-int           __timer_getoverrun:timer_getoverrun(timer_t)                                              1
-int           __timer_delete:timer_delete(timer_t)                                                      1
-int           utimes(const char*, const struct timeval tvp[2])                          1
-int           utimensat(int, const char *, const struct timespec times[2], int)         1
-int           timerfd_create(clockid_t, int)   1
-int           timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *)   1
-int           timerfd_gettime(int, struct itimerspec *)   1
+int           pause()                       all
+int           gettimeofday(struct timeval*, struct timezone*)       all
+int           settimeofday(const struct timeval*, const struct timezone*)   all
+clock_t       times(struct tms*)       all
+int           nanosleep(const struct timespec*, struct timespec*)   all
+int           clock_gettime(clockid_t clk_id, struct timespec* tp)    all
+int           clock_settime(clockid_t clk_id, const struct timespec* tp)  all
+int           clock_getres(clockid_t clk_id, struct timespec* res)   all
+int           clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* req, struct timespec* rem)  all
+int           getitimer(int, const struct itimerval*)   all
+int           setitimer(int, const struct itimerval*, struct itimerval*)  all
+int           __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, timer_t* timerid)    all
+int           __timer_settime:timer_settime(timer_t, int, const struct itimerspec*, struct itimerspec*) all
+int           __timer_gettime:timer_gettime(timer_t, struct itimerspec*)                                all
+int           __timer_getoverrun:timer_getoverrun(timer_t)                                              all
+int           __timer_delete:timer_delete(timer_t)                                                      all
+int           utimes(const char*, const struct timeval tvp[2])                          all
+int           utimensat(int, const char*, const struct timespec times[2], int)         all
+int           timerfd_create(clockid_t, int)   all
+int           timerfd_settime(int, int, const struct itimerspec*, struct itimerspec*)   all
+int           timerfd_gettime(int, struct itimerspec*)   all
 
 # signals
-int     sigaction(int, const struct sigaction *, struct sigaction *)  1
-int     sigprocmask(int, const sigset_t *, sigset_t *)  1
-int     __sigsuspend:sigsuspend(int unused1, int unused2, unsigned mask)  1,1,-1
-int     __sigsuspend:sigsuspend(const sigset_t *mask)  -1,-1,1
-int     __rt_sigaction:rt_sigaction (int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize)  1
-int     __rt_sigprocmask:rt_sigprocmask (int  how, const sigset_t *set, sigset_t *oset, size_t sigsetsize)  1
-int     __rt_sigtimedwait:rt_sigtimedwait(const sigset_t *set, struct siginfo_t  *info, struct timespec_t  *timeout, size_t  sigset_size)  1
-int     sigpending(sigset_t *)  1
-int     signalfd4(int fd, const sigset_t *mask, size_t sizemask, int flags)  1
+int     sigaction(int, const struct sigaction*, struct sigaction*)  all
+int     sigprocmask(int, const sigset_t*, sigset_t*)  all
+int     __sigsuspend:sigsuspend(int unused1, int unused2, unsigned mask)  arm,x86
+int     __sigsuspend:sigsuspend(const sigset_t* mask)  mips
+int     __rt_sigaction:rt_sigaction(int sig, const struct sigaction* act, struct sigaction* oact, size_t sigsetsize)  all
+int     __rt_sigprocmask:rt_sigprocmask(int  how, const sigset_t* set, sigset_t* oset, size_t sigsetsize)  all
+int     __rt_sigtimedwait:rt_sigtimedwait(const sigset_t* set, struct siginfo_t* info, struct timespec_t* timeout, size_t  sigset_size)  all
+int     sigpending(sigset_t*)  all
+int     signalfd4(int fd, const sigset_t* mask, size_t sizemask, int flags)  all
 
 # sockets
-int           socket(int, int, int)              1,-1,1
-int           socketpair(int, int, int, int*)    1,-1,1
-int           bind(int, struct sockaddr *, int)  1,-1,1
-int           connect(int, struct sockaddr *, socklen_t)   1,-1,1
-int           listen(int, int)                   1,-1,1
-int           accept(int, struct sockaddr *, socklen_t *)  1,-1,1
-int           getsockname(int, struct sockaddr *, socklen_t *)  1,-1,1
-int           getpeername(int, struct sockaddr *, socklen_t *)  1,-1,1
-int           sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t)  1,-1,1
-int           recvfrom(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *)  1,-1,1
-int           shutdown(int, int)  1,-1,1
-int           setsockopt(int, int, int, const void *, socklen_t)  1,-1,1
-int           getsockopt(int, int, int, void *, socklen_t *)    1,-1,1
-int           sendmsg(int, const struct msghdr *, unsigned int)  1,-1,1
-int           recvmsg(int, struct msghdr *, unsigned int)   1,-1,1
+int           socket(int, int, int)              arm,mips
+int           socketpair(int, int, int, int*)    arm,mips
+int           bind(int, struct sockaddr*, int)  arm,mips
+int           connect(int, struct sockaddr*, socklen_t)   arm,mips
+int           listen(int, int)                   arm,mips
+int           accept(int, struct sockaddr*, socklen_t*)  arm,mips
+int           getsockname(int, struct sockaddr*, socklen_t*)  arm,mips
+int           getpeername(int, struct sockaddr*, socklen_t*)  arm,mips
+int           sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  arm,mips
+int           recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  arm,mips
+int           shutdown(int, int)  arm,mips
+int           setsockopt(int, int, int, const void*, socklen_t)  arm,mips
+int           getsockopt(int, int, int, void*, socklen_t*)    arm,mips
+int           sendmsg(int, const struct msghdr*, unsigned int)  arm,mips
+int           recvmsg(int, struct msghdr*, unsigned int)   arm,mips
 
 # sockets for x86. These are done as an "indexed" call to socketcall syscall.
-int           socket:socketcall:1 (int, int, int) -1,1,-1
-int           bind:socketcall:2 (int, struct sockaddr *, int)  -1,1,-1
-int           connect:socketcall:3(int, struct sockaddr *, socklen_t)   -1,1,-1
-int           listen:socketcall:4(int, int)                   -1,1,-1
-int           accept:socketcall:5(int, struct sockaddr *, socklen_t *)  -1,1,-1
-int           getsockname:socketcall:6(int, struct sockaddr *, socklen_t *)  -1,1,-1
-int           getpeername:socketcall:7(int, struct sockaddr *, socklen_t *)  -1,1,-1
-int           socketpair:socketcall:8(int, int, int, int*)    -1,1,-1
-int           sendto:socketcall:11(int, const void *, size_t, int, const struct sockaddr *, socklen_t)  -1,1,-1
-int           recvfrom:socketcall:12(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *)  -1,1,-1
-int           shutdown:socketcall:13(int, int)  -1,1,-1
-int           setsockopt:socketcall:14(int, int, int, const void *, socklen_t)  -1,1,-1
-int           getsockopt:socketcall:15(int, int, int, void *, socklen_t *)    -1,1,-1
-int           sendmsg:socketcall:16(int, const struct msghdr *, unsigned int)  -1,1,-1
-int           recvmsg:socketcall:17(int, struct msghdr *, unsigned int)   -1,1,-1
+int           socket:socketcall:1(int, int, int) x86
+int           bind:socketcall:2(int, struct sockaddr*, int)  x86
+int           connect:socketcall:3(int, struct sockaddr*, socklen_t)   x86
+int           listen:socketcall:4(int, int)                   x86
+int           accept:socketcall:5(int, struct sockaddr*, socklen_t*)  x86
+int           getsockname:socketcall:6(int, struct sockaddr*, socklen_t*)  x86
+int           getpeername:socketcall:7(int, struct sockaddr*, socklen_t*)  x86
+int           socketpair:socketcall:8(int, int, int, int*)    x86
+int           sendto:socketcall:11(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  x86
+int           recvfrom:socketcall:12(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  x86
+int           shutdown:socketcall:13(int, int)  x86
+int           setsockopt:socketcall:14(int, int, int, const void*, socklen_t)  x86
+int           getsockopt:socketcall:15(int, int, int, void*, socklen_t*)    x86
+int           sendmsg:socketcall:16(int, const struct msghdr*, unsigned int)  x86
+int           recvmsg:socketcall:17(int, struct msghdr*, unsigned int)   x86
 
 # scheduler & real-time
-int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)  1
-int sched_getscheduler(pid_t pid)  1
-int sched_yield(void)  1
-int sched_setparam(pid_t pid, const struct sched_param *param)  1
-int sched_getparam(pid_t pid, struct sched_param *param)  1
-int sched_get_priority_max(int policy)  1
-int sched_get_priority_min(int policy)  1
-int sched_rr_get_interval(pid_t pid, struct timespec *interval)  1
-int sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set) 1
-int __sched_getaffinity:sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set)  1
-int __getcpu:getcpu(unsigned *cpu, unsigned *node, void *unused) 1
+int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param)  all
+int sched_getscheduler(pid_t pid)  all
+int sched_yield(void)  all
+int sched_setparam(pid_t pid, const struct sched_param* param)  all
+int sched_getparam(pid_t pid, struct sched_param* param)  all
+int sched_get_priority_max(int policy)  all
+int sched_get_priority_min(int policy)  all
+int sched_rr_get_interval(pid_t pid, struct timespec* interval)  all
+int sched_setaffinity(pid_t pid, size_t setsize, const cpu_set_t* set) all
+int __sched_getaffinity:sched_getaffinity(pid_t pid, size_t setsize, cpu_set_t* set)  all
+int __getcpu:getcpu(unsigned* cpu, unsigned* node, void* unused) all
 
 # io priorities
-int ioprio_set(int which, int who, int ioprio) 1
-int ioprio_get(int which, int who) 1
+int ioprio_set(int which, int who, int ioprio) all
+int ioprio_get(int which, int who) all
 
 # other
-int     uname(struct utsname *)  1
-mode_t  umask(mode_t)  1
-int      __reboot:reboot(int, int, int, void *)  1
-int     __syslog:syslog(int, char *, int)  1
-int     init_module(void *, unsigned long, const char *)  1
-int     delete_module(const char*, unsigned int)   1
-int     klogctl:syslog(int, char *, int)   1
-int     sysinfo(struct sysinfo *)  1
-int     personality(unsigned long)  1
-long    perf_event_open(struct perf_event_attr *attr_uptr, pid_t pid, int cpu, int group_fd, unsigned long flags) 1
+int     uname(struct utsname*)  all
+mode_t  umask(mode_t)  all
+int      __reboot:reboot(int, int, int, void*)  all
+int     __syslog:syslog(int, char*, int)  all
+int     init_module(void*, unsigned long, const char*)  all
+int     delete_module(const char*, unsigned int)   all
+int     klogctl:syslog(int, char*, int)   all
+int     sysinfo(struct sysinfo*)  all
+int     personality(unsigned long)  all
+long    perf_event_open(struct perf_event_attr* attr_uptr, pid_t pid, int cpu, int group_fd, unsigned long flags) all
 
 # futex
-int	futex(void *, int, int, void *, void *, int) 1
+int     futex(void*, int, int, void*, void*, int) all
 
 # epoll
-int     epoll_create(int size)     1
-int     epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)    1
-int     epoll_wait(int epfd, struct epoll_event *events, int max, int timeout)   1
+int     epoll_create(int size)     all
+int     epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)    all
+int     epoll_wait(int epfd, struct epoll_event* events, int max, int timeout)   all
 
-int     inotify_init(void)      1
-int     inotify_add_watch(int, const char *, unsigned int)  1
-int     inotify_rm_watch(int, unsigned int)  1
+int     inotify_init(void)      all
+int     inotify_add_watch(int, const char*, unsigned int)  all
+int     inotify_rm_watch(int, unsigned int)  all
 
-int     poll(struct pollfd *, unsigned int, long)  1
+int     poll(struct pollfd*, unsigned int, long)  all
 
-int     eventfd:eventfd2(unsigned int, int)  1
+int     eventfd:eventfd2(unsigned int, int)  all
 
 # ARM-specific ARM_NR_BASE == 0x0f0000 == 983040
-int     __set_tls:__ARM_NR_set_tls(void*)                                 1,-1,-1
-int     cacheflush:__ARM_NR_cacheflush(long start, long end, long flags)  1,-1,-1
+int     __set_tls:__ARM_NR_set_tls(void*)                                 arm
+int     cacheflush:__ARM_NR_cacheflush(long start, long end, long flags)  arm
 
 # MIPS-specific
-int     _flush_cache:cacheflush(char *addr, const int nbytes, const int op) -1,-1,1
-int     syscall(int number,...) -1,-1,1
+int     _flush_cache:cacheflush(char* addr, const int nbytes, const int op) mips
+int     syscall(int number, ...) mips
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index e87ef38..5f2443f 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -21,10 +21,11 @@
 # These are used by the static and dynamic versions of the libc
 # respectively.
 _LIBC_ARCH_STATIC_SRC_FILES := \
-    arch-arm/bionic/exidx_static.c
+    arch-arm/bionic/exidx_static.c \
+    bionic/dl_iterate_phdr_static.c \
 
 _LIBC_ARCH_DYNAMIC_SRC_FILES := \
-    arch-arm/bionic/exidx_dynamic.c
+    arch-arm/bionic/exidx_dynamic.c \
 
 # Remove the C++ fortify function implementations for which there is an
 # arm assembler version.
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
index 08dc78a..4aaa9f1 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcat_chk.S
@@ -41,13 +41,15 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
     push    {r4, r5}
+    .save   {r4, r5}
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
-    .cfi_rel_offset r5, 0
+    .cfi_rel_offset r5, 4
 
     mov     lr, r2
 
@@ -178,7 +180,7 @@
 .L_strlen_done:
     add     r2, r3, r4
     cmp     r2, lr
-    bgt     .L_fortify_check_failed
+    bhi     __strcat_chk_failed
 
     // Set up the registers for the memcpy code.
     mov     r1, r5
@@ -186,13 +188,23 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-    .cfi_adjust_cfa_offset -8
-    .cfi_restore r4
-    .cfi_restore r5
 
-    #include "memcpy_base.S"
+    .cfi_endproc
+END(__strcat_chk)
 
-.L_fortify_check_failed:
+#define MEMCPY_BASE         __strcat_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+
+#include "memcpy_base.S"
+
+ENTRY(__strcat_chk_failed)
+    .cfi_startproc
+    .save   {r0, lr}
+    .save   {r4, r5}
+
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -208,7 +220,7 @@
     .word   error_string-(1b+4)
 
     .cfi_endproc
-END(__strcat_chk)
+END(__strcat_chk_failed)
 
     .data
 error_string:
diff --git a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
index 9fde590..05152e6 100644
--- a/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a15/bionic/__strcpy_chk.S
@@ -40,6 +40,7 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
@@ -150,14 +151,25 @@
     pld     [r1, #64]
     ldr     r0, [sp]
     cmp     r3, lr
-    bge     .L_fortify_check_failed
+    bhs     __strcpy_chk_failed
 
     // Add 1 for copy length to get the string terminator.
     add     r2, r3, #1
 
-    #include "memcpy_base.S"
+    .cfi_endproc
+END(__strcpy_chk)
 
-.L_fortify_check_failed:
+#define MEMCPY_BASE         __strcpy_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__strcpy_chk_failed)
+    .cfi_startproc
+    .save   {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -169,7 +181,7 @@
     .word   error_string-(1b+4)
 
     .cfi_endproc
-END(__strcpy_chk)
+END(__strcpy_chk_failed)
 
     .data
 error_string:
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy.S b/libc/arch-arm/cortex-a15/bionic/memcpy.S
index 8052d62..a843230 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy.S
@@ -65,7 +65,7 @@
 ENTRY(__memcpy_chk)
         .cfi_startproc
         cmp     r2, r3
-        bgt     __memcpy_chk_fail
+        bhi     __memcpy_chk_fail
 
         // Fall through to memcpy...
         .cfi_endproc
@@ -75,18 +75,23 @@
         .cfi_startproc
         pld     [r1, #64]
         push    {r0, lr}
+        .save   {r0, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
 
-        #include "memcpy_base.S"
         .cfi_endproc
 END(memcpy)
 
+#define MEMCPY_BASE         __memcpy_base
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__memcpy_chk_fail)
         .cfi_startproc
-__memcpy_chk_fail:
         // Preserve lr for backtrace.
         push    {lr}
+        .save   {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
 
@@ -100,6 +105,7 @@
 error_message:
         .word   error_string-(1b+8)
         .cfi_endproc
+END(__memcpy_chk_fail)
 
         .data
 error_string:
diff --git a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
index 647e065..0154676 100644
--- a/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a15/bionic/memcpy_base.S
@@ -53,6 +53,13 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+ENTRY(MEMCPY_BASE)
+        .cfi_startproc
+        .save   {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
         // Assumes that n >= 0, and dst, src are valid pointers.
         // For any sizes less than 832 use the neon code that doesn't
         // care about the src alignment. This avoids any checks
@@ -162,20 +169,34 @@
         ands    r3, r3, #0x3
         bne     .L_copy_unknown_alignment
 
+        .cfi_endproc
+END(MEMCPY_BASE)
+
+ENTRY(MEMCPY_BASE_ALIGNED)
+        .cfi_startproc
+        .save   {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
         // To try and improve performance, stack layout changed,
         // i.e., not keeping the stack looking like users expect
         // (highest numbered register at highest address).
-        // TODO: Add debug frame directives.
-        // We don't need exception unwind directives, because the code below
-        // does not throw any exceptions and does not call any other functions.
-        // Generally, newlib functions like this lack debug information for
-        // assembler source.
-        .save   {r4, r5}
         strd    r4, r5, [sp, #-8]!
-        .save   {r6, r7}
+        .save   {r4, r5}
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
         strd    r6, r7, [sp, #-8]!
-        .save   {r8, r9}
+        .save   {r6, r7}
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset r6, 0
+        .cfi_rel_offset r7, 0
         strd    r8, r9, [sp, #-8]!
+        .save   {r8, r9}
+        .cfi_adjust_cfa_offset 8
+        .cfi_rel_offset r8, 0
+        .cfi_rel_offset r9, 4
 
         // Optimized for already aligned dst code.
         ands    ip, r0, #3
@@ -301,3 +322,6 @@
 
         // Src is guaranteed to be at least word aligned by this point.
         b       .L_word_aligned
+
+        .cfi_endproc
+END(MEMCPY_BASE_ALIGNED)
diff --git a/libc/arch-arm/cortex-a15/bionic/memset.S b/libc/arch-arm/cortex-a15/bionic/memset.S
index 5593be6..b5fc6ba 100644
--- a/libc/arch-arm/cortex-a15/bionic/memset.S
+++ b/libc/arch-arm/cortex-a15/bionic/memset.S
@@ -45,6 +45,7 @@
         bls         .L_done
 
         // Preserve lr for backtrace.
+        .save       {lr}
         push        {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
@@ -73,6 +74,7 @@
 
 ENTRY(memset)
         .cfi_startproc
+        .save       {r0}
         stmfd       sp!, {r0}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset r0, 0
diff --git a/libc/arch-arm/cortex-a15/bionic/strcmp.S b/libc/arch-arm/cortex-a15/bionic/strcmp.S
index 7aff7c4..13b329f 100644
--- a/libc/arch-arm/cortex-a15/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a15/bionic/strcmp.S
@@ -123,8 +123,13 @@
         .macro  init
         /* Macro to save temporary registers and prepare magic values.  */
         subs    sp, sp, #16
+        .cfi_def_cfa_offset 16
         strd    r4, r5, [sp, #8]
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
         strd    r6, r7, [sp]
+        .cfi_rel_offset r6, 8
+        .cfi_rel_offset r7, 12
         mvn     r6, #0  /* all F */
         mov     r7, #0  /* all 0 */
         .endm   /* init */
@@ -165,18 +170,20 @@
 #endif /* not  __ARMEB__ */
         .endm /* setup_return */
 
+        .cfi_startproc
         pld [r0, #0]
         pld [r1, #0]
 
         /* Are both strings double-word aligned?  */
         orr     ip, r0, r1
         tst     ip, #7
-        bne     do_align
+        bne     .L_do_align
 
         /* Fast path.  */
+        .save   {r4-r7}
         init
 
-doubleword_aligned:
+.L_doubleword_aligned:
 
         /* Get here when the strings to compare are double-word aligned.  */
         /* Compare two words in every iteration.  */
@@ -189,14 +196,14 @@
         ldrd    r2, r3, [r0], #8
         ldrd    r4, r5, [r1], #8
 
-        magic_compare_and_branch w1=r2, w2=r4, label=return_24
-        magic_compare_and_branch w1=r3, w2=r5, label=return_35
+        magic_compare_and_branch w1=r2, w2=r4, label=.L_return_24
+        magic_compare_and_branch w1=r3, w2=r5, label=.L_return_35
         b       2b
 
-do_align:
+.L_do_align:
         /* Is the first string word-aligned?  */
         ands    ip, r0, #3
-        beq     word_aligned_r0
+        beq     .L_word_aligned_r0
 
         /* Fast compare byte by byte until the first string is word-aligned.  */
         /* The offset of r0 from a word boundary is in ip. Thus, the number of bytes
@@ -204,58 +211,58 @@
         bic     r0, r0, #3
         ldr     r2, [r0], #4
         lsls    ip, ip, #31
-        beq     byte2
-        bcs     byte3
+        beq     .L_byte2
+        bcs     .L_byte3
 
-byte1:
+.L_byte1:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE1_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte2:
+.L_byte2:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE2_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte3:
+.L_byte3:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE3_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbnz  reg=r3, label=word_aligned_r0
+        bne     .L_fast_return
+        m_cbnz  reg=r3, label=.L_word_aligned_r0
 
-fast_return:
+.L_fast_return:
         mov     r0, ip
         bx      lr
 
-word_aligned_r0:
+.L_word_aligned_r0:
         init
         /* The first string is word-aligned.  */
         /* Is the second string word-aligned?  */
         ands    ip, r1, #3
-        bne     strcmp_unaligned
+        bne     .L_strcmp_unaligned
 
-word_aligned:
+.L_word_aligned:
         /* The strings are word-aligned. */
         /* Is the first string double-word aligned?  */
         tst     r0, #4
-        beq     doubleword_aligned_r0
+        beq     .L_doubleword_aligned_r0
 
         /* If r0 is not double-word aligned yet, align it by loading
         and comparing the next word from each string.  */
         ldr     r2, [r0], #4
         ldr     r4, [r1], #4
-        magic_compare_and_branch w1=r2 w2=r4 label=return_24
+        magic_compare_and_branch w1=r2 w2=r4 label=.L_return_24
 
-doubleword_aligned_r0:
+.L_doubleword_aligned_r0:
         /* Get here when r0 is double-word aligned.  */
         /* Is r1 doubleword_aligned?  */
         tst     r1, #4
-        beq     doubleword_aligned
+        beq     .L_doubleword_aligned
 
         /* Get here when the strings to compare are word-aligned,
         r0 is double-word aligned, but r1 is not double-word aligned.  */
@@ -271,9 +278,9 @@
 
         /* Load the next double-word from each string and compare.  */
         ldrd    r2, r3, [r0], #8
-        magic_compare_and_branch w1=r2 w2=r5 label=return_25
+        magic_compare_and_branch w1=r2 w2=r5 label=.L_return_25
         ldrd    r4, r5, [r1], #8
-        magic_compare_and_branch w1=r3 w2=r4 label=return_34
+        magic_compare_and_branch w1=r3 w2=r4 label=.L_return_34
         b       3b
 
         .macro miscmp_word offsetlo offsethi
@@ -297,47 +304,47 @@
         and     r2, r3, r6, S2LOMEM #\offsetlo
         it      eq
         cmpeq   r2, r5
-        bne     return_25
+        bne     .L_return_25
         ldr     r5, [r1], #4
         cmp     ip, #0
         eor r3, r2, r3
         S2HIMEM r2, r5, #\offsethi
         it      eq
         cmpeq   r3, r2
-        bne     return_32
+        bne     .L_return_32
         b       7b
         .endm /* miscmp_word */
 
-strcmp_unaligned:
+.L_strcmp_unaligned:
         /* r0 is word-aligned, r1 is at offset ip from a word.  */
         /* Align r1 to the (previous) word-boundary.  */
         bic     r1, r1, #3
 
         /* Unaligned comparison word by word using LDRs. */
         cmp     ip, #2
-        beq     miscmp_word_16                    /* If ip == 2.  */
-        bge     miscmp_word_24                    /* If ip == 3.  */
+        beq     .L_miscmp_word_16                 /* If ip == 2.  */
+        bge     .L_miscmp_word_24                 /* If ip == 3.  */
         miscmp_word offsetlo=8 offsethi=24        /* If ip == 1.  */
-miscmp_word_16:  miscmp_word offsetlo=16 offsethi=16
-miscmp_word_24:  miscmp_word offsetlo=24 offsethi=8
+.L_miscmp_word_16:  miscmp_word offsetlo=16 offsethi=16
+.L_miscmp_word_24:  miscmp_word offsetlo=24 offsethi=8
 
 
-return_32:
+.L_return_32:
         setup_return w1=r3, w2=r2
-        b       do_return
-return_34:
+        b       .L_do_return
+.L_return_34:
         setup_return w1=r3, w2=r4
-        b       do_return
-return_25:
+        b       .L_do_return
+.L_return_25:
         setup_return w1=r2, w2=r5
-        b       do_return
-return_35:
+        b       .L_do_return
+.L_return_35:
         setup_return w1=r3, w2=r5
-        b       do_return
-return_24:
+        b       .L_do_return
+.L_return_24:
         setup_return w1=r2, w2=r4
 
-do_return:
+.L_do_return:
 
 #ifdef __ARMEB__
         mov     r0, ip
@@ -349,11 +356,16 @@
         ldrd    r6, r7, [sp]
         ldrd    r4, r5, [sp, #8]
         adds    sp, sp, #16
+        .cfi_def_cfa_offset 0
+        .cfi_restore r4
+        .cfi_restore r5
+        .cfi_restore r6
+        .cfi_restore r7
 
         /* There is a zero or a different byte between r1 and r2.  */
         /* r0 contains a mask of all-zero bytes in r1.  */
         /* Using r0 and not ip here because cbz requires low register.  */
-        m_cbz   reg=r0, label=compute_return_value
+        m_cbz   reg=r0, label=.L_compute_return_value
         clz     r0, r0
         /* r0 contains the number of bits on the left of the first all-zero byte in r1.  */
         rsb     r0, r0, #24
@@ -361,7 +373,7 @@
         lsr     r1, r1, r0
         lsr     r2, r2, r0
 
-compute_return_value:
+.L_compute_return_value:
         movs    r0, #1
         cmp     r1, r2
         /* The return value is computed as follows.
@@ -374,4 +386,5 @@
         it      ls
         sbcls   r0, r0, r0
         bx      lr
+        .cfi_endproc
 END(strcmp)
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
index 3f86636..78cf19a 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcat_chk.S
@@ -41,10 +41,12 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
     push    {r4, r5}
+    .save   {r4, r5}
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -181,7 +183,7 @@
 .L_strlen_done:
     add     r2, r3, r4
     cmp     r2, lr
-    bgt     .L_fortify_check_failed
+    bhi     __strcat_chk_fail
 
     // Set up the registers for the memcpy code.
     mov     r1, r5
@@ -189,13 +191,23 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-    .cfi_adjust_cfa_offset -8
-    .cfi_restore r4
-    .cfi_restore r5
 
-    #include "memcpy_base.S"
+    // Fall through into the memcpy_base function.
+    .cfi_endproc
+END(__strcat_chk)
 
-.L_fortify_check_failed:
+#define MEMCPY_BASE         __strcat_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__strcat_chk_fail)
+    .cfi_startproc
+
+    .save   {r0, lr}
+    .save   {r4, r5}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -211,7 +223,7 @@
     .word   error_string-(1b+4)
 
     .cfi_endproc
-END(__strcat_chk)
+END(__strcat_chk_fail)
 
     .data
 error_string:
diff --git a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
index 787b057..d0acf1e 100644
--- a/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/cortex-a9/bionic/__strcpy_chk.S
@@ -40,6 +40,7 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
@@ -152,26 +153,41 @@
     pld     [r1, #64]
     ldr     r0, [sp]
     cmp     r3, lr
-    bge     .L_fortify_check_failed
+    bhs     __strcpy_chk_fail
 
     // Add 1 for copy length to get the string terminator.
     add     r2, r3, #1
 
-    #include "memcpy_base.S"
+    .cfi_endproc
 
-.L_fortify_check_failed:
+    // Fall through into the memcpy_base function.
+END(__strcpy_chk)
+
+#define MEMCPY_BASE         __strcpy_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__strcpy_chk_fail)
+    .cfi_startproc
+
+    .save   {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
     ldr     r0, error_message
     ldr     r1, error_code
 1:
     add     r0, pc
     bl      __fortify_chk_fail
+
 error_code:
     .word   BIONIC_EVENT_STRCPY_BUFFER_OVERFLOW
 error_message:
     .word   error_string-(1b+4)
 
     .cfi_endproc
-END(__strcpy_chk)
+END(__strcpy_chk_fail)
 
     .data
 error_string:
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy.S b/libc/arch-arm/cortex-a9/bionic/memcpy.S
index e7beb25..5c4c428 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy.S
@@ -43,7 +43,7 @@
 ENTRY(__memcpy_chk)
         .cfi_startproc
         cmp         r2, r3
-        bgt         __memcpy_chk_fail
+        bhi         __memcpy_chk_fail
 
         // Fall through to memcpy...
         .cfi_endproc
@@ -51,21 +51,27 @@
 
 ENTRY(memcpy)
         .cfi_startproc
+
         pld     [r1, #0]
         stmfd   sp!, {r0, lr}
+        .save   {r0, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
         pld     [r1, #64]
 
-        #include "memcpy_base.S"
         .cfi_endproc
 END(memcpy)
 
+#define MEMCPY_BASE         __memcpy_base
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__memcpy_chk_fail)
         .cfi_startproc
-__memcpy_chk_fail:
         // Preserve lr for backtrace.
         push    {lr}
+        .save   {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
 
@@ -79,6 +85,7 @@
 error_message:
         .word   error_string-(1b+4)
         .cfi_endproc
+END(__memcpy_chk_fail)
 
         .data
 error_string:
diff --git a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
index 46b5a93..e8ff4f5 100644
--- a/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a9/bionic/memcpy_base.S
@@ -32,15 +32,21 @@
  * cache line.
  */
 
+ENTRY(MEMCPY_BASE)
+        .cfi_startproc
+        .save       {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
         // Check so divider is at least 16 bytes, needed for alignment code.
         cmp         r2, #16
         blo         5f
 
-
         /* check if buffers are aligned. If so, run arm-only version */
         eor         r3, r0, r1
         ands        r3, r3, #0x3
-        beq         11f
+        beq         __memcpy_base_aligned
 
         /* Check the upper size limit for Neon unaligned memory access in memcpy */
         cmp         r2, #224
@@ -131,9 +137,27 @@
 
         ldmfd       sp!, {r0, lr}
         bx          lr
-11:
+
+        .cfi_endproc
+END(MEMCPY_BASE)
+
+ENTRY(MEMCPY_BASE_ALIGNED)
+        .cfi_startproc
+
+        .save       {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
         /* Simple arm-only copy loop to handle aligned copy operations */
-        stmfd       sp!, {r4, r5, r6, r7, r8}
+        stmfd       sp!, {r4-r8}
+        .save       {r4-r8}
+        .cfi_adjust_cfa_offset 20
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
+        .cfi_rel_offset r6, 8
+        .cfi_rel_offset r7, 12
+        .cfi_rel_offset r8, 16
         pld         [r1, #(32 * 4)]
 
         /* Check alignment */
@@ -202,5 +226,8 @@
         ldrbne      r3, [r1]                /*  last byte  */
         strbne      r3, [r0]
 6:
-        ldmfd       sp!, {r4, r5, r6, r7, r8}
+        ldmfd       sp!, {r4-r8}
         ldmfd       sp!, {r0, pc}
+
+        .cfi_endproc
+END(MEMCPY_BASE_ALIGNED)
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index bc25a3e..87d2c08 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -44,6 +44,7 @@
 
         // Preserve lr for backtrace.
         push        {lr}
+        .save       {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
 
@@ -73,11 +74,13 @@
 /* memset() returns its first argument.  */
 ENTRY(memset)
         .cfi_startproc
+
         # The neon memset only wins for less than 132.
         cmp         r2, #132
-        bhi         11f
+        bhi         __memset_large_copy
 
         stmfd       sp!, {r0}
+        .save       {r0}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset r0, 0
 
@@ -112,12 +115,18 @@
         strcsb      r1, [r0], #1
         ldmfd       sp!, {r0}
         bx          lr
-11:
+
+        .cfi_endproc
+END(memset)
+
+ENTRY(__memset_large_copy)
+        .cfi_startproc
+
         /* compute the offset to align the destination
          * offset = (4-(src&3))&3 = -src & 3
          */
-
         stmfd       sp!, {r0, r4-r7, lr}
+        .save       {r0, r4-r7, lr}
         .cfi_def_cfa_offset 24
         .cfi_rel_offset r0, 0
         .cfi_rel_offset r4, 4
@@ -188,7 +197,7 @@
         ldmfd       sp!, {r0, r4-r7, lr}
         bx          lr
         .cfi_endproc
-END(memset)
+END(__memset_large_copy)
 
         .data
 error_string:
diff --git a/libc/arch-arm/cortex-a9/bionic/strcmp.S b/libc/arch-arm/cortex-a9/bionic/strcmp.S
index 9597d0d..232df75 100644
--- a/libc/arch-arm/cortex-a9/bionic/strcmp.S
+++ b/libc/arch-arm/cortex-a9/bionic/strcmp.S
@@ -123,8 +123,13 @@
         .macro  init
         /* Macro to save temporary registers and prepare magic values.  */
         subs    sp, sp, #16
+        .cfi_def_cfa_offset 16
         strd    r4, r5, [sp, #8]
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
         strd    r6, r7, [sp]
+        .cfi_rel_offset r6, 8
+        .cfi_rel_offset r7, 12
         mvn     r6, #0  /* all F */
         mov     r7, #0  /* all 0 */
         .endm   /* init */
@@ -165,18 +170,20 @@
 #endif /* not  __ARMEB__ */
         .endm /* setup_return */
 
+        .cfi_startproc
         pld [r0, #0]
         pld [r1, #0]
 
         /* Are both strings double-word aligned?  */
         orr     ip, r0, r1
         tst     ip, #7
-        bne     do_align
+        bne     .L_do_align
 
         /* Fast path.  */
+        .save   {r4-r7}
         init
 
-doubleword_aligned:
+.L_doubleword_aligned:
 
         /* Get here when the strings to compare are double-word aligned.  */
         /* Compare two words in every iteration.  */
@@ -189,14 +196,14 @@
         ldrd    r2, r3, [r0], #8
         ldrd    r4, r5, [r1], #8
 
-        magic_compare_and_branch w1=r2, w2=r4, label=return_24
-        magic_compare_and_branch w1=r3, w2=r5, label=return_35
+        magic_compare_and_branch w1=r2, w2=r4, label=.L_return_24
+        magic_compare_and_branch w1=r3, w2=r5, label=.L_return_35
         b       2b
 
-do_align:
+.L_do_align:
         /* Is the first string word-aligned?  */
         ands    ip, r0, #3
-        beq     word_aligned_r0
+        beq     .L_word_aligned_r0
 
         /* Fast compare byte by byte until the first string is word-aligned.  */
         /* The offset of r0 from a word boundary is in ip. Thus, the number of bytes
@@ -204,58 +211,58 @@
         bic     r0, r0, #3
         ldr     r2, [r0], #4
         lsls    ip, ip, #31
-        beq     byte2
-        bcs     byte3
+        beq     .L_byte2
+        bcs     .L_byte3
 
-byte1:
+.L_byte1:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE1_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte2:
+.L_byte2:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE2_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte3:
+.L_byte3:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE3_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbnz  reg=r3, label=word_aligned_r0
+        bne     .L_fast_return
+        m_cbnz  reg=r3, label=.L_word_aligned_r0
 
-fast_return:
+.L_fast_return:
         mov     r0, ip
         bx      lr
 
-word_aligned_r0:
+.L_word_aligned_r0:
         init
         /* The first string is word-aligned.  */
         /* Is the second string word-aligned?  */
         ands    ip, r1, #3
-        bne     strcmp_unaligned
+        bne     .L_strcmp_unaligned
 
-word_aligned:
+.L_word_aligned:
         /* The strings are word-aligned. */
         /* Is the first string double-word aligned?  */
         tst     r0, #4
-        beq     doubleword_aligned_r0
+        beq     .L_doubleword_aligned_r0
 
         /* If r0 is not double-word aligned yet, align it by loading
         and comparing the next word from each string.  */
         ldr     r2, [r0], #4
         ldr     r4, [r1], #4
-        magic_compare_and_branch w1=r2 w2=r4 label=return_24
+        magic_compare_and_branch w1=r2 w2=r4 label=.L_return_24
 
-doubleword_aligned_r0:
+.L_doubleword_aligned_r0:
         /* Get here when r0 is double-word aligned.  */
         /* Is r1 doubleword_aligned?  */
         tst     r1, #4
-        beq     doubleword_aligned
+        beq     .L_doubleword_aligned
 
         /* Get here when the strings to compare are word-aligned,
         r0 is double-word aligned, but r1 is not double-word aligned.  */
@@ -271,9 +278,9 @@
 
         /* Load the next double-word from each string and compare.  */
         ldrd    r2, r3, [r0], #8
-        magic_compare_and_branch w1=r2 w2=r5 label=return_25
+        magic_compare_and_branch w1=r2 w2=r5 label=.L_return_25
         ldrd    r4, r5, [r1], #8
-        magic_compare_and_branch w1=r3 w2=r4 label=return_34
+        magic_compare_and_branch w1=r3 w2=r4 label=.L_return_34
         b       3b
 
         .macro miscmp_word offsetlo offsethi
@@ -297,33 +304,33 @@
         and     r2, r3, r6, S2LOMEM #\offsetlo
         it      eq
         cmpeq   r2, r5
-        bne     return_25
+        bne     .L_return_25
         ldr     r5, [r1], #4
         cmp     ip, #0
         eor r3, r2, r3
         S2HIMEM r2, r5, #\offsethi
         it      eq
         cmpeq   r3, r2
-        bne     return_32
+        bne     .L_return_32
         b       7b
         .endm /* miscmp_word */
 
-return_32:
+.L_return_32:
         setup_return w1=r3, w2=r2
-        b       do_return
-return_34:
+        b       .L_do_return
+.L_return_34:
         setup_return w1=r3, w2=r4
-        b       do_return
-return_25:
+        b       .L_do_return
+.L_return_25:
         setup_return w1=r2, w2=r5
-        b       do_return
-return_35:
+        b       .L_do_return
+.L_return_35:
         setup_return w1=r3, w2=r5
-        b       do_return
-return_24:
+        b       .L_do_return
+.L_return_24:
         setup_return w1=r2, w2=r4
 
-do_return:
+.L_do_return:
 
 #ifdef __ARMEB__
         mov     r0, ip
@@ -335,11 +342,16 @@
         ldrd    r6, r7, [sp]
         ldrd    r4, r5, [sp, #8]
         adds    sp, sp, #16
+        .cfi_def_cfa_offset 0
+        .cfi_restore r4
+        .cfi_restore r5
+        .cfi_restore r6
+        .cfi_restore r7
 
         /* There is a zero or a different byte between r1 and r2.  */
         /* r0 contains a mask of all-zero bytes in r1.  */
         /* Using r0 and not ip here because cbz requires low register.  */
-        m_cbz   reg=r0, label=compute_return_value
+        m_cbz   reg=r0, label=.L_compute_return_value
         clz     r0, r0
         /* r0 contains the number of bits on the left of the first all-zero byte in r1.  */
         rsb     r0, r0, #24
@@ -347,7 +359,7 @@
         lsr     r1, r1, r0
         lsr     r2, r2, r0
 
-compute_return_value:
+.L_compute_return_value:
         movs    r0, #1
         cmp     r1, r2
         /* The return value is computed as follows.
@@ -367,7 +379,7 @@
      * bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S for the unedited
      * version of the code.
      */
-strcmp_unaligned:
+.L_strcmp_unaligned:
 	wp1 .req r0
 	wp2 .req r1
 	b1  .req r2
@@ -520,6 +532,11 @@
     ldrd    r6, r7, [sp]
     ldrd    r4, r5, [sp, #8]
     adds    sp, sp, #16
+    .cfi_def_cfa_offset 0
+    .cfi_restore r4
+    .cfi_restore r5
+    .cfi_restore r6
+    .cfi_restore r7
 
 	bx	lr
 
@@ -541,4 +558,5 @@
     adds    sp, sp, #16
 
 	bx	lr
+    .cfi_endproc
 END(strcmp)
diff --git a/libc/arch-arm/krait/bionic/__strcat_chk.S b/libc/arch-arm/krait/bionic/__strcat_chk.S
index 4516d30..956b461 100644
--- a/libc/arch-arm/krait/bionic/__strcat_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcat_chk.S
@@ -41,10 +41,12 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
     push    {r4, r5}
+    .save   {r4, r5}
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -178,7 +180,7 @@
 .L_strlen_done:
     add     r2, r3, r4
     cmp     r2, lr
-    bgt     .L_fortify_check_failed
+    bhi     __strcat_chk_failed
 
     // Set up the registers for the memcpy code.
     mov     r1, r5
@@ -186,13 +188,21 @@
     mov     r2, r4
     add     r0, r0, r3
     pop     {r4, r5}
-    .cfi_adjust_cfa_offset -8
-    .cfi_restore r4
-    .cfi_restore r5
 
-    #include "memcpy_base.S"
+    .cfi_endproc
+END(__strcat_chk)
 
-.L_fortify_check_failed:
+#define MEMCPY_BASE         __strcat_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcat_chk_memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__strcat_chk_failed)
+    .cfi_startproc
+    .save   {r0, lr}
+    .save   {r4, r5}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
     .cfi_adjust_cfa_offset 8
     .cfi_rel_offset r4, 0
     .cfi_rel_offset r5, 4
@@ -208,7 +218,7 @@
     .word   error_string-(1b+4)
 
     .cfi_endproc
-END(__strcat_chk)
+END(__strcat_chk_failed)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/__strcpy_chk.S b/libc/arch-arm/krait/bionic/__strcpy_chk.S
index c57268c..402cac6 100644
--- a/libc/arch-arm/krait/bionic/__strcpy_chk.S
+++ b/libc/arch-arm/krait/bionic/__strcpy_chk.S
@@ -40,6 +40,7 @@
     .cfi_startproc
     pld     [r0, #0]
     push    {r0, lr}
+    .save   {r0, lr}
     .cfi_def_cfa_offset 8
     .cfi_rel_offset r0, 0
     .cfi_rel_offset lr, 4
@@ -150,14 +151,25 @@
     pld     [r1, #64]
     ldr     r0, [sp]
     cmp     r3, lr
-    bge     .L_fortify_check_failed
+    bhs     __strcpy_chk_failed
 
     // Add 1 for copy length to get the string terminator.
     add     r2, r3, #1
 
-    #include "memcpy_base.S"
+    .cfi_endproc
+END(__strcpy_chk)
 
-.L_fortify_check_failed:
+#define MEMCPY_BASE         __strcpy_chk_memcpy_base
+#define MEMCPY_BASE_ALIGNED __strcpy_chk_memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__strcpy_chk_failed)
+    .cfi_startproc
+    .save   {r0, lr}
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset lr, 4
+
     ldr     r0, error_message
     ldr     r1, error_code
 1:
@@ -168,7 +180,7 @@
 error_message:
     .word   error_string-(1b+4)
     .cfi_endproc
-END(__strcpy_chk)
+END(__strcpy_chk_failed)
 
     .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy.S b/libc/arch-arm/krait/bionic/memcpy.S
index 75b2395..ea040bc 100644
--- a/libc/arch-arm/krait/bionic/memcpy.S
+++ b/libc/arch-arm/krait/bionic/memcpy.S
@@ -46,7 +46,7 @@
 ENTRY(__memcpy_chk)
         .cfi_startproc
         cmp         r2, r3
-        bgt         __memcpy_chk_fail
+        bhi         __memcpy_chk_fail
 
         // Fall through to memcpy...
         .cfi_endproc
@@ -56,18 +56,22 @@
         .cfi_startproc
         pld     [r1, #64]
         stmfd   sp!, {r0, lr}
+        .save   {r0, lr}
         .cfi_def_cfa_offset 8
         .cfi_rel_offset r0, 0
         .cfi_rel_offset lr, 4
-
-        #include "memcpy_base.S"
         .cfi_endproc
 END(memcpy)
 
+#define MEMCPY_BASE         __memcpy_base
+#define MEMCPY_BASE_ALIGNED __memcpy_base_aligned
+#include "memcpy_base.S"
+
+ENTRY(__memcpy_chk_fail)
         .cfi_startproc
-__memcpy_chk_fail:
         // Preserve lr for backtrace.
         push    {lr}
+        .save   {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
 
@@ -81,6 +85,7 @@
 error_message:
         .word   error_string-(1b+4)
         .cfi_endproc
+END(__memcpy_chk_fail)
 
         .data
 error_string:
diff --git a/libc/arch-arm/krait/bionic/memcpy_base.S b/libc/arch-arm/krait/bionic/memcpy_base.S
index 48ce477..d87a542 100644
--- a/libc/arch-arm/krait/bionic/memcpy_base.S
+++ b/libc/arch-arm/krait/bionic/memcpy_base.S
@@ -35,6 +35,13 @@
 
 // Assumes neon instructions and a cache line size of 32 bytes.
 
+ENTRY(MEMCPY_BASE)
+        .cfi_startproc
+        .save {r0, lr}
+        .cfi_def_cfa_offset 8
+        .cfi_rel_offset r0, 0
+        .cfi_rel_offset lr, 4
+
         /* do we have at least 16-bytes to copy (needed for alignment below) */
         cmp         r2, #16
         blo         5f
@@ -115,3 +122,6 @@
 
         ldmfd       sp!, {r0, lr}
         bx          lr
+
+        .cfi_endproc
+END(MEMCPY_BASE)
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index 1566132..005dfd8 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -44,6 +44,7 @@
         bls         .L_done
 
         // Preserve lr for backtrace.
+        .save       {lr}
         push        {lr}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset lr, 0
@@ -74,6 +75,7 @@
 /* memset() returns its first argument.  */
 ENTRY(memset)
         .cfi_startproc
+        .save       {r0}
         stmfd       sp!, {r0}
         .cfi_def_cfa_offset 4
         .cfi_rel_offset r0, 0
diff --git a/libc/arch-arm/krait/bionic/strcmp.S b/libc/arch-arm/krait/bionic/strcmp.S
index d614b9d..d4cf3f4 100644
--- a/libc/arch-arm/krait/bionic/strcmp.S
+++ b/libc/arch-arm/krait/bionic/strcmp.S
@@ -123,8 +123,13 @@
         .macro  init
         /* Macro to save temporary registers and prepare magic values.  */
         subs    sp, sp, #16
+        .cfi_def_cfa_offset 16
         strd    r4, r5, [sp, #8]
+        .cfi_rel_offset r4, 0
+        .cfi_rel_offset r5, 4
         strd    r6, r7, [sp]
+        .cfi_rel_offset r6, 8
+        .cfi_rel_offset r7, 12
         mvn     r6, #0  /* all F */
         mov     r7, #0  /* all 0 */
         .endm   /* init */
@@ -165,18 +170,20 @@
 #endif /* not  __ARMEB__ */
         .endm /* setup_return */
 
+        .cfi_startproc
         pld [r0, #0]
         pld [r1, #0]
 
         /* Are both strings double-word aligned?  */
         orr     ip, r0, r1
         tst     ip, #7
-        bne     do_align
+        bne     .L_do_align
 
         /* Fast path.  */
+        .save   {r4-r7}
         init
 
-doubleword_aligned:
+.L_doubleword_aligned:
 
         /* Get here when the strings to compare are double-word aligned.  */
         /* Compare two words in every iteration.  */
@@ -189,14 +196,14 @@
         ldrd    r2, r3, [r0], #8
         ldrd    r4, r5, [r1], #8
 
-        magic_compare_and_branch w1=r2, w2=r4, label=return_24
-        magic_compare_and_branch w1=r3, w2=r5, label=return_35
+        magic_compare_and_branch w1=r2, w2=r4, label=.L_return_24
+        magic_compare_and_branch w1=r3, w2=r5, label=.L_return_35
         b       2b
 
-do_align:
+.L_do_align:
         /* Is the first string word-aligned?  */
         ands    ip, r0, #3
-        beq     word_aligned_r0
+        beq     .L_word_aligned_r0
 
         /* Fast compare byte by byte until the first string is word-aligned.  */
         /* The offset of r0 from a word boundary is in ip. Thus, the number of bytes
@@ -204,58 +211,58 @@
         bic     r0, r0, #3
         ldr     r2, [r0], #4
         lsls    ip, ip, #31
-        beq     byte2
-        bcs     byte3
+        beq     .L_byte2
+        bcs     .L_byte3
 
-byte1:
+.L_byte1:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE1_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte2:
+.L_byte2:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE2_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbz   reg=r3, label=fast_return
+        bne     .L_fast_return
+        m_cbz   reg=r3, label=.L_fast_return
 
-byte3:
+.L_byte3:
         ldrb    ip, [r1], #1
         uxtb    r3, r2, ror #BYTE3_OFFSET
         subs    ip, r3, ip
-        bne     fast_return
-        m_cbnz  reg=r3, label=word_aligned_r0
+        bne     .L_fast_return
+        m_cbnz  reg=r3, label=.L_word_aligned_r0
 
-fast_return:
+.L_fast_return:
         mov     r0, ip
         bx      lr
 
-word_aligned_r0:
+.L_word_aligned_r0:
         init
         /* The first string is word-aligned.  */
         /* Is the second string word-aligned?  */
         ands    ip, r1, #3
-        bne     strcmp_unaligned
+        bne     .L_strcmp_unaligned
 
-word_aligned:
+.L_word_aligned:
         /* The strings are word-aligned. */
         /* Is the first string double-word aligned?  */
         tst     r0, #4
-        beq     doubleword_aligned_r0
+        beq     .L_doubleword_aligned_r0
 
         /* If r0 is not double-word aligned yet, align it by loading
         and comparing the next word from each string.  */
         ldr     r2, [r0], #4
         ldr     r4, [r1], #4
-        magic_compare_and_branch w1=r2 w2=r4 label=return_24
+        magic_compare_and_branch w1=r2 w2=r4 label=.L_return_24
 
-doubleword_aligned_r0:
+.L_doubleword_aligned_r0:
         /* Get here when r0 is double-word aligned.  */
         /* Is r1 doubleword_aligned?  */
         tst     r1, #4
-        beq     doubleword_aligned
+        beq     .L_doubleword_aligned
 
         /* Get here when the strings to compare are word-aligned,
         r0 is double-word aligned, but r1 is not double-word aligned.  */
@@ -271,9 +278,9 @@
 
         /* Load the next double-word from each string and compare.  */
         ldrd    r2, r3, [r0], #8
-        magic_compare_and_branch w1=r2 w2=r5 label=return_25
+        magic_compare_and_branch w1=r2 w2=r5 label=.L_return_25
         ldrd    r4, r5, [r1], #8
-        magic_compare_and_branch w1=r3 w2=r4 label=return_34
+        magic_compare_and_branch w1=r3 w2=r4 label=.L_return_34
         b       3b
 
         .macro miscmp_word offsetlo offsethi
@@ -297,46 +304,46 @@
         and     r2, r3, r6, S2LOMEM #\offsetlo
         it      eq
         cmpeq   r2, r5
-        bne     return_25
+        bne     .L_return_25
         ldr     r5, [r1], #4
         cmp     ip, #0
         eor r3, r2, r3
         S2HIMEM r2, r5, #\offsethi
         it      eq
         cmpeq   r3, r2
-        bne     return_32
+        bne     .L_return_32
         b       7b
         .endm /* miscmp_word */
 
-strcmp_unaligned:
+.L_strcmp_unaligned:
         /* r0 is word-aligned, r1 is at offset ip from a word.  */
         /* Align r1 to the (previous) word-boundary.  */
         bic     r1, r1, #3
 
         /* Unaligned comparison word by word using LDRs. */
         cmp     ip, #2
-        beq     miscmp_word_16                    /* If ip == 2.  */
-        bge     miscmp_word_24                    /* If ip == 3.  */
+        beq     .L_miscmp_word_16                 /* If ip == 2.  */
+        bge     .L_miscmp_word_24                 /* If ip == 3.  */
         miscmp_word offsetlo=8 offsethi=24        /* If ip == 1.  */
-miscmp_word_24:  miscmp_word offsetlo=24 offsethi=8
+.L_miscmp_word_24:  miscmp_word offsetlo=24 offsethi=8
 
 
-return_32:
+.L_return_32:
         setup_return w1=r3, w2=r2
-        b       do_return
-return_34:
+        b       .L_do_return
+.L_return_34:
         setup_return w1=r3, w2=r4
-        b       do_return
-return_25:
+        b       .L_do_return
+.L_return_25:
         setup_return w1=r2, w2=r5
-        b       do_return
-return_35:
+        b       .L_do_return
+.L_return_35:
         setup_return w1=r3, w2=r5
-        b       do_return
-return_24:
+        b       .L_do_return
+.L_return_24:
         setup_return w1=r2, w2=r4
 
-do_return:
+.L_do_return:
 
 #ifdef __ARMEB__
         mov     r0, ip
@@ -348,11 +355,16 @@
         ldrd    r6, r7, [sp]
         ldrd    r4, r5, [sp, #8]
         adds    sp, sp, #16
+        .cfi_def_cfa_offset 0
+        .cfi_restore r4
+        .cfi_restore r5
+        .cfi_restore r6
+        .cfi_restore r7
 
         /* There is a zero or a different byte between r1 and r2.  */
         /* r0 contains a mask of all-zero bytes in r1.  */
         /* Using r0 and not ip here because cbz requires low register.  */
-        m_cbz   reg=r0, label=compute_return_value
+        m_cbz   reg=r0, label=.L_compute_return_value
         clz     r0, r0
         /* r0 contains the number of bits on the left of the first all-zero byte in r1.  */
         rsb     r0, r0, #24
@@ -360,7 +372,7 @@
         lsr     r1, r1, r0
         lsr     r2, r2, r0
 
-compute_return_value:
+.L_compute_return_value:
         movs    r0, #1
         cmp     r1, r2
         /* The return value is computed as follows.
@@ -380,7 +392,7 @@
      * previous version. See bionic/libc/arch-arm/cortex-a15/bionic/strcmp.S
      * for the unedited version of this code.
      */
-miscmp_word_16:
+.L_miscmp_word_16:
 	wp1 .req r0
 	wp2 .req r1
 	b1  .req r2
@@ -453,6 +465,11 @@
     ldrd    r6, r7, [sp]
     ldrd    r4, r5, [sp, #8]
     adds    sp, sp, #16
+    .cfi_def_cfa_offset 0
+    .cfi_restore r4
+    .cfi_restore r5
+    .cfi_restore r6
+    .cfi_restore r7
 
 	bx	lr
 
@@ -472,6 +489,12 @@
     ldrd    r6, r7, [sp]
     ldrd    r4, r5, [sp, #8]
     adds    sp, sp, #16
+    .cfi_def_cfa_offset 0
+    .cfi_restore r4
+    .cfi_restore r5
+    .cfi_restore r6
+    .cfi_restore r7
 
 	bx	lr
+    .cfi_endproc
 END(strcmp)
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index 252a428..33e520f 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -84,6 +84,7 @@
 syscall_src += arch-arm/syscalls/__fcntl64.S
 syscall_src += arch-arm/syscalls/__fstatfs64.S
 syscall_src += arch-arm/syscalls/sendfile.S
+syscall_src += arch-arm/syscalls/sendfile64.S
 syscall_src += arch-arm/syscalls/fstatat.S
 syscall_src += arch-arm/syscalls/mkdirat.S
 syscall_src += arch-arm/syscalls/fchownat.S
@@ -116,6 +117,7 @@
 syscall_src += arch-arm/syscalls/symlink.S
 syscall_src += arch-arm/syscalls/fchdir.S
 syscall_src += arch-arm/syscalls/truncate.S
+syscall_src += arch-arm/syscalls/truncate64.S
 syscall_src += arch-arm/syscalls/setxattr.S
 syscall_src += arch-arm/syscalls/lsetxattr.S
 syscall_src += arch-arm/syscalls/getxattr.S
diff --git a/libc/arch-arm/syscalls/sendfile64.S b/libc/arch-arm/syscalls/sendfile64.S
new file mode 100644
index 0000000..87de344
--- /dev/null
+++ b/libc/arch-arm/syscalls/sendfile64.S
@@ -0,0 +1,15 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+#include <linux/err.h>
+#include <machine/asm.h>
+
+ENTRY(sendfile64)
+    mov     ip, r7
+    ldr     r7, =__NR_sendfile64
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(sendfile64)
diff --git a/libc/arch-arm/syscalls/truncate64.S b/libc/arch-arm/syscalls/truncate64.S
new file mode 100644
index 0000000..059bd97
--- /dev/null
+++ b/libc/arch-arm/syscalls/truncate64.S
@@ -0,0 +1,15 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+#include <linux/err.h>
+#include <machine/asm.h>
+
+ENTRY(truncate64)
+    mov     ip, r7
+    ldr     r7, =__NR_truncate64
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(truncate64)
diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk
index 23393a2..b34b0a9 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -87,6 +87,7 @@
 syscall_src += arch-mips/syscalls/__fcntl64.S
 syscall_src += arch-mips/syscalls/__fstatfs64.S
 syscall_src += arch-mips/syscalls/sendfile.S
+syscall_src += arch-mips/syscalls/sendfile64.S
 syscall_src += arch-mips/syscalls/fstatat.S
 syscall_src += arch-mips/syscalls/mkdirat.S
 syscall_src += arch-mips/syscalls/fchownat.S
@@ -119,6 +120,7 @@
 syscall_src += arch-mips/syscalls/symlink.S
 syscall_src += arch-mips/syscalls/fchdir.S
 syscall_src += arch-mips/syscalls/truncate.S
+syscall_src += arch-mips/syscalls/truncate64.S
 syscall_src += arch-mips/syscalls/setxattr.S
 syscall_src += arch-mips/syscalls/lsetxattr.S
 syscall_src += arch-mips/syscalls/getxattr.S
diff --git a/libc/arch-mips/syscalls/sendfile64.S b/libc/arch-mips/syscalls/sendfile64.S
new file mode 100644
index 0000000..5b74709
--- /dev/null
+++ b/libc/arch-mips/syscalls/sendfile64.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+    .text
+    .globl sendfile64
+    .align 4
+    .ent sendfile64
+
+sendfile64:
+    .set noreorder
+    .cpload $t9
+    li $v0, __NR_sendfile64
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end sendfile64
diff --git a/libc/arch-mips/syscalls/truncate64.S b/libc/arch-mips/syscalls/truncate64.S
new file mode 100644
index 0000000..57f0b5f
--- /dev/null
+++ b/libc/arch-mips/syscalls/truncate64.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+    .text
+    .globl truncate64
+    .align 4
+    .ent truncate64
+
+truncate64:
+    .set noreorder
+    .cpload $t9
+    li $v0, __NR_truncate64
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end truncate64
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 11573de..7180cf2 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -88,6 +88,7 @@
 syscall_src += arch-x86/syscalls/__fcntl64.S
 syscall_src += arch-x86/syscalls/__fstatfs64.S
 syscall_src += arch-x86/syscalls/sendfile.S
+syscall_src += arch-x86/syscalls/sendfile64.S
 syscall_src += arch-x86/syscalls/fstatat.S
 syscall_src += arch-x86/syscalls/mkdirat.S
 syscall_src += arch-x86/syscalls/fchownat.S
@@ -120,6 +121,7 @@
 syscall_src += arch-x86/syscalls/symlink.S
 syscall_src += arch-x86/syscalls/fchdir.S
 syscall_src += arch-x86/syscalls/truncate.S
+syscall_src += arch-x86/syscalls/truncate64.S
 syscall_src += arch-x86/syscalls/setxattr.S
 syscall_src += arch-x86/syscalls/lsetxattr.S
 syscall_src += arch-x86/syscalls/getxattr.S
diff --git a/libc/arch-x86/syscalls/sendfile64.S b/libc/arch-x86/syscalls/sendfile64.S
new file mode 100644
index 0000000..9731806
--- /dev/null
+++ b/libc/arch-x86/syscalls/sendfile64.S
@@ -0,0 +1,30 @@
+/* autogenerated by gensyscalls.py */
+#include <linux/err.h>
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(sendfile64)
+    pushl   %ebx
+    pushl   %ecx
+    pushl   %edx
+    pushl   %esi
+    mov     20(%esp), %ebx
+    mov     24(%esp), %ecx
+    mov     28(%esp), %edx
+    mov     32(%esp), %esi
+    movl    $__NR_sendfile64, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(sendfile64)
diff --git a/libc/arch-x86/syscalls/truncate64.S b/libc/arch-x86/syscalls/truncate64.S
new file mode 100644
index 0000000..f9118bb
--- /dev/null
+++ b/libc/arch-x86/syscalls/truncate64.S
@@ -0,0 +1,27 @@
+/* autogenerated by gensyscalls.py */
+#include <linux/err.h>
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(truncate64)
+    pushl   %ebx
+    pushl   %ecx
+    pushl   %edx
+    mov     16(%esp), %ebx
+    mov     20(%esp), %ecx
+    mov     24(%esp), %edx
+    movl    $__NR_truncate64, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(truncate64)
diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk
index 19c1402..ada5d69 100644
--- a/libc/arch-x86/x86.mk
+++ b/libc/arch-x86/x86.mk
@@ -72,7 +72,7 @@
 	arch-x86/string/bzero.S \
 	bionic/memrchr.c \
 	bionic/memchr.c \
-	string/strchr.cpp \
+	bionic/strchr.cpp \
 	string/strrchr.c \
 	string/index.c \
 	bionic/strnlen.c \
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 1fc490e..714d0bc 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -37,6 +37,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/auxv.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <unistd.h>
 
 #include "atexit.h"
@@ -58,9 +60,16 @@
 // Declared in <private/bionic_ssp.h>.
 uintptr_t __stack_chk_guard = 0;
 
-// Declared in <asm/page.h>.
-unsigned int __page_size = PAGE_SIZE;
-unsigned int __page_shift = PAGE_SHIFT;
+static size_t get_main_thread_stack_size() {
+  rlimit stack_limit;
+  int rlimit_result = getrlimit(RLIMIT_STACK, &stack_limit);
+  if ((rlimit_result == 0) &&
+      (stack_limit.rlim_cur != RLIM_INFINITY) &&
+      (stack_limit.rlim_cur > PTHREAD_STACK_MIN)) {
+    return (stack_limit.rlim_cur & ~(PAGE_SIZE - 1));
+  }
+  return PTHREAD_STACK_SIZE_DEFAULT;
+}
 
 /* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
  * in memory. Beware: all writes to libc globals from this function will
@@ -76,9 +85,9 @@
 void __libc_init_tls(KernelArgumentBlock& args) {
   __libc_auxv = args.auxv;
 
-  unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
-  unsigned stack_size = 128 * 1024;
-  unsigned stack_bottom = stack_top - stack_size;
+  uintptr_t stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
+  size_t stack_size = get_main_thread_stack_size();
+  uintptr_t stack_bottom = stack_top - stack_size;
 
   static void* tls[BIONIC_TLS_SLOTS];
   static pthread_internal_t thread;
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 14105f8..59dc7df 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -49,7 +49,7 @@
 __END_DECLS
 
 #if defined(__cplusplus)
-struct KernelArgumentBlock;
+class KernelArgumentBlock;
 void __LIBC_HIDDEN__ __libc_init_common(KernelArgumentBlock& args);
 #endif
 
diff --git a/libc/bionic/lseek64.c b/libc/bionic/lseek64.c
index db0c413..c24ae64 100644
--- a/libc/bionic/lseek64.c
+++ b/libc/bionic/lseek64.c
@@ -25,16 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <unistd.h>
 
-extern int __llseek(int fd, unsigned long  offset_hi, unsigned long  offset_lo, loff_t*  result, int  whence);
+extern int __llseek(int fd, unsigned long offset_hi, unsigned long offset_lo, off64_t* result, int whence);
 
-off64_t lseek64(int fd, off64_t off, int whence)
-{
-    loff_t  result;
+off64_t lseek64(int fd, off64_t off, int whence) {
+  off64_t result;
+  if (__llseek(fd, (unsigned long)(off >> 32),(unsigned long)(off), &result, whence) < 0) {
+    return -1;
+  }
 
-    if ( __llseek(fd, (unsigned long)(off >> 32),(unsigned long)(off), &result, whence ) < 0 )
-        return -1;
-
-    return result;
+  return result;
 }
diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp
index febc459..75bea58 100644
--- a/libc/bionic/mmap.cpp
+++ b/libc/bionic/mmap.cpp
@@ -37,13 +37,13 @@
 
 #define MMAP2_SHIFT 12 // 2**12 == 4096
 
-void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {
+void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) {
   if (offset & ((1UL << MMAP2_SHIFT)-1)) {
     errno = EINVAL;
     return MAP_FAILED;
   }
 
-  size_t unsigned_offset = static_cast<size_t>(offset); // To avoid sign extension.
+  uint64_t unsigned_offset = static_cast<uint64_t>(offset); // To avoid sign extension.
   void* result = __mmap2(addr, size, prot, flags, fd, unsigned_offset >> MMAP2_SHIFT);
 
   if (result != MAP_FAILED && (flags & (MAP_PRIVATE | MAP_ANONYMOUS)) != 0) {
@@ -53,3 +53,7 @@
 
   return result;
 }
+
+void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {
+  return mmap64(addr, size, prot, flags, fd, static_cast<off64_t>(offset));
+}
diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp
index d7c6c13..2763b0c 100644
--- a/libc/bionic/pthread_attr.cpp
+++ b/libc/bionic/pthread_attr.cpp
@@ -30,16 +30,10 @@
 
 #include "pthread_internal.h"
 
-// Traditionally we give threads a 1MiB stack. When we started allocating per-thread
-// alternate signal stacks to ease debugging of stack overflows, we subtracted the
-// same amount we were using there from the default thread stack size. This should
-// keep memory usage roughly constant.
-#define DEFAULT_THREAD_STACK_SIZE ((1 * 1024 * 1024) - SIGSTKSZ)
-
 int pthread_attr_init(pthread_attr_t* attr) {
   attr->flags = 0;
   attr->stack_base = NULL;
-  attr->stack_size = DEFAULT_THREAD_STACK_SIZE;
+  attr->stack_size = PTHREAD_STACK_SIZE_DEFAULT;
   attr->guard_size = PAGE_SIZE;
   attr->sched_policy = SCHED_NORMAL;
   attr->sched_priority = 0;
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 31b8ca7..6fe2a98 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -77,6 +77,15 @@
 /* Has the thread already exited but not been joined? */
 #define PTHREAD_ATTR_FLAG_ZOMBIE        0x00000008
 
+/*
+ * Traditionally we give threads a 1MiB stack. When we started
+ * allocating per-thread alternate signal stacks to ease debugging of
+ * stack overflows, we subtracted the same amount we were using there
+ * from the default thread stack size. This should keep memory usage
+ * roughly constant.
+ */
+#define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGSTKSZ)
+
 __LIBC_HIDDEN__ extern pthread_internal_t* gThreadList;
 __LIBC_HIDDEN__ extern pthread_mutex_t gThreadListLock;
 
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index e8411b7..56f5c045 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -469,3 +469,15 @@
 void endusershell() {
   UNIMPLEMENTED;
 }
+
+// Portable code should use sysconf(_SC_PAGESIZE) directly instead.
+int getpagesize() {
+  return sysconf(_SC_PAGESIZE);
+}
+
+// These were accidentally declared in <unistd.h> because we stupidly used to inline
+// getpagesize() and __getpageshift(). Needed for backwards compatibility with old NDK apps.
+extern "C" {
+  unsigned int __page_size = PAGE_SIZE;
+  unsigned int __page_shift = PAGE_SHIFT;
+}
diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c
index 4c2e5a2..fd56431 100644
--- a/libc/bionic/system_properties.c
+++ b/libc/bionic/system_properties.c
@@ -325,6 +325,8 @@
 {
     if (off > pa_data_size)
         return NULL;
+    if (!__system_property_area__)
+        return NULL;
 
     return __system_property_area__->data + off;
 }
@@ -384,6 +386,8 @@
 {
     const char *remaining_name = name;
 
+    if (!trie) return NULL;
+
     while (true) {
         char *sep = strchr(remaining_name, '.');
         bool want_subtree = (sep != NULL);
diff --git a/libc/include/link.h b/libc/include/link.h
index 842b448..0edf5df 100644
--- a/libc/include/link.h
+++ b/libc/include/link.h
@@ -43,11 +43,11 @@
   ElfW(Half) dlpi_phnum;
 };
 
+int dl_iterate_phdr(int (*cb)(struct dl_phdr_info*, size_t, void*), void*);
+
 #ifdef __arm__
 typedef long unsigned int* _Unwind_Ptr;
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount);
-#else
-int dl_iterate_phdr(int (*cb)(struct dl_phdr_info*, size_t, void*), void*);
 #endif
 
 __END_DECLS
diff --git a/libc/include/string.h b/libc/include/string.h
index f6b4acf..10ff722 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -46,6 +46,8 @@
 
 extern char*  index(const char *, int) __purefunc;
 extern char*  strchr(const char *, int) __purefunc;
+extern char* __strchr_chk(const char *, int, size_t);
+
 extern char*  strrchr(const char *, int) __purefunc;
 
 extern size_t strlen(const char *) __purefunc;
@@ -238,8 +240,6 @@
     return __strlen_chk(s, bos);
 }
 
-extern char* __strchr_chk(const char *, int, size_t);
-
 __BIONIC_FORTIFY_INLINE
 char* strchr(const char *s, int c) {
     size_t bos = __bos(s);
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index 7a32974..7c5f8d7 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -45,6 +45,7 @@
 #define MREMAP_FIXED    2
 
 extern void*  mmap(void *, size_t, int, int, int, off_t);
+extern void*  mmap64(void *, size_t, int, int, int, off64_t);
 extern int    munmap(void *, size_t);
 extern int    msync(const void *, size_t, int);
 extern int    mprotect(const void *, size_t, int);
diff --git a/libc/include/sys/sendfile.h b/libc/include/sys/sendfile.h
index d5aba26..81a3c44 100644
--- a/libc/include/sys/sendfile.h
+++ b/libc/include/sys/sendfile.h
@@ -25,6 +25,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SYS_SENDFILE_H_
 #define _SYS_SENDFILE_H_
 
@@ -33,7 +34,8 @@
 
 __BEGIN_DECLS
 
-extern ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+extern ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
+extern ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count);
 
 __END_DECLS
 
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
index a0ce405..8b7fea8 100644
--- a/libc/include/sys/types.h
+++ b/libc/include/sys/types.h
@@ -65,7 +65,7 @@
 typedef __kernel_off_t       off_t;
 #endif
 typedef __kernel_loff_t      loff_t;
-typedef loff_t               off64_t;  /* GLibc-specific */
+typedef loff_t               off64_t;
 
 typedef __kernel_pid_t		 pid_t;
 
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index 98970ae..60964f0 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -122,6 +122,7 @@
 extern int fchown(int, uid_t, gid_t);
 extern int lchown(const char *, uid_t, gid_t);
 extern int truncate(const char *, off_t);
+extern int truncate64(const char *, off64_t);
 extern char *getcwd(char *, size_t);
 
 extern int sync(void);
@@ -170,14 +171,7 @@
 
 extern int  acct(const char*  filepath);
 
-static __inline__ int getpagesize(void) {
-  extern unsigned int __page_size;
-  return __page_size;
-}
-static __inline__ int __getpageshift(void) {
-  extern unsigned int __page_shift;
-  return __page_shift;
-}
+int getpagesize(void);
 
 extern int sysconf(int  name);
 
diff --git a/libc/kernel/common/linux/netlink.h b/libc/kernel/common/linux/netlink.h
index b700086..45df44f 100644
--- a/libc/kernel/common/linux/netlink.h
+++ b/libc/kernel/common/linux/netlink.h
@@ -18,117 +18,153 @@
  ****************************************************************************/
 #ifndef __LINUX_NETLINK_H
 #define __LINUX_NETLINK_H
+#include <linux/kernel.h>
 #include <linux/socket.h>
-#include <linux/types.h>
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#include <linux/types.h>
 #define NETLINK_ROUTE 0
 #define NETLINK_UNUSED 1
 #define NETLINK_USERSOCK 2
-#define NETLINK_FIREWALL 3
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#define NETLINK_INET_DIAG 4
+#define NETLINK_FIREWALL 3
+#define NETLINK_SOCK_DIAG 4
 #define NETLINK_NFLOG 5
 #define NETLINK_XFRM 6
-#define NETLINK_SELINUX 7
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NETLINK_SELINUX 7
 #define NETLINK_ISCSI 8
 #define NETLINK_AUDIT 9
 #define NETLINK_FIB_LOOKUP 10
-#define NETLINK_CONNECTOR 11
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NETLINK_CONNECTOR 11
 #define NETLINK_NETFILTER 12
 #define NETLINK_IP6_FW 13
 #define NETLINK_DNRTMSG 14
-#define NETLINK_KOBJECT_UEVENT 15
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NETLINK_KOBJECT_UEVENT 15
 #define NETLINK_GENERIC 16
 #define NETLINK_SCSITRANSPORT 18
 #define NETLINK_ECRYPTFS 19
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NETLINK_RDMA 20
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
-#define NETLINK_IDLETIMER 21
+#define NETLINK_CRYPTO 21
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
 #define MAX_LINKS 32
-struct sockaddr_nl {
- sa_family_t nl_family;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct sockaddr_nl {
+ __kernel_sa_family_t nl_family;
  unsigned short nl_pad;
  __u32 nl_pid;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  __u32 nl_groups;
 };
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 struct nlmsghdr {
  __u32 nlmsg_len;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  __u16 nlmsg_type;
  __u16 nlmsg_flags;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  __u32 nlmsg_seq;
  __u32 nlmsg_pid;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 };
 #define NLM_F_REQUEST 1
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLM_F_MULTI 2
 #define NLM_F_ACK 4
-#define NLM_F_ECHO 8
-#define NLM_F_ROOT 0x100
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NLM_F_ECHO 8
+#define NLM_F_DUMP_INTR 16
+#define NLM_F_ROOT 0x100
 #define NLM_F_MATCH 0x200
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLM_F_ATOMIC 0x400
 #define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
 #define NLM_F_REPLACE 0x100
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLM_F_EXCL 0x200
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLM_F_CREATE 0x400
 #define NLM_F_APPEND 0x800
 #define NLMSG_ALIGNTO 4U
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
-#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
-#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
 #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len),   (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
 #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) &&   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) &&   (nlh)->nlmsg_len <= (len))
 #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLMSG_NOOP 0x1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLMSG_ERROR 0x2
 #define NLMSG_DONE 0x3
 #define NLMSG_OVERRUN 0x4
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NLMSG_MIN_TYPE 0x10
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 struct nlmsgerr {
  int error;
  struct nlmsghdr msg;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 };
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NETLINK_ADD_MEMBERSHIP 1
 #define NETLINK_DROP_MEMBERSHIP 2
 #define NETLINK_PKTINFO 3
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
 #define NETLINK_BROADCAST_ERROR 4
-#define NETLINK_NO_ENOBUFS 5
-struct nl_pktinfo {
- __u32 group;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+struct nl_pktinfo {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 group;
 };
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
 #define NET_MAJOR 36
 enum {
- NETLINK_UNCONNECTED = 0,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ NETLINK_UNCONNECTED = 0,
  NETLINK_CONNECTED,
 };
 struct nlattr {
- __u16 nla_len;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u16 nla_len;
  __u16 nla_type;
 };
 #define NLA_F_NESTED (1 << 15)
-#define NLA_F_NET_BYTEORDER (1 << 14)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NLA_F_NET_BYTEORDER (1 << 14)
 #define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
 #define NLA_ALIGNTO 4
 #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
-#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
 #endif
diff --git a/libc/kernel/common/linux/sock_diag.h b/libc/kernel/common/linux/sock_diag.h
new file mode 100644
index 0000000..0dc2902
--- /dev/null
+++ b/libc/kernel/common/linux/sock_diag.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI__SOCK_DIAG_H__
+#define _UAPI__SOCK_DIAG_H__
+#include <linux/types.h>
+#define SOCK_DIAG_BY_FAMILY 20
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct sock_diag_req {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+enum {
+ SK_MEMINFO_RMEM_ALLOC,
+ SK_MEMINFO_RCVBUF,
+ SK_MEMINFO_WMEM_ALLOC,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ SK_MEMINFO_SNDBUF,
+ SK_MEMINFO_FWD_ALLOC,
+ SK_MEMINFO_WMEM_QUEUED,
+ SK_MEMINFO_OPTMEM,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ SK_MEMINFO_BACKLOG,
+ SK_MEMINFO_VARS,
+};
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libc/kernel/common/linux/taskstats.h b/libc/kernel/common/linux/taskstats.h
index 0e1cb67..fd7e9ed 100644
--- a/libc/kernel/common/linux/taskstats.h
+++ b/libc/kernel/common/linux/taskstats.h
@@ -18,12 +18,17 @@
  ****************************************************************************/
 #ifndef _LINUX_TASKSTATS_H
 #define _LINUX_TASKSTATS_H
-#define TASKSTATS_VERSION 1
-struct taskstats {
+#include <linux/types.h>
+#define TASKSTATS_VERSION 8
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TS_COMM_LEN 32
+struct taskstats {
  __u16 version;
- __u16 padding[3];
- __u64 cpu_count;
+ __u32 ac_exitcode;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 ac_flag;
+ __u8 ac_nice;
+ __u64 cpu_count __attribute__((aligned(8)));
  __u64 cpu_delay_total;
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  __u64 blkio_count;
@@ -33,6 +38,46 @@
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  __u64 cpu_run_real_total;
  __u64 cpu_run_virtual_total;
+ char ac_comm[TS_COMM_LEN];
+ __u8 ac_sched __attribute__((aligned(8)));
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 ac_pad[3];
+ __u32 ac_uid __attribute__((aligned(8)));
+ __u32 ac_gid;
+ __u32 ac_pid;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 ac_ppid;
+ __u32 ac_btime;
+ __u64 ac_etime __attribute__((aligned(8)));
+ __u64 ac_utime;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 ac_stime;
+ __u64 ac_minflt;
+ __u64 ac_majflt;
+ __u64 coremem;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 virtmem;
+ __u64 hiwater_rss;
+ __u64 hiwater_vm;
+ __u64 read_char;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 write_char;
+ __u64 read_syscalls;
+ __u64 write_syscalls;
+#define TASKSTATS_HAS_IO_ACCOUNTING
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 read_bytes;
+ __u64 write_bytes;
+ __u64 cancelled_write_bytes;
+ __u64 nvcsw;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 nivcsw;
+ __u64 ac_utimescaled;
+ __u64 ac_stimescaled;
+ __u64 cpu_scaled_run_real_total;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 freepages_count;
+ __u64 freepages_delay_total;
 };
 enum {
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
@@ -52,22 +97,23 @@
  TASKSTATS_TYPE_AGGR_PID,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  TASKSTATS_TYPE_AGGR_TGID,
+ TASKSTATS_TYPE_NULL,
  __TASKSTATS_TYPE_MAX,
 };
-#define TASKSTATS_TYPE_MAX (__TASKSTATS_TYPE_MAX - 1)
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define TASKSTATS_TYPE_MAX (__TASKSTATS_TYPE_MAX - 1)
 enum {
  TASKSTATS_CMD_ATTR_UNSPEC = 0,
  TASKSTATS_CMD_ATTR_PID,
- TASKSTATS_CMD_ATTR_TGID,
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ TASKSTATS_CMD_ATTR_TGID,
  TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
  TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
  __TASKSTATS_CMD_ATTR_MAX,
-};
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
 #define TASKSTATS_CMD_ATTR_MAX (__TASKSTATS_CMD_ATTR_MAX - 1)
 #define TASKSTATS_GENL_NAME "TASKSTATS"
 #define TASKSTATS_GENL_VERSION 0x1
-#endif
 /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#endif
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index d15b1ca..9ea3647 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -113,7 +113,7 @@
 __END_DECLS
 
 #if defined(__cplusplus)
-struct KernelArgumentBlock;
+class KernelArgumentBlock;
 extern __LIBC_HIDDEN__ void __libc_init_tls(KernelArgumentBlock& args);
 #endif
 
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index e3a40bc..a175d6f 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -93,3 +93,5 @@
 
 #define FLOCKFILE(fp)   do { if (__isthreaded) flockfile(fp); } while (0)
 #define FUNLOCKFILE(fp) do { if (__isthreaded) funlockfile(fp); } while (0)
+
+#define FLOATING_POINT
diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c
index 646b6b1..b101145 100644
--- a/libc/stdio/vfprintf.c
+++ b/libc/stdio/vfprintf.c
@@ -451,7 +451,12 @@
 			goto rflag;
 #endif
 		case 'h':
-			flags |= SHORTINT;
+			if (*fmt == 'h') {
+				fmt++;
+				flags |= CHARINT;
+			} else {
+				flags |= SHORTINT;
+			}
 			goto rflag;
 		case 'j':
 			flags |= MAXINT;
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
index dccf9e3..baa41be 100644
--- a/libc/tools/bionic_utils.py
+++ b/libc/tools/bionic_utils.py
@@ -51,7 +51,7 @@
         """ parse a syscall spec line.
 
         line processing, format is
-           return type    func_name[:syscall_name[:call_id]] ( [paramlist] )   (syscall_number[,syscall_number_x86])|stub
+           return type    func_name[:syscall_name[:call_id]] ( [paramlist] )   architecture_list
         """
         pos_lparen = line.find('(')
         E          = self.E
@@ -102,34 +102,27 @@
             syscall_params = []
             params         = "void"
 
-        number = line[pos_rparen+1:].strip()
-        if number == "stub":
-            syscall_common = -1
-            syscall_arm  = -1
-            syscall_x86 = -1
-            syscall_mips = -1
+        # Parse the architecture list.
+        syscall_common = -1
+        syscall_arm  = -1
+        syscall_x86 = -1
+        syscall_mips = -1
+        arch_list = line[pos_rparen+1:].strip()
+        if arch_list == "custom":
+            pass
+        elif arch_list == "all":
+            syscall_common = 1
         else:
-            try:
-                if number[0] == '#':
-                    number = number[1:].strip()
-                numbers = string.split(number,',')
-                if len(numbers) == 1:
-                    syscall_common = int(numbers[0])
-                    syscall_arm = -1
-                    syscall_x86 = -1
-                    syscall_mips = -1
+            for arch in string.split(arch_list, ','):
+                if arch == "arm":
+                    syscall_arm = 1
+                elif arch == "x86":
+                    syscall_x86 = 1
+                elif arch == "mips":
+                    syscall_mips = 1
                 else:
-                    if len(numbers) == 3:
-                        syscall_common = -1
-                        syscall_arm  = int(numbers[0])
-                        syscall_x86 = int(numbers[1])
-                        syscall_mips = int(numbers[2])
-                    else:
-                        E("invalid syscall number format in '%s'" % line)
-                        return
-            except:
-                E("invalid syscall number in '%s'" % line)
-                return
+                    E("invalid syscall architecture list in '%s'" % line)
+                    return
 
         global verbose
         if verbose >= 2:
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index b23eca4..f374541 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -2114,7 +2114,15 @@
   return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
 }
 
-static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int* data_size) {
+static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
+                                     const char* olson_id, int* data_size) {
+  const char* path_prefix = getenv(path_prefix_variable);
+  if (path_prefix == NULL) {
+    fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
+    return -1;
+  }
+  char path[PATH_MAX];
+  snprintf(path, sizeof(path), "%s/%s", path_prefix, path_suffix);
   int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
   if (fd == -1) {
     XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
@@ -2202,10 +2210,9 @@
 }
 
 static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
-  // TODO: use $ANDROID_DATA and $ANDROID_ROOT like libcore, to support bionic on the host.
-  int fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/tzdata", olson_id, data_size);
+  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/tzdata", olson_id, data_size);
   if (fd < 0) {
-    fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata", olson_id, data_size);
+    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size);
     if (fd == -2) {
       // The first thing that 'recovery' does is try to format the current time. It doesn't have
       // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 378f521..548364c 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -30,12 +30,8 @@
 
 void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; }
 
-#elif defined(__i386__) || defined(__mips__)
+#endif
 
 /* we munge the cb definition so we don't have to include any headers here.
  * It won't affect anything since these are just symbols anyway */
 int dl_iterate_phdr(int (*cb)(void *info, void *size, void *data), void *data) { return 0; }
-
-#else
-#error Unsupported architecture. Only mips, arm and x86 are supported.
-#endif
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 638164d..946f79e 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -146,11 +146,10 @@
 }
 
 #if defined(ANDROID_ARM_LINKER)
-//   0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
-//   0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
+//   0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888 8888888
+//   0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012 3456789
 #define ANDROID_LIBDL_STRTAB \
-    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_unwind_find_exidx\0"
-
+    "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0dl_iterate_phdr\0dl_unwind_find_exidx\0"
 #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
 //   0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667
 //   0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890
@@ -181,10 +180,9 @@
   ELF32_SYM_INITIALIZER(21, &dlerror, 1),
   ELF32_SYM_INITIALIZER(29, &dladdr, 1),
   ELF32_SYM_INITIALIZER(36, &android_update_LD_LIBRARY_PATH, 1),
-#if defined(ANDROID_ARM_LINKER)
-  ELF32_SYM_INITIALIZER(67, &dl_unwind_find_exidx, 1),
-#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
   ELF32_SYM_INITIALIZER(67, &dl_iterate_phdr, 1),
+#if defined(ANDROID_ARM_LINKER)
+  ELF32_SYM_INITIALIZER(83, &dl_unwind_find_exidx, 1),
 #endif
 };
 
@@ -207,7 +205,11 @@
 // Note that adding any new symbols here requires
 // stubbing them out in libdl.
 static unsigned gLibDlBuckets[1] = { 1 };
+#if defined(ANDROID_ARM_LINKER)
+static unsigned gLibDlChains[9] = { 0, 2, 3, 4, 5, 6, 7, 8, 0 };
+#else
 static unsigned gLibDlChains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 };
+#endif
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
 soinfo libdl_info = {
@@ -223,8 +225,8 @@
     strtab: ANDROID_LIBDL_STRTAB,
     symtab: gLibDlSymtab,
 
-    nbucket: 1,
-    nchain: 8,
+    nbucket: sizeof(gLibDlBuckets)/sizeof(unsigned),
+    nchain: sizeof(gLibDlChains)/sizeof(unsigned),
     bucket: gLibDlBuckets,
     chain: gLibDlChains,
 
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 623be29..0f20181 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -414,7 +414,7 @@
     return NULL;
 }
 
-#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
+#endif
 
 /* Here, we only have to provide a callback to iterate across all the
  * loaded libraries. gcc_eh does the rest. */
@@ -437,8 +437,6 @@
     return rv;
 }
 
-#endif
-
 static Elf32_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
     Elf32_Sym* symtab = si->symtab;
     const char* strtab = si->strtab;
diff --git a/tests/Android.mk b/tests/Android.mk
index 534aa30..e60b908 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -80,6 +80,7 @@
     string_test.cpp \
     strings_test.cpp \
     stubs_test.cpp \
+    sys_sendfile_test.cpp \
     sys_stat_test.cpp \
     system_properties_test.cpp \
     time_test.cpp \
@@ -188,6 +189,28 @@
 endif
 
 # -----------------------------------------------------------------------------
+# Run the unit tests built against x86 bionic on an x86 host.
+# -----------------------------------------------------------------------------
+
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+ifeq ($(TARGET_ARCH),x86)
+# gtest needs EXTERNAL_STORAGE for death test output.
+# bionic itself should always work relative to ANDROID_DATA or ANDROID_ROOT.
+# We create /data/local/tmp to be as much like the regular target environment
+# as possible.
+bionic-unit-tests-run-on-host: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/linker
+	mkdir -p $(TARGET_OUT_DATA)/local/tmp
+	cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin
+	cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin
+	ANDROID_DATA=$(TARGET_OUT_DATA) \
+	ANDROID_ROOT=$(TARGET_OUT) \
+	EXTERNAL_STORAGE=$(TARGET_OUT_DATA)/local/tmp \
+	LD_LIBRARY_PATH=$(TARGET_OUT_SHARED_LIBRARIES) \
+		$(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests
+endif
+endif
+
+# -----------------------------------------------------------------------------
 # FORTIFY_SOURCE tests
 # -----------------------------------------------------------------------------
 
diff --git a/tests/TemporaryFile.h b/tests/TemporaryFile.h
new file mode 100644
index 0000000..878fb13
--- /dev/null
+++ b/tests/TemporaryFile.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+class TemporaryFile {
+ public:
+  TemporaryFile() {
+#if __BIONIC__
+    const char* tmp_dir = "/data/local/tmp";
+#else
+    const char* tmp_dir = "/tmp";
+#endif
+    snprintf(filename, sizeof(filename), "%s/TemporaryFile-XXXXXX", tmp_dir);
+    fd = mkstemp(filename);
+  }
+
+  ~TemporaryFile() {
+    close(fd);
+    unlink(filename);
+  }
+
+  int fd;
+  char filename[1024];
+};
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index aa13736..5ec15b8 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -717,3 +717,58 @@
   ASSERT_EQ('\0', dst[13]);
   ASSERT_EQ('\0', dst[14]);
 }
+
+TEST(TEST_NAME, strcat_chk_max_int_size) {
+  char buf[10];
+  memset(buf, 'A', sizeof(buf));
+  buf[0] = 'a';
+  buf[1] = '\0';
+  char* res = __strcat_chk(buf, "01234567", (size_t)-1);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('a',  buf[0]);
+  ASSERT_EQ('0',  buf[1]);
+  ASSERT_EQ('1',  buf[2]);
+  ASSERT_EQ('2',  buf[3]);
+  ASSERT_EQ('3',  buf[4]);
+  ASSERT_EQ('4',  buf[5]);
+  ASSERT_EQ('5',  buf[6]);
+  ASSERT_EQ('6',  buf[7]);
+  ASSERT_EQ('7',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+}
+
+extern "C" char* __strcpy_chk(char*, const char*, size_t);
+
+TEST(TEST_NAME, strcpy_chk_max_int_size) {
+  char buf[10];
+  char* res = __strcpy_chk(buf, "012345678", (size_t)-1);
+  ASSERT_EQ(buf, res);
+  ASSERT_EQ('0',  buf[0]);
+  ASSERT_EQ('1',  buf[1]);
+  ASSERT_EQ('2',  buf[2]);
+  ASSERT_EQ('3',  buf[3]);
+  ASSERT_EQ('4',  buf[4]);
+  ASSERT_EQ('5',  buf[5]);
+  ASSERT_EQ('6',  buf[6]);
+  ASSERT_EQ('7',  buf[7]);
+  ASSERT_EQ('8',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+}
+
+extern "C" void* __memcpy_chk(void*, const void*, size_t, size_t);
+
+TEST(TEST_NAME, memcpy_chk_max_int_size) {
+  char buf[10];
+  void* res = __memcpy_chk(buf, "012345678", sizeof(buf), (size_t)-1);
+  ASSERT_EQ((void*)buf, res);
+  ASSERT_EQ('0',  buf[0]);
+  ASSERT_EQ('1',  buf[1]);
+  ASSERT_EQ('2',  buf[2]);
+  ASSERT_EQ('3',  buf[3]);
+  ASSERT_EQ('4',  buf[4]);
+  ASSERT_EQ('5',  buf[5]);
+  ASSERT_EQ('6',  buf[6]);
+  ASSERT_EQ('7',  buf[7]);
+  ASSERT_EQ('8',  buf[8]);
+  ASSERT_EQ('\0', buf[9]);
+}
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 2e779d8..18fa64a 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -182,6 +183,132 @@
   snprintf(buf, sizeof(buf), "%zd", v);
 }
 
+TEST(stdio, snprintf_smoke) {
+  char buf[BUFSIZ];
+
+  snprintf(buf, sizeof(buf), "a");
+  EXPECT_STREQ("a", buf);
+
+  snprintf(buf, sizeof(buf), "%%");
+  EXPECT_STREQ("%", buf);
+
+  snprintf(buf, sizeof(buf), "01234");
+  EXPECT_STREQ("01234", buf);
+
+  snprintf(buf, sizeof(buf), "a%sb", "01234");
+  EXPECT_STREQ("a01234b", buf);
+
+  char* s = NULL;
+  snprintf(buf, sizeof(buf), "a%sb", s);
+  EXPECT_STREQ("a(null)b", buf);
+
+  snprintf(buf, sizeof(buf), "aa%scc", "bb");
+  EXPECT_STREQ("aabbcc", buf);
+
+  snprintf(buf, sizeof(buf), "a%cc", 'b');
+  EXPECT_STREQ("abc", buf);
+
+  snprintf(buf, sizeof(buf), "a%db", 1234);
+  EXPECT_STREQ("a1234b", buf);
+
+  snprintf(buf, sizeof(buf), "a%db", -8123);
+  EXPECT_STREQ("a-8123b", buf);
+
+  snprintf(buf, sizeof(buf), "a%hdb", 0x7fff0010);
+  EXPECT_STREQ("a16b", buf);
+
+  snprintf(buf, sizeof(buf), "a%hhdb", 0x7fffff10);
+  EXPECT_STREQ("a16b", buf);
+
+  snprintf(buf, sizeof(buf), "a%lldb", 0x1000000000LL);
+  EXPECT_STREQ("a68719476736b", buf);
+
+  snprintf(buf, sizeof(buf), "a%ldb", 70000L);
+  EXPECT_STREQ("a70000b", buf);
+
+  snprintf(buf, sizeof(buf), "a%pb", reinterpret_cast<void*>(0xb0001234));
+  EXPECT_STREQ("a0xb0001234b", buf);
+
+  snprintf(buf, sizeof(buf), "a%xz", 0x12ab);
+  EXPECT_STREQ("a12abz", buf);
+
+  snprintf(buf, sizeof(buf), "a%Xz", 0x12ab);
+  EXPECT_STREQ("a12ABz", buf);
+
+  snprintf(buf, sizeof(buf), "a%08xz", 0x123456);
+  EXPECT_STREQ("a00123456z", buf);
+
+  snprintf(buf, sizeof(buf), "a%5dz", 1234);
+  EXPECT_STREQ("a 1234z", buf);
+
+  snprintf(buf, sizeof(buf), "a%05dz", 1234);
+  EXPECT_STREQ("a01234z", buf);
+
+  snprintf(buf, sizeof(buf), "a%8dz", 1234);
+  EXPECT_STREQ("a    1234z", buf);
+
+  snprintf(buf, sizeof(buf), "a%-8dz", 1234);
+  EXPECT_STREQ("a1234    z", buf);
+
+  snprintf(buf, sizeof(buf), "A%-11sZ", "abcdef");
+  EXPECT_STREQ("Aabcdef     Z", buf);
+
+  snprintf(buf, sizeof(buf), "A%s:%dZ", "hello", 1234);
+  EXPECT_STREQ("Ahello:1234Z", buf);
+
+  snprintf(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5);
+  EXPECT_STREQ("a005:5:05z", buf);
+
+  void* p = NULL;
+  snprintf(buf, sizeof(buf), "a%d,%pz", 5, p);
+  EXPECT_STREQ("a5,0x0z", buf);
+
+  snprintf(buf, sizeof(buf), "a%lld,%d,%d,%dz", 0x1000000000LL, 6, 7, 8);
+  EXPECT_STREQ("a68719476736,6,7,8z", buf);
+
+  snprintf(buf, sizeof(buf), "a_%f_b", 1.23f);
+  EXPECT_STREQ("a_1.230000_b", buf);
+
+  snprintf(buf, sizeof(buf), "a_%g_b", 3.14d);
+  EXPECT_STREQ("a_3.14_b", buf);
+}
+
+TEST(stdio, snprintf_d_INT_MAX) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%d", INT_MAX);
+  EXPECT_STREQ("2147483647", buf);
+}
+
+TEST(stdio, snprintf_d_INT_MIN) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%d", INT_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+}
+
+TEST(stdio, snprintf_ld_LONG_MAX) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%ld", LONG_MAX);
+  EXPECT_STREQ("2147483647", buf);
+}
+
+TEST(stdio, snprintf_ld_LONG_MIN) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%ld", LONG_MIN);
+  EXPECT_STREQ("-2147483648", buf);
+}
+
+TEST(stdio, snprintf_lld_LLONG_MAX) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%lld", LLONG_MAX);
+  EXPECT_STREQ("9223372036854775807", buf);
+}
+
+TEST(stdio, snprintf_lld_LLONG_MIN) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%lld", LLONG_MIN);
+  EXPECT_STREQ("-9223372036854775808", buf);
+}
+
 TEST(stdio, popen) {
   FILE* fp = popen("cat /proc/version", "r");
   ASSERT_TRUE(fp != NULL);
diff --git a/tests/sys_sendfile_test.cpp b/tests/sys_sendfile_test.cpp
new file mode 100644
index 0000000..bf23d3d
--- /dev/null
+++ b/tests/sys_sendfile_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include "TemporaryFile.h"
+
+#include <sys/sendfile.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+TEST(sys_sendfile, sendfile) {
+  TemporaryFile src_file;
+  ASSERT_EQ(5, TEMP_FAILURE_RETRY(write(src_file.fd, "hello", 5)));
+
+  TemporaryFile dst_file;
+
+  off_t offset = 2;
+  size_t count = 2;
+  ssize_t rc = sendfile(dst_file.fd, src_file.fd, &offset, count);
+  ASSERT_EQ(2, rc);
+  ASSERT_EQ(4, offset);
+
+  ASSERT_EQ(0, lseek(dst_file.fd, 0, SEEK_SET));
+  char buf[3];
+  buf[2] = '\0';
+  ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(dst_file.fd, &buf, 2)));
+  ASSERT_STREQ("ll", buf);
+}
+
+#if __BIONIC__
+TEST(sys_sendfile, sendfile64) {
+  TemporaryFile src_file;
+  ASSERT_EQ(5, TEMP_FAILURE_RETRY(write(src_file.fd, "hello", 5)));
+
+  TemporaryFile dst_file;
+
+  off64_t offset = 2;
+  size_t count = 2;
+  ssize_t rc = sendfile64(dst_file.fd, src_file.fd, &offset, count);
+  ASSERT_EQ(2, rc);
+  ASSERT_EQ(4, offset);
+
+  ASSERT_EQ(0, lseek(dst_file.fd, 0, SEEK_SET));
+  char buf[3];
+  buf[2] = '\0';
+  ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(dst_file.fd, &buf, 2)));
+  ASSERT_STREQ("ll", buf);
+}
+#endif
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 3ccaf3b..3193083 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <gtest/gtest.h>
+#include "TemporaryFile.h"
 
 #include <stdint.h>
 #include <unistd.h>
@@ -32,3 +33,43 @@
   void* final_break = sbrk(0);
   ASSERT_EQ(final_break, new_break);
 }
+
+TEST(unistd, truncate) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, close(tf.fd));
+  ASSERT_EQ(0, truncate(tf.filename, 123));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, truncate64) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, close(tf.fd));
+  ASSERT_EQ(0, truncate64(tf.filename, 123));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, ftruncate) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, ftruncate(tf.fd, 123));
+  ASSERT_EQ(0, close(tf.fd));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}
+
+TEST(unistd, ftruncate64) {
+  TemporaryFile tf;
+  ASSERT_EQ(0, ftruncate64(tf.fd, 123));
+  ASSERT_EQ(0, close(tf.fd));
+
+  struct stat sb;
+  ASSERT_EQ(0, stat(tf.filename, &sb));
+  ASSERT_EQ(123, sb.st_size);
+}