summaryrefslogtreecommitdiff
path: root/modutils/insmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'modutils/insmod.c')
-rw-r--r--modutils/insmod.c131
1 files changed, 127 insertions, 4 deletions
diff --git a/modutils/insmod.c b/modutils/insmod.c
index 7af1359..50f272e 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -20,6 +20,12 @@
* 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>
@@ -80,6 +86,10 @@
#define BB_GOT_ENTRY_SIZE 4
#endif
+#if defined(__mips__)
+// neither used
+#endif
+
//----------------------------------------------------------------------------
//--------modutils module.h, lines 45-242
//----------------------------------------------------------------------------
@@ -109,7 +119,7 @@
#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)
@@ -1098,6 +1220,7 @@ int arch_create_got(struct obj_file *f)
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: