diff options
| -rw-r--r-- | libc/Android.mk | 1 | ||||
| -rw-r--r-- | libc/SYSCALLS.TXT | 1 | ||||
| -rw-r--r-- | libc/arch-arm/bionic/tgkill.S | 51 | ||||
| -rw-r--r-- | libc/arch-sh/syscalls.mk | 1 | ||||
| -rw-r--r-- | libc/arch-sh/syscalls/tgkill.S | 32 | ||||
| -rw-r--r-- | libc/arch-x86/syscalls.mk | 1 | ||||
| -rw-r--r-- | libc/arch-x86/syscalls/tgkill.S | 29 | ||||
| -rw-r--r-- | libc/bionic/pthread.c | 9 | ||||
| -rw-r--r-- | libc/include/sys/linux-syscalls.h | 2 | ||||
| -rw-r--r-- | libc/include/sys/linux-unistd.h | 1 | ||||
| -rw-r--r-- | linker/Android.mk | 22 | ||||
| -rw-r--r-- | linker/linker.c | 142 | ||||
| -rw-r--r-- | linker/linker.h | 1 |
13 files changed, 243 insertions, 50 deletions
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 @@ libc_common_src_files += \ 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 @@ void* __brk:brk(void*) 45 # 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/setresgid.S 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/setresgid.S 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 @@ void ATTRIBUTES _thread_created_hook(pid_t thread_id); #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 @@ static void *mkstack(size_t size, size_t guard_size) 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 @@ static void pthread_key_clean_all(void) } // 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 pthread_kill(pthread_t tid, int sig) 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 @@ int setresgid (gid_t, gid_t, gid_t); 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 @@ LOCAL_SRC_FILES:= \ 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 - -# 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_LDFLAGS := -shared -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 @@ static void free_info(soinfo *si) 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 @@ const char *addr_to_name(unsigned addr) } } - if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){ - return "linker"; - } - return ""; } @@ -354,12 +341,10 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) 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 @@ static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name) 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 @@ _do_lookup(soinfo *si, const char *name, unsigned *base) 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 @@ _do_lookup(soinfo *si, const char *name, unsigned *base) * 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 @@ static int link_image(soinfo *si, unsigned wr_offset) 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 @@ int main(int argc, char **argv) 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 @@ unsigned __linker_init(unsigned **elfdata) 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 @@ typedef struct soinfo soinfo; #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 |
