diff options
author | Shin-ichiro KAWASAKI <shinichiro.kawasaki.mg@hitachi.com> | 2009-11-06 10:36:37 +0900 |
---|---|---|
committer | Tony Sim <sim.chinyeow@renesas.com> | 2009-11-06 10:36:37 +0900 |
commit | ad13c57298e57d33c130fb03a2c6494da573408c (patch) | |
tree | 9c3977ff3a5ffdd64e333ebd198717e0aee99bba /linker | |
parent | 92b10af793da235659198cf38ff2e0237c181058 (diff) | |
download | bionic-ad13c57298e57d33c130fb03a2c6494da573408c.zip bionic-ad13c57298e57d33c130fb03a2c6494da573408c.tar.gz bionic-ad13c57298e57d33c130fb03a2c6494da573408c.tar.bz2 |
added and modified linker to support SuperH architecture
Diffstat (limited to 'linker')
-rw-r--r-- | linker/Android.mk | 11 | ||||
-rw-r--r-- | linker/arch/sh/begin.S | 50 | ||||
-rw-r--r-- | linker/dlfcn.c | 12 | ||||
-rw-r--r-- | linker/linker.c | 131 | ||||
-rw-r--r-- | linker/linker.h | 24 |
5 files changed, 224 insertions, 4 deletions
diff --git a/linker/Android.mk b/linker/Android.mk index 3d3ad92..6c26eb3 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -9,7 +9,12 @@ LOCAL_SRC_FILES:= \ debugger.c \ ba.c +ifeq ($(TARGET_ARCH),sh) +# SH-4A series virtual address range from 0x00000000 to 0x7FFFFFFF. +LINKER_TEXT_BASE := 0x70000100 +else LINKER_TEXT_BASE := 0xB0000100 +endif # The maximum size set aside for the linker, from # LINKER_TEXT_BASE rounded down to a megabyte. @@ -31,7 +36,11 @@ else ifeq ($(TARGET_ARCH),x86) LOCAL_CFLAGS += -DANDROID_X86_LINKER else - $(error Unsupported TARGET_ARCH $(TARGET_ARCH)) + ifeq ($(TARGET_ARCH),sh) + LOCAL_CFLAGS += -DANDROID_SH_LINKER + else + $(error Unsupported TARGET_ARCH $(TARGET_ARCH)) + endif endif endif diff --git a/linker/arch/sh/begin.S b/linker/arch/sh/begin.S new file mode 100644 index 0000000..6f49557 --- /dev/null +++ b/linker/arch/sh/begin.S @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 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. + */ +.text +.align 4 +.type _start,#function +.globl _start + +_start: + mov r15, r4 + + mov.l 0f, r0 + jsr @r0 + nop + + /* linker init returns the _entry address in the main image */ + jmp @r0 + nop + + .balign 4 +0: .long __linker_init + + .section .ctors, "wa" + .globl __CTOR_LIST__ +__CTOR_LIST__: + .long -1 diff --git a/linker/dlfcn.c b/linker/dlfcn.c index b54674f..611bfd3 100644 --- a/linker/dlfcn.c +++ b/linker/dlfcn.c @@ -137,6 +137,12 @@ int dlclose(void *handle) #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0" +#elif defined(ANDROID_SH_LINKER) +// 0000000 00011111 111112 22222222 2333333333344444 +// 0123456 78901234 567890 12345678 9012345678901234 +#define ANDROID_LIBDL_STRTAB \ + "dlopen\0dlclose\0dlsym\0dlerror\0dl_iterate_phdr\0" + #else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */ #error Unsupported architecture. Only ARM and x86 are presently supported. #endif @@ -181,6 +187,12 @@ static Elf32_Sym libdl_symtab[] = { st_info: STB_GLOBAL << 4, st_shndx: 1, }, +#elif defined(ANDROID_SH_LINKER) + { st_name: 29, + st_value: (Elf32_Addr) &dl_iterate_phdr, + st_info: STB_GLOBAL << 4, + st_shndx: 1, + }, #endif }; diff --git a/linker/linker.c b/linker/linker.c index 27fe9d7..50eb415 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -345,7 +345,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) *pcount = 0; return NULL; } -#elif defined(ANDROID_X86_LINKER) +#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_SH_LINKER) /* Here, we only have to provide a callback to iterate across all the * loaded libraries. gcc_eh does the rest. */ int @@ -1294,6 +1294,100 @@ static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) return 0; } +#if defined(ANDROID_SH_LINKER) +static int reloc_library_a(soinfo *si, Elf32_Rela *rela, unsigned count) +{ + Elf32_Sym *symtab = si->symtab; + const char *strtab = si->strtab; + Elf32_Sym *s; + unsigned base; + Elf32_Rela *start = rela; + unsigned idx; + + for (idx = 0; idx < count; ++idx) { + unsigned type = ELF32_R_TYPE(rela->r_info); + unsigned sym = ELF32_R_SYM(rela->r_info); + unsigned reloc = (unsigned)(rela->r_offset + si->base); + unsigned sym_addr = 0; + char *sym_name = NULL; + + DEBUG("%5d Processing '%s' relocation at index %d\n", pid, + si->name, idx); + if(sym != 0) { + sym_name = (char *)(strtab + symtab[sym].st_name); + s = _do_lookup(si, sym_name, &base); + if(s == 0) { + DL_ERR("%5d cannot locate '%s'...", pid, sym_name); + return -1; + } +#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); + return -1; + } +#endif + if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) { + DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not " + "handle this yet", pid, si->name, s->st_shndx, + s->st_value); + return -1; + } + sym_addr = (unsigned)(s->st_value + base); + COUNT_RELOC(RELOC_SYMBOL); + } else { + s = 0; + } + +/* TODO: This is ugly. Split up the relocations by arch into + * different files. + */ + switch(type){ + case R_SH_JUMP_SLOT: + COUNT_RELOC(RELOC_ABSOLUTE); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, + reloc, sym_addr, sym_name); + *((unsigned*)reloc) = sym_addr; + break; + case R_SH_GLOB_DAT: + COUNT_RELOC(RELOC_ABSOLUTE); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, + reloc, sym_addr, sym_name); + *((unsigned*)reloc) = sym_addr; + break; + case R_SH_DIR32: + COUNT_RELOC(RELOC_ABSOLUTE); + MARK(rela->r_offset); + TRACE_TYPE(RELO, "%5d RELO DIR32 %08x <- %08x %s\n", pid, + reloc, sym_addr, sym_name); + *((unsigned*)reloc) += sym_addr; + break; + case R_SH_RELATIVE: + COUNT_RELOC(RELOC_RELATIVE); + MARK(rela->r_offset); + if(sym){ + DL_ERR("%5d odd RELATIVE form...", pid); + return -1; + } + TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid, + reloc, si->base); + *((unsigned*)reloc) += si->base; + break; + + default: + DL_ERR("%5d unknown reloc type %d @ %p (%d)", + pid, type, rela, (int) (rela - start)); + return -1; + } + rela++; + } + return 0; +} +#endif /* ANDROID_SH_LINKER */ + /* Please read the "Initialization and Termination functions" functions. * of the linker design note in bionic/linker/README.TXT to understand @@ -1546,24 +1640,40 @@ static int link_image(soinfo *si, unsigned wr_offset) case DT_SYMTAB: si->symtab = (Elf32_Sym *) (si->base + *d); break; +#if !defined(ANDROID_SH_LINKER) case DT_PLTREL: if(*d != DT_REL) { DL_ERR("DT_RELA not supported"); goto fail; } break; +#endif +#ifdef ANDROID_SH_LINKER + case DT_JMPREL: + si->plt_rela = (Elf32_Rela*) (si->base + *d); + break; + case DT_PLTRELSZ: + si->plt_rela_count = *d / sizeof(Elf32_Rela); + break; +#else case DT_JMPREL: si->plt_rel = (Elf32_Rel*) (si->base + *d); break; case DT_PLTRELSZ: si->plt_rel_count = *d / 8; break; +#endif case DT_REL: si->rel = (Elf32_Rel*) (si->base + *d); break; case DT_RELSZ: si->rel_count = *d / 8; break; +#ifdef ANDROID_SH_LINKER + case DT_RELASZ: + si->rela_count = *d / sizeof(Elf32_Rela); + break; +#endif case DT_PLTGOT: /* Save this in case we decide to do lazy binding. We don't yet. */ si->plt_got = (unsigned *)(si->base + *d); @@ -1572,9 +1682,15 @@ static int link_image(soinfo *si, unsigned wr_offset) // Set the DT_DEBUG entry to the addres of _r_debug for GDB *d = (int) &_r_debug; break; +#ifdef ANDROID_SH_LINKER case DT_RELA: + si->rela = (Elf32_Rela *) (si->base + *d); + break; +#else + case DT_RELA: DL_ERR("%5d DT_RELA not supported", pid); goto fail; +#endif case DT_INIT: si->init_func = (void (*)(void))(si->base + *d); DEBUG("%5d %s constructors (init func) found at %p\n", @@ -1654,6 +1770,19 @@ static int link_image(soinfo *si, unsigned wr_offset) goto fail; } +#ifdef ANDROID_SH_LINKER + if(si->plt_rela) { + DEBUG("[ %5d relocating %s plt ]\n", pid, si->name ); + if(reloc_library_a(si, si->plt_rela, si->plt_rela_count)) + goto fail; + } + if(si->rela) { + DEBUG("[ %5d relocating %s ]\n", pid, si->name ); + if(reloc_library_a(si, si->rela, si->rela_count)) + goto fail; + } +#endif /* ANDROID_SH_LINKER */ + si->flags |= FLAG_LINKED; DEBUG("[ %5d finished linking %s ]\n", pid, si->name); diff --git a/linker/linker.h b/linker/linker.h index 69042c0..2fe61b1 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -122,6 +122,14 @@ struct soinfo Elf32_Rel *rel; unsigned rel_count; +#ifdef ANDROID_SH_LINKER + Elf32_Rela *plt_rela; + unsigned plt_rela_count; + + Elf32_Rela *rela; + unsigned rela_count; +#endif /* ANDROID_SH_LINKER */ + unsigned *preinit_array; unsigned preinit_array_count; @@ -147,10 +155,15 @@ struct soinfo extern soinfo libdl_info; /* these must all be powers of two */ +#ifdef ARCH_SH +#define LIBBASE 0x60000000 +#define LIBLAST 0x70000000 +#define LIBINC 0x00100000 +#else #define LIBBASE 0x80000000 #define LIBLAST 0x90000000 #define LIBINC 0x00100000 - +#endif #ifdef ANDROID_ARM_LINKER @@ -167,6 +180,13 @@ extern soinfo libdl_info; #define R_386_JUMP_SLOT 7 #define R_386_RELATIVE 8 +#elif defined(ANDROID_SH_LINKER) + +#define R_SH_DIR32 1 +#define R_SH_GLOB_DAT 163 +#define R_SH_JUMP_SLOT 164 +#define R_SH_RELATIVE 165 + #endif /* ANDROID_*_LINKER */ @@ -209,7 +229,7 @@ const char *linker_get_error(void); #ifdef ANDROID_ARM_LINKER typedef long unsigned int *_Unwind_Ptr; _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); -#elif defined(ANDROID_X86_LINKER) +#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_SH_LINKER) int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *); #endif |