Thought of another janitorial item for the list.
[oweals/busybox.git] / insmod.c
index 7af135902a9e9e49a0af0534bee265355343b076..50f272edb4602b67bfd90d0f9abfb548d1998a35 100644 (file)
--- a/insmod.c
+++ b/insmod.c
  *   I've only tested the code on mpc8xx platforms in big-endian mode.
  *   Did some cleanup and added BB_USE_xxx_ENTRIES...
  *
+ * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
+ *   based on modutils-2.4.2
+ *   MIPS specific support for Elf loading and relocation.
+ *   Copyright 1996, 1997 Linux International.
+ *   Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+ *
  * Based almost entirely on the Linux modutils-2.3.11 implementation.
  *   Copyright 1996, 1997 Linux International.
  *   New implementation contributed by Richard Henderson <rth@tamu.edu>
 #define BB_GOT_ENTRY_SIZE 4
 #endif
 
+#if defined(__mips__)
+// neither used
+#endif
+
 //----------------------------------------------------------------------------
 //--------modutils module.h, lines 45-242
 //----------------------------------------------------------------------------
 #ifndef MODUTILS_MODULE_H
 static const int MODUTILS_MODULE_H = 1;
 
-#ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
+#ident "$Id: insmod.c,v 1.50 2001/02/24 20:01:53 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
@@ -315,7 +325,7 @@ int delete_module(const char *);
 #ifndef MODUTILS_OBJ_H
 static const int MODUTILS_OBJ_H = 1;
 
-#ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
+#ident "$Id: insmod.c,v 1.50 2001/02/24 20:01:53 andersen Exp $"
 
 /* The relocatable object is manipulated using elfin types.  */
 
@@ -361,6 +371,18 @@ static const int MODUTILS_OBJ_H = 1;
 #define Elf32_RelM     Elf32_Rela
 #define ELFDATAM        ELFDATA2MSB
 
+#elif defined(__mips__)
+
+#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
+#define SHT_RELM       SHT_REL
+#define Elf32_RelM     Elf32_Rel
+#ifdef __MIPSEB__
+#define ELFDATAM        ELFDATA2MSB
+#endif
+#ifdef __MIPSEL__
+#define ELFDATAM        ELFDATA2LSB
+#endif
+
 #elif defined(__i386__)
 
 /* presumably we can use these for anything but the SH and ARM*/
@@ -594,6 +616,15 @@ struct arch_got_entry {
 };
 #endif
 
