Merge "MIPS support to sys/ headers"
diff --git a/libc/Android.mk b/libc/Android.mk
index 46dd8d6..fd81d7e 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -529,13 +529,13 @@
     libc_common_cflags += -DANDROID_SMP=0
 endif
 
-# Needed to access private/__dso_handle.h from
-# crtbegin_xxx.c and crtend_xxx.c
-#
-libc_crt_target_cflags += -I$(LOCAL_PATH)/private
+# crtbrand.c needs <stdint.h> and a #define for the platform SDK version.
+libc_crt_target_cflags += \
+    -I$(LOCAL_PATH)/include  \
+    -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
 
 ifeq ($(TARGET_ARCH),arm)
-libc_crt_target_cflags += -DCRT_LEGACY_WORKAROUND
+    libc_crt_target_cflags += -DCRT_LEGACY_WORKAROUND
 endif
 
 # Define some common includes
@@ -548,8 +548,9 @@
 
 # Needed to access private/__dso_handle.h from
 # crtbegin_xxx.S and crtend_xxx.S
-#
-libc_crt_target_cflags += -I$(LOCAL_PATH)/private -I$(LOCAL_PATH)/arch-$(TARGET_ARCH)/include
+libc_crt_target_cflags += \
+    -I$(LOCAL_PATH)/private \
+    -I$(LOCAL_PATH)/arch-$(TARGET_ARCH)/include
 
 # Define the libc run-time (crt) support object files that must be built,
 # which are needed to build all other objects (shared/static libs and
@@ -577,6 +578,22 @@
     libc_crt_target_crtstart_file := $(LOCAL_PATH)/arch-$(TARGET_ARCH)/bionic/crtbegin.S
     libc_crt_target_crtstart_so_file := $(LOCAL_PATH)/arch-$(TARGET_ARCH)/bionic/crtbegin_so.S
 endif
+
+# See the comment in crtbrand.c for the reason why we need to generate
+# crtbrand.s before generating crtbrand.o.
+GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbrand.s
+$(GEN): $(LOCAL_PATH)/bionic/crtbrand.c
+	@mkdir -p $(dir $@)
+	$(TARGET_CC) $(libc_crt_target_so_cflags) -S -o $@ $<
+	sed -i -e '/\.note\.ABI-tag/s/progbits/note/' $@
+ALL_GENERATED_SOURCES += $(GEN)
+
+GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbrand.o
+$(GEN): $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbrand.s
+	@mkdir -p $(dir $@)
+	$(TARGET_CC) $(libc_crt_target_so_cflags) -o $@ -c $<
+ALL_GENERATED_SOURCES += $(GEN)
+
 GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_so.o
 $(GEN): $(libc_crt_target_crtstart_so_file)
 	@mkdir -p $(dir $@)
@@ -603,19 +620,30 @@
 endif # TARGET_ARCH == x86 || TARGET_ARCH == arm
 
 
+GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_static1.o
+$(GEN): $(libc_crt_target_crtstart_file)
+	@mkdir -p $(dir $@)
+	$(TARGET_CC) $(libc_crt_target_cflags) -o $@ -c $<
+ALL_GENERATED_SOURCES += $(GEN)
+
 GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_static.o
+$(GEN): $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_static1.o $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbrand.o
+	@mkdir -p $(dir $@)
+	$(TARGET_LD) -r -o $@ $^
+ALL_GENERATED_SOURCES += $(GEN)
+
+GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_dynamic1.o
 $(GEN): $(libc_crt_target_crtstart_file)
 	@mkdir -p $(dir $@)
 	$(TARGET_CC) $(libc_crt_target_cflags) -o $@ -c $<
 ALL_GENERATED_SOURCES += $(GEN)
 
 GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_dynamic.o
-$(GEN): $(libc_crt_target_crtstart_file)
+$(GEN): $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbegin_dynamic1.o $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtbrand.o
 	@mkdir -p $(dir $@)
-	$(TARGET_CC) $(libc_crt_target_cflags) -o $@ -c $<
+	$(TARGET_LD) -r -o $@ $^
 ALL_GENERATED_SOURCES += $(GEN)
 
-
 # We rename crtend.o to crtend_android.o to avoid a
 # name clash between gcc and bionic.
 GEN := $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/crtend_android.o
diff --git a/libc/NOTICE b/libc/NOTICE
index d9e6818..e992c18 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -380,3 +380,27 @@
 SUCH DAMAGE.
 
 
+Copyright 2000 David E. O'Brien, John D. Polstra.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
diff --git a/libc/arch-sh/syscalls/tgkill.S b/libc/arch-sh/syscalls/tgkill.S
deleted file mode 100644
index 222f836..0000000
--- a/libc/arch-sh/syscalls/tgkill.S
+++ /dev/null
@@ -1,32 +0,0 @@
-/* autogenerated by gensyscalls.py */
-#include <sys/linux-syscalls.h>
-
-    .text
-    .type tgkill, @function
-    .globl tgkill
-    .align 4
-
-tgkill:
-
-    /* invoke trap */
-    mov.l   0f, r3  /* trap num */
-    trapa   #(3 + 0x10)
-
-    /* check return value */
-    cmp/pz  r0
-    bt      __NR_tgkill_end
-
-    /* keep error number */
-    sts.l   pr, @-r15
-    mov.l   1f, r1
-    jsr     @r1
-    mov     r0, r4
-    lds.l   @r15+, pr
-
-__NR_tgkill_end:
-    rts
-    nop
-
-    .align  2
-0:  .long   __NR_tgkill
-1:  .long   __set_syscall_errno
diff --git a/libc/arch-x86/bionic/syscall.S b/libc/arch-x86/bionic/syscall.S
index 8370f0b..49d6f8d 100644
--- a/libc/arch-x86/bionic/syscall.S
+++ b/libc/arch-x86/bionic/syscall.S
@@ -1,15 +1,13 @@
 /*
  * Generic syscall call.
- * Upon entry
- *	%eax: system call number
- *	%ebx: arg0 to system call
- *	%ecx: arg..
- *	%edx: arg..
- *	%esi: arg..
- *	%edi: arg..
- * We push these (to save them) load them up with the
- * values from the calling frame (not all will actually be valid)
- * and make the syscall.
+ * Upon entry:
+ *	%eax: system call number  - caller save
+ *	%ebx: arg0 to system call -   callee save
+ *	%ecx: arg1                - caller save
+ *	%edx: arg2                - caller save
+ *	%esi: arg3                -   callee save
+ *	%edi: arg4                -   callee save
+ *	%ebp: arg5                -   callee save
  */
 
 #include <sys/linux-syscalls.h>
@@ -20,26 +18,37 @@
     .align 4
 
 syscall:
+    # Push the callee save registers.
     push    %ebx
     push    %esi
     push    %edi
-    mov     16(%esp),%eax
-    mov     20(%esp),%ebx
-    mov     24(%esp),%ecx
-    mov     28(%esp),%edx
-    mov     32(%esp),%esi
-    mov     36(%esp),%edi
+    push    %ebp
 
+    # Load all the arguments from the calling frame.
+    # (Not all will be valid, depending on the syscall.)
+    mov     20(%esp),%eax
+    mov     24(%esp),%ebx
+    mov     28(%esp),%ecx
+    mov     32(%esp),%edx
+    mov     36(%esp),%esi
+    mov     40(%esp),%edi
+    mov     44(%esp),%ebp
+
+    # Make the system call.
     int     $0x80
 
+    # Error?
     cmpl    $-4095, %eax
     jb      1f
+    # Yes, so set errno.
     negl    %eax
     pushl   %eax
     call    __set_errno
     addl    $4, %esp
     orl     $-1, %eax
 1:
+    # Restore the callee save registers.
+    pop    %ebp
     pop    %edi
     pop    %esi
     pop    %ebx
diff --git a/libc/arch-x86/include/machine/_types.h b/libc/arch-x86/include/machine/_types.h
index 65892a1..d3d9eeb 100644
--- a/libc/arch-x86/include/machine/_types.h
+++ b/libc/arch-x86/include/machine/_types.h
@@ -58,8 +58,6 @@
 #  endif
 #endif
 
-#include <linux/types.h>
-
 /* 7.18.1.1 Exact-width integer types */
 typedef	__signed char		__int8_t;
 typedef	unsigned char		__uint8_t;
diff --git a/libc/bionic/crtbrand.c b/libc/bionic/crtbrand.c
new file mode 100644
index 0000000..31fcbc7
--- /dev/null
+++ b/libc/bionic/crtbrand.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright 2000 David E. O'Brien, John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#define ABI_VENDOR	"Android"
+#define ABI_SECTION	".note.android.ident"
+#define ABI_NOTETYPE	1
+#define ABI_ANDROID_API	PLATFORM_SDK_VERSION
+
+/*
+ * Special ".note" entry to tag an Android binary and specify the ABI version.
+ *
+ * For all arches except sparc, gcc emits the section directive for the
+ * following struct with a PROGBITS type.  However, the section should be
+ * of NOTE type, according to the Generic SysV ABI spec.
+ *
+ * Unfortunately, there is no clean way to tell gcc to use another section type,
+ * so this C file (or the C file that includes it) must be compiled in multiple
+ * steps:
+ *
+ * - Compile the .c file to a .s file.
+ * - Edit the .s file to change the 'progbits' type to 'note', for the section
+ *   directive that defines the .note.ABI-tag section.
+ * - Compile the .s file to an object file.
+ *
+ * These steps are done in the invididual Makefiles for each applicable arch.
+ */
+static const struct {
+    int32_t	namesz;
+    int32_t	descsz;
+    int32_t	type;
+    char	name[sizeof ABI_VENDOR];
+    int32_t	android_api;
+} abitag __attribute__ ((section (ABI_SECTION), aligned(4), used)) = {
+    sizeof ABI_VENDOR,
+    sizeof(int32_t),
+    ABI_NOTETYPE,
+    ABI_VENDOR,
+    ABI_ANDROID_API,
+};
diff --git a/libc/include/string.h b/libc/include/string.h
index 8e472e7..d1dc4c4 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -147,6 +147,7 @@
     return __builtin___memset_chk(s, c, n, __builtin_object_size (s, 0));
 }
 
+#if !defined(__clang__)
 extern size_t __strlcpy_real(char *, const char *, size_t)
     __asm__(__USER_LABEL_PREFIX__ "strlcpy");
 extern void __strlcpy_error()
@@ -223,6 +224,7 @@
 
     return __strlen_chk(s, bos);
 }
+#endif  /* !defined(__clang__) */
 
 
 #endif /* defined(__BIONIC_FORTIFY_INLINE) */
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index af19554..4658866 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -127,9 +127,20 @@
 #      define __get_tls() ( *((volatile void **) 0xffff0ff0) )
 #    endif
 #  endif /* !LIBC_STATIC */
-#else /* !ARM */
+#elif defined(__mips__)
+#    define __get_tls() \
+    ({ register unsigned int __val asm("v1");   \
+        asm (                                   \
+            "   .set    push\n"                 \
+            "   .set    mips32r2\n"             \
+            "   rdhwr   %0,$29\n"               \
+            "   .set    pop\n"                  \
+            : "=r"(__val)                       \
+            );                                  \
+        (volatile void*)__val; })
+#else
 extern void*  __get_tls( void );
-#endif /* !ARM */
+#endif
 
 /* return the stack base and size, used by our malloc debugger */
 extern void*  __get_stack_base(int  *p_stack_size);
diff --git a/libc/private/logd.h b/libc/private/logd.h
index 8970daf..c81a91a 100644
--- a/libc/private/logd.h
+++ b/libc/private/logd.h
@@ -59,6 +59,10 @@
     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int __libc_android_log_write(int prio, const char* tag, const char* buffer);
 int __libc_android_log_print(int prio, const char *tag, const char *fmt, ...);
 int __libc_android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
@@ -66,4 +70,8 @@
 void __libc_android_log_event_int(int32_t tag, int value);
 void __libc_android_log_event_uid(int32_t tag);
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif /* _ANDROID_BIONIC_LOGD_H */
diff --git a/libc/zoneinfo/zoneinfo.dat b/libc/zoneinfo/zoneinfo.dat
index 82d6b9c..3d0b53c 100644
--- a/libc/zoneinfo/zoneinfo.dat
+++ b/libc/zoneinfo/zoneinfo.dat
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.idx b/libc/zoneinfo/zoneinfo.idx
index 2268706..ac6bbc9 100644
--- a/libc/zoneinfo/zoneinfo.idx
+++ b/libc/zoneinfo/zoneinfo.idx
Binary files differ
diff --git a/libc/zoneinfo/zoneinfo.version b/libc/zoneinfo/zoneinfo.version
index e606761..f9e9d44 100644
--- a/libc/zoneinfo/zoneinfo.version
+++ b/libc/zoneinfo/zoneinfo.version
@@ -1 +1 @@
-2012d
+2012e
diff --git a/linker/Android.mk b/linker/Android.mk
index d207f95..b519976 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -3,13 +3,13 @@
 
 LOCAL_SRC_FILES:= \
 	arch/$(TARGET_ARCH)/begin.S \
-	linker.c \
+	debugger.c \
+	dlfcn.c \
+	linker.cpp \
 	linker_environ.c \
 	linker_format.c \
 	linker_phdr.c \
-	rt.c \
-	dlfcn.c \
-	debugger.c
+	rt.c
 
 LOCAL_LDFLAGS := -shared
 
@@ -23,15 +23,14 @@
 #
 LOCAL_CFLAGS += -DLINKER_DEBUG=0
 
-# we need to access the Bionic private header <bionic_tls.h>
-# in the linker; duplicate the HAVE_ARM_TLS_REGISTER definition
-# from the libc build
+# We need to access Bionic private headers in the linker...
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/../libc/
+
+# ...one of which is <private/bionic_tls.h>, for which we
+# need HAVE_ARM_TLS_REGISTER.
 ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
     LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
 endif
