Add support for the NEC v850e processor.
authorMiles Bader <miles@lsi.nec.co.jp>
Mon, 1 Apr 2002 09:34:25 +0000 (09:34 -0000)
committerMiles Bader <miles@lsi.nec.co.jp>
Mon, 1 Apr 2002 09:34:25 +0000 (09:34 -0000)
modutils/insmod.c

index 2fa48083b0d6dbb16adfc7c38de738104cfd52a9..f53fdadeb5259abfe304e6fae84b7bbffdbc1a3e 100644 (file)
@@ -3,12 +3,14 @@
  * Mini insmod implementation for busybox
  *
  * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 
- * and MIPS.
+ * MIPS, and v850e.
  *
  * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
- * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1999,2000,2001,2002 by Erik Andersen <andersee@debian.org>
  * and Ron Alder <alder@lineo.com>
  *
+ * Modified by Miles Bader <miles@gnu.org> to support the NEC V850E.
+ *
  * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
  * and (theoretically) SH3. I have only tested SH4 in little endian mode.
  *
 // neither used
 #endif
 
+#if defined (__v850e__)
+#define CONFIG_USE_PLT_ENTRIES
+#define CONFIG_PLT_ENTRY_SIZE 8
+#endif
+
 //----------------------------------------------------------------------------
 //--------modutils module.h, lines 45-242
 //----------------------------------------------------------------------------
 #ifndef MODUTILS_MODULE_H
 static const int MODUTILS_MODULE_H = 1;
 
-#ident "$Id: insmod.c,v 1.78 2001/12/29 04:15:13 andersen Exp $"
+#ident "$Id: insmod.c,v 1.79 2002/04/01 09:34:25 miles Exp $"
 
 /* This file contains the structures used by the 2.0 and 2.1 kernels.
    We do not use the kernel headers directly because we do not wish
@@ -350,7 +357,7 @@ int delete_module(const char *);
 #ifndef MODUTILS_OBJ_H
 static const int MODUTILS_OBJ_H = 1;
 
-#ident "$Id: insmod.c,v 1.78 2001/12/29 04:15:13 andersen Exp $"
+#ident "$Id: insmod.c,v 1.79 2002/04/01 09:34:25 miles Exp $"
 
 /* The relocatable object is manipulated using elfin types.  */
 
@@ -449,6 +456,19 @@ static const int MODUTILS_OBJ_H = 1;
 #define SHT_RELM                       SHT_RELA
 #define Elf32_RelM                     Elf32_Rela
 
+#elif defined (__v850e__)
+
+#ifndef EM_CYGNUS_V850 /* grumble */
+#define EM_CYGNUS_V850                 0x9080
+#endif
+
+#define MATCH_MACHINE(x)       ((x) == EM_V850 || (x) == EM_CYGNUS_V850)
+#define SHT_RELM               SHT_RELA
+#define Elf32_RelM             Elf32_Rela
+#define ELFDATAM               ELFDATA2LSB
+
+#define SYMBOL_PREFIX  "_"
+
 #else
 #error Sorry, but insmod.c does not yet support this architecture...
 #endif
@@ -626,6 +646,12 @@ static int arch_init_module (struct obj_file *f, struct new_module *);
 
 
 
+/* SPFX is always a string, so it can be concatenated to string constants.  */
+#ifdef SYMBOL_PREFIX
+#define SPFX   SYMBOL_PREFIX
+#else
+#define SPFX   ""
+#endif
 
 
 #define _PATH_MODULES  "/lib/modules"
