modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
authorEric Andersen <andersen@codepoet.org>
Sun, 24 Sep 2000 03:44:29 +0000 (03:44 -0000)
committerEric Andersen <andersen@codepoet.org>
Sun, 24 Sep 2000 03:44:29 +0000 (03:44 -0000)
insmod.c
modutils/insmod.c

index b0e797af76b080629f8e18650b3edd9f98400eb9..136f9f06205208af3a36eb700e985e95e31a55c1 100644 (file)
--- a/insmod.c
+++ b/insmod.c
@@ -6,6 +6,13 @@
  * Written by Erik Andersen <andersen@lineo.com>
  * and Ron Alder <alder@lineo.com>
  *
+ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+ * and (theoretically) SH3. Note that there is still no true
+ * multiple architecture support. You just get SH3|SH4|i386, despite
+ * the mention of ARM and m68k--which may or may not work (but
+ * almost certainly do not, due to at least MATCH_MACHINE). I have
+ * only tested SH4 in little endian mode.
+ *
  * 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>
@@ -70,7 +77,7 @@
 #ifndef MODUTILS_MODULE_H
 #define MODUTILS_MODULE_H 1
 
-#ident "$Id: insmod.c,v 1.23 2000/09/22 00:38:07 andersen Exp $"
+#ident "$Id: insmod.c,v 1.24 2000/09/24 03:44:29 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
@@ -276,7 +283,7 @@ int delete_module(const char *);
 #ifndef MODUTILS_OBJ_H
 #define MODUTILS_OBJ_H 1
 
-#ident "$Id: insmod.c,v 1.23 2000/09/22 00:38:07 andersen Exp $"
+#ident "$Id: insmod.c,v 1.24 2000/09/24 03:44:29 andersen Exp $"
 
 /* The relocatable object is manipulated using elfin types.  */
 
@@ -286,14 +293,41 @@ int delete_module(const char *);
 
 /* Machine-specific elf macros for i386 et al.  */
 
+/* the SH changes have only been tested on the SH4 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
+#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
+#endif
+
 #define ELFCLASSM      ELFCLASS32
 #define ELFDATAM       ELFDATA2LSB
 
-#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
 
+
+#if defined(__sh__)
+
+#define MATCH_MACHINE(x) (x == EM_SH)
+#define SHT_RELM       SHT_RELA
+#define Elf32_RelM     Elf32_Rela
+
+#else
+
+/* presumably we can use these for anything but the SH */
+/* this is the previous behavior, but it does result in
+   insmod.c being broken on anything except i386 */
+
+#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
 #define SHT_RELM       SHT_REL
 #define Elf32_RelM     Elf32_Rel
 
+#endif
 
 #ifndef ElfW
 # if ELFCLASSM == ELFCLASS32
@@ -486,24 +520,29 @@ int flag_export = 1;
 
 /*======================================================================*/
 