-LOCAL_CFLAGS += \
-    -I$(LOCAL_PATH)/../libc/private \
-    -I$(LOCAL_PATH)/../libc/arch-$(TARGET_ARCH)/bionic
 
 ifeq ($(TARGET_ARCH),arm)
     LOCAL_CFLAGS += -DANDROID_ARM_LINKER
diff --git a/linker/README.TXT b/linker/README.TXT
index f920b97..1770c87 100644
--- a/linker/README.TXT
+++ b/linker/README.TXT
@@ -8,44 +8,6 @@
 dynamic linker.
 
 
-Prelinking:
------------
-
-System libraries in Android are internally prelinked, which means that
-any internal relocations within them are stripped from the corresponding
-shared object, in order to reduce size and speed up loading.
-
-Such libraries can only be loaded at the very specific virtual memory address
-they have been prelinked to (during the build process). The list of prelinked
-system libraries and their corresponding virtual memory address is found in
-the file:
-
-   build/core/prelink-linux-<arch>.map
-
-It should be updated each time a new system library is added to the
-system.
-
-The prelink step happens at build time, and uses the 'soslim' and 'apriori'
-tools:
-
-  - 'apriori' is the real prelink tool which removes relocations from the
-    shared object, however, it must be given a list of symbols to remove
-    from the file.
-
-  - 'soslim' is used to find symbols in an executable ELF file
-    and generate a list that can be passed to 'apriori'.
-
-By default, these tools are only used to remove internal symbols from
-libraries, though they have been designed to allow more aggressive
-optimizations (e.g. 'global' prelinking and symbol stripping, which
-prevent replacing individual system libraries though).
-
-You can disable prelinking at build time by modifying your Android.mk with
-a line like:
-
-    LOCAL_PRELINK_MODULE := false
-
-
 Initialization and Termination functions:
 -----------------------------------------
 
diff --git a/linker/arch/x86/begin.S b/linker/arch/x86/begin.S
index 0c0fc3d..baa386f 100644
--- a/linker/arch/x86/begin.S
+++ b/linker/arch/x86/begin.S
@@ -44,4 +44,4 @@
         popl   %esp
         jmp    *%eax
 
-#include "__stack_chk_fail_local.S"
+#include "arch-x86/bionic/__stack_chk_fail_local.S"
diff --git a/linker/debugger.c b/linker/debugger.c
index 7a1dd15..dde66f3 100644
--- a/linker/debugger.c
+++ b/linker/debugger.c
@@ -156,7 +156,7 @@
  * Catches fatal signals so we can ask debuggerd to ptrace us before
  * we crash.
  */
-void debugger_signal_handler(int n, siginfo_t* info, void* unused)
+void debugger_signal_handler(int n, siginfo_t* info, void* unused __attribute__((unused)))
 {
     char msgbuf[128];
     unsigned tid;
diff --git a/linker/linker.c b/linker/linker.cpp
similarity index 83%
rename from linker/linker.c
rename to linker/linker.cpp
index e0c3bce..b2d813f 100644
--- a/linker/linker.c
+++ b/linker/linker.cpp
@@ -26,25 +26,23 @@
  * SUCH DAMAGE.
  */
 
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <linux/auxvec.h>
-
+#include <pthread.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dlfcn.h>
-#include <sys/stat.h>
-
-#include <pthread.h>
-
-#include <sys/mman.h>
-
 #include <sys/atomics.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-/* special private C library header - see Android.mk */
-#include <bionic_tls.h>
+// Private C library headers.
+#include <private/bionic_tls.h>
+#include <private/logd.h>
 
 #include "linker.h"
 #include "linker_debug.h"
@@ -79,8 +77,8 @@
  * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
  *   headers provide versions that are negative...
  * - allocate space for soinfo structs dynamically instead of
- *   having a hard limit (64)
-*/
+ *   having a hard limit (SO_MAX)
+ */
 
 
 static int soinfo_link_image(soinfo *si, unsigned wr_offset);
@@ -126,24 +124,30 @@
 unsigned bitmask[4096];
 #endif
 
-#define HOODLUM(name, ret, ...)                                               \
-    ret name __VA_ARGS__                                                      \
-    {                                                                         \
-        char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
-        write(2, errstr, sizeof(errstr));                                     \
-        abort();                                                              \
+// You shouldn't try to call memory-allocating functions in the dynamic linker.
+// Guard against the most obvious ones.
+#define DISALLOW_ALLOCATION(return_type, name, ...)                             \
+    return_type name __VA_ARGS__                                                \
+    {                                                                           \
+        const char* msg = "ERROR: " #name " called from the dynamic linker!\n"; \
+         __libc_android_log_write(ANDROID_LOG_FATAL, "linker", msg);            \
+        write(2, msg, sizeof(msg));                                             \
+        abort();                                                                \
     }
-HOODLUM(malloc, void *, (size_t size));
-HOODLUM(free, void, (void *ptr));
-HOODLUM(realloc, void *, (void *ptr, size_t size));
-HOODLUM(calloc, void *, (size_t cnt, size_t size));
+#define UNUSED __attribute__((unused))
+DISALLOW_ALLOCATION(void*, malloc, (size_t u UNUSED));
+DISALLOW_ALLOCATION(void, free, (void* u UNUSED));
+DISALLOW_ALLOCATION(void*, realloc, (void* u1 UNUSED, size_t u2 UNUSED));
+DISALLOW_ALLOCATION(void*, calloc, (size_t u1 UNUSED, size_t u2 UNUSED));
 
 static char tmp_err_buf[768];
 static char __linker_dl_err_buf[768];
+#define BASENAME(s) (strrchr(s, '/') != NULL ? strrchr(s, '/') + 1 : s)
 #define DL_ERR(fmt, x...)                                                     \
     do {                                                                      \
         format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),       \
-                 "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
+            "(%s:%d, pid %d) %s: " fmt,                                       \
+            BASENAME(__FILE__), __LINE__, pid, __func__, ##x);                \
         ERROR(fmt "\n", ##x);                                                 \
     } while(0)
 
@@ -156,7 +160,7 @@
  * This function is an empty stub where GDB locates a breakpoint to get notified
  * about linker activity.
  */
-extern void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(void);
+extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity(void);
 
 static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
                                   RT_CONSISTENT, 0};
@@ -243,7 +247,7 @@
     pthread_mutex_unlock(&_r_debug_lock);
 }
 
