Merge "libc: provide atomic operations will full barriers for NDK apps."
diff --git a/libc/Android.mk b/libc/Android.mk
index bfa56e5..207a133 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -354,6 +354,7 @@
arch-arm/bionic/kill.S \
arch-arm/bionic/libgcc_compat.c \
arch-arm/bionic/tkill.S \
+ arch-arm/bionic/tgkill.S \
arch-arm/bionic/memcmp.S \
arch-arm/bionic/memcmp16.S \
arch-arm/bionic/memcpy.S \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 46e7b1f..fa02edc 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -63,6 +63,7 @@
# 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,37
int tkill(pid_t tid, int sig) -1,238
+int tgkill(pid_t tgid, pid_t tid, int sig) -1,270
int __ptrace:ptrace(int request, int pid, void* addr, void* data) 26
int __set_thread_area:set_thread_area(void* user_desc) -1,243
int __getpriority:getpriority(int, int) 96
diff --git a/libc/arch-arm/bionic/tgkill.S b/libc/arch-arm/bionic/tgkill.S
new file mode 100644
index 0000000..da5c0af
--- /dev/null
+++ b/libc/arch-arm/bionic/tgkill.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* unlike our auto-generated syscall stubs, this code saves lr
+ on the stack, as well as a few other registers. this makes
+ our stack unwinder happy, when we generate debug stack
+ traces after the C library or other parts of the system
+ abort due to a fatal runtime error (e.g. detection
+ of a corrupted malloc heap).
+*/
+
+#include <sys/linux-syscalls.h>
+#include <machine/asm.h>
+
+#ifndef __NR_tgkill
+#define __NR_tgkill 268
+#endif
+
+ENTRY(tgkill)
+ stmfd sp!, {r4-r7, ip, lr}
+ ldr r7, =__NR_tgkill
+ swi #0
+ ldmfd sp!, {r4-r7, ip, lr}
+ movs r0, r0
+ bxpl lr
+ b __set_syscall_errno
+END(tgkill)
diff --git a/libc/arch-sh/syscalls.mk b/libc/arch-sh/syscalls.mk
index 1d87600..d4e4583 100644
--- a/libc/arch-sh/syscalls.mk
+++ b/libc/arch-sh/syscalls.mk
@@ -26,6 +26,7 @@
syscall_src += arch-sh/syscalls/__brk.S
syscall_src += arch-sh/syscalls/kill.S
syscall_src += arch-sh/syscalls/tkill.S
+syscall_src += arch-sh/syscalls/tgkill.S
syscall_src += arch-sh/syscalls/__ptrace.S
syscall_src += arch-sh/syscalls/__set_thread_area.S
syscall_src += arch-sh/syscalls/__getpriority.S
diff --git a/libc/arch-sh/syscalls/tgkill.S b/libc/arch-sh/syscalls/tgkill.S
new file mode 100644
index 0000000..222f836
--- /dev/null
+++ b/libc/arch-sh/syscalls/tgkill.S
@@ -0,0 +1,32 @@
+/* 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/syscalls.mk b/libc/arch-x86/syscalls.mk
index 3b85025..13edeb0 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -26,6 +26,7 @@
syscall_src += arch-x86/syscalls/__brk.S
syscall_src += arch-x86/syscalls/kill.S
syscall_src += arch-x86/syscalls/tkill.S
+syscall_src += arch-x86/syscalls/tgkill.S
syscall_src += arch-x86/syscalls/__ptrace.S
syscall_src += arch-x86/syscalls/__set_thread_area.S
syscall_src += arch-x86/syscalls/__getpriority.S
diff --git a/libc/arch-x86/syscalls/tgkill.S b/libc/arch-x86/syscalls/tgkill.S
new file mode 100644
index 0000000..99af740
--- /dev/null
+++ b/libc/arch-x86/syscalls/tgkill.S
@@ -0,0 +1,29 @@
+/* autogenerated by gensyscalls.py */
+#include <sys/linux-syscalls.h>
+
+ .text
+ .type tgkill, @function
+ .globl tgkill
+ .align 4
+
+tgkill:
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ mov 16(%esp), %ebx
+ mov 20(%esp), %ecx
+ mov 24(%esp), %edx
+ movl $__NR_tgkill, %eax
+ int $0x80
+ cmpl $-129, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno
+ addl $4, %esp
+ orl $-1, %eax
+1:
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index b56822f..63d885a 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -81,9 +81,6 @@
#define PTHREAD_ATTR_FLAG_USER_STACK 0x00000002
#define DEFAULT_STACKSIZE (1024 * 1024)
-#define STACKBASE 0x10000000
-
-static uint8_t * gStackBase = (uint8_t *)STACKBASE;
static pthread_mutex_t mmap_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -252,7 +249,7 @@
pthread_mutex_lock(&mmap_lock);
- stack = mmap((void *)gStackBase, size,
+ stack = mmap(NULL, size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
-1, 0);
@@ -1839,7 +1836,7 @@
}
// man says this should be in <linux/unistd.h>, but it isn't
-extern int tkill(int tid, int sig);
+extern int tgkill(int tgid, int tid, int sig);
int pthread_kill(pthread_t tid, int sig)
{
@@ -1847,7 +1844,7 @@
int old_errno = errno;
pthread_internal_t * thread = (pthread_internal_t *)tid;
- ret = tkill(thread->kernel_id, sig);
+ ret = tgkill(getpid(), thread->kernel_id, sig);
if (ret < 0) {
ret = errno;
errno = old_errno;
diff --git a/libc/include/sys/linux-syscalls.h b/libc/include/sys/linux-syscalls.h
index 7b74a4b..930508a 100644
--- a/libc/include/sys/linux-syscalls.h
+++ b/libc/include/sys/linux-syscalls.h
@@ -198,6 +198,7 @@
#define __NR_waitid (__NR_SYSCALL_BASE + 284)
#define __NR_kill (__NR_SYSCALL_BASE + 37)
#define __NR_tkill (__NR_SYSCALL_BASE + 238)
+#define __NR_tgkill (__NR_SYSCALL_BASE + 270)
#define __NR_set_thread_area (__NR_SYSCALL_BASE + 243)
#define __NR_openat (__NR_SYSCALL_BASE + 295)
#define __NR_madvise (__NR_SYSCALL_BASE + 219)
@@ -242,6 +243,7 @@
#define __NR_waitid (__NR_SYSCALL_BASE + 284)
#define __NR_kill (__NR_SYSCALL_BASE + 37)
#define __NR_tkill (__NR_SYSCALL_BASE + 238)
+#define __NR_tgkill (__NR_SYSCALL_BASE + 270)
#define __NR_set_thread_area (__NR_SYSCALL_BASE + 243)
#define __NR_vfork (__NR_SYSCALL_BASE + 190)
#define __NR_openat (__NR_SYSCALL_BASE + 295)
diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h
index ae9077f..f463127 100644
--- a/libc/include/sys/linux-unistd.h
+++ b/libc/include/sys/linux-unistd.h
@@ -32,6 +32,7 @@
void* __brk (void*);
int kill (pid_t, int);
int tkill (pid_t tid, int sig);
+int tgkill (pid_t tgid, pid_t tid, int sig);
int __ptrace (int request, int pid, void* addr, void* data);
int __set_thread_area (void* user_desc);
int __getpriority (int, int);
diff --git a/linker/Android.mk b/linker/Android.mk
index 7793f8d..74c7453 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -10,27 +10,9 @@
dlfcn.c \
debugger.c
-ifeq ($(TARGET_ARCH),sh)
-# SH-4A series virtual address range from 0x00000000 to 0x7FFFFFFF.
-LINKER_TEXT_BASE := 0x70000100
-else
-# This is aligned to 4K page boundary so that both GNU ld and gold work. Gold
-# actually produces a correct binary with starting address 0xB0000100 but the
-# extra objcopy step to rename symbols causes the resulting binary to be misaligned
-# and unloadable. Increasing the alignment adds an extra 3840 bytes in padding
-# but switching to gold saves about 1M of space.
-LINKER_TEXT_BASE := 0xB0001000
-endif
+LOCAL_LDFLAGS := -shared
-# The maximum size set aside for the linker, from
-# LINKER_TEXT_BASE rounded down to a megabyte.
-LINKER_AREA_SIZE := 0x01000000
-
-LOCAL_LDFLAGS := -Wl,-Ttext,$(LINKER_TEXT_BASE)
-
-LOCAL_CFLAGS += -DPRELINK
-LOCAL_CFLAGS += -DLINKER_TEXT_BASE=$(LINKER_TEXT_BASE)
-LOCAL_CFLAGS += -DLINKER_AREA_SIZE=$(LINKER_AREA_SIZE)
+LOCAL_CFLAGS += -fno-stack-protector
# Set LINKER_DEBUG to either 1 or 0
#
diff --git a/linker/linker.c b/linker/linker.c
index 792ece6..c560507 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -313,15 +313,6 @@
freelist = si;
}
-#ifndef LINKER_TEXT_BASE
-#error "linker's makefile must define LINKER_TEXT_BASE"
-#endif
-#ifndef LINKER_AREA_SIZE
-#error "linker's makefile must define LINKER_AREA_SIZE"
-#endif
-#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
-#define LINKER_TOP (LINKER_BASE + (LINKER_AREA_SIZE))
-
const char *addr_to_name(unsigned addr)
{
soinfo *si;
@@ -332,10 +323,6 @@
}
}
- if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){
- return "linker";
- }
-
return "";
}
@@ -354,12 +341,10 @@
soinfo *si;
unsigned addr = (unsigned)pc;
- if ((addr < LINKER_BASE) || (addr >= LINKER_TOP)) {
- for (si = solist; si != 0; si = si->next){
- if ((addr >= si->base) && (addr < (si->base + si->size))) {
- *pcount = si->ARM_exidx_count;
- return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
- }
+ for (si = solist; si != 0; si = si->next){
+ if ((addr >= si->base) && (addr < (si->base + si->size))) {
+ *pcount = si->ARM_exidx_count;
+ return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
}
}
*pcount = 0;
@@ -420,6 +405,33 @@
return NULL;
}
+/*
+ * Essentially the same method as _elf_lookup() above, but only
+ * searches for LOCAL symbols
+ */
+static Elf32_Sym *_elf_lookup_local(soinfo *si, unsigned hash, const char *name)
+{
+ Elf32_Sym *symtab = si->symtab;
+ const char *strtab = si->strtab;
+ unsigned n = hash % si->nbucket;;
+
+ TRACE_TYPE(LOOKUP, "%5d LOCAL SEARCH %s in %s@0x%08x %08x %d\n", pid,
+ name, si->name, si->base, hash, hash % si->nbucket);
+ for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
+ Elf32_Sym *s = symtab + n;
+ if (strcmp(strtab + s->st_name, name)) continue;
+ if (ELF32_ST_BIND(s->st_info) != STB_LOCAL) continue;
+ /* no section == undefined */
+ if(s->st_shndx == 0) continue;
+
+ TRACE_TYPE(LOOKUP, "%5d FOUND LOCAL %s in %s (%08x) %d\n", pid,
+ name, si->name, s->st_value, s->st_size);
+ return s;
+ }
+
+ return NULL;
+}
+
static unsigned elfhash(const char *_name)
{
const unsigned char *name = (const unsigned char *) _name;
@@ -443,7 +455,17 @@
soinfo *lsi = si;
int i;
- /* Look for symbols in the local scope first (the object who is
+ /* If we are trying to find a symbol for the linker itself, look
+ * for LOCAL symbols first. Avoid using LOCAL symbols for other
+ * shared libraries until we have a better understanding of what
+ * might break by doing so. */
+ if (si->flags & FLAG_LINKER) {
+ s = _elf_lookup_local(si, elf_hash, name);
+ if(s != NULL)
+ goto done;
+ }
+
+ /* Look for symbols in the local scope (the object who is
* searching). This happens with C++ templates on i386 for some
* reason.
*
@@ -452,6 +474,7 @@
* dynamic linking. Some systems return the first definition found
* and some the first non-weak definition. This is system dependent.
* Here we return the first definition found for simplicity. */
+
s = _elf_lookup(si, elf_hash, name);
if(s != NULL)
goto done;
@@ -1719,10 +1742,10 @@
DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
si->base, si->flags);
- if (si->flags & FLAG_EXE) {
+ if (si->flags & (FLAG_EXE | FLAG_LINKER)) {
/* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for
- * linkage info if this is the executable. If this was a
- * dynamic lib, that would have been done at load time.
+ * linkage info if this is the executable or the linker itself.
+ * If this was a dynamic lib, that would have been done at load time.
*
* TODO: It's unfortunate that small pieces of this are
* repeated from the load_library routine. Refactor this just
@@ -2084,7 +2107,12 @@
static void * __tls_area[ANDROID_TLS_SLOTS];
-unsigned __linker_init(unsigned **elfdata)
+/*
+ * This code is called after the linker has linked itself and
+ * fixed it's own GOT. It is safe to make references to externs
+ * and other non-local data at this point.
+ */
+static unsigned __linker_init_post_relocation(unsigned **elfdata)
{
static soinfo linker_soinfo;
@@ -2272,3 +2300,69 @@
si->entry);
return si->entry;
}
+
+/*
+ * Find the value of AT_BASE passed to us by the kernel. This is the load
+ * location of the linker.
+ */
+static unsigned find_linker_base(unsigned **elfdata) {
+ int argc = (int) *elfdata;
+ char **argv = (char**) (elfdata + 1);
+ unsigned *vecs = (unsigned*) (argv + argc + 1);
+ while (vecs[0] != 0) {
+ vecs++;
+ }
+
+ /* The end of the environment block is marked by two NULL pointers */
+ vecs++;
+
+ while(vecs[0]) {
+ if (vecs[0] == AT_BASE) {
+ return vecs[1];
+ }
+ vecs += 2;
+ }
+
+ return 0; // should never happen
+}
+
+/*
+ * This is the entry point for the linker, called from begin.S. This
+ * method is responsible for fixing the linker's own relocations, and
+ * then calling __linker_init_post_relocation().
+ *
+ * Because this method is called before the linker has fixed it's own
+ * relocations, any attempt to reference an extern variable, extern
+ * function, or other GOT reference will generate a segfault.
+ */
+unsigned __linker_init(unsigned **elfdata) {
+ unsigned linker_addr = find_linker_base(elfdata);
+ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
+ Elf32_Phdr *phdr =
+ (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
+
+ soinfo linker_so;
+ memset(&linker_so, 0, sizeof(soinfo));
+
+ linker_so.base = linker_addr;
+ linker_so.dynamic = (unsigned *) -1;
+ linker_so.phdr = phdr;
+ linker_so.phnum = elf_hdr->e_phnum;
+ linker_so.flags |= FLAG_LINKER;
+ linker_so.wrprotect_start = 0xffffffff;
+ linker_so.wrprotect_end = 0;
+
+ if (link_image(&linker_so, 0)) {
+ // It would be nice to print an error message, but if the linker
+ // can't link itself, there's no guarantee that we'll be able to
+ // call write() (because it involves a GOT reference).
+ //
+ // This situation should never occur unless the linker itself
+ // is corrupt.
+ exit(-1);
+ }
+
+ // We have successfully fixed our own relocations. It's safe to run
+ // the main part of the linker now.
+ return __linker_init_post_relocation(elfdata);
+}
diff --git a/linker/linker.h b/linker/linker.h
index 7b1ba51..aa1e5e7 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -83,6 +83,7 @@
#define FLAG_LINKED 0x00000001
#define FLAG_ERROR 0x00000002
#define FLAG_EXE 0x00000004 // The main executable
+#define FLAG_LINKER 0x00000010 // The linker itself
#define SOINFO_NAME_LEN 128