OSDN Git Service

Patch from Paul Mundt <lethal@linux-sh.org>:
authorEric Andersen <andersen@codepoet.org>
Wed, 17 Dec 2003 08:07:14 +0000 (08:07 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 17 Dec 2003 08:07:14 +0000 (08:07 -0000)
Here's the patch for the ldso bits for sh64. This is still in need of a bunch
of debugging, testing, etc. and is really only being submitted for general
completeness. This assumes that the previous patches I've submitted have
already been applied.

I plan on playing with this and buildroot some more later, as I'd definitely
like to see buildroot images for sh64.

extra/Configs/Config.sh
ldso/ldso/sh64/boot1_arch.h [new file with mode: 0644]
ldso/ldso/sh64/dl-startup.h [new file with mode: 0644]
ldso/ldso/sh64/dl-syscalls.h [new file with mode: 0644]
ldso/ldso/sh64/dl-sysdep.h [new file with mode: 0644]
ldso/ldso/sh64/elfinterp.c [new file with mode: 0644]
ldso/ldso/sh64/ld_syscalls.h [new file with mode: 0644]
ldso/ldso/sh64/ld_sysdep.h [new file with mode: 0644]
ldso/ldso/sh64/resolve.S [new file with mode: 0644]

index 2edee55..82f9e36 100644 (file)
@@ -59,7 +59,6 @@ config CONFIG_SH4
 
 config CONFIG_SH5
        select UCLIBC_HAS_MMU
-       select ARCH_HAS_NO_LDSO
        bool "SH5"
 
 endchoice
diff --git a/ldso/ldso/sh64/boot1_arch.h b/ldso/ldso/sh64/boot1_arch.h
new file mode 100644 (file)
index 0000000..0a538ac
--- /dev/null
@@ -0,0 +1,25 @@
+/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
+ * will work as expected and cope with whatever platform specific wierdness is
+ * needed for this architecture.
+ */
+
+asm("" \
+"      .section .text..SHmedia32,\"ax\"\n"                             \
+"      .globl _dl_boot\n"                                              \
+"      .type _dl_boot, @function\n"                                    \
+"      .align 5\n"                                                     \
+"_dl_boot:\n"                                                          \
+"      ! Set r12 to point to GOT\n"                                    \
+"      movi    (((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) >> 16) & 65535), r12\n"  \
+"      shori   ((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) & 65535), r12\n"          \
+".LZZZ3:\n"                                                            \
+"      ptrel/u r12, tr0\n"                                             \
+"      gettr   tr0, r12        ! GOT address\n"                        \
+"      add     r18, r63, r11   ! save return address - needed?\n"      \
+"      add     r15, r63, r2    ! arg = stack pointer\n"                \
+"      pt      _dl_boot2, tr0  ! should work even if PIC\n"            \
+"      blink   tr0, r18        ! call _dl_boot2 - user EP is in r2\n"  \
+);
+
+#define _dl_boot _dl_boot2
+#define LD_BOOT(X)   static void * __attribute__ ((unused)) _dl_boot (X)
diff --git a/ldso/ldso/sh64/dl-startup.h b/ldso/ldso/sh64/dl-startup.h
new file mode 100644 (file)
index 0000000..0a538ac
--- /dev/null
@@ -0,0 +1,25 @@
+/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
+ * will work as expected and cope with whatever platform specific wierdness is
+ * needed for this architecture.
+ */
+
+asm("" \
+"      .section .text..SHmedia32,\"ax\"\n"                             \
+"      .globl _dl_boot\n"                                              \
+"      .type _dl_boot, @function\n"                                    \
+"      .align 5\n"                                                     \
+"_dl_boot:\n"                                                          \
+"      ! Set r12 to point to GOT\n"                                    \
+"      movi    (((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) >> 16) & 65535), r12\n"  \
+"      shori   ((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) & 65535), r12\n"          \
+".LZZZ3:\n"                                                            \
+"      ptrel/u r12, tr0\n"                                             \
+"      gettr   tr0, r12        ! GOT address\n"                        \
+"      add     r18, r63, r11   ! save return address - needed?\n"      \
+"      add     r15, r63, r2    ! arg = stack pointer\n"                \
+"      pt      _dl_boot2, tr0  ! should work even if PIC\n"            \
+"      blink   tr0, r18        ! call _dl_boot2 - user EP is in r2\n"  \
+);
+
+#define _dl_boot _dl_boot2
+#define LD_BOOT(X)   static void * __attribute__ ((unused)) _dl_boot (X)
diff --git a/ldso/ldso/sh64/dl-syscalls.h b/ldso/ldso/sh64/dl-syscalls.h
new file mode 100644 (file)
index 0000000..34da5d6
--- /dev/null
@@ -0,0 +1,9 @@
+/* Define the __set_errno macro as nothing so that we don't bother
+ * setting errno, which is important since we make system calls
+ * before the errno symbol is dynamicly linked. */
+
+#include <errno.h>
+#undef __set_errno
+#define __set_errno(X) {(void)(X);}
+#include "sys/syscall.h"
+
diff --git a/ldso/ldso/sh64/dl-sysdep.h b/ldso/ldso/sh64/dl-sysdep.h
new file mode 100644 (file)
index 0000000..241cde9
--- /dev/null
@@ -0,0 +1,170 @@
+/* vi: set sw=8 ts=8: */
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/* 
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long *)ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE)                              \
+{                                                              \
+       GOT_BASE[2] = (unsigned long)_dl_linux_resolve;         \
+       GOT_BASE[1] = (unsigned long)(MODULE);                  \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+
+/* 
+ * We need to do this stupidity here as the preprocessor will choke when
+ * SYMTAB is NULL if we do this in PERFORM_BOOTSTRAP_RELOC().
+ */
+
+#include <elf.h>
+
+static inline int __extract_lsb_from_symtab(Elf32_Sym *symtab)
+{
+       static int lsb = 0;
+
+       /* Check for SHmedia/SHcompact */
+       if (symtab)
+               lsb = symtab->st_other & 4;
+       
+       return lsb;
+}
+
+/*
+ * While on the subject of stupidity, there appear to be some conflicts with
+ * regards to several relocation types as far as binutils is concerned
+ * (Barcelona and Madrid both appear to use an out of date elf.h, whereas
+ * native Catalonia has all of the necessary definitions. As a workaround,
+ * we'll just define them here for sanity..
+ */
+#ifndef R_SH_RELATIVE_LOW16
+#  define R_SH_RELATIVE_LOW16          197
+#  define R_SH_RELATIVE_MEDLOW16       198
+#  define R_SH_IMM_LOW16               246
+#  define R_SH_IMM_LOW16_PCREL         247
+#  define R_SH_IMM_MEDLOW16            248
+#  define R_SH_IMM_MEDLOW16_PCREL      249
+#endif
+
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB)           \
+       const unsigned int r_type = ELF32_R_TYPE((RELP)->r_info);       \
+       int lsb = __extract_lsb_from_symtab(SYMTAB);                    \
+                                                                       \
+       switch (r_type) {                                               \
+       case R_SH_REL32:                                                \
+               *(REL)  = (SYMBOL) + (RELP)->r_addend                   \
+                           - (unsigned long)(REL);                     \
+               break;                                                  \
+       case R_SH_DIR32:                                                \
+       case R_SH_GLOB_DAT:                                             \
+       case R_SH_JMP_SLOT:                                             \
+               *(REL)  = ((SYMBOL) + (RELP)->r_addend) | lsb;          \
+               break;                                                  \
+       case R_SH_RELATIVE:                                             \
+               *(REL)  = (LOAD) + (RELP)->r_addend;                    \
+               break;                                                  \
+       case R_SH_RELATIVE_LOW16:                                       \
+       case R_SH_RELATIVE_MEDLOW16:                                    \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = (LOAD) + (RELP)->r_addend;                      \
+                                                                       \
+               if (r_type == R_SH_RELATIVE_MEDLOW16)                   \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_IMM_LOW16:                                            \
+       case R_SH_IMM_MEDLOW16:                                         \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = ((SYMBOL) + (RELP)->r_addend) | lsb;            \
+                                                                       \
+               if (r_type == R_SH_IMM_MEDLOW16)                        \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_IMM_LOW16_PCREL:                                      \
+       case R_SH_IMM_MEDLOW16_PCREL:                                   \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = (SYMBOL) + (RELP)->r_addend                     \
+                         - (unsigned long)(REL);                       \
+                                                                       \
+               if (r_type == R_SH_IMM_MEDLOW16_PCREL)                  \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_NONE:                                                 \
+               break;                                                  \
+       default:                                                        \
+               SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type ");  \
+               SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1);    \
+               SEND_STDERR("REL, SYMBOL, LOAD: ");                     \
+               SEND_ADDRESS_STDERR(REL, 0);                            \
+               SEND_STDERR(", ");                                      \
+               SEND_ADDRESS_STDERR(SYMBOL, 0);                         \
+               SEND_STDERR(", ");                                      \
+               SEND_ADDRESS_STDERR(LOAD, 1);                           \
+               _dl_exit(1);                                            \
+       }
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  This routine has to exit the current function, then 
+ * call the _dl_elf_main function.
+ */
+
+#define START()   return _dl_elf_main;
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+#define MAGIC1 EM_SH
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "sh64"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+
+#define do_rem(result, n, base)  result = (n % base)
+
+/* 4096 bytes alignment */
+#define PAGE_ALIGN 0xfffff000
+#define ADDR_ALIGN 0xfff
+#define OFFS_ALIGN 0x7ffff000
+
diff --git a/ldso/ldso/sh64/elfinterp.c b/ldso/ldso/sh64/elfinterp.c
new file mode 100644 (file)
index 0000000..c85e497
--- /dev/null
@@ -0,0 +1,536 @@
+/* vi: set sw=8 ts=8: */
+/*
+ * ldso/ldso/sh64/elfinterp.c
+ * 
+ * SuperH (sh64) ELF shared library loader suppport
+ *
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 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.
+ */
+
+#ifdef __SUPPORT_LD_DEBUG__
+static const char *_dl_reltypes_tab[] = {
+       /* SHcompact relocs */
+         [0] = "R_SH_NONE",            "R_SH_DIR32",
+               "R_SH_REL32",           "R_SH_DIR8WPN",
+         [4] = "R_SH_IND12W",          "R_SH_DIR8WPL",
+               "R_SH_DIR8WPZ",         "R_SH_DIR8BP",
+         [8] = "R_SH_DIR8W",           "R_SH_DIR8L",
+        [25] = "R_SH_SWITCH16",        "R_SH_SWITCH32",
+               "R_SH_USES",            "R_SH_COUNT",
+        [29] = "R_SH_ALIGN",           "R_SH_CODE",
+               "R_SH_DATA",            "R_SH_LABEL",
+        [33] = "R_SH_SWITCH8",         "R_SH_GNU_VTINHERIT",
+               "R_SH_GNU_VTENTRY",
+       [160] = "R_SH_GOT32",           "R_SH_PLT32",
+               "R_SH_COPY",            "R_SH_GLOB_DAT",
+       [164] = "R_SH_JMP_SLOT",        "R_SH_RELATIVE",
+               "R_SH_GOTOFF",          "R_SH_GOTPC",
+
+       /* SHmedia relocs */
+        [45] = "R_SH_DIR5U",           "R_SH_DIR6U",
+               "R_SH_DIR6S",           "R_SH_DIR10S",
+        [49] = "R_SH_DIR10SW",         "R_SH_DIR10SL",
+               "R_SH_DIR10SQ",
+       [169] = "R_SH_GOT_LOW16",       "R_SH_GOT_MEDLOW16",
+               "R_SH_GOT_MEDHI16",     "R_SH_GOT_HI16",
+       [173] = "R_SH_GOTPLT_LOW16",    "R_SH_GOTPLT_MEDLOW16",
+               "R_SH_GOTPLT_MEDHI16",  "R_SH_GOTPLT_HI16",
+       [177] = "R_SH_PLT_LOW16",       "R_SH_PLT_MEDLOW16",
+               "R_SH_PLT_MEDHI16",     "R_SH_PLT_HI16",
+       [181] = "R_SH_GOTOFF_LOW16",    "R_SH_GOTOFF_MEDLOW16",
+               "R_SH_GOTOFF_MEDHI16",  "R_SH_GOTOFF_HI16",
+       [185] = "R_SH_GOTPC_LOW16",     "R_SH_GOTPC_MEDLOW16",
+               "R_SH_GOTPC_MEDHI16",   "R_SH_GOTPC_HI16",
+       [189] = "R_SH_GOT10BY4",        "R_SH_GOTPLT10BY4",
+               "R_SH_GOT10BY8",        "R_SH_GOTPLT10BY8",
+       [193] = "R_SH_COPY64",          "R_SH_GLOB_DAT64",
+               "R_SH_JMP_SLOT64",      "R_SH_RELATIVE64",
+       [197] = "R_SH_RELATIVE_LOW16",  "R_SH_RELATIVE_MEDLOW16",
+               "R_SH_RELATIVE_MEDHI16","R_SH_RELATIVE_HI16",
+       [242] = "R_SH_SHMEDIA_CODE",    "R_SH_PT_16",
+               "R_SH_IMMS16",          "R_SH_IMMU16",
+       [246] = "R_SH_IMM_LOW16",       "R_SH_IMM_LOW16_PCREL",
+               "R_SH_IMM_MEDLOW16",    "R_SH_IMM_MEDLOW16_PCREL",
+       [250] = "R_SH_IMM_MEDHI16",     "R_SH_IMM_MEDHI16_PCREL",
+               "R_SH_IMM_HI16",        "R_SH_IMM_HI16_PCREL",
+       [254] = "R_SH_64",              "R_SH_64_PCREL",
+};
+
+static const char *_dl_reltypes(int type)
+{
+       static char buf[22];  
+       const char *str;
+       int tabsize;
+
+       tabsize = sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0]);
+       str     = _dl_reltypes_tab[type];
+  
+       if (type >= tabsize || str == NULL)
+               str =_dl_simple_ltoa(buf, (unsigned long)(type));
+
+       return str;
+}
+
+static void debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
+{
+       if (!_dl_debug_symbols || !symtab_index)
+               return;
+
+       _dl_dprintf(_dl_debug_file,
+               "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
+               strtab + symtab[symtab_index].st_name,
+               symtab[symtab_index].st_value,
+               symtab[symtab_index].st_size,
+               symtab[symtab_index].st_info,
+               symtab[symtab_index].st_other,
+               symtab[symtab_index].st_shndx);
+}
+
+static void debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
+{
+       if (!_dl_debug_reloc)
+               return;
+
+       if (_dl_debug_symbols) {
+               _dl_dprintf(_dl_debug_file, "\n\t");
+       } else {
+               int symtab_index;
+               const char *sym;
+
+               symtab_index = ELF32_R_SYM(rpnt->r_info);
+               sym = symtab_index ? strtab + symtab[symtab_index].st_name
+                                  : "sym=0x0";
+               _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
+       }
+
+       _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
+                   _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
+                   rpnt->r_offset);
+
+#ifdef ELF_USES_RELOCA
+       _dl_dprintf(_dl_debug_file, "\taddend=%x", rpnt->r_addend);
+#endif
+
+       _dl_dprintf(_dl_debug_file, "\n");
+
+}
+#endif /* __SUPPORT_LD_DEBUG__ */
+
+/* Program to load an ELF binary on a linux system, and run it.
+   References to symbols in sharable libraries can be resolved by either
+   an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+extern int _dl_linux_resolve(void);
+
+unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
+{
+       int reloc_type;
+       ELF_RELOC *this_reloc;
+       char *strtab;
+       Elf32_Sym *symtab;
+       int symtab_index;
+       char *rel_addr;
+       char *new_addr;
+       char **got_addr;
+       unsigned long instr_addr;
+       char *symname;
+
+       rel_addr = (char *)(tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
+
+       this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
+       reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+       symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+       symtab = (Elf32_Sym *)(intptr_t)
+               (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+       strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+       symname = strtab + symtab[symtab_index].st_name;
+
+       if (reloc_type != R_SH_JMP_SLOT) {
+               _dl_dprintf(2, "%s: Incorrect relocation type in jump reloc\n", 
+                           _dl_progname);
+               _dl_exit(1);
+       }
+       
+       /* Address of jump instruction to fix up */
+       instr_addr = ((unsigned long)this_reloc->r_offset + 
+                       (unsigned long)tpnt->loadaddr);
+       got_addr = (char **)instr_addr;
+
+
+       /* Get the address of the GOT entry */
+       new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
+       if (!new_addr) {
+               new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
+
+               if (new_addr)
+                       return (unsigned long)new_addr;
+               
+               _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
+                           _dl_progname, symname);
+               _dl_exit(1);
+       }
+
+#ifdef __SUPPORT_LD_DEBUG__
+       if ((unsigned long)got_addr < 0x20000000) {
+               if (_dl_debug_bindings) {
+                       _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
+                                   symname);
+
+                       if (_dl_debug_detail)
+                               _dl_dprintf(_dl_debug_file, 
+                                           "\n\tpatched %x ==> %x @ %x\n",
+                                           *got_addr, new_addr, got_addr);
+               }
+       }
+
+       if (!_dl_debug_nofixups)
+               *got_addr = new_addr;
+#else
+       *got_addr = new_addr;
+#endif
+
+       return (unsigned long)new_addr;
+}
+
+static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+                    unsigned long rel_addr, unsigned long rel_size,
+                    int (*reloc_fnc)(struct elf_resolve *tpnt,
+                                     struct dyn_elf *scope,
+                                     ELF_RELOC *rpnt, Elf32_Sym *symtab,
+                                     char *strtab))
+{
+       unsigned int i;
+       char *strtab;
+       Elf32_Sym *symtab;
+       ELF_RELOC *rpnt;
+       int symtab_index;
+
+       /* Now parse the relocation information */
+       rpnt = (ELF_RELOC *)(intptr_t)(rel_addr + tpnt->loadaddr);
+       rel_size = rel_size / sizeof(ELF_RELOC);
+
+       symtab = (Elf32_Sym *)(intptr_t)
+               (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+       strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+       for (i = 0; i < rel_size; i++, rpnt++) {
+               int res;
+           
+               symtab_index = ELF32_R_SYM(rpnt->r_info);
+               
+               /* When the dynamic linker bootstrapped itself, it resolved
+                  some symbols. Make sure we do not do them again */
+               if (!symtab_index && tpnt->libtype == program_interpreter)
+                       continue;
+               if (symtab_index && tpnt->libtype == program_interpreter &&
+                   _dl_symbol(strtab + symtab[symtab_index].st_name))
+                       continue;
+
+#ifdef __SUPPORT_LD_DEBUG__
+               debug_sym(symtab,strtab,symtab_index);
+               debug_reloc(symtab,strtab,rpnt);
+#endif
+
+               res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
+               if (res == 0)
+                       continue;
+
+               _dl_dprintf(2, "\n%s: ",_dl_progname);
+               
+               if (symtab_index)
+                       _dl_dprintf(2, "symbol '%s': ",
+                               strtab + symtab[symtab_index].st_name);
+                 
+               if (res < 0) {
+                       int reloc_type = ELF32_R_TYPE(rpnt->r_info);
+
+                       _dl_dprintf(2, "can't handle reloc type "
+#ifdef __SUPPORT_LD_DEBUG__
+                                       "%s\n", _dl_reltypes(reloc_type)
+#else
+                                       "%x\n", reloc_type
+#endif                 
+                       );
+
+                       _dl_exit(-res);
+               } else if (res > 0) {
+                       _dl_dprintf(2, "can't resolve symbol\n");
+
+                       return res;
+               }
+       }
+
+       return 0;
+}
+
+static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
+                       ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
+{
+        int reloc_type;
+       int symtab_index, lsb;
+       char *symname;
+       unsigned long *reloc_addr;
+       unsigned long symbol_addr;
+#ifdef __SUPPORT_LD_DEBUG__
+       unsigned long old_val;
+#endif
+  
+       reloc_type   = ELF32_R_TYPE(rpnt->r_info);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr  = 0;
+       lsb          = symtab[symtab_index].st_other & 4;
+       symname      = strtab + symtab[symtab_index].st_name;
+       reloc_addr   = (unsigned long *)(intptr_t)
+               (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
+
+       if (symtab_index) {
+               int stb;
+
+               symbol_addr = (unsigned long)_dl_find_hash(symname, scope, 
+                               (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL),
+                                symbolrel);
+
+               /*
+                * We want to allow undefined references to weak symbols - this
+                * might have been intentional. We should not be linking local
+                * symbols here, so all bases should be covered.
+                */
+               stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
+
+               if (stb == STB_GLOBAL && !symbol_addr) {
+#ifdef __SUPPORT_LD_DEBUG__
+                       _dl_dprintf(2, "\tglobal symbol '%s' "
+                                   "already defined in '%s'\n",
+                                   symname, tpnt->libname);
+#endif
+                       return 0;
+               }
+       }
+
+#ifdef __SUPPORT_LD_DEBUG__
+       old_val = *reloc_addr;
+#endif
+
+       switch (reloc_type) {
+       case R_SH_NONE:
+               break;
+       case R_SH_COPY:
+               /* handled later on */
+               break;
+       case R_SH_DIR32:
+       case R_SH_GLOB_DAT:
+       case R_SH_JMP_SLOT:
+               *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
+               break;
+       case R_SH_REL32:
+               *reloc_addr = symbol_addr + rpnt->r_addend -
+                       (unsigned long)reloc_addr;
+               break;
+       case R_SH_RELATIVE:
+               *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
+               break;
+       case R_SH_RELATIVE_LOW16:
+       case R_SH_RELATIVE_MEDLOW16:
+           {
+               unsigned long word, value;
+
+               word = (unsigned long)reloc_addr & ~0x3fffc00;
+               value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
+
+               if (reloc_type == R_SH_RELATIVE_MEDLOW16)
+                       value >>= 16;
+
+               word |= (value & 0xffff) << 10;
+               *reloc_addr = word;
+
+               break;
+           }
+       case R_SH_IMM_LOW16:
+       case R_SH_IMM_MEDLOW16:
+           {
+               unsigned long word, value;
+
+               word = (unsigned long)reloc_addr & ~0x3fffc00;
+               value = (symbol_addr + rpnt->r_addend) | lsb;
+
+               if (reloc_type == R_SH_IMM_MEDLOW16)
+                       value >>= 16;
+
+               word |= (value & 0xffff) << 10;
+               *reloc_addr = word;
+
+               break;
+           }
+       case R_SH_IMM_LOW16_PCREL:
+       case R_SH_IMM_MEDLOW16_PCREL:
+           {
+               unsigned long word, value;
+
+               word = (unsigned long)reloc_addr & ~0x3fffc00;
+               value = symbol_addr + rpnt->r_addend -
+                       (unsigned long)reloc_addr;
+
+               if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
+                       value >>= 16;
+
+               word |= (value & 0xffff) << 10;
+               *reloc_addr = word;
+
+               break;
+           }
+       default:
+               return -1; /*call _dl_exit(1) */
+       }
+
+#ifdef __SUPPORT_LD_DEBUG__
+       if (_dl_debug_reloc && _dl_debug_detail)
+               _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
+                           old_val, *reloc_addr, reloc_addr);
+#endif
+
+       return 0;
+}
+static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+                            ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
+{
+       int reloc_type, symtab_index, lsb;
+       unsigned long *reloc_addr;
+#ifdef __SUPPORT_LD_DEBUG__
+       unsigned long old_val;
+#endif
+
+       reloc_type   = ELF32_R_TYPE(rpnt->r_info);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       lsb          = symtab[symtab_index].st_other & 4;
+       reloc_addr   = (unsigned long *)(intptr_t)
+               (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
+       
+#ifdef __SUPPORT_LD_DEBUG__
+       old_val = *reloc_addr;
+#endif
+
+       switch (reloc_type) {
+       case R_SH_NONE:
+               break;
+       case R_SH_JMP_SLOT:
+               *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
+               break;
+       default:
+               return -1; /*call _dl_exit(1) */
+       }
+
+#ifdef __SUPPORT_LD_DEBUG__
+       if (_dl_debug_reloc && _dl_debug_detail)
+               _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
+                           old_val, *reloc_addr, reloc_addr);
+#endif
+
+       return 0;
+}
+
+/* This is done as a separate step, because there are cases where
+   information is first copied and later initialized.  This results in
+   the wrong information being copied.  Someone at Sun was complaining about
+   a bug in the handling of _COPY by SVr4, and this may in fact be what he
+   was talking about.  Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+   at all */
+static int _dl_do_copy(struct elf_resolve *tpnt, struct dyn_elf *scope,
+                      ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
+{
+        int reloc_type;
+       int symtab_index;
+       unsigned long *reloc_addr;
+       unsigned long symbol_addr;
+       char *symname;
+       int goof = 0;
+         
+       reloc_addr = (unsigned long *)(intptr_t)
+               (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
+       reloc_type = ELF32_R_TYPE(rpnt->r_info);
+
+       if (reloc_type != R_SH_COPY) 
+               return 0;
+
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr  = 0;
+       symname      = strtab + symtab[symtab_index].st_name;
+               
+       if (symtab_index) {
+               symbol_addr = (unsigned long)
+                       _dl_find_hash(symname, scope, NULL, copyrel);
+
+               if (!symbol_addr)
+                       goof++;
+       }
+
+       if (!goof) {
+#ifdef __SUPPORT_LD_DEBUG__
+               if (_dl_debug_move)
+                       _dl_dprintf(_dl_debug_file,
+                                   "\n%s move %x bytes from %x to %x",
+                                   symname, symtab[symtab_index].st_size,
+                                   symbol_addr, symtab[symtab_index].st_value);
+#endif
+
+               _dl_memcpy((char *)symtab[symtab_index].st_value, 
+                          (char *)symbol_addr, symtab[symtab_index].st_size);
+       }
+
+       return goof;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
+               unsigned long rel_addr, unsigned long rel_size, int type)
+{
+       _dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
+}
+
+int _dl_parse_relocation_information(struct elf_resolve *tpnt,
+               unsigned long rel_addr, unsigned long rel_size, int type)
+{
+       return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr,
+                        rel_size, _dl_do_reloc);
+}
+
+int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
+    unsigned long rel_size, int type)
+{
+       return _dl_parse(xpnt->dyn, xpnt->next, rel_addr,
+                        rel_size, _dl_do_copy);
+}
+
diff --git a/ldso/ldso/sh64/ld_syscalls.h b/ldso/ldso/sh64/ld_syscalls.h
new file mode 100644 (file)
index 0000000..34da5d6
--- /dev/null
@@ -0,0 +1,9 @@
+/* Define the __set_errno macro as nothing so that we don't bother
+ * setting errno, which is important since we make system calls
+ * before the errno symbol is dynamicly linked. */
+
+#include <errno.h>
+#undef __set_errno
+#define __set_errno(X) {(void)(X);}
+#include "sys/syscall.h"
+
diff --git a/ldso/ldso/sh64/ld_sysdep.h b/ldso/ldso/sh64/ld_sysdep.h
new file mode 100644 (file)
index 0000000..241cde9
--- /dev/null
@@ -0,0 +1,170 @@
+/* vi: set sw=8 ts=8: */
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/* 
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long *)ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE)                              \
+{                                                              \
+       GOT_BASE[2] = (unsigned long)_dl_linux_resolve;         \
+       GOT_BASE[1] = (unsigned long)(MODULE);                  \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+
+/* 
+ * We need to do this stupidity here as the preprocessor will choke when
+ * SYMTAB is NULL if we do this in PERFORM_BOOTSTRAP_RELOC().
+ */
+
+#include <elf.h>
+
+static inline int __extract_lsb_from_symtab(Elf32_Sym *symtab)
+{
+       static int lsb = 0;
+
+       /* Check for SHmedia/SHcompact */
+       if (symtab)
+               lsb = symtab->st_other & 4;
+       
+       return lsb;
+}
+
+/*
+ * While on the subject of stupidity, there appear to be some conflicts with
+ * regards to several relocation types as far as binutils is concerned
+ * (Barcelona and Madrid both appear to use an out of date elf.h, whereas
+ * native Catalonia has all of the necessary definitions. As a workaround,
+ * we'll just define them here for sanity..
+ */
+#ifndef R_SH_RELATIVE_LOW16
+#  define R_SH_RELATIVE_LOW16          197
+#  define R_SH_RELATIVE_MEDLOW16       198
+#  define R_SH_IMM_LOW16               246
+#  define R_SH_IMM_LOW16_PCREL         247
+#  define R_SH_IMM_MEDLOW16            248
+#  define R_SH_IMM_MEDLOW16_PCREL      249
+#endif
+
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB)           \
+       const unsigned int r_type = ELF32_R_TYPE((RELP)->r_info);       \
+       int lsb = __extract_lsb_from_symtab(SYMTAB);                    \
+                                                                       \
+       switch (r_type) {                                               \
+       case R_SH_REL32:                                                \
+               *(REL)  = (SYMBOL) + (RELP)->r_addend                   \
+                           - (unsigned long)(REL);                     \
+               break;                                                  \
+       case R_SH_DIR32:                                                \
+       case R_SH_GLOB_DAT:                                             \
+       case R_SH_JMP_SLOT:                                             \
+               *(REL)  = ((SYMBOL) + (RELP)->r_addend) | lsb;          \
+               break;                                                  \
+       case R_SH_RELATIVE:                                             \
+               *(REL)  = (LOAD) + (RELP)->r_addend;                    \
+               break;                                                  \
+       case R_SH_RELATIVE_LOW16:                                       \
+       case R_SH_RELATIVE_MEDLOW16:                                    \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = (LOAD) + (RELP)->r_addend;                      \
+                                                                       \
+               if (r_type == R_SH_RELATIVE_MEDLOW16)                   \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_IMM_LOW16:                                            \
+       case R_SH_IMM_MEDLOW16:                                         \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = ((SYMBOL) + (RELP)->r_addend) | lsb;            \
+                                                                       \
+               if (r_type == R_SH_IMM_MEDLOW16)                        \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_IMM_LOW16_PCREL:                                      \
+       case R_SH_IMM_MEDLOW16_PCREL:                                   \
+       {                                                               \
+               unsigned long word, value;                              \
+                                                                       \
+               word = (unsigned long)(REL) & ~0x3fffc00;               \
+               value = (SYMBOL) + (RELP)->r_addend                     \
+                         - (unsigned long)(REL);                       \
+                                                                       \
+               if (r_type == R_SH_IMM_MEDLOW16_PCREL)                  \
+                       value >>= 16;                                   \
+                                                                       \
+               word |= (value & 0xffff) << 10;                         \
+               *(REL)  = word;                                         \
+               break;                                                  \
+       }                                                               \
+       case R_SH_NONE:                                                 \
+               break;                                                  \
+       default:                                                        \
+               SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type ");  \
+               SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1);    \
+               SEND_STDERR("REL, SYMBOL, LOAD: ");                     \
+               SEND_ADDRESS_STDERR(REL, 0);                            \
+               SEND_STDERR(", ");                                      \
+               SEND_ADDRESS_STDERR(SYMBOL, 0);                         \
+               SEND_STDERR(", ");                                      \
+               SEND_ADDRESS_STDERR(LOAD, 1);                           \
+               _dl_exit(1);                                            \
+       }
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  This routine has to exit the current function, then 
+ * call the _dl_elf_main function.
+ */
+
+#define START()   return _dl_elf_main;
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+#define MAGIC1 EM_SH
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "sh64"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+
+#define do_rem(result, n, base)  result = (n % base)
+
+/* 4096 bytes alignment */
+#define PAGE_ALIGN 0xfffff000
+#define ADDR_ALIGN 0xfff
+#define OFFS_ALIGN 0x7ffff000
+
diff --git a/ldso/ldso/sh64/resolve.S b/ldso/ldso/sh64/resolve.S
new file mode 100644 (file)
index 0000000..f57b082
--- /dev/null
@@ -0,0 +1,95 @@
+/* vi: set sw=8 ts=8: */
+/* 
+ * ldso/ldso/sh64/resolve.S
+ * 
+ * SuperH (sh64) dynamic resolver support
+ *
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 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.
+ */
+
+       .section .text..SHmedia32,"ax"
+       .globl  _dl_linux_resolver
+       .globl  _dl_linux_resolve
+       .type   _dl_linux_resolve, @function
+
+       .balign 16
+_dl_linux_resolve:
+       addi    r15, -72, r15           ! make room on the stack
+       pt      _dl_linux_resolver, tr0
+       st.q    r15, 0, r2              ! save regs
+       st.q    r15, 8, r3
+       st.q    r15, 16, r4
+       st.q    r15, 24, r5
+       st.q    r15, 32, r6
+       st.q    r15, 40, r7
+       st.q    r15, 48, r8
+       st.q    r15, 56, r9
+       st.q    r15, 64, r18
+
+#ifdef HAVE_FPU
+       addi    r15, -48, r15           ! make room for FP regs
+       fst.d   r15, 0, dr0             ! save FP regs
+       fst.d   r15, 8, dr2
+       fst.d   r15, 16, dr4
+       fst.d   r15, 24, dr6
+       fst.d   r15, 32, dr8
+       fst.d   r15, 40, dr10
+#endif
+
+       /*
+        * Args for _dl_linux_resolver(), set in r17/r21 by PLT code
+        */
+
+       add     r17, r63, r2            ! link map address
+       add     r21, r63, r3            ! GOT offset
+       blink   tr0, r18                ! call _dl_linux_resolver()
+       ptabs/l r2, tr0                 ! save result = addr of function called
+       
+#ifdef HAVE_FPU
+       fld.d   r15, 0, dr0             ! restore FP regs
+       fld.d   r15, 8, dr2
+       fld.d   r15, 16, dr4
+       fld.d   r15, 24, dr6
+       fld.d   r15, 32, dr8
+       fld.d   r15, 40, dr10
+       addi    r15, 48, r15
+#endif
+
+       ld.q    r15, 0, r2              ! restore regs
+       ld.q    r15, 8, r3
+       ld.q    r15, 16, r4
+       ld.q    r15, 24, r5
+       ld.q    r15, 32, r6
+       ld.q    r15, 40, r7
+       ld.q    r15, 48, r8
+       ld.q    r15, 56, r9
+       ld.q    r15, 64, r18
+
+       addi    r15, 72, r15
+       blink   tr0, r63                ! jump to function address
+
+       .size   _dl_linux_resolve, . - _dl_linux_resolve
+