-void notify_gdb_of_libraries()
+extern "C" void notify_gdb_of_libraries()
 {
     _r_debug.r_state = RT_ADD;
     rtld_db_dlactivity();
@@ -253,10 +257,8 @@
 
 static soinfo *soinfo_alloc(const char *name)
 {
-    soinfo *si;
-
-    if(strlen(name) >= SOINFO_NAME_LEN) {
-        DL_ERR("%5d library name %s too long", pid, name);
+    if (strlen(name) >= SOINFO_NAME_LEN) {
+        DL_ERR("library name \"%s\" too long", name);
         return NULL;
     }
 
@@ -264,15 +266,15 @@
        done only by dlclose(), which is not likely to be used.
     */
     if (!freelist) {
-        if(socount == SO_MAX) {
-            DL_ERR("%5d too many libraries when loading %s", pid, name);
+        if (socount == SO_MAX) {
+            DL_ERR("too many libraries when loading \"%s\"", name);
             return NULL;
         }
         freelist = sopool + socount++;
         freelist->next = NULL;
     }
 
-    si = freelist;
+    soinfo* si = freelist;
     freelist = freelist->next;
 
     /* Make sure we get a clean block of soinfo */
@@ -287,8 +289,12 @@
     return si;
 }
 
-static void soinfo_free(soinfo *si)
+static void soinfo_free(soinfo* si)
 {
+    if (si == NULL) {
+        return;
+    }
+
     soinfo *prev = NULL, *trav;
 
     TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
@@ -300,7 +306,7 @@
     }
     if (trav == NULL) {
         /* si was not ni solist */
-        DL_ERR("%5d name %s is not in solist!", pid, si->name);
+        DL_ERR("name \"%s\" is not in solist!", si->name);
         return;
     }
 
@@ -315,17 +321,16 @@
 
 const char *addr_to_name(unsigned addr)
 {
-    soinfo *si;
-
-    for(si = solist; si != 0; si = si->next){
-        if((addr >= si->base) && (addr < (si->base + si->size))) {
+    for (soinfo* si = solist; si != 0; si = si->next) {
+        if ((addr >= si->base) && (addr < (si->base + si->size))) {
             return si->name;
         }
     }
-
     return "";
 }
 
+#ifdef ANDROID_ARM_LINKER
+
 /* For a given PC, find the .so that it belongs to.
  * Returns the base address of the .ARM.exidx section
  * for that .so, and the number of 8-byte entries
@@ -335,7 +340,6 @@
  *
  * This function is exposed via dlfcn.c and libdl.so.
  */
-#ifdef ANDROID_ARM_LINKER
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
 {
     soinfo *si;
@@ -350,7 +354,9 @@
    *pcount = 0;
     return NULL;
 }
+
 #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_MIPS_LINKER)
+
 /* Here, we only have to provide a callback to iterate across all the
  * loaded libraries. gcc_eh does the rest. */
 int
@@ -372,6 +378,7 @@
     }
     return rv;
 }
+
 #endif
 
 static Elf32_Sym *soinfo_elf_lookup(soinfo *si, unsigned hash, const char *name)
@@ -454,8 +461,7 @@
         if(d[0] == DT_NEEDED){
             lsi = (soinfo *)d[1];
             if (!validate_soinfo(lsi)) {
-                DL_ERR("%5d bad DT_NEEDED pointer in %s",
-                       pid, lsi->name);
+                DL_ERR("bad DT_NEEDED pointer in \"%s\"", lsi->name);
                 return NULL;
             }
 
@@ -638,35 +644,33 @@
     return -1;
 }
 
-typedef struct {
-    long mmap_addr;
-    char tag[4]; /* 'P', 'R', 'E', ' ' */
-} prelink_info_t;
-
-/* Returns the requested base address if the library is prelinked,
- * and 0 otherwise.  */
-static unsigned long
-is_prelinked(int fd, const char *name)
+// Returns 'true' if the library is prelinked or on failure so we error out
+// either way. We no longer support prelinking.
+static bool is_prelinked(int fd, const char* name)
 {
-    off_t sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
+    struct prelink_info_t {
+        long mmap_addr;
+        char tag[4]; // "PRE ".
+    };
+
+    off_t sz = lseek(fd, -sizeof(struct prelink_info_t), SEEK_END);
     if (sz < 0) {
-        DL_ERR("lseek() failed!");
-        return 0;
+        DL_ERR("lseek failed: %s", strerror(errno));
+        return true;
     }
 
-    prelink_info_t info;
+    struct prelink_info_t info;
     int rc = TEMP_FAILURE_RETRY(read(fd, &info, sizeof(info)));
     if (rc != sizeof(info)) {
-        WARN("Could not read prelink_info_t structure for `%s`\n", name);
-        return 0;
+        DL_ERR("could not read prelink_info_t structure for \"%s\":", name, strerror(errno));
+        return true;
     }
 
-    if (memcmp(info.tag, "PRE ", 4)) {
-        WARN("`%s` is not a prelinked library\n", name);
-        return 0;
+    if (memcmp(info.tag, "PRE ", 4) == 0) {
+        DL_ERR("prelinked libraries no longer supported: %s", name);
+        return true;
     }
-
-    return (unsigned long)info.mmap_addr;
+    return false;
 }
 
 /* verify_elf_header
@@ -697,101 +701,106 @@
     return 0;
 }
 
+struct scoped_fd {
+    ~scoped_fd() {
+        if (fd != -1) {
+            close(fd);
+        }
+    }
+    int fd;
+};
 
-static soinfo *
-load_library(const char *name)
+struct soinfo_ptr {
+    soinfo_ptr(const char* name) {
+        const char* bname = strrchr(name, '/');
+        ptr = soinfo_alloc(bname ? bname + 1 : name);
+    }
+    ~soinfo_ptr() {
+        soinfo_free(ptr);
+    }
+    soinfo* release() {
+        soinfo* result = ptr;
+        ptr = NULL;
+        return result;
+    }
+    soinfo* ptr;
+};
+
+// TODO: rewrite linker_phdr.h to use a class, then lose this.
+struct phdr_ptr {
+    phdr_ptr() : phdr_mmap(NULL) {}
+    ~phdr_ptr() {
+        if (phdr_mmap != NULL) {
+            phdr_table_unload(phdr_mmap, phdr_size);
+        }
+    }
+    void* phdr_mmap;
+    Elf32_Addr phdr_size;
+};
+
+static soinfo* load_library(const char* name)
 {
-    int fd = open_library(name);
-    int ret, cnt;
-    unsigned ext_sz;
-    unsigned req_base;
-    const char *bname;
-    struct stat sb;
-    soinfo *si = NULL;
-    Elf32_Ehdr  header[1];
-    int         phdr_count;
-    void*       phdr_mmap = NULL;
-    Elf32_Addr  phdr_size;
-    const Elf32_Phdr* phdr_table;
-
-    void*       load_start = NULL;
-    Elf32_Addr  load_size = 0;
-    Elf32_Addr  load_bias = 0;
-
-    if (fd == -1) {
-        DL_ERR("Library '%s' not found", name);
+    // Open the file.
+    scoped_fd fd;
+    fd.fd = open_library(name);
+    if (fd.fd == -1) {
+        DL_ERR("library \"%s\" not found", name);
         return NULL;
     }
 
-    /* Read the ELF header first */
-    ret = TEMP_FAILURE_RETRY(read(fd, (void*)header, sizeof(header)));
+    // Read the ELF header.
+    Elf32_Ehdr header[1];
+    int ret = TEMP_FAILURE_RETRY(read(fd.fd, (void*)header, sizeof(header)));
     if (ret < 0) {
-        DL_ERR("%5d can't read file %s: %s", pid, name, strerror(errno));
-        goto fail;
+        DL_ERR("can't read file \"%s\": %s", name, strerror(errno));
+        return NULL;
     }
     if (ret != (int)sizeof(header)) {
-        DL_ERR("%5d too small to be an ELF executable: %s", pid, name);
-        goto fail;
+        DL_ERR("too small to be an ELF executable: %s", name);
+        return NULL;
     }
     if (verify_elf_header(header) < 0) {
-        DL_ERR("%5d not a valid ELF executable: %s", pid, name);
-        goto fail;
+        DL_ERR("not a valid ELF executable: %s", name);
+        return NULL;
     }
 
-    /* Then read the program header table */
-    ret = phdr_table_load(fd, header->e_phoff, header->e_phnum,
-                          &phdr_mmap, &phdr_size, &phdr_table);
+    // Read the program header table.
+    const Elf32_Phdr* phdr_table;
+    phdr_ptr phdr_holder;
+    ret = phdr_table_load(fd.fd, header->e_phoff, header->e_phnum,
+                          &phdr_holder.phdr_mmap, &phdr_holder.phdr_size, &phdr_table);
     if (ret < 0) {
-        DL_ERR("%5d can't load program header table: %s: %s", pid,
-               name, strerror(errno));
-        goto fail;
+        DL_ERR("can't load program header table: %s: %s", name, strerror(errno));
+        return NULL;
     }
-    phdr_count = header->e_phnum;
+    size_t phdr_count = header->e_phnum;
 
-    /* Get the load extents and the prelinked load address, if any */
-    ext_sz = phdr_table_get_load_size(phdr_table, phdr_count);
+    // Get the load extents.
+    Elf32_Addr ext_sz = phdr_table_get_load_size(phdr_table, phdr_count);
+    TRACE("[ %5d - '%s' wants sz=0x%08x ]\n", pid, name, ext_sz);
     if (ext_sz == 0) {
-        DL_ERR("%5d no loadable segments in file: %s", pid, name);
-        goto fail;
+        DL_ERR("no loadable segments in file: %s", name);
+        return NULL;
     }
 
-    req_base = (unsigned) is_prelinked(fd, name);
-    if (req_base == (unsigned)-1) {
-        DL_ERR("%5d can't read end of library: %s: %s", pid, name,
-               strerror(errno));
-        goto fail;
-    }
-    if (req_base != 0) {
-        TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
-              pid, name, req_base);
-    } else {
-        TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
+    // We no longer support pre-linked libraries.
+    if (is_prelinked(fd.fd, name)) {
+        return NULL;
     }
 
-    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
-          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
-
-    /* Now configure the soinfo struct where we'll store all of our data
-     * for the ELF object. If the loading fails, we waste the entry, but
-     * same thing would happen if we failed during linking. Configuring the
-     * soinfo struct here is a lot more convenient.
-     */
-    bname = strrchr(name, '/');
-    si = soinfo_alloc(bname ? bname + 1 : name);
-    if (si == NULL)
-        goto fail;
-
-    /* Reserve address space for all loadable segments */
+    // Reserve address space for all loadable segments.
+    void* load_start = NULL;
+    Elf32_Addr load_size = 0;
+    Elf32_Addr load_bias = 0;
     ret = phdr_table_reserve_memory(phdr_table,
                                     phdr_count,
-                                    req_base,
                                     &load_start,
                                     &load_size,
                                     &load_bias);
     if (ret < 0) {
-        DL_ERR("%5d Can't reserve %d bytes from 0x%08x in address space for %s: %s",
-               pid, ext_sz, req_base, name, strerror(errno));
-        goto fail;
+        DL_ERR("can't reserve %d bytes in address space for \"%s\": %s",
+               ext_sz, name, strerror(errno));
+        return NULL;
     }
 
     TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
@@ -800,14 +809,12 @@
     /* Map all the segments in our address space with default protections */
     ret = phdr_table_load_segments(phdr_table,
                                    phdr_count,
-                                   load_start,
-                                   load_size,
                                    load_bias,
-                                   fd);
+                                   fd.fd);
     if (ret < 0) {
-        DL_ERR("%5d Can't map loadable segments for %s: %s",
-               pid, name, strerror(errno));
-        goto fail;
+        DL_ERR("can't map loadable segments for \"%s\": %s",
+               name, strerror(errno));
+        return NULL;
     }
 
     /* Unprotect the segments, i.e. make them writable, to allow
@@ -819,36 +826,30 @@
                                         phdr_count,
                                         load_bias);
     if (ret < 0) {
-        DL_ERR("%5d Can't unprotect loadable segments for %s: %s",
-               pid, name, strerror(errno));
-        goto fail;
+        DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+               name, strerror(errno));
+        return NULL;
     }
 
-    si->base = (Elf32_Addr) load_start;
-    si->size = load_size;
-    si->load_bias = load_bias;
-    si->flags = 0;
-    si->entry = 0;
-    si->dynamic = (unsigned *)-1;
-    si->phnum = phdr_count;
-    si->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias);
-    if (si->phdr == NULL) {
-        DL_ERR("%5d Can't find loaded PHDR for %s",
-               pid, name);
-        goto fail;
+    soinfo_ptr si(name);
+    if (si.ptr == NULL) {
+        return NULL;
     }
 
-    phdr_table_unload(phdr_mmap, phdr_size);
-    close(fd);
-    return si;
-
-fail:
-    if (si) soinfo_free(si);
-    if (phdr_mmap != NULL) {
-        phdr_table_unload(phdr_mmap, phdr_size);
+    si.ptr->base = (Elf32_Addr) load_start;
+    si.ptr->size = load_size;
+    si.ptr->load_bias = load_bias;
+    si.ptr->flags = 0;
+    si.ptr->entry = 0;
+    si.ptr->dynamic = (unsigned *)-1;
+    si.ptr->phnum = phdr_count;
+    si.ptr->phdr = phdr_table_get_loaded_phdr(phdr_table, phdr_count, load_bias);
+    if (si.ptr->phdr == NULL) {
+        DL_ERR("can't find loaded PHDR for \"%s\"", name);
+        return NULL;
     }
-    close(fd);
-    return NULL;
+
+    return si.release();
 }
 
 static soinfo *
@@ -891,11 +892,11 @@
     for(si = solist; si != 0; si = si->next){
         if(!strcmp(bname, si->name)) {
             if(si->flags & FLAG_ERROR) {
-                DL_ERR("%5d '%s' failed to load previously", pid, bname);
+                DL_ERR("\"%s\" failed to load previously", bname);
                 return NULL;
             }
             if(si->flags & FLAG_LINKED) return si;
-            DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
+            DL_ERR("OOPS: recursive link to \"%s\"", si->name);
             return NULL;
         }
     }
@@ -908,8 +909,7 @@
 }
 
 /* TODO:
- *   notify gdb of unload
- *   for non-prelinked libraries, find a way to decrement libbase
+ *   find a way to decrement libbase
  */
 static void call_destructors(soinfo *si);
 unsigned soinfo_unload(soinfo *si)
@@ -925,9 +925,9 @@
          */
         if (phdr_table_unprotect_gnu_relro(si->phdr, si->phnum,
                                            si->load_bias) < 0) {
-            DL_ERR("%5d %s: could not undo GNU_RELRO protections. "
+            DL_ERR("%s: could not undo GNU_RELRO protections. "
                     "Expect a crash soon. errno=%d (%s)",
-                    pid, si->name, errno, strerror(errno));
+                    si->name, errno, strerror(errno));
         }
 
         for(d = si->dynamic; *d; d += 2) {
@@ -945,8 +945,8 @@
                     soinfo_unload(lsi);
                 }
                 else
-                    DL_ERR("%5d %s: could not unload dependent library",
-                           pid, si->name);
+                    DL_ERR("\"%s\": could not unload dependent library",
+                           si->name);
             }
         }
 
@@ -972,12 +972,10 @@
     Elf32_Sym *symtab = si->symtab;
     const char *strtab = si->strtab;
     Elf32_Sym *s;
-    unsigned base;
     Elf32_Addr offset;
     Elf32_Rel *start = rel;
-    unsigned idx;
 
-    for (idx = 0; idx < count; ++idx, ++rel) {
+    for (size_t idx = 0; idx < count; ++idx, ++rel) {
         unsigned type = ELF32_R_TYPE(rel->r_info);
         unsigned sym = ELF32_R_SYM(rel->r_info);
         unsigned reloc = (unsigned)(rel->r_offset + si->load_bias);
@@ -997,7 +995,7 @@
                    reference..   */
                 s = &symtab[sym];
                 if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
-                    DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
+                    DL_ERR("cannot locate \"%s\"...", sym_name);
                     return -1;
                 }
 
@@ -1043,8 +1041,8 @@
                        not found in run-time.  */
 #endif /* ANDROID_ARM_LINKER */
                 default:
-                    DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n",
-                                 pid, type, rel, (int) (rel - start));
+                    DL_ERR("unknown weak reloc type %d @ %p (%d)",
+                                 type, rel, (int) (rel - start));
                     return -1;
                 }
             } else {
@@ -1052,8 +1050,8 @@
 #if 0
                 if((base == 0) && (si->base != 0)){
                         /* linking from libraries to main image is bad */
-                    DL_ERR("%5d cannot locate '%s'...",
-                           pid, strtab + symtab[sym].st_name);
+                    DL_ERR("cannot locate \"%s\"...",
+                           strtab + symtab[sym].st_name);
                     return -1;
                 }
 #endif
@@ -1140,8 +1138,8 @@
 #endif /* ANDROID_*_LINKER */
             COUNT_RELOC(RELOC_RELATIVE);
             MARK(rel->r_offset);
-            if(sym){
-                DL_ERR("%5d odd RELATIVE form...", pid);
+            if (sym) {
+                DL_ERR("odd RELATIVE form...", pid);
                 return -1;
             }
             TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
@@ -1180,8 +1178,8 @@
 #endif /* ANDROID_ARM_LINKER */
 
         default:
-            DL_ERR("%5d unknown reloc type %d @ %p (%d)",
-                  pid, type, rel, (int) (rel - start));
+            DL_ERR("unknown reloc type %d @ %p (%d)",
+                   type, rel, (int) (rel - start));
             return -1;
         }
     }
@@ -1240,7 +1238,7 @@
                reference..   */
             s = &symtab[g];
             if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
-                DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
+                DL_ERR("cannot locate \"%s\"...", sym_name);
                 return -1;
             }
             *got = 0;
@@ -1320,9 +1318,8 @@
         TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
     } else {
         if (si->preinit_array) {
-            DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
-                   " This is INVALID.", pid, si->name,
-                   (unsigned)si->preinit_array);
+            DL_ERR("shared library \"%s\" has a preinit_array table @ 0x%08x. "
+                   "This is INVALID.", si->name, (unsigned) si->preinit_array);
         }
     }
 
@@ -1332,8 +1329,7 @@
             if(d[0] == DT_NEEDED){
                 soinfo* lsi = (soinfo *)d[1];
                 if (!validate_soinfo(lsi)) {
-                    DL_ERR("%5d bad DT_NEEDED pointer in %s",
-                           pid, si->name);
+                    DL_ERR("bad DT_NEEDED pointer in \"%s\"", si->name);
                 } else {
                     soinfo_call_constructors(lsi);
                 }
@@ -1383,7 +1379,7 @@
 
     dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
     if (dev_null < 0) {
-        DL_ERR("Cannot open /dev/null.");
+        DL_ERR("cannot open /dev/null: %s", strerror(errno));
         return -1;
     }
     TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
@@ -1392,24 +1388,22 @@
        with /dev/null, dup /dev/null to it.  */
     for (i = 0; i < 3; i++) {
         /* If it is /dev/null already, we are done. */
-        if (i == dev_null)
+        if (i == dev_null) {
             continue;
+        }
 
         TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
-        /* The man page of fcntl does not say that fcntl(..,F_GETFL)
-           can be interrupted but we do this just to be safe. */
-        do {
-          status = fcntl(i, F_GETFL);
-        } while (status < 0 && errno == EINTR);
+        status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
 
-        /* If file is openned, we are good. */
-        if (status >= 0)
-          continue;
+        /* If file is opened, we are good. */
+        if (status != -1) {
+            continue;
+        }
 
         /* The only error we allow is that the file descriptor does not
            exist, in which case we dup /dev/null to it. */
         if (errno != EBADF) {
-            DL_ERR("nullify_stdio: unhandled error %s", strerror(errno));
+            DL_ERR("fcntl failed: %s", strerror(errno));
             return_value = -1;
             continue;
         }
@@ -1417,12 +1411,9 @@
         /* Try dupping /dev/null to this stdio file descriptor and
            repeat if there is a signal.  Note that any errors in closing
            the stdio descriptor are lost.  */
-        do {
-            status = dup2(dev_null, i);
-        } while (status < 0 && errno == EINTR);
-
+        status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
         if (status < 0) {
-            DL_ERR("nullify_stdio: dup2 error %s", strerror(errno));
+            DL_ERR("dup2 failed: %s", strerror(errno));
             return_value = -1;
             continue;
         }
@@ -1431,12 +1422,9 @@
     /* If /dev/null is not one of the stdio file descriptors, close it. */
     if (dev_null > 2) {
         TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
-        do {
-            status = close(dev_null);
-        } while (status < 0 && errno == EINTR);
-
-        if (status < 0) {
-            DL_ERR("nullify_stdio: close error %s", strerror(errno));
+        status = TEMP_FAILURE_RETRY(close(dev_null));
+        if (status == -1) {
+            DL_ERR("close failed: %s", strerror(errno));
             return_value = -1;
         }
     }
@@ -1464,7 +1452,7 @@
     si->dynamic = phdr_table_get_dynamic_section(phdr, phnum, base);
     if (si->dynamic == NULL) {
         if (!relocating_linker) {
-            DL_ERR("%5d missing PT_DYNAMIC?!", pid);
+            DL_ERR("missing PT_DYNAMIC?!");
         }
         goto fail;
     } else {
@@ -1485,8 +1473,8 @@
             /* We can't call DL_ERR if the linker's relocations haven't
              * been performed yet */
             if (!relocating_linker) {
-                DL_ERR("%5d Can't unprotect segments for %s: %s",
-                       pid, si->name, strerror(errno));
+                DL_ERR("can't unprotect segments for \"%s\": %s",
+                       si->name, strerror(errno));
             }
             goto fail;
         }
@@ -1537,7 +1525,7 @@
 #endif
             break;
          case DT_RELA:
-            DL_ERR("%5d DT_RELA not supported", pid);
+            DL_ERR("DT_RELA not supported");
             goto fail;
         case DT_INIT:
             si->init_func = (void (*)(void))(base + *d);
@@ -1633,7 +1621,7 @@
            pid, si->base, si->strtab, si->symtab);
 
     if((si->strtab == 0) || (si->symtab == 0)) {
-        DL_ERR("%5d missing essential tables", pid);
+        DL_ERR("missing essential tables");
         goto fail;
     }
 
@@ -1645,8 +1633,8 @@
             soinfo *lsi = find_library(ldpreload_names[i]);
             if(lsi == 0) {
                 strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
-                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
-                       pid, ldpreload_names[i], si->name, tmp_err_buf);
+                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
+                       ldpreload_names[i], si->name, tmp_err_buf);
                 goto fail;
             }
             lsi->refcount++;
