summaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-11-08 16:09:17 -0800
committerJean-Baptiste Queru <jbq@google.com>2009-11-08 16:09:17 -0800
commit10be95cffc7f2b02d8baac55a9cf1b16d8afbadb (patch)
tree372359d357eb01bd7c3160cb20339c20c317804f /linker
parent47c5e30b61bad28731e4acff2d690a4207801f27 (diff)
parentad13c57298e57d33c130fb03a2c6494da573408c (diff)
downloadbionic-10be95cffc7f2b02d8baac55a9cf1b16d8afbadb.zip
bionic-10be95cffc7f2b02d8baac55a9cf1b16d8afbadb.tar.gz
bionic-10be95cffc7f2b02d8baac55a9cf1b16d8afbadb.tar.bz2
merge from open-source master
Diffstat (limited to 'linker')
-rw-r--r--linker/Android.mk11
-rw-r--r--linker/arch/sh/begin.S50
-rw-r--r--linker/dlfcn.c12
-rw-r--r--linker/linker.c131
-rw-r--r--linker/linker.h24
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 053713c..039926c 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 53d3b01..9779290 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -367,7 +367,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
@@ -1370,6 +1370,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
@@ -1622,24 +1716,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);
@@ -1648,9 +1758,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",
@@ -1738,6 +1854,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 d289c81..2e51338 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