@@ -828,9 +854,22 @@ arch_apply_relocation(struct obj_file *f,
        case R_PPC_NONE:
 #elif defined(__mips__)
        case R_MIPS_NONE:
+#elif defined (__v850e__)
+       case R_V850_NONE:
 #endif
                break;
 
+#if defined (__v850e__)
+       case R_V850_32:
+               /* We write two shorts instead of a long because even
+                  32-bit insns only need half-word alignment, but
+                  32-bit data needs to be long-word aligned.  */
+               v += ((unsigned short *)loc)[0];
+               v += ((unsigned short *)loc)[1] << 16;
+               ((unsigned short *)loc)[0] = v & 0xffff;
+               ((unsigned short *)loc)[1] = (v >> 16) & 0xffff;
+               break;
+#else /* !__v850e__ */
 #if defined(__sh__)
        case R_SH_DIR32:
 #elif defined(__arm__)
@@ -846,6 +885,8 @@ arch_apply_relocation(struct obj_file *f,
 #endif
                *loc += v;
                break;
+#endif /* __v850e__ */
+
 #if defined(__mc68000__)
     case R_68K_8:
                if (v > 0xff)
@@ -1000,6 +1041,9 @@ arch_apply_relocation(struct obj_file *f,
 #endif
 #if defined(__powerpc__)
        case R_PPC_REL24:
+#endif
+#if defined (__v850e__)
+       case R_V850_22_PCREL:
 #endif
       /* find the plt entry and initialize it if necessary */
       assert(isym != NULL);
@@ -1020,6 +1064,13 @@ arch_apply_relocation(struct obj_file *f,
          ip[1] = 0x396b0000 + (v & 0xffff);          /* addi r11,r11,sym@l */
          ip[2] = 0x7d6903a6;                         /* mtctr r11 */
          ip[3] = 0x4e800420;                         /* bctr */
+#endif
+#if defined (__v850e__)
+               /* We have to trash a register, so we assume that any control
+                  transfer more than 21-bits away must be a function call
+                  (so we can use a call-clobbered register).  */
+               ip[0] = 0x0621 + ((v & 0xffff) << 16);   /* mov sym, r1 ... */
+               ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */
 #endif
                pe->inited = 1;
          }
@@ -1027,12 +1078,20 @@ arch_apply_relocation(struct obj_file *f,
       /* relative distance to target */
       v -= dot;
       /* if the target is too far away.... */
-      if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
-           /* go via the plt */
-           v = plt + pe->offset - dot;
-         }
+#if defined (__arm__) || defined (__powerpc__)
+      if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+#elif defined (__v850e__)
+      if ((Elf32_Sword)v > 0x1fffff || (Elf32_Sword)v < (Elf32_Sword)-0x200000)
+#endif
+             /* go via the plt */
+             v = plt + pe->offset - dot;
+
+#if defined (__v850e__)
+      if (v & 1)
+#else
       if (v & 3)
-           ret = obj_reloc_dangerous;
+#endif
+             ret = obj_reloc_dangerous;
 
       /* merge the offset into the instruction. */
 #if defined(__arm__)
@@ -1044,6 +1103,17 @@ arch_apply_relocation(struct obj_file *f,
 #if defined(__powerpc__)
       *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
 #endif
+#if defined (__v850e__)
+      /* We write two shorts instead of a long because even 32-bit insns
+        only need half-word alignment, but the 32-bit data write needs
+        to be long-word aligned.  */
+      ((unsigned short *)loc)[0] =
+             (*(unsigned short *)loc & 0xffc0) /* opcode + reg */
+             | ((v >> 16) & 0x3f);             /* offs high part */
+      ((unsigned short *)loc)[1] =
+             (v & 0xffff);                    /* offs low part */
+#endif
+
       break;
 #endif /* CONFIG_USE_PLT_ENTRIES */
 
@@ -1203,6 +1273,12 @@ static int arch_create_got(struct obj_file *f)
                                break;
 #endif
 
+#if defined (__v850e__)
+                       case R_V850_22_PCREL:
+                               pltneeded = 1;
+                               break;
+#endif
+
 #if defined(__arm__)
                        case R_ARM_PC24:
                        case R_ARM_PLT32:
@@ -1250,8 +1326,8 @@ static int arch_create_got(struct obj_file *f)
                                pltneeded = 0;
                        }
 #endif
-                       }
                }
+       }
 
 #if defined(CONFIG_USE_GOT_ENTRIES)
        if (got_offset) {
@@ -1610,19 +1686,45 @@ add_symbols_from(
        struct new_module_symbol *s;
        size_t i;
        int used = 0;
+#ifdef SYMBOL_PREFIX
+       char *name_buf = 0;
+       size_t name_alloced_size = 0;
+#endif
 
        for (i = 0, s = syms; i < nsyms; ++i, ++s) {
-
-               /* Only add symbols that are already marked external.  If we
-                  override locals we may cause problems for argument initialization.
-                  We will also create a false dependency on the module.  */
+               /* Only add symbols that are already marked external.
+                  If we override locals we may cause problems for
+                  argument initialization.  We will also create a false
+                  dependency on the module.  */
                struct obj_symbol *sym;
-
-               sym = obj_find_symbol(f, (char *) s->name);
-               if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
-                       sym = obj_add_symbol(f, (char *) s->name, -1,
-                                                                ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
-                                                                idx, s->value, 0);
+               char *name = (char *)s->name;
+
+#ifdef SYMBOL_PREFIX
+               /* Prepend SYMBOL_PREFIX to the symbol's name (the
+                  kernel exports `C names', but module object files
+                  reference `linker names').  */
+               size_t extra = sizeof SYMBOL_PREFIX;
+               size_t name_size = strlen (name) + extra;
+               if (name_size > name_alloced_size) {
+                       name_alloced_size = name_size * 2;
+                       name_buf = alloca (name_alloced_size);
+               }
+               strcpy (name_buf, SYMBOL_PREFIX);
+               strcpy (name_buf + extra - 1, name);
+               name = name_buf;
+#endif /* SYMBOL_PREFIX */
+
+               sym = obj_find_symbol(f, name);
+               if (sym && !(ELFW(ST_BIND) (sym->info) == STB_LOCAL)) {
+#ifdef SYMBOL_PREFIX
+                       /* Put NAME_BUF into more permanent storage.  */
+                       name = xmalloc (name_size);
+                       strcpy (name, name_buf);
+#endif
+                       sym = obj_add_symbol(f, name, -1,
+                                            ELFW(ST_INFO) (STB_GLOBAL,
+                                                           STT_NOTYPE),
+                                            idx, s->value, 0);
                        /* Did our symbol just get installed?  If so, mark the
                           module as "used".  */
                        if (sym->secidx == idx)
@@ -2012,9 +2114,9 @@ old_init_module(const char *m_name, struct obj_file *f,
        /* Fill in routines.  */
 
        routines.init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+               obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module"));
        routines.cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+               obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module"));
 
        /* Whew!  All of the initialization is complete.  Collect the final
           module image and give it to the kernel.  */
@@ -2053,7 +2155,7 @@ static int
 new_process_module_arguments(struct obj_file *f, int argc, char **argv)
 {
        while (argc > 0) {
-               char *p, *q, *key;
+               char *p, *q, *key, *sym_name;
                struct obj_symbol *sym;
                char *contents, *loc;
                int min, max, n;
@@ -2076,7 +2178,14 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv)
                        return 0;
                }
 
-               sym = obj_find_symbol(f, key);
+#ifdef SYMBOL_PREFIX
+               sym_name = alloca (strlen (key) + sizeof SYMBOL_PREFIX);
+               strcpy (sym_name, SYMBOL_PREFIX);
+               strcat (sym_name, key);
+#else
+               sym_name = key;
+#endif
+               sym = obj_find_symbol(f, sym_name);
 
                /* Also check that the parameter was not resolved from the kernel.  */
                if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
@@ -2440,9 +2549,9 @@ static int new_create_this_module(struct obj_file *f, const char *m_name)
                                                                                   sizeof(struct new_module));
        memset(sec->contents, 0, sizeof(struct new_module));
 
-       obj_add_symbol(f, "__this_module", -1,
-                                  ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
-                                  sizeof(struct new_module));
+       obj_add_symbol(f, SPFX "__this_module", -1,
+                      ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0,
+                      sizeof(struct new_module));
 
        obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
                                         m_name);
@@ -2468,7 +2577,7 @@ static int new_create_module_ksymtab(struct obj_file *f)
                if (!sec)
                        return 0;
 
-               tm = obj_find_symbol(f, "__this_module");
+               tm = obj_find_symbol(f, SPFX "__this_module");
                dep = (struct new_module_ref *) sec->contents;
                for (i = 0; i < n_ext_modules; ++i)
                        if (ext_modules[i].used) {
@@ -2554,9 +2663,9 @@ new_init_module(const char *m_name, struct obj_file *f,
        }
 
        module->init =
-               obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+               obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module"));
        module->cleanup =
-               obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module"));
+               obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module"));
 
        sec = obj_find_section(f, "__ex_table");
        if (sec) {
@@ -3201,9 +3310,9 @@ static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase)
 static void hide_special_symbols(struct obj_file *f)
 {
        static const char *const specials[] = {
-               "cleanup_module",
-               "init_module",
-               "kernel_version",
+               SPFX "cleanup_module",
+               SPFX "init_module",
+               SPFX "kernel_version",
                NULL
        };