@@ -1660,8 +1648,8 @@
             soinfo *lsi = find_library(si->strtab + d[1]);
             if(lsi == 0) {
                 strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
-                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
-                       pid, si->strtab + d[1], si->name, tmp_err_buf);
+                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by %s",
+                       si->strtab + d[1], si->name, tmp_err_buf);
                 goto fail;
             }
             /* Save the soinfo of the loaded DT_NEEDED library in the payload
@@ -1699,15 +1687,15 @@
     /* All relocations are done, we can protect our segments back to
      * read-only. */
     if (phdr_table_protect_segments(si->phdr, si->phnum, si->load_bias) < 0) {
-        DL_ERR("%5d Can't protect segments for %s: %s",
-               pid, si->name, strerror(errno));
+        DL_ERR("can't protect segments for \"%s\": %s",
+               si->name, strerror(errno));
         goto fail;
     }
 
     /* We can also turn on GNU RELRO protection */
     if (phdr_table_protect_gnu_relro(si->phdr, si->phnum, si->load_bias) < 0) {
-        DL_ERR("%5d Can't enable GNU RELRO protection for %s: %s",
-               pid, si->name, strerror(errno));
+        DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
+               si->name, strerror(errno));
         goto fail;
     }
 
@@ -1717,8 +1705,9 @@
     ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
 
      */