+#if defined(__mips__)
+struct mips_hi16
+{
+  struct mips_hi16 *next;
+  Elf32_Addr *addr;
+  Elf32_Addr value;
+};
+#endif
+
 struct arch_file {
        struct obj_file root;
 #if defined(BB_USE_PLT_ENTRIES)
@@ -602,6 +633,9 @@ struct arch_file {
 #if defined(BB_USE_GOT_ENTRIES)
        struct obj_section *got;
 #endif
+#if defined(__mips__)
+       struct mips_hi16 *mips_hi16_list;
+#endif
 };
 
 struct arch_symbol {
@@ -724,6 +758,9 @@ struct obj_file *arch_new_file(void)
 #if defined(BB_USE_GOT_ENTRIES)
        f->got = NULL;
 #endif
+#if defined(__mips__)
+       f->mips_hi16_list = NULL;
+#endif
 
        return &f->root;
 }
@@ -783,6 +820,8 @@ arch_apply_relocation(struct obj_file *f,
        case R_386_NONE:
 #elif defined(__powerpc__)
        case R_PPC_NONE:
+#elif defined(__mips__)
+       case R_MIPS_NONE:
 #endif
                break;
 
@@ -794,6 +833,8 @@ arch_apply_relocation(struct obj_file *f,
        case R_386_32:  
 #elif defined(__powerpc__)
        case R_PPC_ADDR32:
+#elif defined(__mips__)
+       case R_MIPS_32:
 #endif
                *loc += v;
                break;
@@ -812,6 +853,86 @@ arch_apply_relocation(struct obj_file *f,
                break;
 #endif
 
+#if defined(__mips__)
+       case R_MIPS_26:
+               if (v % 4)
+                       ret = obj_reloc_dangerous;
+               if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
+                       ret = obj_reloc_overflow;
+               *loc =
+                   (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
+                                           0x03ffffff);
+               break;
+
+       case R_MIPS_HI16:
+               {
+                       struct mips_hi16 *n;
+
+                       /* We cannot relocate this one now because we don't know the value
+                          of the carry we need to add.  Save the information, and let LO16
+                          do the actual relocation.  */
+                       n = (struct mips_hi16 *) xmalloc(sizeof *n);
+                       n->addr = loc;
+                       n->value = v;
+                       n->next = ifile->mips_hi16_list;
+                       ifile->mips_hi16_list = n;
+                       break;
+               }
+
+       case R_MIPS_LO16:
+               {
+                       unsigned long insnlo = *loc;
+                       Elf32_Addr val, vallo;
+
+                       /* Sign extend the addend we extract from the lo insn.  */
+                       vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+                       if (ifile->mips_hi16_list != NULL) {
+                               struct mips_hi16 *l;
+
+                               l = ifile->mips_hi16_list;
+                               while (l != NULL) {
+                                       struct mips_hi16 *next;
+                                       unsigned long insn;
+
+                                       /* The value for the HI16 had best be the same. */
+                                       assert(v == l->value);
+
+                                       /* Do the HI16 relocation.  Note that we actually don't
+                                          need to know anything about the LO16 itself, except where
+                                          to find the low 16 bits of the addend needed by the LO16.  */
+                                       insn = *l->addr;
+                                       val =
+                                           ((insn & 0xffff) << 16) +
+                                           vallo;
+                                       val += v;
+
+                                       /* Account for the sign extension that will happen in the
+                                          low bits.  */
+                                       val =
+                                           ((val >> 16) +
+                                            ((val & 0x8000) !=
+                                             0)) & 0xffff;
+
+                                       insn = (insn & ~0xffff) | val;
+                                       *l->addr = insn;
+
+                                       next = l->next;
+                                       free(l);
+                                       l = next;
+                               }
+
+                               ifile->mips_hi16_list = NULL;
+                       }
+
+                       /* Ok, we're done with the HI16 relocs.  Now deal with the LO16.  */
+                       val = v + vallo;
+                       insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+                       *loc = insnlo;
+                       break;
+               }
+#endif
+
 #if defined(__arm__)
 #elif defined(__sh__)
         case R_SH_REL32:
@@ -977,6 +1098,7 @@ arch_apply_relocation(struct obj_file *f,
 
 int arch_create_got(struct obj_file *f)
 {
+#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)
        struct arch_file *ifile = (struct arch_file *) f;
        int i;
 #if defined(BB_USE_GOT_ENTRIES)
@@ -1097,6 +1219,7 @@ int arch_create_got(struct obj_file *f)
                ifile->plt = obj_create_alloced_section(f, ".plt", 
                                                        BB_PLT_ENTRY_SIZE, 
                                                        plt_offset);
+#endif
 #endif
        return 1;
 }
@@ -2772,7 +2895,7 @@ int obj_create_image(struct obj_file *f, char *image)
        for (sec = f->load_order; sec; sec = sec->load_next) {
                char *secimg;
 
-               if (sec->header.sh_size == 0)
+               if (sec->contents == 0 || sec->header.sh_size == 0)
                        continue;
 
                secimg = image + (sec->header.sh_addr - base);
@@ -2857,7 +2980,7 @@ struct obj_file *obj_load(FILE * fp)
                sec->header = section_headers[i];
                sec->idx = i;
 
-               switch (sec->header.sh_type) {
+               if(sec->header.sh_size) switch (sec->header.sh_type) {
                case SHT_NULL:
                case SHT_NOTE:
                case SHT_NOBITS: