diff --git a/linker/Android.mk b/linker/Android.mk index 717e9c43b..60f291ce0 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -10,9 +10,27 @@ LOCAL_SRC_FILES:= \ dlfcn.c \ debugger.c -LOCAL_LDFLAGS := -shared +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_CFLAGS += -fno-stack-protector +# 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) # Set LINKER_DEBUG to either 1 or 0 # diff --git a/linker/linker.c b/linker/linker.c index cf66211db..504fb9359 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -313,6 +313,15 @@ 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; @@ -323,6 +332,10 @@ const char *addr_to_name(unsigned addr) } } + if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){ + return "linker"; + } + return ""; } @@ -341,10 +354,12 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) soinfo *si; unsigned addr = (unsigned)pc; - 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); + 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); + } } } *pcount = 0; @@ -405,33 +420,6 @@ 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; @@ -455,17 +443,7 @@ _do_lookup(soinfo *si, const char *name, unsigned *base) soinfo *lsi = si; int i; - /* 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 + /* Look for symbols in the local scope first (the object who is * searching). This happens with C++ templates on i386 for some * reason. * @@ -474,7 +452,6 @@ _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; @@ -2107,12 +2084,7 @@ int main(int argc, char **argv) static void * __tls_area[ANDROID_TLS_SLOTS]; -/* - * 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) +unsigned __linker_init(unsigned **elfdata) { static soinfo linker_soinfo; @@ -2289,80 +2261,3 @@ static unsigned __linker_init_post_relocation(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; - - /* - * Find the DYNAMIC section of the linker itself, so we can - * fix our own relocations. - */ - int i; - for (i = 0; i < linker_so.phnum; i++) { - if (phdr[i].p_type == PT_DYNAMIC) { - linker_so.dynamic = (unsigned *)(linker_so.base + phdr[i].p_vaddr); - break; - } - } - - if ((linker_so.dynamic != (unsigned char*) -1) - && 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 aa1e5e76e..7b1ba51eb 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -83,7 +83,6 @@ 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