-    if (program_is_setuid)
-        nullify_closed_stdio ();
+    if (program_is_setuid) {
+        nullify_closed_stdio();
+    }
     notify_gdb_of_load(si);
     return 0;
 
@@ -1728,53 +1717,43 @@
     return -1;
 }
 
-static void parse_library_path(const char *path, char *delim)
+static void parse_path(const char* path, const char* delimiters,
+                       const char** array, char* buf, size_t buf_size, size_t max_count)
 {
-    size_t len;
-    char *ldpaths_bufp = ldpaths_buf;
-    int i = 0;
-
-    len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf));
-
-    while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) {
-        if (*ldpaths[i] != '\0')
-            ++i;
+    if (path == NULL) {
+        return;
     }
 
-    /* Forget the last path if we had to truncate; this occurs if the 2nd to
-     * last char isn't '\0' (i.e. not originally a delim). */
-    if (i > 0 && len >= sizeof(ldpaths_buf) &&
-            ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') {
-        ldpaths[i - 1] = NULL;
-    } else {
-        ldpaths[i] = NULL;
-    }
-}
+    size_t len = strlcpy(buf, path, buf_size);
 
-static void parse_preloads(const char *path, char *delim)
-{
-    size_t len;
-    char *ldpreloads_bufp = ldpreloads_buf;
-    int i = 0;
-
-    len = strlcpy(ldpreloads_buf, path, sizeof(ldpreloads_buf));
-
-    while (i < LDPRELOAD_MAX && (ldpreload_names[i] = strsep(&ldpreloads_bufp, delim))) {
-        if (*ldpreload_names[i] != '\0') {
+    size_t i = 0;
+    char* buf_p = buf;
+    while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
+        if (*array[i] != '\0') {
             ++i;
         }
     }
 
-    /* Forget the last path if we had to truncate; this occurs if the 2nd to
-     * last char isn't '\0' (i.e. not originally a delim). */
-    if (i > 0 && len >= sizeof(ldpreloads_buf) &&
-            ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') {
-        ldpreload_names[i - 1] = NULL;
+    // Forget the last path if we had to truncate; this occurs if the 2nd to
+    // last char isn't '\0' (i.e. wasn't originally a delimiter).
+    if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
+        array[i - 1] = NULL;
     } else {
-        ldpreload_names[i] = NULL;
+        array[i] = NULL;
     }
 }
 
+static void parse_LD_LIBRARY_PATH(const char* path) {
+    parse_path(path, ":", ldpaths,
+               ldpaths_buf, sizeof(ldpaths_buf), LDPATH_MAX);
+}
+
+static void parse_LD_PRELOAD(const char* path) {
+    // We have historically supported ':' as well as ' ' in LD_PRELOAD.
+    parse_path(path, " :", ldpreload_names,
+               ldpreloads_buf, sizeof(ldpreloads_buf), LDPRELOAD_MAX);
+}
+
 /*
  * This code is called after the linker has linked itself and
  * fixed it's own GOT. It is safe to make references to externs
@@ -1917,13 +1896,9 @@
     si->dynamic = (unsigned *)-1;
     si->refcount = 1;
 
-        /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
-    if (ldpath_env)
-        parse_library_path(ldpath_env, ":");
-
-    if (ldpreload_env) {
-        parse_preloads(ldpreload_env, " :");
-    }
+    // Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
+    parse_LD_LIBRARY_PATH(ldpath_env);
+    parse_LD_PRELOAD(ldpreload_env);
 
     if(soinfo_link_image(si, 0)) {
         char errmsg[] = "CANNOT LINK EXECUTABLE\n";
@@ -2047,7 +2022,7 @@
  * relocations, any attempt to reference an extern variable, extern
  * function, or other GOT reference will generate a segfault.
  */
-unsigned __linker_init(unsigned **elfdata) {
+extern "C" unsigned __linker_init(unsigned **elfdata) {
     unsigned linker_addr = find_linker_base(elfdata);
     Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
     Elf32_Phdr *phdr =
diff --git a/linker/linker.h b/linker/linker.h
index cb2eab6..ce811df 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -34,6 +34,10 @@
 #include <elf.h>
 #include <sys/exec_elf.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #undef PAGE_MASK
 #undef PAGE_SIZE
 #define PAGE_SIZE 4096
@@ -106,7 +110,7 @@
 
 struct soinfo
 {
-    const char name[SOINFO_NAME_LEN];
+    char name[SOINFO_NAME_LEN];
     const Elf32_Phdr *phdr;
     int phnum;
     unsigned entry;
@@ -244,4 +248,8 @@
 int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #endif
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif
diff --git a/linker/linker_environ.h b/linker/linker_environ.h
index 98ad1de..d5f75a1 100644
--- a/linker/linker_environ.h
+++ b/linker/linker_environ.h
@@ -28,6 +28,10 @@
 #ifndef LINKER_ENVIRON_H
 #define LINKER_ENVIRON_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Call this function before anything else. 'vecs' must be the pointer
  * to the environment block in the ELF data block. The function returns
  * the start of the aux vectors after the env block.
@@ -47,8 +51,12 @@
  * after this function. */
 extern const char* linker_env_get(const char* name);
 
-/* Remove unsecure environment variables. This should be used when
+/* Remove insecure environment variables. This should be used when
  * running setuid programs. */
 extern void        linker_env_secure(void);
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif /* LINKER_ENVIRON_H */
diff --git a/linker/linker_format.c b/linker/linker_format.c
index d305740..f60e259 100644
--- a/linker/linker_format.c
+++ b/linker/linker_format.c
@@ -312,7 +312,7 @@
 
 #else /* !CUSTOM_LOG_VPRINT */
 
-extern int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
+extern "C" int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
 
 #endif /* !CUSTOM_LOG_VPRINT */
 
diff --git a/linker/linker_format.h b/linker/linker_format.h
index 6ae2bad..3766b62 100644
--- a/linker/linker_format.h
+++ b/linker/linker_format.h
@@ -31,6 +31,10 @@
 #include <stdarg.h>
 #include <stddef.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Formatting routines for the dynamic linker's debug traces */
 /* We want to avoid dragging the whole C library fprintf()   */
 /* implementation into the dynamic linker since this creates */
@@ -38,4 +42,8 @@
 
 int format_buffer(char *buffer, size_t bufsize, const char *format, ...);
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif /* _LINKER_FORMAT_H */
diff --git a/linker/linker_phdr.c b/linker/linker_phdr.c
index c9f194b..beb756f 100644
--- a/linker/linker_phdr.c
+++ b/linker/linker_phdr.c
@@ -180,24 +180,25 @@
  * This returns 0 if there are no loadable segments.
  */
 Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
-                                    int               phdr_count)
+                                    size_t phdr_count)
 {
-    int nn;
-
     Elf32_Addr min_vaddr = 0xFFFFFFFFU;
     Elf32_Addr max_vaddr = 0x00000000U;
 
-    for (nn = 0; nn < phdr_count; nn++) {
-        const Elf32_Phdr* phdr = &phdr_table[nn];
+    for (size_t i = 0; i < phdr_count; ++i) {
+        const Elf32_Phdr* phdr = &phdr_table[i];
 
-        if (phdr->p_type != PT_LOAD)
+        if (phdr->p_type != PT_LOAD) {
             continue;
+        }
 
-        if (phdr->p_vaddr < min_vaddr)
+        if (phdr->p_vaddr < min_vaddr) {
             min_vaddr = phdr->p_vaddr;
+        }
 
-        if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
+        if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
             max_vaddr = phdr->p_vaddr + phdr->p_memsz;
+        }
     }
 
     if (min_vaddr > max_vaddr) {
@@ -217,8 +218,6 @@
  * Input:
  *   phdr_table    -> program header table
  *   phdr_count    -> number of entries in the tables
- *   required_base -> for prelinked libraries, mandatory load address
- *                    of the first loadable segment. 0 otherwise.
  * Output:
  *   load_start    -> first page of reserved address space range
  *   load_size     -> size in bytes of reserved address space range
@@ -229,26 +228,19 @@
  */
 int
 phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
-                          int               phdr_count,
-                          Elf32_Addr        required_base,
-                          void**            load_start,
-                          Elf32_Addr*       load_size,
-                          Elf32_Addr*       load_bias)
+                          size_t phdr_count,
+                          void** load_start,
+                          Elf32_Addr* load_size,
+                          Elf32_Addr* load_bias)
 {
     Elf32_Addr size = phdr_table_get_load_size(phdr_table, phdr_count);
-    void*      start;
-    int        nn, mmap_flags;
-
     if (size == 0) {
         errno = EINVAL;
         return -1;
     }
 
-    mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
-    if (required_base != 0)
-        mmap_flags |= MAP_FIXED;
-
-    start = mmap((void*)required_base, size, PROT_NONE, mmap_flags, -1, 0);
+    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+    void* start = mmap(NULL, size, PROT_NONE, mmap_flags, -1, 0);
     if (start == MAP_FAILED) {
         return -1;
     }
@@ -257,8 +249,8 @@
     *load_size  = size;
     *load_bias  = 0;
 
-    for (nn = 0; nn < phdr_count; nn++) {
-        const Elf32_Phdr* phdr = &phdr_table[nn];
+    for (size_t i = 0; i < phdr_count; ++i) {
+        const Elf32_Phdr* phdr = &phdr_table[i];
         if (phdr->p_type == PT_LOAD) {
             *load_bias = (Elf32_Addr)start - PAGE_START(phdr->p_vaddr);
             break;
@@ -274,8 +266,6 @@
  * Input:
  *   phdr_table    -> program header table
  *   phdr_count    -> number of entries in the table
- *   load_start    -> start address of reserved memory range.
- *   load_size     -> size of reserved memory range.
  *   load_bias     -> load offset.
  *   fd            -> input file descriptor.
  *
@@ -285,8 +275,6 @@
 int
 phdr_table_load_segments(const Elf32_Phdr* phdr_table,
                          int               phdr_count,
-                         void*             load_start,
-                         Elf32_Addr        load_size,
                          Elf32_Addr        load_bias,
                          int               fd)
 {
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index d542e46..753c7e7 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -37,6 +37,10 @@
 
 #include "linker.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* See linker_phdr.c for all usage documentation */
 
 int
@@ -52,21 +56,18 @@
 
 Elf32_Addr
 phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
-                         int               phdr_count);
+                         size_t phdr_count);
 
 int
 phdr_table_reserve_memory(const Elf32_Phdr* phdr_table,
-                          int               phdr_count,
-                          Elf32_Addr        required_base,
-                          void**            load_start,
-                          Elf32_Addr*       load_size,
-                          Elf32_Addr*       load_bias);
+                          size_t phdr_count,
+                          void** load_start,
+                          Elf32_Addr* load_size,
+                          Elf32_Addr* load_bias);
 
 int
 phdr_table_load_segments(const Elf32_Phdr* phdr_table,
                          int               phdr_count,
-                         void*             load_start,
-                         Elf32_Addr        load_size,
                          Elf32_Addr        load_bias,
                          int               fd);
 
@@ -109,4 +110,8 @@
                                int               phdr_count,
                                Elf32_Addr        load_bias);
 
+#ifdef __cplusplus
+};
+#endif
+
 #endif /* LINKER_PHDR_H */