-struct i386_got_entry {
+/* previously, these were named i386_* but since we could be
+   compiling for the sh, I've renamed them to the more general
+   arch_* These structures are the same between the x86 and SH, 
+   and we can't support anything else right now anyway. In the
+   future maybe they should be #if defined'd */
+
+struct arch_got_entry {
        int offset;
        unsigned offset_done:1;
        unsigned reloc_done:1;
 };
 
-struct i386_file {
+struct arch_file {
        struct obj_file root;
        struct obj_section *got;
 };
 
-struct i386_symbol {
+struct arch_symbol {
        struct obj_symbol root;
-       struct i386_got_entry gotent;
+       struct arch_got_entry gotent;
 };
 
 
-
 struct external_module {
        const char *name;
        ElfW(Addr) addr;
@@ -535,6 +574,17 @@ _syscall1(int, delete_module, const char *, name)
 extern int delete_module(const char *);
 #endif
 
+/* This is kind of troublesome. See, we don't actually support
+   the m68k or the arm the same way we support i386 and (now)
+   sh. In doing my SH patch, I just assumed that whatever works
+   for i386 also works for m68k and arm since currently insmod.c
+   does nothing special for them. If this isn't true, the below
+   line is rather misleading IMHO, and someone should either
+   change it or add more proper architecture-dependent support
+   for these boys.
+
+   -- Bryan Rittmeyer <bryan@ixiacom.com>                    */
+
 #if defined(__i386__) || defined(__m68k__) || defined(__arm__)
 /* Jump through hoops to fixup error return codes */
 #define __NR__create_module  __NR_create_module
@@ -588,7 +638,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf,
 
 struct obj_file *arch_new_file(void)
 {
-       struct i386_file *f;
+       struct arch_file *f;
        f = xmalloc(sizeof(*f));
        f->got = NULL;
        return &f->root;
@@ -601,20 +651,25 @@ struct obj_section *arch_new_section(void)
 
 struct obj_symbol *arch_new_symbol(void)
 {
-       struct i386_symbol *sym;
+       struct arch_symbol *sym;
        sym = xmalloc(sizeof(*sym));
        memset(&sym->gotent, 0, sizeof(sym->gotent));
        return &sym->root;
 }
+
 enum obj_reloc
 arch_apply_relocation(struct obj_file *f,
                                          struct obj_section *targsec,
                                          struct obj_section *symsec,
                                          struct obj_symbol *sym,
+#if defined(__sh__)
+                                         Elf32_Rela * rel, Elf32_Addr v)
+#else
                                          Elf32_Rel * rel, Elf32_Addr v)
+#endif
 {
-       struct i386_file *ifile = (struct i386_file *) f;
-       struct i386_symbol *isym = (struct i386_symbol *) sym;
+       struct arch_file *ifile = (struct arch_file *) f;
+       struct arch_symbol *isym = (struct arch_symbol *) sym;
 
        Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset);
        Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
@@ -623,32 +678,86 @@ arch_apply_relocation(struct obj_file *f,
        enum obj_reloc ret = obj_reloc_ok;
 
        switch (ELF32_R_TYPE(rel->r_info)) {
+
+/* even though these constants seem to be the same for
+   the i386 and the sh, we "#if define" them for clarity
+   and in case that ever changes */
+#if defined(__sh__)
+       case R_SH_NONE:
+#else
        case R_386_NONE:
+#endif
                break;
 
+#if defined(__sh__)
+       case R_SH_DIR32:
+#else
        case R_386_32:
+#endif
                *loc += v;
                break;
 
+#if defined(__sh__)
+        case R_SH_REL32:
+#else
        case R_386_PLT32:
        case R_386_PC32:
+#endif
                *loc += v - dot;
                break;
 
+#if defined(__sh__)
+        case R_SH_PLT32:
+                *loc = v - dot;
+                break;
+#endif
+
+
+#if defined(__sh__)
+        case R_SH_GLOB_DAT:
+        case R_SH_JMP_SLOT:
+                       *loc = v;
+                break;
+#else
        case R_386_GLOB_DAT:
        case R_386_JMP_SLOT:
                *loc = v;
                break;
+#endif
 
-       case R_386_RELATIVE:
+#if defined(__sh__)
+        case R_SH_RELATIVE:
+               *loc += f->baseaddr + rel->r_addend;
+                break;
+#else
+        case R_386_RELATIVE:
                *loc += f->baseaddr;
                break;
+#endif
 
+#if defined(__sh__)
+        case R_SH_GOTPC:
+               assert(got != 0);
+               *loc += got - dot + rel->r_addend;;
+               break;
+#else
        case R_386_GOTPC:
                assert(got != 0);
                *loc += got - dot;
                break;
+#endif
 
+#if defined(__sh__)
+       case R_SH_GOT32:
+               assert(isym != NULL);
+               if (!isym->gotent.reloc_done) {
+                       isym->gotent.reloc_done = 1;
+                       *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
+                               v;
+               }
+               *loc += isym->gotent.offset + rel->r_addend;
+               break;
+#else
        case R_386_GOT32:
                assert(isym != NULL);
                if (!isym->gotent.reloc_done) {
@@ -658,8 +767,13 @@ arch_apply_relocation(struct obj_file *f,
                }
                *loc += isym->gotent.offset;
                break;
+#endif
 
+#if defined(__sh__)
+       case R_SH_GOTOFF:
+#else
        case R_386_GOTOFF:
+#endif
                assert(got != 0);
                *loc += v - got;
                break;
@@ -674,13 +788,17 @@ arch_apply_relocation(struct obj_file *f,
 
 int arch_create_got(struct obj_file *f)
 {
-       struct i386_file *ifile = (struct i386_file *) f;
+       struct arch_file *ifile = (struct arch_file *) f;
        int i, n, offset = 0, gotneeded = 0;
 
        n = ifile->root.header.e_shnum;
        for (i = 0; i < n; ++i) {
                struct obj_section *relsec, *symsec, *strsec;
+#if defined(__sh__)
+               Elf32_Rela *rel, *relend;
+#else
                Elf32_Rel *rel, *relend;
+#endif
                Elf32_Sym *symtab;
                const char *strtab;
 
@@ -691,24 +809,39 @@ int arch_create_got(struct obj_file *f)
                symsec = ifile->root.sections[relsec->header.sh_link];
                strsec = ifile->root.sections[symsec->header.sh_link];
 
+
+#if defined(__sh__)
+               rel = (Elf32_Rela *) relsec->contents;
+               relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
+#else
                rel = (Elf32_Rel *) relsec->contents;
                relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+#endif
                symtab = (Elf32_Sym *) symsec->contents;
                strtab = (const char *) strsec->contents;
 
                for (; rel < relend; ++rel) {
                        Elf32_Sym *extsym;
-                       struct i386_symbol *intsym;
+                       struct arch_symbol *intsym;
                        const char *name;
 
                        switch (ELF32_R_TYPE(rel->r_info)) {
+#if defined(__sh__)
+                       case R_SH_GOTPC:
+                       case R_SH_GOTOFF:
+#else
                        case R_386_GOTPC:
                        case R_386_GOTOFF:
+#endif
                                gotneeded = 1;
                        default:
                                continue;
 
+#if defined(__sh__)
+                       case R_SH_GOT32:
+#else
                        case R_386_GOT32:
+#endif
                                break;
                        }
 
@@ -718,7 +851,7 @@ int arch_create_got(struct obj_file *f)
                        else
                                name = f->sections[extsym->st_shndx]->name;
                        intsym =
-                               (struct i386_symbol *) obj_find_symbol(&ifile->root, name);
+                               (struct arch_symbol *) obj_find_symbol(&ifile->root, name);
 
                        if (!intsym->gotent.offset_done) {
                                intsym->gotent.offset_done = 1;
index b0e797af76b080629f8e18650b3edd9f98400eb9..136f9f06205208af3a36eb700e985e95e31a55c1 100644 (file)
@@ -6,6 +6,13 @@
  * Written by Erik Andersen <andersen@lineo.com>
  * and Ron Alder <alder@lineo.com>
  *
+ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+ * and (theoretically) SH3. Note that there is still no true
+ * multiple architecture support. You just get SH3|SH4|i386, despite
+ * the mention of ARM and m68k--which may or may not work (but
+ * almost certainly do not, due to at least MATCH_MACHINE). I have
+ * only tested SH4 in little endian mode.
+ *
  * 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>
@@ -70,7 +77,7 @@
 #ifndef MODUTILS_MODULE_H
 #define MODUTILS_MODULE_H 1
 
-#ident "$Id: insmod.c,v 1.23 2000/09/22 00:38:07 andersen Exp $"
+#ident "$Id: insmod.c,v 1.24 2000/09/24 03:44:29 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
@@ -276,7 +283,7 @@ int delete_module(const char *);
 #ifndef MODUTILS_OBJ_H
 #define MODUTILS_OBJ_H 1
 
-#ident "$Id: insmod.c,v 1.23 2000/09/22 00:38:07 andersen Exp $"
+#ident "$Id: insmod.c,v 1.24 2000/09/24 03:44:29 andersen Exp $"
 
 /* The relocatable object is manipulated using elfin types.  */
 
@@ -286,14 +293,41 @@ int delete_module(const char *);
 
 /* Machine-specific elf macros for i386 et al.  */
 
+/* the SH changes have only been tested on the SH4 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
+#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
+#endif
+
 #define ELFCLASSM      ELFCLASS32
 #define ELFDATAM       ELFDATA2LSB
 
-#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
 
+
+#if defined(__sh__)
+
+#define MATCH_MACHINE(x) (x == EM_SH)
+#define SHT_RELM       SHT_RELA
+#define Elf32_RelM     Elf32_Rela
+
+#else
+
+/* presumably we can use these for anything but the SH */
+/* this is the previous behavior, but it does result in
+   insmod.c being broken on anything except i386 */
+
+#define MATCH_MACHINE(x)  (x == EM_386 || x == EM_486)
 #define SHT_RELM       SHT_REL
 #define Elf32_RelM     Elf32_Rel
 
+#endif
 
 #ifndef ElfW
 # if ELFCLASSM == ELFCLASS32
@@ -486,24 +520,29 @@ int flag_export = 1;
 
 /*======================================================================*/
 
-struct i386_got_entry {
+/* previously, these were named i386_* but since we could be
+   compiling for the sh, I've renamed them to the more general
+   arch_* These structures are the same between the x86 and SH, 
+   and we can't support anything else right now anyway. In the
+   future maybe they should be #if defined'd */
+
+struct arch_got_entry {
        int offset;
        unsigned offset_done:1;
        unsigned reloc_done:1;
 };
 
-struct i386_file {
+struct arch_file {
        struct obj_file root;
        struct obj_section *got;
 };
 
-struct i386_symbol {
+struct arch_symbol {
        struct obj_symbol root;
-       struct i386_got_entry gotent;
+       struct arch_got_entry gotent;
 };
 
 
-
 struct external_module {
        const char *name;
        ElfW(Addr) addr;
@@ -535,6 +574,17 @@ _syscall1(int, delete_module, const char *, name)
 extern int delete_module(const char *);
 #endif
 
+/* This is kind of troublesome. See, we don't actually support
+   the m68k or the arm the same way we support i386 and (now)
+   sh. In doing my SH patch, I just assumed that whatever works
+   for i386 also works for m68k and arm since currently insmod.c
+   does nothing special for them. If this isn't true, the below
+   line is rather misleading IMHO, and someone should either
+   change it or add more proper architecture-dependent support
+   for these boys.
+
+   -- Bryan Rittmeyer <bryan@ixiacom.com>                    */
+
 #if defined(__i386__) || defined(__m68k__) || defined(__arm__)
 /* Jump through hoops to fixup error return codes */
 #define __NR__create_module  __NR_create_module
@@ -588,7 +638,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf,
 
 struct obj_file *arch_new_file(void)
 {
-       struct i386_file *f;
+       struct arch_file *f;
        f = xmalloc(sizeof(*f));
        f->got = NULL;
        return &f->root;
@@ -601,20 +651,25 @@ struct obj_section *arch_new_section(void)
 
 struct obj_symbol *arch_new_symbol(void)
 {
-       struct i386_symbol *sym;
+       struct arch_symbol *sym;
        sym = xmalloc(sizeof(*sym));
        memset(&sym->gotent, 0, sizeof(sym->gotent));
        return &sym->root;
 }
+
 enum obj_reloc
 arch_apply_relocation(struct obj_file *f,
                                          struct obj_section *targsec,
                                          struct obj_section *symsec,
                                          struct obj_symbol *sym,
+#if defined(__sh__)
+                                         Elf32_Rela * rel, Elf32_Addr v)
+#else
                                          Elf32_Rel * rel, Elf32_Addr v)
+#endif
 {
-       struct i386_file *ifile = (struct i386_file *) f;
-       struct i386_symbol *isym = (struct i386_symbol *) sym;
+       struct arch_file *ifile = (struct arch_file *) f;
+       struct arch_symbol *isym = (struct arch_symbol *) sym;
 
        Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset);
        Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
@@ -623,32 +678,86 @@ arch_apply_relocation(struct obj_file *f,
        enum obj_reloc ret = obj_reloc_ok;
 
        switch (ELF32_R_TYPE(rel->r_info)) {
+
+/* even though these constants seem to be the same for
+   the i386 and the sh, we "#if define" them for clarity
+   and in case that ever changes */
+#if defined(__sh__)
+       case R_SH_NONE:
+#else
        case R_386_NONE:
+#endif
                break;
 
+#if defined(__sh__)
+       case R_SH_DIR32:
+#else
        case R_386_32:
+#endif
                *loc += v;
                break;
 
+#if defined(__sh__)
+        case R_SH_REL32:
+#else
        case R_386_PLT32:
        case R_386_PC32:
+#endif
                *loc += v - dot;
                break;
 
+#if defined(__sh__)
+        case R_SH_PLT32:
+                *loc = v - dot;
+                break;
+#endif
+
+
+#if defined(__sh__)
+        case R_SH_GLOB_DAT:
+        case R_SH_JMP_SLOT:
+                       *loc = v;
+                break;
+#else
        case R_386_GLOB_DAT:
        case R_386_JMP_SLOT:
                *loc = v;
                break;
+#endif
 
-       case R_386_RELATIVE:
+#if defined(__sh__)
+        case R_SH_RELATIVE:
+               *loc += f->baseaddr + rel->r_addend;
+                break;
+#else
+        case R_386_RELATIVE:
                *loc += f->baseaddr;
                break;
+#endif
 
+#if defined(__sh__)
+        case R_SH_GOTPC:
+               assert(got != 0);
+               *loc += got - dot + rel->r_addend;;
+               break;
+#else
        case R_386_GOTPC:
                assert(got != 0);
                *loc += got - dot;
                break;
+#endif
 
+#if defined(__sh__)
+       case R_SH_GOT32:
+               assert(isym != NULL);
+               if (!isym->gotent.reloc_done) {
+                       isym->gotent.reloc_done = 1;
+                       *(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
+                               v;
+               }
+               *loc += isym->gotent.offset + rel->r_addend;
+               break;
+#else
        case R_386_GOT32:
                assert(isym != NULL);
                if (!isym->gotent.reloc_done) {
@@ -658,8 +767,13 @@ arch_apply_relocation(struct obj_file *f,
                }
                *loc += isym->gotent.offset;
                break;
+#endif
 
+#if defined(__sh__)
+       case R_SH_GOTOFF:
+#else
        case R_386_GOTOFF:
+#endif
                assert(got != 0);
                *loc += v - got;
                break;
@@ -674,13 +788,17 @@ arch_apply_relocation(struct obj_file *f,
 
 int arch_create_got(struct obj_file *f)
 {
-       struct i386_file *ifile = (struct i386_file *) f;
+       struct arch_file *ifile = (struct arch_file *) f;
        int i, n, offset = 0, gotneeded = 0;
 
        n = ifile->root.header.e_shnum;
        for (i = 0; i < n; ++i) {
                struct obj_section *relsec, *symsec, *strsec;
+#if defined(__sh__)
+               Elf32_Rela *rel, *relend;
+#else
                Elf32_Rel *rel, *relend;
+#endif
                Elf32_Sym *symtab;
                const char *strtab;
 
@@ -691,24 +809,39 @@ int arch_create_got(struct obj_file *f)
                symsec = ifile->root.sections[relsec->header.sh_link];
                strsec = ifile->root.sections[symsec->header.sh_link];
 
+
+#if defined(__sh__)
+               rel = (Elf32_Rela *) relsec->contents;
+               relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
+#else
                rel = (Elf32_Rel *) relsec->contents;
                relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+#endif
                symtab = (Elf32_Sym *) symsec->contents;
                strtab = (const char *) strsec->contents;
 
                for (; rel < relend; ++rel) {
                        Elf32_Sym *extsym;
-                       struct i386_symbol *intsym;
+                       struct arch_symbol *intsym;
                        const char *name;
 
                        switch (ELF32_R_TYPE(rel->r_info)) {
+#if defined(__sh__)
+                       case R_SH_GOTPC:
+                       case R_SH_GOTOFF:
+#else
                        case R_386_GOTPC:
                        case R_386_GOTOFF:
+#endif
                                gotneeded = 1;
                        default:
                                continue;
 
+#if defined(__sh__)
+                       case R_SH_GOT32:
+#else
                        case R_386_GOT32:
+#endif
                                break;
                        }
 
@@ -718,7 +851,7 @@ int arch_create_got(struct obj_file *f)
                        else
                                name = f->sections[extsym->st_shndx]->name;
                        intsym =
-                               (struct i386_symbol *) obj_find_symbol(&ifile->root, name);
+                               (struct arch_symbol *) obj_find_symbol(&ifile->root, name);
 
                        if (!intsym->gotent.offset_done) {
                                intsym->gotent.offset_done = 1;