Patch from Paul Mundt (lethal) adding sh64 insmod support for busybox
[oweals/busybox.git] / modutils / insmod.c
index 84617fa4856dd411b07808e4c21b23d875c4c262..c5cab1997ac0c0341a279b43eaa5523c38aa1d1f 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Mini insmod implementation for busybox
  *
- * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, 
+ * This version of insmod supports x86, ARM, SH3/4/5, powerpc, m68k, 
  * MIPS, and v850e.
  *
  * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
  * very minor changes required to also work with StrongArm and presumably
  * all ARM based systems.
  *
+ * Paul Mundt <lethal@linux-sh.org> 08-Aug-2003.
+ *   Integrated support for sh64 (SH-5), from preliminary modutils
+ *   patches from Benedict Gaster <benedict.gaster@superh.com>.
+ *   Currently limited to support for 32bit ABI.
+ *
  * Magnus Damm <damm@opensource.se> 22-May-2002.
  *   The plt and got code are now using the same structs.
  *   Added generic linked list code to fully support PowerPC.
 #define Elf32_RelM     Elf32_Rela
 #define ELFCLASSM      ELFCLASS32
 
-/* the SH changes have only been tested on the SH4 in =little endian= mode */
+/* the SH changes have only been tested in =little endian= mode */
 /* I'm not sure about big endian, so let's warn: */
 
-#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__)
-#error insmod.c may require changes for use on big endian SH4/SH3
+#if defined(__sh__) && defined(__BIG_ENDIAN__)
+#error insmod.c may require changes for use on big endian SH
 #endif
 
 /* it may or may not work on the SH1/SH2... So let's error on those
    also */
-#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__))))
-#error insmod.c may require changes for non-SH3/SH4 use
+#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && \
+       (defined(__sh__))
+#error insmod.c may require changes for SH1 or SH2 use
 #endif
 #endif
 
 #ifndef MODUTILS_MODULE_H
 static const int MODUTILS_MODULE_H = 1;
 
-#ident "$Id: insmod.c,v 1.99 2003/07/22 08:56:50 andersen Exp $"
+#ident "$Id: insmod.c,v 1.100 2003/08/13 19:56:33 andersen 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
@@ -468,7 +474,7 @@ int delete_module(const char *);
 #ifndef MODUTILS_OBJ_H
 static const int MODUTILS_OBJ_H = 1;
 
-#ident "$Id: insmod.c,v 1.99 2003/07/22 08:56:50 andersen Exp $"
+#ident "$Id: insmod.c,v 1.100 2003/08/13 19:56:33 andersen Exp $"
 
 /* The relocatable object is manipulated using elfin types.  */
 
@@ -1201,7 +1207,51 @@ arch_apply_relocation(struct obj_file *f,
                *loc = v - got;
                break;
 
-#endif
+#if defined(__SH5__)
+       case R_SH_IMM_MEDLOW16:
+       case R_SH_IMM_LOW16:
+               {
+                       Elf32_Addr word;
+
+                       if (ELF32_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16)
+                               v >>= 16;
+
+                       /*
+                        *  movi and shori have the format:
+                        *
+                        *  |  op  | imm  | reg | reserved |
+                        *   31..26 25..10 9.. 4 3   ..   0
+                        *
+                        * so we simply mask and or in imm.
+                        */
+                       word = *loc & ~0x3fffc00;
+                       word |= (v & 0xffff) << 10;
+
+                       *loc = word;
+
+                       break;
+               }
+
+       case R_SH_IMM_MEDLOW16_PCREL:
+       case R_SH_IMM_LOW16_PCREL:
+               {
+                       Elf32_Addr word;
+
+                       word = *loc & ~0x3fffc00;
+
+                       v -= dot;
+
+                       if (ELF32_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL)
+                               v >>= 16;
+
+                       word |= (v & 0xffff) << 10;
+
+                       *loc = word;
+
+                       break;
+               }
+#endif /* __SH5__ */
+#endif /* __sh__ */
 
        default:
         printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
@@ -3470,14 +3520,26 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits)
 
                                /* Insert all symbols into the hash table.  */
                                for (j = 1, ++sym; j < nsym; ++j, ++sym) {
+                                       ElfW(Addr) val = sym->st_value;
                                        const char *name;
                                        if (sym->st_name)
                                                name = strtab + sym->st_name;
                                        else
                                                name = f->sections[sym->st_shndx]->name;
 
+#if defined(__SH5__)
+                                       /*
+                                        * For sh64 it is possible that the target of a branch
+                                        * requires a mode switch (32 to 16 and back again).
+                                        *
+                                        * This is implied by the lsb being set in the target
+                                        * address for SHmedia mode and clear for SHcompact.
+                                        */
+                                       val |= sym->st_other & 4;
+#endif
+
                                        obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
-                                                                  sym->st_value, sym->st_size);
+                                                                  val, sym->st_size);
                                }
                        }
                        break;