summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/insmod-modutils/obj
diff options
context:
space:
mode:
authorGuillaume Cottenceau <gc@mandriva.com>2001-02-22 17:21:43 +0000
committerGuillaume Cottenceau <gc@mandriva.com>2001-02-22 17:21:43 +0000
commit31d44a623579fbca300f20bc751c7278c4375980 (patch)
treee54cb0772ebc6ffce9fc7ccdcc61d094751d3b54 /mdk-stage1/insmod-modutils/obj
parent446293819c1c265f0799036bde77f98145187ecf (diff)
downloaddrakx-backup-do-not-use-31d44a623579fbca300f20bc751c7278c4375980.tar
drakx-backup-do-not-use-31d44a623579fbca300f20bc751c7278c4375980.tar.gz
drakx-backup-do-not-use-31d44a623579fbca300f20bc751c7278c4375980.tar.bz2
drakx-backup-do-not-use-31d44a623579fbca300f20bc751c7278c4375980.tar.xz
drakx-backup-do-not-use-31d44a623579fbca300f20bc751c7278c4375980.zip
use modutils for non Intel arch's
Diffstat (limited to 'mdk-stage1/insmod-modutils/obj')
-rw-r--r--mdk-stage1/insmod-modutils/obj/Makefile31
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_alpha.c305
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_arm.c318
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_common.c399
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_hppa.c668
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_hppa64.c686
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_i386.c245
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_ia64.c1065
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_kallsyms.c292
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_load.c354
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_m68k.c147
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_mips.c238
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_ppc.c255
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_reloc.c435
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_s390.c245
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_sparc.c226
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_sparc64.c352
17 files changed, 6261 insertions, 0 deletions
diff --git a/mdk-stage1/insmod-modutils/obj/Makefile b/mdk-stage1/insmod-modutils/obj/Makefile
new file mode 100644
index 000000000..9bcf8bac8
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/Makefile
@@ -0,0 +1,31 @@
+ #******************************************************************************
+ #
+ # insmod from modutils (generic)
+ #
+ # $Id$
+ #
+ # Copyright 1996, 1997 Linux International.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+all: libobj.a
+
+clean:
+ rm -f *.o *.a
+
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -I./../include -D_GNU_SOURCE -DELF_MACHINE_H='"elf_$(ARCH).h"' -DARCH_$(ARCH) -DCONFIG_ROOT_CHECK_OFF=0
+
+OBJS = obj_kallsyms.o obj_common.o obj_load.o obj_reloc.o obj_$(ARCH).o
+
+libobj.a: $(OBJS)
+ ar cru $@ $^
+ ranlib $@
+
+.c.o:
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -c $<
diff --git a/mdk-stage1/insmod-modutils/obj/obj_alpha.c b/mdk-stage1/insmod-modutils/obj/obj_alpha.c
new file mode 100644
index 000000000..4006b3442
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_alpha.c
@@ -0,0 +1,305 @@
+/* Alpha specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+/*======================================================================*/
+
+struct alpha_got_entry
+{
+ struct alpha_got_entry *next;
+ ElfW(Addr) addend;
+ int offset;
+ int reloc_done;
+};
+
+struct alpha_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct alpha_symbol
+{
+ struct obj_symbol root;
+ struct alpha_got_entry *got_entries;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct alpha_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct alpha_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->got_entries = NULL;
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+ struct alpha_symbol *asym = (struct alpha_symbol *)sym;
+
+ unsigned long *lloc = (unsigned long *)(targsec->contents + rel->r_offset);
+ unsigned int *iloc = (unsigned int *)lloc;
+ Elf64_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf64_Addr gp = af->got->header.sh_addr + 0x8000;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ case R_ALPHA_NONE:
+ case R_ALPHA_LITUSE:
+ break;
+
+ case R_ALPHA_REFQUAD:
+ *lloc += v;
+ break;
+
+ case R_ALPHA_GPREL32:
+ v -= gp;
+ if ((Elf64_Sxword)v > 0x7fffffff
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
+ ret = obj_reloc_overflow;
+ *iloc = v;
+ break;
+
+ case R_ALPHA_LITERAL:
+ {
+ struct alpha_got_entry *gotent;
+
+ assert(asym != NULL);
+ gotent = asym->got_entries;
+ while (gotent->addend != rel->r_addend)
+ gotent = gotent->next;
+
+ if (!gotent->reloc_done)
+ {
+ *(unsigned long *)(af->got->contents + gotent->offset) = v;
+ gotent->reloc_done = 1;
+ }
+
+ *iloc = (*iloc & ~0xffff) | ((gotent->offset - 0x8000) & 0xffff);
+ }
+ break;
+
+ case R_ALPHA_GPDISP:
+ {
+ unsigned int *p_ldah, *p_lda;
+ unsigned int i_ldah, i_lda, hi, lo;
+
+ p_ldah = iloc;
+ p_lda = (unsigned int *)((char *)iloc + rel->r_addend);
+ i_ldah = *p_ldah;
+ i_lda = *p_lda;
+
+ /* Make sure the instructions are righteous. */
+ if ((i_ldah >> 26) != 9 || (i_lda >> 26) != 8)
+ ret = obj_reloc_dangerous;
+
+ /* Extract the existing addend. */
+ v = (i_ldah & 0xffff) << 16 | (i_lda & 0xffff);
+ v = (v ^ 0x80008000) - 0x80008000;
+
+ v += gp - dot;
+
+ if ((Elf64_Sxword)v >= 0x7fff8000
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
+ ret = obj_reloc_overflow;
+
+ /* Modify the instructions and finish up. */
+ lo = v & 0xffff;
+ hi = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
+
+ *p_ldah = (i_ldah & 0xffff0000) | hi;
+ *p_lda = (i_lda & 0xffff0000) | lo;
+ }
+ break;
+
+ case R_ALPHA_BRADDR:
+ v -= dot + 4;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ else if ((Elf64_Sxword)v > 0x3fffff
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x400000)
+ ret = obj_reloc_overflow;
+ v /= 4;
+
+ *iloc = (*iloc & ~0x1fffff) | (v & 0x1fffff);
+ break;
+
+ case R_ALPHA_HINT:
+ v -= dot + 4;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ v /= 4;
+
+ *iloc = (*iloc & ~0x3fff) | (v & 0x3fff);
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+ int i, n, offset = 0;
+
+ n = af->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = af->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = af->root.sections[relsec->header.sh_link];
+ strsec = af->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ struct alpha_got_entry *ent;
+ Elf64_Sym *extsym;
+ struct alpha_symbol *intsym;
+ const char *name;
+
+ if (ELF64_R_TYPE(rel->r_info) != R_ALPHA_LITERAL)
+ continue;
+
+ extsym = &symtab[ELF64_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct alpha_symbol *)obj_find_symbol(&af->root, name);
+
+ for (ent = intsym->got_entries; ent ; ent = ent->next)
+ if (ent->addend == rel->r_addend)
+ goto found;
+
+ ent = xmalloc(sizeof(*ent));
+ ent->addend = rel->r_addend;
+ ent->offset = offset;
+ ent->reloc_done = 0;
+ ent->next = intsym->got_entries;
+ intsym->got_entries = ent;
+ offset += 8;
+
+ found:;
+ }
+ }
+
+ if (offset > 0x10000)
+ {
+ error(".got section overflow: %#x > 0x10000", offset);
+ return 0;
+ }
+
+ /* We always want a .got section so that we always have a GP for
+ use with GPDISP and GPREL32 relocs. Besides, if the section
+ is empty we don't use up space anyway. */
+ af->got = obj_create_alloced_section(&af->root, ".got", 8, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+
+ mod->gp = af->got->header.sh_addr + 0x8000;
+
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_arm.c b/mdk-stage1/insmod-modutils/obj/obj_arm.c
new file mode 100644
index 000000000..7a843f947
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_arm.c
@@ -0,0 +1,318 @@
+/* ARM specific support for Elf loading and relocation.
+ Copyright 1996, 1997, 1998 Linux International.
+
+ Contributed by Phil Blundell <philb@gnu.org>
+ and wms <woody@corelcomputer.com>
+ based on the i386 code by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct arm_plt_entry
+{
+ int offset;
+ int allocated:1;
+ int inited:1; // has been set up
+};
+
+struct arm_got_entry
+{
+ int offset;
+ int allocated : 1;
+ unsigned reloc_done : 1;
+};
+
+struct arm_file
+{
+ struct obj_file root;
+ struct obj_section *plt;
+ struct obj_section *got;
+};
+
+struct arm_symbol
+{
+ struct obj_symbol root;
+ struct arm_plt_entry pltent;
+ struct arm_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct arm_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct arm_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ memset(&sym->pltent, 0, sizeof(sym->pltent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct arm_file *afile = (struct arm_file *)f;
+ struct arm_symbol *asym = (struct arm_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = afile->got ? afile->got->header.sh_addr : 0;
+ Elf32_Addr plt = afile->plt ? afile->plt->header.sh_addr : 0;
+
+ struct arm_plt_entry *pe;
+ unsigned long *ip;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_ARM_NONE:
+ break;
+
+ case R_ARM_ABS32:
+ *loc += v;
+ break;
+
+ case R_ARM_GOT32:
+ /* needs an entry in the .got: set it, once */
+ if (! asym->gotent.reloc_done)
+ {
+ asym->gotent.reloc_done = 1;
+ *(Elf32_Addr *)(afile->got->contents + asym->gotent.offset) = v;
+ }
+ /* make the reloc with_respect_to_.got */
+ *loc += asym->gotent.offset;
+ break;
+
+ /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ (which is .got)
+ similar to branch, but is full 32 bits relative */
+ case R_ARM_GOTPC:
+ assert(got);
+ *loc += got - dot;
+ break;
+
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ /* find the plt entry and initialize it if necessary */
+ assert(asym != NULL);
+ pe = (struct arm_plt_entry*) &asym->pltent;
+ if (! pe->inited)
+ {
+ ip = (unsigned long *) (afile->plt->contents + pe->offset);
+ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
+ ip[1] = v; /* sym@ */
+ pe->inited = 1;
+ }
+
+ /* 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 (v & 3)
+ ret = obj_reloc_dangerous;
+
+ /* Convert to words. */
+ v >>= 2;
+
+ /* merge the offset into the instruction. */
+ *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
+ break;
+
+ /* address relative to the got */
+ case R_ARM_GOTOFF:
+ assert(got);
+ *loc += v - got;
+ break;
+
+ default:
+ printf("Warning: unhandled reloc %d\n",ELF32_R_TYPE(rel->r_info));
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct arm_file *afile = (struct arm_file *) f;
+ int i;
+ struct obj_section *sec, *syms, *strs;
+ ElfW(Rel) *rel, *relend;
+ ElfW(Sym) *symtab, *extsym;
+ const char *strtab, *name;
+ struct arm_symbol *intsym;
+ struct arm_plt_entry *pe;
+ struct arm_got_entry *ge;
+ int got_offset = 0, plt_offset = 0;
+
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type != SHT_RELM)
+ continue;
+ syms = f->sections[sec->header.sh_link];
+ strs = f->sections[syms->header.sh_link];
+
+ rel = (ElfW(RelM) *) sec->contents;
+ relend = rel + (sec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) syms->contents;
+ strtab = (const char *) strs->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+
+ switch(ELF32_R_TYPE(rel->r_info)) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct arm_symbol *) obj_find_symbol(f, name);
+
+ pe = &intsym->pltent;
+
+ if (! pe->allocated)
+ {
+ pe->allocated = 1;
+ pe->offset = plt_offset;
+ plt_offset += 8;
+ pe->inited = 0;
+ }
+ break;
+
+ /* these two don_t need got entries, but they need
+ the .got to exist */
+ case R_ARM_GOTOFF:
+ case R_ARM_GOTPC:
+ if (got_offset==0) got_offset = 4;
+ break;
+
+ case R_ARM_GOT32:
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct arm_symbol *) obj_find_symbol(f, name);
+
+ ge = (struct arm_got_entry *) &intsym->gotent;
+ if (! ge->allocated)
+ {
+ ge->allocated = 1;
+ ge->offset = got_offset;
+ got_offset += sizeof(void*);
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ /* if there was a _GLOBAL_OFFSET_TABLE_, then the .got section
+ exists already; find it and use it */
+ if (got_offset)
+ {
+ struct obj_section* sec = obj_find_section(f, ".got");
+ if (sec)
+ obj_extend_section(sec, got_offset);
+ else
+ {
+ sec = obj_create_alloced_section(f, ".got", 8, got_offset);
+ assert(sec);
+ }
+ afile->got = sec;
+ }
+
+ if (plt_offset)
+ afile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_common.c b/mdk-stage1/insmod-modutils/obj/obj_common.c
new file mode 100644
index 000000000..2a6606c94
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_common.c
@@ -0,0 +1,399 @@
+/* Elf file, section, and symbol manipulation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <obj.h>
+#include <util.h>
+#include <module.h>
+
+/*======================================================================*/
+
+/* Standard ELF hash function. */
+inline unsigned long
+obj_elf_hash_n(const char *name, unsigned long n)
+{
+ unsigned long h = 0;
+ unsigned long g;
+ unsigned char ch;
+
+ while (n > 0)
+ {
+ ch = *name++;
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0)
+ {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ n--;
+ }
+ return h;
+}
+
+unsigned long
+obj_elf_hash (const char *name)
+{
+ return obj_elf_hash_n(name, strlen(name));
+}
+
+void
+obj_set_symbol_compare (struct obj_file *f,
+ int (*cmp)(const char *, const char *),
+ unsigned long (*hash)(const char *))
+{
+ if (cmp)
+ f->symbol_cmp = cmp;
+ if (hash)
+ {
+ struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+ int i;
+
+ f->symbol_hash = hash;
+
+ memcpy(tmptab, f->symtab, sizeof(tmptab));
+ memset(f->symtab, 0, sizeof(f->symtab));
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = tmptab[i]; sym ; sym = next)
+ {
+ unsigned long h = hash(sym->name) % HASH_BUCKETS;
+ next = sym->next;
+ sym->next = f->symtab[h];
+ f->symtab[h] = sym;
+ }
+ }
+}
+
+struct obj_symbol *
+obj_add_symbol (struct obj_file *f, const char *name, unsigned long symidx,
+ int info, int secidx, ElfW(Addr) value, unsigned long size)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+ int n_type = ELFW(ST_TYPE)(info);
+ int n_binding = ELFW(ST_BIND)(info);
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ {
+ int o_secidx = sym->secidx;
+ int o_info = sym->info;
+ int o_type = ELFW(ST_TYPE)(o_info);
+ int o_binding = ELFW(ST_BIND)(o_info);
+
+ /* A redefinition! Is it legal? */
+
+ if (secidx == SHN_UNDEF)
+ return sym;
+ else if (o_secidx == SHN_UNDEF)
+ goto found;
+ else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL)
+ {
+ /* Cope with local and global symbols of the same name
+ in the same object file, as might have been created
+ by ld -r. The only reason locals are now seen at this
+ level at all is so that we can do semi-sensible things
+ with parameters. */
+
+ struct obj_symbol *nsym, **p;
+
+ nsym = arch_new_symbol();
+ nsym->next = sym->next;
+ nsym->ksymidx = -1;
+
+ /* Excise the old (local) symbol from the hash chain. */
+ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+ continue;
+ *p = sym = nsym;
+ goto found;
+ }
+ else if (n_binding == STB_LOCAL)
+ {
+ /* Another symbol of the same name has already been defined.
+ Just add this to the local table. */
+ sym = arch_new_symbol();
+ sym->next = NULL;
+ sym->ksymidx = -1;
+ f->local_symtab[symidx] = sym;
+ goto found;
+ }
+ else if (n_binding == STB_WEAK)
+ return sym;
+ else if (o_binding == STB_WEAK)
+ goto found;
+ /* Don't unify COMMON symbols with object types the programmer
+ doesn't expect. */
+ else if (secidx == SHN_COMMON
+ && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+ return sym;
+ else if (o_secidx == SHN_COMMON
+ && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+ goto found;
+ else
+ {
+ /* Don't report an error if the symbol is coming from
+ the kernel or some external module. */
+ if (secidx <= SHN_HIRESERVE)
+ error("%s multiply defined", name);
+ return sym;
+ }
+ }
+
+ /* Completely new symbol. */
+ sym = arch_new_symbol();
+ sym->next = f->symtab[hash];
+ f->symtab[hash] = sym;
+ sym->ksymidx = -1;
+
+ if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
+ if (symidx >= f->local_symtab_size)
+ error("local symbol %s with index %ld exceeds local_symtab_size %ld",
+ name, (long) symidx, (long) f->local_symtab_size);
+ else
+ f->local_symtab[symidx] = sym;
+ }
+
+found:
+ sym->name = name;
+ sym->value = value;
+ sym->size = size;
+ sym->secidx = secidx;
+ sym->info = info;
+ sym->r_type = 0; /* should be R_arch_NONE for all arch */
+
+ return sym;
+}
+
+struct obj_symbol *
+obj_find_symbol (struct obj_file *f, const char *name)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ return sym;
+
+ return NULL;
+}
+
+ElfW(Addr)
+obj_symbol_final_value (struct obj_file *f, struct obj_symbol *sym)
+{
+ if (sym)
+ {
+ if (sym->secidx >= SHN_LORESERVE)
+ return sym->value;
+
+ return sym->value + f->sections[sym->secidx]->header.sh_addr;
+ }
+ else
+ {
+ /* As a special case, a NULL sym has value zero. */
+ return 0;
+ }
+}
+
+struct obj_section *
+obj_find_section (struct obj_file *f, const char *name)
+{
+ int i, n = f->header.e_shnum;
+
+ for (i = 0; i < n; ++i)
+ if (strcmp(f->sections[i]->name, name) == 0)
+ return f->sections[i];
+
+ return NULL;
+}
+
+static int
+obj_load_order_prio(struct obj_section *a)
+{
+ unsigned long af, ac;
+
+ af = a->header.sh_flags;
+
+ ac = 0;
+ if (a->name[0] != '.' || strlen(a->name) != 10 ||
+ strcmp(a->name + 5, ".init")) ac |= 32;
+ if (af & SHF_ALLOC) ac |= 16;
+ if (!(af & SHF_WRITE)) ac |= 8;
+ if (af & SHF_EXECINSTR) ac |= 4;
+ if (a->header.sh_type != SHT_NOBITS) ac |= 2;
+#if defined(ARCH_ia64)
+ if (af & SHF_IA_64_SHORT) ac -= 1;
+#endif
+
+ return ac;
+}
+
+void
+obj_insert_section_load_order (struct obj_file *f, struct obj_section *sec)
+{
+ struct obj_section **p;
+ int prio = obj_load_order_prio(sec);
+ for (p = f->load_order_search_start; *p ; p = &(*p)->load_next)
+ if (obj_load_order_prio(*p) < prio)
+ break;
+ sec->load_next = *p;
+ *p = sec;
+}
+
+struct obj_section *
+obj_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+struct obj_section *
+obj_create_alloced_section_first (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ sec->load_next = f->load_order;
+ f->load_order = sec;
+ if (f->load_order_search_start == &f->load_order)
+ f->load_order_search_start = &sec->load_next;
+
+ return sec;
+}
+
+void *
+obj_extend_section (struct obj_section *sec, unsigned long more)
+{
+ unsigned long oldsize = sec->header.sh_size;
+ sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+ return sec->contents + oldsize;
+}
+
+/* Convert an object pointer (address) to a native pointer and vice versa.
+ * It gets interesting when the object has 64 bit pointers but modutils
+ * is running 32 bit. This is nasty code but it stops the compiler giving
+ * spurious warning messages. "I know what I am doing" ...
+ */
+
+void *
+obj_addr_to_native_ptr (ElfW(Addr) addr)
+{
+ unsigned int convert = (sizeof(void *) << 8) + sizeof(addr); /* to, from */
+ union obj_ptr_4 p4;
+ union obj_ptr_8 p8;
+ switch (convert) {
+ case 0x0404:
+ p4.addr = addr;
+ return(p4.ptr);
+ break;
+ case 0x0408:
+ p4.addr = addr;
+ if (p4.addr != addr) {
+ error("obj_addr_to_native_ptr truncation %" tgt_long_fmt "x",
+ (tgt_long) addr);
+ exit(1);
+ }
+ return(p4.ptr);
+ break;
+ case 0x0804:
+ p8.addr = addr;
+ return(p8.ptr);
+ break;
+ case 0x0808:
+ p8.addr = addr;
+ return(p8.ptr);
+ break;
+ default:
+ error("obj_addr_to_native_ptr unknown conversion 0x%04x", convert);
+ exit(1);
+ }
+}
+
+ElfW(Addr)
+obj_native_ptr_to_addr (void *ptr)
+{
+ unsigned int convert = (sizeof(ElfW(Addr)) << 8) + sizeof(ptr); /* to, from */
+ union obj_ptr_4 p4;
+ union obj_ptr_8 p8;
+ switch (convert) {
+ case 0x0404:
+ p4.ptr = ptr;
+ return(p4.addr);
+ break;
+ case 0x0408:
+ p8.ptr = ptr;
+ p4.addr = p8.addr;
+ if (p4.addr != p8.addr) {
+ error("obj_native_ptr_to_addr truncation %" tgt_long_fmt "x",
+ (tgt_long) p8.addr);
+ exit(1);
+ }
+ return(p4.addr);
+ break;
+ case 0x0804:
+ p4.ptr = ptr;
+ return(p4.addr); /* compiler expands to 8 */
+ break;
+ case 0x0808:
+ p8.ptr = ptr;
+ return(p8.addr);
+ break;
+ default:
+ error("obj_native_ptr_to_addr unknown conversion 0x%04x", convert);
+ exit(1);
+ }
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_hppa.c b/mdk-stage1/insmod-modutils/obj/obj_hppa.c
new file mode 100644
index 000000000..4207e692e
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_hppa.c
@@ -0,0 +1,668 @@
+/*
+ * PA-RISC specific support for Elf loading and relocation.
+ * Copyright 2000 David Huggins-Daines <dhd@linuxcare.com>, Linuxcare Inc.
+ * Copyright 2000 Richard Hirst <rhirst@linuxcare.com>, Linuxcare Inc.
+ *
+ * Based on the IA-64 support, which is:
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+#include <modstat.h> /* For ksyms */
+
+
+typedef struct _hppa_stub_t
+{
+ struct _hppa_stub_t *next;
+ int offset;
+ int reloc_done;
+} hppa_stub_t;
+
+typedef struct _hppa_symbol_t
+{
+ struct obj_symbol root;
+ hppa_stub_t *stub;
+} hppa_symbol_t;
+
+typedef struct _hppa_file_t
+{
+ struct obj_file root;
+ struct obj_section *stub;
+ Elf32_Addr dp;
+} hppa_file_t;
+
+/* The ABI defines various more esoteric types, but these are the only
+ ones we actually need. */
+enum hppa_fsel
+{
+ e_fsel,
+ e_lsel,
+ e_rsel,
+ e_lrsel,
+ e_rrsel
+};
+
+/* This could be a call to obj_create_alloced_section() followed
+ * by an overwrite of sec->header.sh_flags.
+ */
+
+struct obj_section *
+obj_hppa_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size,
+ unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+struct obj_file *
+arch_new_file (void)
+{
+ hppa_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->stub = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ hppa_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->stub = NULL;
+ return &sym->root;
+}
+
+/* This is called for architecture specific sections we might need to
+ do special things to. */
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+/* =================================================================
+
+ These functions are from libhppa.h in the GNU BFD library.
+ (c) 1990, 91, 92, 93, 94, 95, 96, 98, 99, 2000
+ Free Software Foundation, Inc.
+
+ ================================================================= */
+
+/* The *sign_extend functions are used to assemble various bitfields
+ taken from an instruction and return the resulting immediate
+ value. */
+
+static inline int
+sign_extend (x, len)
+ int x, len;
+{
+ int signbit = (1 << (len - 1));
+ int mask = (signbit << 1) - 1;
+ return ((x & mask) ^ signbit) - signbit;
+}
+
+static inline int
+low_sign_extend (x, len)
+ int x, len;
+{
+ return (x >> 1) - ((x & 1) << (len - 1));
+}
+
+
+/* The re_assemble_* functions prepare an immediate value for
+ insertion into an opcode. pa-risc uses all sorts of weird bitfields
+ in the instruction to hold the value. */
+
+static inline int
+sign_unext (x, len)
+ int x, len;
+{
+ int len_ones;
+
+ len_ones = (1 << len) - 1;
+
+ return x & len_ones;
+}
+
+static inline int
+low_sign_unext (x, len)
+ int x, len;
+{
+ int temp;
+ int sign;
+
+ sign = (x >> (len-1)) & 1;
+
+ temp = sign_unext (x, len-1);
+
+ return (temp << 1) | sign;
+}
+
+static inline int
+re_assemble_3 (as3)
+ int as3;
+{
+ return (( (as3 & 4) << (13-2))
+ | ((as3 & 3) << (13+1)));
+}
+
+static inline int
+re_assemble_12 (as12)
+ int as12;
+{
+ return (( (as12 & 0x800) >> 11)
+ | ((as12 & 0x400) >> (10 - 2))
+ | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_14 (as14)
+ int as14;
+{
+ return (( (as14 & 0x1fff) << 1)
+ | ((as14 & 0x2000) >> 13));
+}
+
+static inline int
+re_assemble_16 (as16)
+ int as16;
+{
+ int s, t;
+
+ /* Unusual 16-bit encoding, for wide mode only. */
+ t = (as16 << 1) & 0xffff;
+ s = (as16 & 0x8000);
+ return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+static inline int
+re_assemble_17 (as17)
+ int as17;
+{
+ return (( (as17 & 0x10000) >> 16)
+ | ((as17 & 0x0f800) << (16 - 11))
+ | ((as17 & 0x00400) >> (10 - 2))
+ | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_21 (as21)
+ int as21;
+{
+ return (( (as21 & 0x100000) >> 20)
+ | ((as21 & 0x0ffe00) >> 8)
+ | ((as21 & 0x000180) << 7)
+ | ((as21 & 0x00007c) << 14)
+ | ((as21 & 0x000003) << 12));
+}
+
+static inline int
+re_assemble_22 (as22)
+ int as22;
+{
+ return (( (as22 & 0x200000) >> 21)
+ | ((as22 & 0x1f0000) << (21 - 16))
+ | ((as22 & 0x00f800) << (16 - 11))
+ | ((as22 & 0x000400) >> (10 - 2))
+ | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+
+/* Handle field selectors for PA instructions.
+ The L and R (and LS, RS etc.) selectors are used in pairs to form a
+ full 32 bit address. eg.
+
+ LDIL L'start,%r1 ; put left part into r1
+ LDW R'start(%r1),%r2 ; add r1 and right part to form address
+
+ This function returns sign extended values in all cases.
+*/
+
+static inline unsigned int
+hppa_field_adjust (value, addend, r_field)
+ unsigned int value;
+ int addend;
+ enum hppa_fsel r_field;
+{
+ unsigned int sym_val;
+
+ sym_val = value - addend;
+ switch (r_field)
+ {
+ case e_fsel:
+ /* F: No change. */
+ break;
+
+ case e_lsel:
+ /* L: Select top 21 bits. */
+ value = value >> 11;
+ break;
+
+ case e_rsel:
+ /* R: Select bottom 11 bits. */
+ value = value & 0x7ff;
+ break;
+
+ case e_lrsel:
+ /* LR: L with rounding of the addend to nearest 8k. */
+ value = sym_val + ((addend + 0x1000) & -0x2000);
+ value = value >> 11;
+ break;
+
+ case e_rrsel:
+ /* RR: R with rounding of the addend to nearest 8k.
+ We need to return a value such that 2048 * LR'x + RR'x == x
+ ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800))
+ . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000))
+ . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */
+ value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000);
+ break;
+
+ default:
+ abort();
+ }
+ return value;
+}
+
+/* Insert VALUE into INSN using R_FORMAT to determine exactly what
+ bits to change. */
+
+static inline int
+hppa_rebuild_insn (insn, value, r_format)
+ int insn;
+ int value;
+ int r_format;
+{
+ switch (r_format)
+ {
+ case 11:
+ return (insn & ~ 0x7ff) | low_sign_unext (value, 11);
+
+ case 12:
+ return (insn & ~ 0x1ffd) | re_assemble_12 (value);
+
+
+ case 10:
+ return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8);
+
+ case -11:
+ return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4);
+
+ case 14:
+ return (insn & ~ 0x3fff) | re_assemble_14 (value);
+
+
+ case -10:
+ return (insn & ~ 0xfff1) | re_assemble_16 (value & -8);
+
+ case -16:
+ return (insn & ~ 0xfff9) | re_assemble_16 (value & -4);
+
+ case 16:
+ return (insn & ~ 0xffff) | re_assemble_16 (value);
+
+
+ case 17:
+ return (insn & ~ 0x1f1ffd) | re_assemble_17 (value);
+
+ case 21:
+ return (insn & ~ 0x1fffff) | re_assemble_21 (value);
+
+ case 22:
+ return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value);
+
+ case 32:
+ return value;
+
+ default:
+ abort ();
+ }
+ return insn;
+}
+
+/* ====================================================================
+
+ End of functions from GNU BFD.
+
+ ==================================================================== */
+
+/* This is where we get the opportunity to create any extra dynamic
+ sections we might need. In our case we do not need a GOT because
+ our code is not PIC, but we do need to create a stub section.
+
+ This is significantly less complex than what we do for shared
+ libraries because, obviously, modules are not shared. Also we have
+ no issues related to symbol visibility, lazy linking, etc.
+ The kernels dp is fixed (at symbol data_start), and we can fix up any
+ DPREL refs in the module to use that same dp value.
+ All PCREL17F refs result in a stub with the following format:
+
+ ldil L'func_addr,%r1
+ be,n R'func_addr(%sr4,%r1)
+
+ Note, all PCREL17F get a stub, regardless of whether they are
+ local or external. With local ones, and external ones to other
+ modules, there is a good chance we could manage without the stub.
+ I'll leave that for a future optimisation.
+ */
+
+#define LDIL_R1 0x20200000 /* ldil L'XXX,%r1 */
+#define BE_N_SR4_R1 0xe0202002 /* be,n R'XXX(%sr4,%r1) */
+
+#define STUB_SIZE 8
+
+int
+arch_create_got(struct obj_file *f)
+{
+ hppa_file_t *hfile = (hppa_file_t *)f;
+ int i, n;
+ int stub_offset = 0;
+
+ /* Create stub section.
+ * XXX set flags, see obj_ia64.c
+ */
+ hfile->stub = obj_create_alloced_section(f, ".stub", STUB_SIZE, 0);
+
+ /* Actually this is a lot like check_relocs() in a BFD backend. We
+ walk all sections and all their relocations and look for ones
+ that need special treatment. */
+ n = hfile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf32_Rela *rel, *relend;
+ Elf32_Sym *symtab;
+ char const *strtab;
+
+ relsec = hfile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = hfile->root.sections[relsec->header.sh_link];
+ strsec = hfile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (char const *)strsec->contents;
+
+ for (; rel < relend; rel++)
+ {
+ int need_stub = 0;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ default:
+ continue;
+
+ case R_PARISC_PCREL17F:
+ need_stub = 1;
+ break;
+ }
+
+ if (need_stub)
+ {
+ Elf32_Sym *extsym;
+ hppa_symbol_t *hsym;
+ char const *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF32_R_SYM(rel->r_info);
+ extsym = symtab + symndx;
+ if (ELF32_ST_BIND(extsym->st_info) == STB_LOCAL)
+ hsym = (hppa_symbol_t *) f->local_symtab[symndx];
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ hsym = (hppa_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = hsym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_stub)
+ {
+ hppa_stub_t *stub;
+
+ if (hsym->stub == NULL)
+ {
+ stub = (hppa_stub_t *) xmalloc(sizeof(hppa_stub_t));
+ stub->offset = stub_offset;
+ stub->reloc_done = 0;
+ hsym->stub = stub;
+ stub_offset += STUB_SIZE;
+ need_stub = 0;
+ }
+ }
+ }
+ }
+ }
+ if (stub_offset)
+ {
+ hfile->stub->contents = xmalloc(stub_offset);
+ hfile->stub->header.sh_size = stub_offset;
+ }
+ return 1;
+}
+
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ hppa_file_t *hfile = (hppa_file_t *) f;
+ hppa_symbol_t *hsym = (hppa_symbol_t *) sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+ Elf32_Addr dp = hfile->dp;
+ Elf32_Word r_info = ELF32_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+ enum hppa_fsel fsel = e_fsel; /* Avoid compiler warning */
+ unsigned int r_format;
+
+ /* Fix up the value, and determine whether we can handle this
+ relocation. */
+ switch (r_info)
+ {
+ case R_PARISC_PLABEL32:
+ case R_PARISC_DIR32:
+ case R_PARISC_DIR21L:
+ case R_PARISC_DIR14R:
+ /* Easy. */
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DPREL14R:
+ v -= dp;
+ break;
+
+ case R_PARISC_PCREL17F:
+ /* Find an import stub. */
+ assert(hsym->stub != NULL);
+ assert(hfile->stub != NULL);
+ /* XXX Optimise. We may not need a stub for short branches */
+ if (!hsym->stub->reloc_done) {
+ /* Need to create the .stub entry */
+ Elf32_Addr *pstub, stubv;
+
+ pstub = (Elf32_Addr *)(hfile->stub->contents + hsym->stub->offset);
+ pstub[0] = LDIL_R1;
+ pstub[1] = BE_N_SR4_R1;
+ stubv = hppa_field_adjust(v, rel->r_addend, e_lrsel);
+ pstub[0] = hppa_rebuild_insn(pstub[0], stubv, 21);
+ stubv = hppa_field_adjust(v, rel->r_addend, e_rrsel);
+ stubv >>= 2; /* Branch; divide by 4 */
+ pstub[1] = hppa_rebuild_insn(pstub[1], stubv, 17);
+ hsym->stub->reloc_done = 1;
+ }
+ v = hsym->stub->offset + hfile->stub->header.sh_addr;
+ break;
+
+ default:
+ return obj_reloc_unhandled;
+ }
+
+ /* Find the field selector. */
+ switch (r_info)
+ {
+ case R_PARISC_DIR32:
+ case R_PARISC_PLABEL32:
+ case R_PARISC_PCREL17F:
+ fsel = e_fsel;
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DIR21L:
+ fsel = e_lrsel;
+ break;
+
+ case R_PARISC_DPREL14R:
+ case R_PARISC_DIR14R:
+ fsel = e_rrsel;
+ break;
+ }
+
+ v = hppa_field_adjust(v, rel->r_addend, fsel);
+
+ switch (r_info)
+ {
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL17R:
+ case R_PARISC_PCREL22F:
+ v = v - dot - 8;
+ case R_PARISC_DIR17F:
+ case R_PARISC_DIR17R:
+ /* This is a branch. Divide the offset by four. */
+ v >>= 2;
+ break;
+ default:
+ break;
+ }
+
+ /* Find the format. */
+ switch (r_info)
+ {
+ case R_PARISC_DIR32:
+ case R_PARISC_PLABEL32:
+ r_format = 32;
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DIR21L:
+ r_format = 21;
+ break;
+
+ case R_PARISC_PCREL17F:
+ r_format = 17;
+ break;
+
+ case R_PARISC_DPREL14R:
+ case R_PARISC_DIR14R:
+ r_format = 14;
+ break;
+
+ default:
+ abort();
+ }
+
+ *loc = hppa_rebuild_insn(*loc, v, r_format);
+
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *sec)
+{
+ struct module_symbol *s;
+ int i;
+ hppa_file_t *hfile = (hppa_file_t *)f;
+
+ /* Initialise dp to the kernels dp (symbol data_start)
+ */
+ for (i = 0, s = ksyms; i < nksyms; i++, s++)
+ if (!strcmp((char *)s->name, "data_start"))
+ break;
+ if (i >= nksyms) {
+ error("Cannot initialise dp, 'data_start' not found\n");
+ return 1;
+ }
+ hfile->dp = s->value;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/insmod-modutils/obj/obj_hppa64.c b/mdk-stage1/insmod-modutils/obj/obj_hppa64.c
new file mode 100644
index 000000000..fe32911ff
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_hppa64.c
@@ -0,0 +1,686 @@
+/*
+ * hppa parisc64 specific support for Elf loading and relocation.
+ * Copyright 2000 Richard Hirst <rhirst@linuxcare.com>, Linuxcare Inc.
+ *
+ * Based on ia64 specific support which was
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE ~FALSE
+#endif
+
+/*======================================================================*/
+
+typedef struct _hppa64_opd_t
+{
+ int offset;
+ int reloc_done;
+} hppa64_opd_t;
+
+typedef struct _hppa64_stub_t
+{
+ struct _hppa64_stub_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} hppa64_stub_t;
+
+typedef struct _hppa64_got_t
+{
+ struct _hppa64_got_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} hppa64_got_t;
+
+typedef struct _hppa64_symbol_t
+{
+ struct obj_symbol root;
+ hppa64_got_t *gotent;
+ hppa64_opd_t *opdent;
+ hppa64_stub_t *stubent;
+} hppa64_symbol_t;
+
+typedef struct _hppa64_file_t
+{
+ struct obj_file root;
+ struct obj_section *got;
+ struct obj_section *opd;
+ struct obj_section *stub;
+ Elf64_Addr gp;
+ Elf64_Addr text;
+ Elf64_Addr data;
+ Elf64_Addr bss;
+} hppa64_file_t;
+
+/*
+ * XXX This stub assumes it can reach the .got entry with a +/- 8K offset
+ * from dp. Perhaps we should use a .plt for these entries to give a
+ * greater chance of that being true.
+ *
+ * 53 7b 00 00 ldd 0(dp),dp
+ * R_PARISC_LTOFF14R <.got entry offset from dp>
+ * 53 61 00 20 ldd 10(dp),r1
+ * e8 20 d0 00 bve (r1)
+ * 53 7b 00 30 ldd 18(dp),dp
+ *
+ * We need a different stub for millicode calls, which doesn't screw
+ * dp:
+ *
+ * 53 61 00 00 ldd 0(dp),r1
+ * R_PARISC_LTOFF14R <.got entry offset from dp>
+ * 50 21 00 20 ldd 10(r1),r1
+ * e8 20 d0 00 bve (r1)
+ * 08 00 02 40 nop
+ *
+ */
+
+/* NOTE: to keep the code cleaner we make all stubs the same size.
+ */
+
+#define SIZEOF_STUB 16
+
+unsigned char hppa64_stub_extern[] =
+{
+ 0x53, 0x7b, 0x00, 0x00,
+ 0x53, 0x61, 0x00, 0x20,
+ 0xe8, 0x20, 0xd0, 0x00,
+ 0x53, 0x7b, 0x00, 0x30,
+};
+
+unsigned char hppa64_stub_millicode[] =
+{
+ 0x53, 0x61, 0x00, 0x00,
+ 0x50, 0x21, 0x00, 0x20,
+ 0xe8, 0x20, 0xd0, 0x00,
+ 0x08, 0x00, 0x02, 0x40,
+};
+
+/*======================================================================*/
+
+enum obj_reloc
+patch_14r(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if (v & 0x80000000)
+ v |= ~0x7ff;
+ else
+ v &= 0x7ff;
+ i &= ~ 0x3fff;
+ i |= (v & 0x1fff) << 1 |
+ (v & 0x2000) >> 13;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+enum obj_reloc
+patch_21l(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ v &= 0xfffff800;
+ if (v & 0x80000000)
+ v += 0x800;
+ i &= ~ 0x1fffff;
+ i |= (v & 0x80000000) >> 31 |
+ (v & 0x7ff00000) >> 19 |
+ (v & 0x000c0000) >> 4 |
+ (v & 0x0003e000) << 3 |
+ (v & 0x00001800) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+/* All 14 bits this time... This is used to patch the .got offset in
+ * a stub for PCREL22F.
+ */
+
+enum obj_reloc
+patch_14r2(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if ((Elf64_Sxword)v64 > 0x1fffL ||
+ (Elf64_Sxword)v64 < -0x2000L)
+ return obj_reloc_overflow;
+ i &= ~ 0x3fff;
+ i |= (v & 0x2000) >> 13 |
+ (v & 0x1fff) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+enum obj_reloc
+patch_22f(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if ((Elf64_Sxword)v64 > 0x800000-1 ||
+ (Elf64_Sxword)v64 < -0x800000)
+ return obj_reloc_overflow;
+
+ i &= ~ 0x03ff1ffd;
+ i |= (v & 0x00800000) >> 23 |
+ (v & 0x007c0000) << 3 |
+ (v & 0x0003e000) << 3 |
+ (v & 0x00001000) >> 10 |
+ (v & 0x00000ffc) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+struct obj_section *
+obj_hppa64_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size, unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ hppa64_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ f->opd = NULL;
+ f->stub = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ hppa64_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->gotent = NULL;
+ sym->opdent = NULL;
+ sym->stubent = NULL;
+ return &sym->root;
+}
+
+/* This may not be needed, but does no harm (copied from ia64).
+ */
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_PARISC_EXT :
+ sec->contents = NULL;
+ break;
+
+ case SHT_PARISC_UNWIND :
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data: %m");
+ return -1;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+ default:
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+ return 0;
+}
+
+int
+arch_create_got(struct obj_file *f)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ int i;
+ int n;
+ int got_offset = 0;
+ int opd_offset = 64;
+ int stub_offset = 0;
+
+ n = hfile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = hfile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = hfile->root.sections[relsec->header.sh_link];
+ strsec = hfile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ int need_got = FALSE;
+ int need_opd = FALSE;
+ int need_stub = FALSE;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ default:
+ {
+ unsigned r_info = ELF64_R_TYPE(rel->r_info);
+ printf("r_info 0x%x not handled\n", r_info);
+ }
+ continue;
+ case R_PARISC_LTOFF14R:
+ case R_PARISC_LTOFF21L:
+ /* These are simple indirect references to symbols through the
+ * DLT. We need to create a DLT entry for any symbols which
+ * appears in a DLTIND relocation.
+ */
+ need_got = TRUE;
+ break;
+ case R_PARISC_PCREL22F:
+ /* These are function calls. Depending on their precise
+ * target we may need to make a stub for them. The stub
+ * uses the dlt, so we need to create dlt entries for
+ * these symbols too.
+ */
+ need_got = TRUE;
+ need_stub = TRUE;
+ break;
+ case R_PARISC_DIR64:
+ break;
+ case R_PARISC_FPTR64:
+ /* This is a simple OPD entry (only created for local symbols,
+ * see below).
+ */
+ need_opd = TRUE;
+ break;
+ }
+
+ if (need_got || need_opd || need_stub)
+ {
+ Elf64_Sym *extsym;
+ hppa64_symbol_t *isym;
+ const char *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF64_R_SYM(rel->r_info);
+ extsym = &symtab[symndx];
+ if (ELF64_ST_BIND(extsym->st_info) == STB_LOCAL)
+ {
+ isym = (hppa64_symbol_t *) f->local_symtab[symndx];
+ }
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ isym = (hppa64_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = isym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_stub)
+ {
+ hppa64_stub_t *stub;
+
+ for (stub = isym->stubent; stub != NULL; stub = stub->next)
+ if (stub->addend == rel->r_addend)
+ break;
+ if (stub == NULL)
+ {
+ stub = (hppa64_stub_t *) xmalloc(sizeof(hppa64_stub_t));
+ stub->next = isym->stubent;
+ stub->addend = rel->r_addend;
+ stub->offset = stub_offset;
+ stub->reloc_done = FALSE;
+ isym->stubent = stub;
+ {
+ stub_offset += SIZEOF_STUB;
+ }
+ need_stub = FALSE;
+ }
+ }
+ if (need_got)
+ {
+ hppa64_got_t *got;
+
+ for (got = isym->gotent; got != NULL; got = got->next)
+ if (got->addend == rel->r_addend)
+ break;
+ if (got == NULL)
+ {
+ got = (hppa64_got_t *) xmalloc(sizeof(hppa64_got_t));
+ got->next = isym->gotent;
+ got->addend = rel->r_addend;
+ got->offset = got_offset;
+ got->reloc_done = FALSE;
+ isym->gotent = got;
+ got_offset += 8;
+ need_got = FALSE;
+ }
+ }
+ if (need_opd && local)
+ {
+ hppa64_opd_t *opd;
+
+ if (isym->opdent == NULL)
+ {
+ opd = (hppa64_opd_t *) xmalloc(sizeof(hppa64_opd_t));
+ opd->offset = opd_offset;
+ opd->reloc_done = FALSE;
+ isym->opdent = opd;
+ opd_offset += 32;
+ need_opd = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ hfile->got = obj_hppa64_create_alloced_section(f, ".got", 8, got_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_PARISC_SHORT));
+ assert(hfile->got != NULL);
+
+ hfile->opd = obj_hppa64_create_alloced_section(f, ".opd", 16, opd_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_PARISC_SHORT));
+ assert(hfile->opd != NULL);
+
+ if (stub_offset > 0)
+ {
+ hfile->stub = obj_hppa64_create_alloced_section(f, ".stub", 16,
+ stub_offset, (SHF_ALLOC | SHF_EXECINSTR | SHF_PARISC_SHORT));
+ assert(hfile->stub != NULL);
+ }
+
+ return 1;
+}
+
+
+/* This is a small simple version which seems to work fine. ia64 has
+ * a much more complex algorithm. We point dp at the end of the .got,
+ * which is the start of the .opd.
+ */
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ int n = f->header.e_shnum;
+ int i;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+
+ /* Pick a sensible value for gp */
+ hfile->gp = hfile->got->header.sh_addr + hfile->got->header.sh_size;
+
+ return 1;
+}
+
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *) f;
+ hppa64_symbol_t *isym = (hppa64_symbol_t *) sym;
+
+ Elf64_Word *loc = (Elf64_Word *)(targsec->contents + rel->r_offset);
+ Elf64_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+
+ Elf64_Addr got = hfile->got->header.sh_addr;
+ Elf64_Addr gp = hfile->gp;
+
+ Elf64_Xword r_info = ELF64_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (r_info)
+ {
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ case R_PARISC_LTOFF14R:
+ case R_PARISC_LTOFF21L:
+ {
+ hppa64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ if (r_info == R_PARISC_LTOFF14R)
+ ret = patch_14r(v, loc);
+ else
+ ret = patch_21l(v, loc);
+ }
+ break;
+ case R_PARISC_PCREL22F:
+ {
+ hppa64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->got->contents + ge->offset) = v;
+ }
+ if ((isym->root.secidx > SHN_HIRESERVE) ||
+ ((Elf64_Sxword) (v - dot - 8) > 0x800000-1) ||
+ ((Elf64_Sxword) (v - dot - 8) < -0x800000))
+ {
+ hppa64_stub_t *se;
+
+ for (se = isym->stubent; se != NULL && se->addend != rel->r_addend; )
+ se = se->next;
+ assert(se != NULL);
+ if (!se->reloc_done)
+ {
+ /* This requires that we can get from dp to the entry in +/- 8K,
+ * or +/- 1000 entries. patch_14r2() will check that.
+ * Only need these dlt entries for calls to external/far
+ * functions, so should probably put them in a seperate section
+ * before dlt and point dp at the section. Change to that
+ * scheme if we hit problems with big modules.
+ */
+ unsigned char *stub;
+
+ if (!strncmp(isym->root.name, "$$", 2))
+ stub = hppa64_stub_millicode;
+ else
+ stub = hppa64_stub_extern;
+ se->reloc_done = TRUE;
+ memcpy((Elf64_Addr *)(hfile->stub->contents + se->offset),
+ stub, SIZEOF_STUB);
+ v = (Elf64_Addr)(hfile->got->header.sh_addr + ge->offset) - gp;
+ ret = patch_14r2(v, (Elf64_Word *)(hfile->stub->contents + se->offset));
+ }
+ v = hfile->stub->header.sh_addr + se->offset;
+ }
+ v = v - dot - 8;
+ if (ret == obj_reloc_ok)
+ ret = patch_22f(v, loc);
+ }
+ break;
+ case R_PARISC_DIR64:
+ {
+ loc[0] = v >> 32;
+ loc[1] = v;
+ }
+ break;
+ case R_PARISC_FPTR64:
+ {
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE) /* local */
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->opd->contents + isym->opdent->offset + 16) = v;
+ *(Elf64_Addr *)(hfile->opd->contents + isym->opdent->offset + 24) = gp;
+ }
+ v = hfile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ loc[0] = v >> 32;
+ loc[1] = v;
+ }
+ break;
+ }
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ Elf64_Addr *opd = (Elf64_Addr *)(hfile->opd->contents);
+
+ opd[0] = 0;
+ opd[1] = 0;
+ if ((opd[2] = mod->init) != 0)
+ {
+ opd[3] = hfile->gp;
+ mod->init = hfile->opd->header.sh_addr;
+ }
+
+ opd[4] = 0;
+ opd[5] = 0;
+ if ((opd[6] = mod->cleanup) != 0)
+ {
+ opd[7] = hfile->gp;
+ mod->cleanup = hfile->opd->header.sh_addr + 32;
+ }
+
+ return 1;
+}
+
+/* XXX Is this relevant to parisc? */
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *archdata_sec)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ struct archdata {
+ unsigned tgt_long unw_table;
+ unsigned tgt_long segment_base;
+ unsigned tgt_long unw_start;
+ unsigned tgt_long unw_end;
+ unsigned tgt_long gp;
+ } *ad;
+ int i;
+ struct obj_section *sec;
+
+ free(archdata_sec->contents);
+ archdata_sec->contents = xmalloc(sizeof(struct archdata));
+ memset(archdata_sec->contents, 0, sizeof(struct archdata));
+ archdata_sec->header.sh_size = sizeof(struct archdata);
+
+ ad = (struct archdata *)(archdata_sec->contents);
+ ad->gp = hfile->gp;
+ ad->unw_start = 0;
+ ad->unw_end = 0;
+ ad->unw_table = 0;
+ ad->segment_base = f->sections[1]->header.sh_addr;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type == SHT_PARISC_UNWIND)
+ {
+ ad->unw_start = sec->header.sh_addr;
+ ad->unw_end = sec->header.sh_addr + sec->header.sh_size;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_i386.c b/mdk-stage1/insmod-modutils/obj/obj_i386.c
new file mode 100644
index 000000000..28df3448c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_i386.c
@@ -0,0 +1,245 @@
+/* i386 specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct i386_got_entry
+{
+ int offset;
+ unsigned offset_done : 1;
+ unsigned reloc_done : 1;
+};
+
+struct i386_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct i386_symbol
+{
+ struct obj_symbol root;
+ struct i386_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct i386_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct i386_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct i386_file *ifile = (struct i386_file *)f;
+ struct i386_symbol *isym = (struct i386_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_386_NONE:
+ break;
+
+ case R_386_32:
+ *loc += v;
+ break;
+
+ case R_386_PLT32:
+ case R_386_PC32:
+ *loc += v - dot;
+ break;
+
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_386_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_386_GOTPC:
+ assert(got != 0);
+ *loc += got - dot;
+ break;
+
+ case R_386_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;
+ break;
+
+ case R_386_GOTOFF:
+ assert(got != 0);
+ *loc += v - got;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct i386_file *ifile = (struct i386_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;
+ Elf32_Rel *rel, *relend;
+ Elf32_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_REL)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rel *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ Elf32_Sym *extsym;
+ struct i386_symbol *intsym;
+ const char *name;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_386_GOTPC:
+ case R_386_GOTOFF:
+ gotneeded = 1;
+ default:
+ continue;
+
+ case R_386_GOT32:
+ break;
+ }
+
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct i386_symbol *)obj_find_symbol(&ifile->root, name);
+
+ if (!intsym->gotent.offset_done)
+ {
+ intsym->gotent.offset_done = 1;
+ intsym->gotent.offset = offset;
+ offset += 4;
+ }
+ }
+ }
+
+ if (offset > 0 || gotneeded)
+ ifile->got = obj_create_alloced_section(&ifile->root, ".got", 4, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_ia64.c b/mdk-stage1/insmod-modutils/obj/obj_ia64.c
new file mode 100644
index 000000000..4f92c5d27
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_ia64.c
@@ -0,0 +1,1065 @@
+/*
+ * ia64 specific support for Elf loading and relocation.
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE ~FALSE
+#endif
+
+/*======================================================================*/
+
+typedef struct _ia64_opd_t
+{
+ int offset;
+ int reloc_done;
+} ia64_opd_t;
+
+typedef struct _ia64_plt_t
+{
+ struct _ia64_plt_t *next;
+ Elf64_Addr addend;
+ int text_offset;
+ int data_offset;
+ int reloc_done;
+} ia64_plt_t;
+
+typedef struct _ia64_got_t
+{
+ struct _ia64_got_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} ia64_got_t;
+
+typedef struct _ia64_symbol_t
+{
+ struct obj_symbol root;
+ ia64_got_t *gotent;
+ ia64_opd_t *opdent;
+ ia64_plt_t *pltent;
+} ia64_symbol_t;
+
+typedef struct _ia64_file_t
+{
+ struct obj_file root;
+ struct obj_section *got;
+ struct obj_section *opd;
+ struct obj_section *pltt;
+ struct obj_section *pltd;
+ Elf64_Addr gp;
+ Elf64_Addr text;
+ Elf64_Addr data;
+ Elf64_Addr bss;
+} ia64_file_t;
+
+/*
+ * aa=gp rel address of the function descriptor in the .IA_64.pltoff section
+ */
+unsigned char ia64_plt_local[] =
+{
+ 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=aa,gp;; */
+ 0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0, /* ld8 r16=[r15],8 */
+ 0x01, 0x08, 0x00, 0x84, /* mov r14=gp;; */
+ 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 gp=[r15] */
+ 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */
+ 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */
+};
+
+unsigned char ia64_plt_extern[] =
+{
+ 0x0b, 0x80, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r16=aa,gp;; */
+ 0xf0, 0x00, 0x40, 0x30, 0x20, 0x00, /* ld8 r15=[r16] */
+ 0x00, 0x00, 0x04, 0x00, /* nop.i 0x0;; */
+ 0x0b, 0x80, 0x20, 0x1e, 0x18, 0x14, /* [MMI] ld8 r16=[r15],8;; */
+ 0x10, 0x00, 0x3c, 0x30, 0x20, 0xc0, /* ld8 gp=[r15] */
+ 0x00, 0x09, 0x00, 0x07, /* mov b6=r16;; */
+ 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0x0 */
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* nop.i 0x0 */
+ 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */
+};
+
+/*======================================================================*/
+
+/*
+ * return the instruction at slot in bundle
+ */
+Elf64_Xword
+obj_ia64_ins_extract_from_bundle(Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ switch (slot)
+ {
+ case 0 :
+ return (*bundle >> 5) & 0x1ffffffffff;
+
+ case 1 :
+ return (((*bundle >> 46) & 0x3ffff) |
+ (*(bundle + 1) << 18)) & 0x1ffffffffff;
+
+ case 2 :
+ return (*(bundle + 1) >> 23) & 0x1ffffffffff;
+
+ default:
+ }
+ return (-1);
+}
+
+/*
+ * insert a instruction at slot in bundle
+ */
+void
+obj_ia64_ins_insert_in_bundle(Elf64_Addr *bundle, Elf64_Xword slot, Elf64_Xword ins)
+{
+ Elf64_Xword i;
+ Elf64_Xword in = ins & 0x1ffffffffff;
+
+ switch (slot)
+ {
+ case 0 :
+ i = *bundle & 0xffffc0000000001f;
+ *bundle = i | (in << 5);
+ break;
+
+ case 1 :
+ i = *bundle & 0x00003fffffffffff;
+ *bundle = i | (in << 46);
+
+ ++bundle;
+ i = *bundle & 0xffffffffff800000;
+ *bundle = i | (in >> 18);
+ break;
+
+ case 2 :
+ ++bundle;
+ i = *bundle & 0x00000000007fffff;
+ *bundle = i | (in << 23);
+ break;
+ }
+}
+
+/*
+ * add a immediate 14 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm14(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee07f01fff;
+ ins |= ((v & 0x2000) << 23) | ((v & 0x1f80) << 20) | ((v & 0x007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ if (((Elf64_Sxword) v > 8191) || ((Elf64_Sxword) v < -8192))
+ return obj_reloc_overflow;
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 22 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm22(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffe000301fff;
+ ins |= ((v & 0x200000) << 15) | ((v & 0x1f0000) << 6) |
+ ((v & 0x00ff80) << 20) | ((v & 0x00007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ if (((Elf64_Sxword) v > 2097151) || ((Elf64_Sxword) v < -2097152))
+ return obj_reloc_overflow;
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 1) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21b(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee00001fff;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fffff0) << 9);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 2) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21m(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee000fe03f;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fff800) << 9) |
+ ((v & 0x00007f0) << 2);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 3) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21f(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffeffc00003f;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fffff0) << 2);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 64 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm64(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ assert(slot == 1);
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee000101ff;
+ ins |= ((v & 0x8000000000000000) >> 28) | ((v & 0x0000000000200000)) |
+ ((v & 0x00000000001f0000) << 6) | ((v & 0x000000000000ff80) << 20) |
+ ((v & 0x000000000000007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ obj_ia64_ins_insert_in_bundle(bundle, ++slot, ((v & 0x7fffffffffc00000) >> 22));
+ return obj_reloc_ok;
+}
+
+/*
+ * create a plt entry
+ */
+enum obj_reloc
+obj_ia64_generate_plt(Elf64_Addr v,
+ Elf64_Addr gp,
+ ia64_file_t *ifile,
+ ia64_symbol_t *isym,
+ ia64_plt_t *pltent)
+{
+ *(Elf64_Addr *)(ifile->pltd->contents + pltent->data_offset) = v;
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ /* local entry */
+ *(Elf64_Addr *)(ifile->pltd->contents + pltent->data_offset + 8) = gp;
+ memcpy((Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset),
+ ia64_plt_local, sizeof(ia64_plt_local));
+ }
+ else
+ {
+ /* external entry */
+ memcpy((Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset),
+ ia64_plt_extern, sizeof(ia64_plt_extern));
+ }
+ return obj_ia64_ins_imm22(
+ (ifile->pltd->header.sh_addr + pltent->data_offset - gp),
+ (Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset), 0);
+}
+
+struct obj_section *
+obj_ia64_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size, unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ ia64_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ f->opd = NULL;
+ f->pltt = NULL;
+ f->pltd = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ ia64_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->gotent = NULL;
+ sym->opdent = NULL;
+ sym->pltent = NULL;
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_IA_64_EXT :
+ sec->contents = NULL;
+ break;
+
+ case SHT_IA_64_UNWIND :
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data: %m");
+ return -1;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+
+ default:
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+ return 0;
+}
+
+int
+arch_create_got(struct obj_file *f)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ int i;
+ int n;
+ int got_offset = 0;
+ int opd_offset = 32;
+ int plt_text_offset = 0;
+ int plt_data_offset = 0;
+
+ n = ifile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ int need_got = FALSE;
+ int need_opd = FALSE;
+ int need_plt = FALSE;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ default:
+ continue;
+
+ case R_IA64_FPTR64I : /* @fptr(sym + add), mov imm64 */
+ case R_IA64_FPTR32LSB : /* @fptr(sym + add), data4 LSB */
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ need_opd = TRUE;
+ break;
+
+ case R_IA64_LTOFF22 : /* @ltoff(sym + add), add imm22 */
+ case R_IA64_LTOFF22X :
+ case R_IA64_LTOFF64I : /* @ltoff(sym + add), mov imm64 */
+ need_got = TRUE;
+ break;
+
+ case R_IA64_LTOFF_FPTR22 : /* @ltoff(@fptr(s+a)), imm22 */
+ case R_IA64_LTOFF_FPTR64I : /* @ltoff(@fptr(s+a)), imm64 */
+ case R_IA64_LTOFF_FPTR32LSB :
+ case R_IA64_LTOFF_FPTR64LSB :
+ need_got = TRUE;
+ need_opd = TRUE;
+ break;
+
+ case R_IA64_PLTOFF22 : /* @pltoff(sym + add), add imm22 */
+ case R_IA64_PLTOFF64I : /* @pltoff(sym + add), mov imm64 */
+ case R_IA64_PLTOFF64LSB : /* @pltoff(sym + add), data8 LSB */
+
+ case R_IA64_PCREL21B : /* @pcrel(sym + add), ptb, call */
+ case R_IA64_PCREL21M : /* @pcrel(sym + add), chk.s */
+ case R_IA64_PCREL21F : /* @pcrel(sym + add), fchkf */
+ need_plt = TRUE;
+ break;
+ }
+
+ if (need_got || need_opd || need_plt)
+ {
+ Elf64_Sym *extsym;
+ ia64_symbol_t *isym;
+ const char *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF64_R_SYM(rel->r_info);
+ extsym = &symtab[symndx];
+ if (ELF64_ST_BIND(extsym->st_info) == STB_LOCAL)
+ {
+ isym = (ia64_symbol_t *) f->local_symtab[symndx];
+ }
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ isym = (ia64_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = isym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_plt)
+ {
+ ia64_plt_t *plt;
+
+ for (plt = isym->pltent; plt != NULL; plt = plt->next)
+ if (plt->addend == rel->r_addend)
+ break;
+ if (plt == NULL)
+ {
+ plt = (ia64_plt_t *) xmalloc(sizeof(ia64_plt_t));
+ plt->next = isym->pltent;
+ plt->addend = rel->r_addend;
+ plt->text_offset = plt_text_offset;
+ plt->data_offset = plt_data_offset;
+ plt->reloc_done = FALSE;
+ isym->pltent = plt;
+ if (local)
+ {
+ plt_text_offset += sizeof(ia64_plt_local);
+ plt_data_offset += 16;
+ }
+ else
+ {
+ plt_text_offset += sizeof(ia64_plt_extern);
+ plt_data_offset += 8;
+ }
+ need_plt = FALSE;
+ }
+ }
+ if (need_got)
+ {
+ ia64_got_t *got;
+
+ for (got = isym->gotent; got != NULL; got = got->next)
+ if (got->addend == rel->r_addend)
+ break;
+ if (got == NULL)
+ {
+ got = (ia64_got_t *) xmalloc(sizeof(ia64_got_t));
+ got->next = isym->gotent;
+ got->addend = rel->r_addend;
+ got->offset = got_offset;
+ got->reloc_done = FALSE;
+ isym->gotent = got;
+ got_offset += 8;
+ need_got = FALSE;
+ }
+ }
+ if (need_opd && local)
+ {
+ ia64_opd_t *opd;
+
+ if (isym->opdent == NULL)
+ {
+ opd = (ia64_opd_t *) xmalloc(sizeof(ia64_opd_t));
+ opd->offset = opd_offset;
+ opd->reloc_done = FALSE;
+ isym->opdent = opd;
+ opd_offset += 16;
+ need_opd = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ ifile->got = obj_ia64_create_alloced_section(f, ".got", 8, got_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->got != NULL);
+
+ ifile->opd = obj_ia64_create_alloced_section(f, ".opd", 16, opd_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->opd != NULL);
+
+ if (plt_text_offset > 0)
+ {
+ ifile->pltt = obj_ia64_create_alloced_section(f, ".plt", 16,
+ plt_text_offset, (SHF_ALLOC | SHF_EXECINSTR | SHF_IA_64_SHORT));
+ ifile->pltd = obj_ia64_create_alloced_section(f, ".IA_64.pltoff",
+ 16, plt_data_offset, (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->pltt != NULL);
+ assert(ifile->pltd != NULL);
+ }
+
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ Elf64_Addr min_addr = (Elf64_Addr) -1;
+ Elf64_Addr max_addr = 0;
+ Elf64_Addr min_short_addr = (Elf64_Addr) -1;
+ Elf64_Addr max_short_addr = 0;
+ Elf64_Addr gp;
+ Elf64_Addr text = (Elf64_Addr) -1;
+ Elf64_Addr data = (Elf64_Addr) -1;
+ Elf64_Addr bss = (Elf64_Addr) -1;
+ int n = f->header.e_shnum;
+ int i;
+
+ /*
+ * Finalize the addresses of the sections, find the min and max
+ * address of all sections marked short, and collect min and max
+ * address of any type, for use in selecting a nice gp.
+ *
+ * The algorithm used for selecting set the GP value was taken from
+ * the ld/bfd code contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ {
+ Elf64_Shdr *header = &f->sections[i]->header;
+ Elf64_Addr lo;
+ Elf64_Addr hi;
+
+ header->sh_addr += base;
+ if (header->sh_flags & SHF_ALLOC)
+ {
+ lo = header->sh_addr;
+ hi = header->sh_addr + header->sh_size;
+ if (hi < lo)
+ hi = (Elf64_Addr) -1;
+
+ if (min_addr > lo)
+ min_addr = lo;
+ if (max_addr < hi)
+ max_addr = hi;
+ if (header->sh_flags & SHF_IA_64_SHORT)
+ {
+ if (min_short_addr > lo)
+ min_short_addr = lo;
+ if (max_short_addr < hi)
+ max_short_addr = hi;
+ }
+ if ((header->sh_type & SHT_NOBITS) && (lo < bss))
+ bss = lo;
+ else if ((header->sh_flags & SHF_EXECINSTR) && (lo < text))
+ text = lo;
+ else if (lo < data)
+ data = lo;
+ }
+ }
+ /* Pick a sensible value for gp */
+
+ /* Start with just the address of the .got */
+ gp = ifile->got->header.sh_addr;
+
+ /*
+ * If it is possible to address the entire image, but we
+ * don't with the choice above, adjust.
+ */
+ if ((max_addr - min_addr < 0x400000) && (max_addr - gp <= 0x200000) &&
+ (gp - min_addr > 0x200000))
+ {
+ gp = min_addr + 0x200000;
+ }
+ else if (max_short_addr != 0)
+ {
+ /* If we don't cover all the short data, adjust */
+ if (max_short_addr - gp >= 0x200000)
+ gp = min_short_addr + 0x200000;
+
+ /* If we're addressing stuff past the end, adjust back */
+ if (gp > max_addr)
+ gp = max_addr - 0x200000 + 8;
+ }
+
+ /*
+ * Validate whether all SHF_IA_64_SHORT sections are within
+ * range of the chosen GP.
+ */
+ if (max_short_addr != 0)
+ {
+ if (max_short_addr - min_short_addr >= 0x400000)
+ {
+ error("short data segment overflowed (0x%lx >= 0x400000)",
+ (unsigned long)(max_short_addr - min_short_addr));
+ return 0;
+ }
+ else if (((gp > min_short_addr) && (gp - min_short_addr > 0x200000)) ||
+ ((gp < max_short_addr) && (max_short_addr - gp >= 0x200000)))
+ {
+ error("GP does not cover short data segment");
+ return 0;
+ }
+ }
+ ifile->gp = gp;
+ ifile->text = text;
+ ifile->data = data;
+ ifile->bss = bss;
+ return 1;
+}
+
+/* Targets can be unaligned, use memcpy instead of assignment */
+#define COPY_64LSB(loc, v) \
+ do { \
+ Elf64_Xword reloc = (v); \
+ memcpy((void *)(loc), &reloc, 8); \
+ } while(0)
+#define COPY_32LSB(loc, v) \
+ do { \
+ Elf32_Xword reloc = (v); \
+ memcpy((void *)(loc), &reloc, 4); \
+ if ((v) != reloc) \
+ ret = obj_reloc_overflow; \
+ } while(0)
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ ia64_file_t *ifile = (ia64_file_t *) f;
+ ia64_symbol_t *isym = (ia64_symbol_t *) sym;
+
+ Elf64_Addr loc = (Elf64_Addr)(targsec->contents + rel->r_offset);
+ Elf64_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+
+ Elf64_Addr got = ifile->got->header.sh_addr;
+ Elf64_Addr gp = ifile->gp;
+
+ Elf64_Addr *bundle = (Elf64_Addr *)(loc & ~0x03);
+ Elf64_Xword slot = loc & 0x03;
+
+ Elf64_Xword r_info = ELF64_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ /* We cannot load modules compiled with -mconstant-gp */
+#ifndef EF_IA_64_CONS_GP
+#define EF_IA_64_CONS_GP 0x00000040
+#endif
+#ifndef EF_IA_64_NOFUNCDESC_CONS_GP
+#define EF_IA_64_NOFUNCDESC_CONS_GP 0x00000080
+#endif
+ if (f->header.e_flags & (EF_IA_64_CONS_GP | EF_IA_64_NOFUNCDESC_CONS_GP))
+ return obj_reloc_constant_gp;
+
+ switch (r_info)
+ {
+ case R_IA64_NONE : /* none */
+ case R_IA64_LDXMOV : /* Use of LTOFF22X. */
+ break;
+
+ case R_IA64_IMM14 : /* symbol + addend, add imm14 */
+ ret = obj_ia64_ins_imm14(v, bundle, slot);
+ break;
+
+ case R_IA64_IMM22 : /* symbol + addend, add imm22 */
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_IMM64 : /* symbol + addend, movl imm64 */
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_DIR32LSB : /* symbol + addend, data4 LSB */
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_DIR64LSB : /* symbol + addend, data8 LSB */
+ COPY_64LSB(loc, v);
+ break;
+
+ case R_IA64_GPREL22 : /* @gprel(sym + add), add imm22 */
+ v -= gp;
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_GPREL64I : /* @gprel(sym + add), mov imm64 */
+ v -= gp;
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_GPREL32LSB : /* @gprel(sym + add), data4 LSB */
+ COPY_32LSB(loc, v-gp);
+ break;
+
+ case R_IA64_GPREL64LSB : /* @gprel(sym + add), data8 LSB */
+ COPY_64LSB(loc, v-gp);
+ break;
+
+ case R_IA64_LTOFF22 : /* @ltoff(sym + add), add imm22 */
+ case R_IA64_LTOFF22X : /* LTOFF22, relaxable. */
+ case R_IA64_LTOFF64I : /* @ltoff(sym + add), mov imm64 */
+ {
+ ia64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ if (r_info == R_IA64_LTOFF64I)
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ else
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ }
+ break;
+
+ case R_IA64_PLTOFF22 : /* @pltoff(sym + add), add imm22 */
+ case R_IA64_PLTOFF64I : /* @pltoff(sym + add), mov imm64 */
+ case R_IA64_PLTOFF64LSB : /* @pltoff(sym + add), data8 LSB */
+ {
+ ia64_plt_t *pe;
+
+ assert(isym != NULL);
+ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->reloc_done)
+ {
+ pe->reloc_done = TRUE;
+ ret = obj_ia64_generate_plt(v, gp, ifile, isym, pe);
+ }
+ v = ifile->pltt->header.sh_addr + pe->text_offset - gp;
+ switch (r_info)
+ {
+ case R_IA64_PLTOFF22 :
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_PLTOFF64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_PLTOFF64LSB :
+ COPY_64LSB(loc, v);
+ break;
+ }
+ }
+ break;
+
+ case R_IA64_FPTR64I : /* @fptr(sym + add), mov imm64 */
+ case R_IA64_FPTR32LSB : /* @fptr(sym + add), data4 LSB */
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset) = v;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset + 8) = gp;
+ }
+ v = ifile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ switch (r_info)
+ {
+ case R_IA64_FPTR64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_FPTR32LSB :
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ /* Target can be unaligned */
+ COPY_64LSB(loc, v);
+ break;
+ }
+ break;
+
+ case R_IA64_PCREL21B : /* @pcrel(sym + add), ptb, call */
+ case R_IA64_PCREL21M : /* @pcrel(sym + add), chk.s */
+ case R_IA64_PCREL21F : /* @pcrel(sym + add), fchkf */
+ assert(isym != NULL);
+ if ((isym->root.secidx > SHN_HIRESERVE) ||
+ ((Elf64_Sxword) (v - dot) > 16777215) ||
+ ((Elf64_Sxword) (v - dot) < -16777216))
+ {
+ ia64_plt_t *pe;
+
+ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->reloc_done)
+ {
+ pe->reloc_done = TRUE;
+ ret = obj_ia64_generate_plt(v, gp, ifile, isym, pe);
+ }
+ v = ifile->pltt->header.sh_addr + pe->text_offset;
+ }
+ v -= dot;
+ switch (r_info)
+ {
+ case R_IA64_PCREL21B :
+ ret = obj_ia64_ins_pcrel21b(v, bundle, slot);
+ break;
+
+ case R_IA64_PCREL21M :
+ ret = obj_ia64_ins_pcrel21m(v, bundle, slot);
+ break;
+
+ case R_IA64_PCREL21F :
+ ret = obj_ia64_ins_pcrel21f(v, bundle, slot);
+ break;
+ }
+ break;
+
+ case R_IA64_PCREL32LSB : /* @pcrel(sym + add), data4 LSB */
+ COPY_32LSB(loc, v-dot);
+ break;
+
+ case R_IA64_PCREL64LSB : /* @pcrel(sym + add), data8 LSB */
+ COPY_64LSB(loc, v-dot);
+ break;
+
+ case R_IA64_LTOFF_FPTR22 : /* @ltoff(@fptr(s+a)), imm22 */
+ case R_IA64_LTOFF_FPTR64I : /* @ltoff(@fptr(s+a)), imm64 */
+ case R_IA64_LTOFF_FPTR32LSB : /* @ltoff(@fptr(s+a)), data4 */
+ case R_IA64_LTOFF_FPTR64LSB : /* @ltoff(@fptr(s+a)), data8 */
+ {
+ ia64_got_t *ge;
+
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset) = v;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset + 8) = gp;
+ }
+ v = ifile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ switch (r_info)
+ {
+ case R_IA64_LTOFF_FPTR22 :
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_LTOFF_FPTR64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_LTOFF_FPTR32LSB :
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_LTOFF_FPTR64LSB :
+ COPY_64LSB(loc, v);
+ break;
+ }
+ }
+ break;
+
+ case R_IA64_SEGREL32LSB : /* @segrel(sym + add), data4 LSB */
+ case R_IA64_SEGREL64LSB : /* @segrel(sym + add), data8 LSB */
+ if (targsec->header.sh_type & SHT_NOBITS)
+ v = ifile->bss - v;
+ else if (targsec->header.sh_flags & SHF_EXECINSTR)
+ v = ifile->text - v;
+ else
+ v = ifile->data - v;
+ if (r_info == R_IA64_SEGREL32LSB)
+ COPY_32LSB(loc, v);
+ else
+ COPY_64LSB(loc, v);
+ break;
+
+ case R_IA64_SECREL32LSB : /* @secrel(sym + add), data4 LSB */
+ COPY_32LSB(loc, targsec->header.sh_addr - v);
+ break;
+
+ case R_IA64_SECREL64LSB : /* @secrel(sym + add), data8 LSB */
+ COPY_64LSB(loc, targsec->header.sh_addr - v);
+ break;
+
+ /*
+ * We don't handle the big-endian relocates
+ *
+ * R_IA64_DIR32MSB symbol + addend, data4 MSB
+ * R_IA64_DIR64MSB symbol + addend, data8 MSB
+ * R_IA64_GPREL32MSB @gprel(sym + add), data4 MSB
+ * R_IA64_GPREL64MSB @gprel(sym + add), data8 MSB
+ * R_IA64_PLTOFF64MSB @pltoff(sym + add), data8 MSB
+ * R_IA64_FPTR32MSB @fptr(sym + add), data4 MSB
+ * R_IA64_FPTR64MSB @fptr(sym + add), data8 MSB
+ * R_IA64_PCREL32MSB @pcrel(sym + add), data4 MSB
+ * R_IA64_PCREL64MSB @pcrel(sym + add), data8 MSB
+ * R_IA64_SEGREL32MSB @segrel(sym + add), data4 MSB
+ * R_IA64_SEGREL64MSB @segrel(sym + add), data8 MSB
+ * R_IA64_SECREL32MSB @secrel(sym + add), data4 MSB
+ * R_IA64_SECREL64MSB @secrel(sym + add), data8 MSB
+ * R_IA64_REL32MSB data 4 + REL
+ * R_IA64_REL64MSB data 8 + REL
+ * R_IA64_LTV32MSB symbol + addend, data4 MSB
+ * R_IA64_LTV64MSB symbol + addend, data8 MSB
+ * R_IA64_IPLTMSB dynamic reloc, imported PLT, MSB
+ */
+ default:
+ case R_IA64_REL32LSB : /* data 4 + REL */
+ case R_IA64_REL64LSB : /* data 8 + REL */
+ case R_IA64_LTV32LSB : /* symbol + addend, data4 LSB */
+ case R_IA64_LTV64LSB : /* symbol + addend, data8 LSB */
+ case R_IA64_IPLTLSB : /* dynamic reloc, imported PLT, LSB */
+ ret = obj_reloc_unhandled;
+ break;
+ }
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ Elf64_Addr *opd = (Elf64_Addr *)(ifile->opd->contents);
+
+ if ((opd[0] = mod->init) != 0)
+ {
+ opd[1] = ifile->gp;
+ mod->init = ifile->opd->header.sh_addr;
+ }
+
+ if ((opd[2] = mod->cleanup) != 0)
+ {
+ opd[3] = ifile->gp;
+ mod->cleanup = ifile->opd->header.sh_addr + 16;
+ }
+
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *archdata_sec)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ struct archdata {
+ unsigned tgt_long unw_table;
+ unsigned tgt_long segment_base;
+ unsigned tgt_long unw_start;
+ unsigned tgt_long unw_end;
+ unsigned tgt_long gp;
+ } *ad;
+ int i;
+ struct obj_section *sec;
+
+ free(archdata_sec->contents);
+ archdata_sec->contents = xmalloc(sizeof(struct archdata));
+ memset(archdata_sec->contents, 0, sizeof(struct archdata));
+ archdata_sec->header.sh_size = sizeof(struct archdata);
+
+ ad = (struct archdata *)(archdata_sec->contents);
+ ad->gp = ifile->gp;
+ ad->unw_start = 0;
+ ad->unw_end = 0;
+ ad->unw_table = 0;
+ ad->segment_base = f->sections[1]->header.sh_addr;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type == SHT_IA_64_UNWIND)
+ {
+ ad->unw_start = sec->header.sh_addr;
+ ad->unw_end = sec->header.sh_addr + sec->header.sh_size;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c b/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c
new file mode 100644
index 000000000..8385fb892
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c
@@ -0,0 +1,292 @@
+/* Build a section containing all non-stack symbols.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "obj.h"
+#include "kallsyms.h"
+#include "util.h"
+
+/*======================================================================*/
+
+#define EXPAND_BY 4096 /* Arbitrary */
+
+/* Append a string to the big list of strings */
+
+static void
+append_string (const char *s, char **strings,
+ ElfW(Word) *strings_size, ElfW(Word) *strings_left)
+{
+ int l = strlen(s) + 1;
+ while (l > *strings_left) {
+ *strings = xrealloc(*strings, *strings_size += EXPAND_BY);
+ *strings_left += EXPAND_BY;
+ }
+ memcpy((char *)*strings+*strings_size-*strings_left, s, l);
+ *strings_left -= l;
+}
+
+
+/* Append a symbol to the big list of symbols */
+
+static void
+append_symbol (const struct kallsyms_symbol *s,
+ struct kallsyms_symbol **symbols,
+ ElfW(Word) *symbols_size, ElfW(Word) *symbols_left)
+{
+ int l = sizeof(*s);
+ while (l > *symbols_left) {
+ *symbols = xrealloc(*symbols, *symbols_size += EXPAND_BY);
+ *symbols_left += EXPAND_BY;
+ }
+ memcpy((char *)*symbols+*symbols_size-*symbols_left, s, l);
+ *symbols_left -= l;
+}
+
+/* qsort compare routine to sort symbols */
+
+static const char *sym_strings;
+
+static int
+symbol_compare (const void *a, const void *b)
+{
+ struct kallsyms_symbol *c = (struct kallsyms_symbol *) a;
+ struct kallsyms_symbol *d = (struct kallsyms_symbol *) b;
+
+ if (c->symbol_addr > d->symbol_addr)
+ return(1);
+ if (c->symbol_addr < d->symbol_addr)
+ return(-1);
+ return(strcmp(sym_strings+c->name_off, sym_strings+d->name_off));
+}
+
+
+/* Extract all symbols from the input obj_file, ignore ones that are
+ * no use for debugging, build an output obj_file containing only the
+ * kallsyms section.
+ *
+ * The kallsyms section is a bit unusual. It deliberately has no
+ * relocatable data, all "pointers" are represented as byte offsets
+ * into the the section. This means it can be stored anywhere without
+ * relocation problems. In particular it can be stored within a kernel
+ * image, it can be stored separately from the kernel image, it can be
+ * appended to a module just before loading, it can be stored in a
+ * separate area etc.
+ *
+ * Format of the kallsyms section.
+ *
+ * Header:
+ * Size of header.
+ * Total size of kallsyms data, including strings.
+ * Number of loaded sections.
+ * Offset to first section entry from start of header.
+ * Size of each section entry, excluding the name string.
+ * Number of symbols.
+ * Offset to first symbol entry from start of header.
+ * Size of each symbol entry, excluding the name string.
+ *
+ * Section entry - one per loaded section.
+ * Start of section[1].
+ * Size of section.
+ * Offset to name of section, from start of strings.
+ * Section flags.
+ *
+ * Symbol entry - one per symbol in the input file[2].
+ * Offset of section that owns this symbol, from start of section data.
+ * Address of symbol within the real section[1].
+ * Offset to name of symbol, from start of strings.
+ *
+ * Notes: [1] This is an exception to the "represent pointers as
+ * offsets" rule, it is a value, not an offset. The start
+ * address of a section or a symbol is extracted from the
+ * obj_file data which may contain absolute or relocatable
+ * addresses. If the addresses are relocatable then the
+ * caller must adjust the section and/or symbol entries in
+ * kallsyms after relocation.
+ * [2] Only symbols that fall within loaded sections are stored.
+ */
+
+int
+obj_kallsyms (struct obj_file *fin, struct obj_file **fout_result)
+{
+ struct obj_file *fout;
+ int i, loaded = 0, *fin_to_allsym_map;
+ struct obj_section *isec, *osec;
+ struct kallsyms_header *a_hdr;
+ struct kallsyms_section *a_sec;
+ ElfW(Off) sec_off;
+ struct kallsyms_symbol *symbols = NULL, a_sym;
+ ElfW(Word) symbols_size = 0, symbols_left = 0;
+ char *strings = NULL, *p;
+ ElfW(Word) strings_size = 0, strings_left = 0;
+ ElfW(Off) file_offset;
+ static char strtab[] = "\000" KALLSYMS_SEC_NAME;
+
+ /* Create the kallsyms section. */
+ fout = arch_new_file();
+ memset(fout, 0, sizeof(*fout));
+ fout->symbol_cmp = strcmp;
+ fout->symbol_hash = obj_elf_hash;
+ fout->load_order_search_start = &fout->load_order;
+
+ /* Copy file characteristics from input file and modify to suit */
+ memcpy(&fout->header, &fin->header, sizeof(fout->header));
+ fout->header.e_type = ET_REL; /* Output is relocatable */
+ fout->header.e_entry = 0; /* No entry point */
+ fout->header.e_phoff = 0; /* No program header */
+ file_offset = sizeof(fout->header); /* Step over Elf header */
+ fout->header.e_shoff = file_offset; /* Section headers next */
+ fout->header.e_phentsize = 0; /* No program header */
+ fout->header.e_phnum = 0; /* No program header */
+ fout->header.e_shnum = KALLSYMS_IDX+1; /* Initial, strtab, kallsyms */
+ fout->header.e_shstrndx = KALLSYMS_IDX-1; /* strtab */
+ file_offset += fout->header.e_shentsize * fout->header.e_shnum;
+
+ /* Populate the section data for kallsyms itself */
+ fout->sections = xmalloc(sizeof(*(fout->sections))*fout->header.e_shnum);
+ memset(fout->sections, 0, sizeof(*(fout->sections))*fout->header.e_shnum);
+
+ fout->sections[0] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->header.sh_type = SHT_NULL;
+ osec->header.sh_link = SHN_UNDEF;
+
+ fout->sections[KALLSYMS_IDX-1] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->name = ".strtab";
+ osec->header.sh_type = SHT_STRTAB;
+ osec->header.sh_link = SHN_UNDEF;
+ osec->header.sh_offset = file_offset;
+ osec->header.sh_size = sizeof(strtab);
+ osec->contents = xmalloc(sizeof(strtab));
+ memcpy(osec->contents, strtab, sizeof(strtab));
+ file_offset += osec->header.sh_size;
+
+ fout->sections[KALLSYMS_IDX] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->name = KALLSYMS_SEC_NAME;
+ osec->header.sh_name = 1; /* Offset in strtab */
+ osec->header.sh_type = SHT_PROGBITS; /* Load it */
+ osec->header.sh_flags = SHF_ALLOC; /* Read only data */
+ osec->header.sh_link = SHN_UNDEF;
+ osec->header.sh_addralign = sizeof(ElfW(Word));
+ file_offset = (file_offset + osec->header.sh_addralign - 1)
+ & -(osec->header.sh_addralign);
+ osec->header.sh_offset = file_offset;
+
+ /* How many loaded sections are there? */
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ if (fin->sections[i]->header.sh_flags & SHF_ALLOC)
+ ++loaded;
+ }
+
+ /* Initial contents, header + one entry per input section. No strings. */
+ osec->header.sh_size = sizeof(*a_hdr) + loaded*sizeof(*a_sec);
+ a_hdr = (struct kallsyms_header *) osec->contents =
+ xmalloc(osec->header.sh_size);
+ memset(osec->contents, 0, osec->header.sh_size);
+ a_hdr->size = sizeof(*a_hdr);
+ a_hdr->sections = loaded;
+ a_hdr->section_off = a_hdr->size;
+ a_hdr->section_size = sizeof(*a_sec);
+ a_hdr->symbol_off = osec->header.sh_size;
+ a_hdr->symbol_size = sizeof(a_sym);
+ a_hdr->start = (ElfW(Addr))(~0);
+
+ /* Map input section numbers to kallsyms section offsets. */
+ sec_off = 0; /* Offset to first kallsyms section entry */
+ fin_to_allsym_map = xmalloc(sizeof(*fin_to_allsym_map)*fin->header.e_shnum);
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ isec = fin->sections[i];
+ if (isec->header.sh_flags & SHF_ALLOC) {
+ fin_to_allsym_map[isec->idx] = sec_off;
+ sec_off += a_hdr->section_size;
+ }
+ else
+ fin_to_allsym_map[isec->idx] = -1; /* Ignore this section */
+ }
+
+ /* Copy the loaded section data. */
+ a_sec = (struct kallsyms_section *) ((char *) a_hdr + a_hdr->section_off);
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ isec = fin->sections[i];
+ if (!(isec->header.sh_flags & SHF_ALLOC))
+ continue;
+ a_sec->start = isec->header.sh_addr;
+ a_sec->size = isec->header.sh_size;
+ a_sec->flags = isec->header.sh_flags;
+ a_sec->name_off = strings_size - strings_left;
+ append_string(isec->name, &strings, &strings_size, &strings_left);
+ if (a_sec->start < a_hdr->start)
+ a_hdr->start = a_sec->start;
+ if (a_sec->start+a_sec->size > a_hdr->end)
+ a_hdr->end = a_sec->start+a_sec->size;
+ ++a_sec;
+ }
+
+ /* Build the kallsyms symbol table from the symbol hashes. */
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym = fin->symtab[i];
+ for (sym = fin->symtab[i]; sym ; sym = sym->next) {
+ if (!sym || sym->secidx >= fin->header.e_shnum)
+ continue;
+ if ((a_sym.section_off = fin_to_allsym_map[sym->secidx]) == -1)
+ continue;
+ if (strcmp(sym->name, "gcc2_compiled.") == 0 ||
+ strncmp(sym->name, "__insmod_", 9) == 0)
+ continue;
+ a_sym.symbol_addr = sym->value;
+ if (fin->header.e_type == ET_REL)
+ a_sym.symbol_addr += fin->sections[sym->secidx]->header.sh_addr;
+ a_sym.name_off = strings_size - strings_left;
+ append_symbol(&a_sym, &symbols, &symbols_size, &symbols_left);
+ append_string(sym->name, &strings, &strings_size, &strings_left);
+ ++a_hdr->symbols;
+ }
+ }
+ free(fin_to_allsym_map);
+
+ /* Sort the symbols into ascending order by address and name */
+ sym_strings = strings; /* For symbol_compare */
+ qsort((char *) symbols, (unsigned) a_hdr->symbols,
+ sizeof(* symbols), symbol_compare);
+ sym_strings = NULL;
+
+ /* Put the lot together */
+ osec->header.sh_size = a_hdr->total_size =
+ a_hdr->symbol_off +
+ a_hdr->symbols*a_hdr->symbol_size +
+ strings_size - strings_left;
+ a_hdr = (struct kallsyms_header *) osec->contents =
+ xrealloc(a_hdr, a_hdr->total_size);
+ p = (char *)a_hdr + a_hdr->symbol_off;
+ memcpy(p, symbols, a_hdr->symbols*a_hdr->symbol_size);
+ free(symbols);
+ p += a_hdr->symbols*a_hdr->symbol_size;
+ a_hdr->string_off = p - (char *)a_hdr;
+ memcpy(p, strings, strings_size - strings_left);
+ free(strings);
+
+ *fout_result = fout;
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_load.c b/mdk-stage1/insmod-modutils/obj/obj_load.c
new file mode 100644
index 000000000..4db20a998
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_load.c
@@ -0,0 +1,354 @@
+/* Elf file reader.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+ obj_free() added by Björn Ekwall <bj0rn@blox.se> March 1999
+ Support for kallsyms Keith Owens <kaos@ocs.com.au> April 2000
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <alloca.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "obj.h"
+#include "util.h"
+
+/*======================================================================*/
+
+struct obj_file *
+obj_load (int fp, Elf32_Half e_type, const char *filename)
+{
+ struct obj_file *f;
+ ElfW(Shdr) *section_headers;
+ int shnum, i;
+ char *shstrtab;
+
+ /* Read the file header. */
+
+ f = arch_new_file();
+ memset(f, 0, sizeof(*f));
+ f->symbol_cmp = strcmp;
+ f->symbol_hash = obj_elf_hash;
+ f->load_order_search_start = &f->load_order;
+
+ gzf_lseek(fp, 0, SEEK_SET);
+ if (gzf_read(fp, &f->header, sizeof(f->header)) != sizeof(f->header))
+ {
+ error("error reading ELF header %s: %m", filename);
+ return NULL;
+ }
+
+ if (f->header.e_ident[EI_MAG0] != ELFMAG0
+ || f->header.e_ident[EI_MAG1] != ELFMAG1
+ || f->header.e_ident[EI_MAG2] != ELFMAG2
+ || f->header.e_ident[EI_MAG3] != ELFMAG3)
+ {
+ error("%s is not an ELF file", filename);
+ return NULL;
+ }
+ if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+ || f->header.e_ident[EI_DATA] != ELFDATAM
+ || f->header.e_ident[EI_VERSION] != EV_CURRENT
+ || !MATCH_MACHINE(f->header.e_machine))
+ {
+ error("ELF file %s not for this architecture", filename);
+ return NULL;
+ }
+ if (f->header.e_type != e_type && e_type != ET_NONE)
+ {
+ switch (e_type) {
+ case ET_REL:
+ error("ELF file %s not a relocatable object", filename);
+ break;
+ case ET_EXEC:
+ error("ELF file %s not an executable object", filename);
+ break;
+ default:
+ error("ELF file %s has wrong type, expecting %d got %d",
+ filename, e_type, f->header.e_type);
+ break;
+ }
+ return NULL;
+ }
+
+ /* Read the section headers. */
+
+ if (f->header.e_shentsize != sizeof(ElfW(Shdr)))
+ {
+ error("section header size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)f->header.e_shentsize,
+ (unsigned long)sizeof(ElfW(Shdr)));
+ return NULL;
+ }
+
+ shnum = f->header.e_shnum;
+ f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
+ memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
+
+ section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+ gzf_lseek(fp, f->header.e_shoff, SEEK_SET);
+ if (gzf_read(fp, section_headers, sizeof(ElfW(Shdr))*shnum) != sizeof(ElfW(Shdr))*shnum)
+ {
+ error("error reading ELF section headers %s: %m", filename);
+ return NULL;
+ }
+
+ /* Read the section data. */
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec;
+
+ f->sections[i] = sec = arch_new_section();
+ memset(sec, 0, sizeof(*sec));
+
+ sec->header = section_headers[i];
+ sec->idx = i;
+
+ switch (sec->header.sh_type)
+ {
+ case SHT_NULL:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ /* ignore */
+ break;
+
+ case SHT_PROGBITS:
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ case SHT_RELM:
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data %s: %m", filename);
+ return NULL;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+
+#if SHT_RELM == SHT_REL
+ case SHT_RELA:
+ if (sec->header.sh_size) {
+ error("RELA relocations not supported on this architecture %s", filename);
+ return NULL;
+ }
+ break;
+#else
+ case SHT_REL:
+ if (sec->header.sh_size) {
+ error("REL relocations not supported on this architecture %s", filename);
+ return NULL;
+ }
+ break;
+#endif
+
+ default:
+ if (sec->header.sh_type >= SHT_LOPROC)
+ {
+ if (arch_load_proc_section(sec, fp) < 0)
+ return NULL;
+ break;
+ }
+
+ error("can't handle sections of type %ld %s",
+ (long)sec->header.sh_type, filename);
+ return NULL;
+ }
+ }
+
+ /* Do what sort of interpretation as needed by each section. */
+
+ shstrtab = f->sections[f->header.e_shstrndx]->contents;
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+ sec->name = shstrtab + sec->header.sh_name;
+ }
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+
+ /* .modinfo and .modstring should be contents only but gcc has no
+ * attribute for that. The kernel may have marked these sections as
+ * ALLOC, ignore the allocate bit.
+ */
+ if (strcmp(sec->name, ".modinfo") == 0 ||
+ strcmp(sec->name, ".modstring") == 0)
+ sec->header.sh_flags &= ~SHF_ALLOC;
+
+ if (sec->header.sh_flags & SHF_ALLOC)
+ obj_insert_section_load_order(f, sec);
+
+ switch (sec->header.sh_type)
+ {
+ case SHT_SYMTAB:
+ {
+ unsigned long nsym, j;
+ char *strtab;
+ ElfW(Sym) *sym;
+
+ if (sec->header.sh_entsize != sizeof(ElfW(Sym)))
+ {
+ error("symbol size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)sec->header.sh_entsize,
+ (unsigned long)sizeof(ElfW(Sym)));
+ return NULL;
+ }
+
+ nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+ strtab = f->sections[sec->header.sh_link]->contents;
+ sym = (ElfW(Sym) *) sec->contents;
+
+ /* Allocate space for a table of local symbols. */
+ j = f->local_symtab_size = sec->header.sh_info;
+ f->local_symtab = xmalloc(j *= sizeof(struct obj_symbol *));
+ memset(f->local_symtab, 0, j);
+
+ /* Insert all symbols into the hash table. */
+ for (j = 1, ++sym; j < nsym; ++j, ++sym)
+ {
+ const char *name;
+ if (sym->st_name)
+ name = strtab+sym->st_name;
+ else
+ name = f->sections[sym->st_shndx]->name;
+
+ obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+ sym->st_value, sym->st_size);
+
+ }
+ }
+ break;
+ }
+ }
+
+ /* second pass to add relocation data to symbols */
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+ switch (sec->header.sh_type)
+ {
+ case SHT_RELM:
+ {
+ unsigned long nrel, j;
+ ElfW(RelM) *rel;
+ struct obj_section *symtab;
+ char *strtab;
+ if (sec->header.sh_entsize != sizeof(ElfW(RelM)))
+ {
+ error("relocation entry size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)sec->header.sh_entsize,
+ (unsigned long)sizeof(ElfW(RelM)));
+ return NULL;
+ }
+
+ nrel = sec->header.sh_size / sizeof(ElfW(RelM));
+ rel = (ElfW(RelM) *) sec->contents;
+ symtab = f->sections[sec->header.sh_link];
+ strtab = f->sections[symtab->header.sh_link]->contents;
+
+ /* Save the relocate type in each symbol entry. */
+ for (j = 0; j < nrel; ++j, ++rel)
+ {
+ ElfW(Sym) *extsym;
+ struct obj_symbol *intsym;
+ unsigned long symndx;
+ symndx = ELFW(R_SYM)(rel->r_info);
+ if (symndx)
+ {
+ extsym = ((ElfW(Sym) *) symtab->contents) + symndx;
+ if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL)
+ {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ }
+ else
+ {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+ intsym->r_type = ELFW(R_TYPE)(rel->r_info);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ f->filename = xstrdup(filename);
+
+ return f;
+}
+
+void obj_free(struct obj_file *f)
+{
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ struct obj_symbol *next;
+ int i;
+ int n;
+
+ if (f->sections) {
+ n = f->header.e_shnum;
+ for (i = 0; i < n; ++i) {
+ if ((sec = f->sections[i]) != NULL) {
+ if (sec->contents)
+ free(sec->contents);
+ free(sec);
+ }
+ }
+ free(f->sections);
+ }
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ for (sym = f->symtab[i]; sym; sym = next) {
+ next = sym->next;
+ free(sym);
+ }
+ }
+
+ if (f->local_symtab)
+ free(f->local_symtab);
+
+ if (f->filename)
+ free((char *)(f->filename));
+
+ if (f->persist)
+ free((char *)(f->persist));
+
+ free(f);
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_m68k.c b/mdk-stage1/insmod-modutils/obj/obj_m68k.c
new file mode 100644
index 000000000..cb485aed7
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_m68k.c
@@ -0,0 +1,147 @@
+/* m68k specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ char *loc = targsec->contents + rel->r_offset;
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_68K_NONE:
+ break;
+
+ case R_68K_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *(char *)loc = v;
+ break;
+ case R_68K_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *(short *)loc = v;
+ break;
+ case R_68K_32:
+ *(int *)loc = v;
+ break;
+
+ case R_68K_PC8:
+ v -= dot;
+ if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80)
+ ret = obj_reloc_overflow;
+ *(char *)loc = v;
+ break;
+ case R_68K_PC16:
+ v -= dot;
+ if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000)
+ ret = obj_reloc_overflow;
+ *(short *)loc = v;
+ break;
+ case R_68K_PC32:
+ *(int *)loc = v - dot;
+ break;
+
+ case R_68K_RELATIVE:
+ *(int *)loc += ef->baseaddr;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_mips.c b/mdk-stage1/insmod-modutils/obj/obj_mips.c
new file mode 100644
index 000000000..c2315b659
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_mips.c
@@ -0,0 +1,238 @@
+/* MIPS specific support for Elf loading and relocation.
+ Copyright 1997, 1998 Linux International.
+ Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct mips_hi16
+{
+ struct mips_hi16 *next;
+ Elf32_Addr *addr;
+ Elf32_Addr value;
+};
+
+struct mips_file
+{
+ struct obj_file root;
+ struct mips_hi16 *mips_hi16_list;
+};
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct mips_file *mf;
+
+ mf = xmalloc(sizeof(*mf));
+ mf->mips_hi16_list = NULL;
+
+ return (struct obj_file *) mf;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_MIPS_DEBUG:
+ case SHT_MIPS_REGINFO:
+ /* Actually these two sections are as useless as something can be ... */
+ sec->contents = NULL;
+ break;
+
+ case SHT_MIPS_LIBLIST:
+ case SHT_MIPS_CONFLICT:
+ case SHT_MIPS_GPTAB:
+ case SHT_MIPS_UCODE:
+ case SHT_MIPS_OPTIONS:
+ case SHT_MIPS_DWARF:
+ case SHT_MIPS_EVENTS:
+ /* These shouldn't ever be in a module file. */
+ error("Unhandled section header type: %08x", sec->header.sh_type);
+
+ default:
+ /* We don't even know the type. This time it might as well be a
+ supernova. */
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct mips_file *mf = (struct mips_file *)f;
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ enum obj_reloc ret = obj_reloc_ok;
+
+ /* _gp_disp is a magic symbol for PIC which is not supported for
+ the kernel and loadable modules. */
+ if (strcmp(sym->name, "_gp_disp") == 0)
+ ret = obj_reloc_unhandled;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_MIPS_NONE:
+ break;
+
+ case R_MIPS_32:
+ *loc += v;
+ break;
+
+ 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 = mf->mips_hi16_list;
+ mf->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 (mf->mips_hi16_list != NULL)
+ {
+ struct mips_hi16 *l;
+
+ l = mf->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;
+ }
+
+ mf->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;
+ }
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_ppc.c b/mdk-stage1/insmod-modutils/obj/obj_ppc.c
new file mode 100644
index 000000000..89bb8e46b
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_ppc.c
@@ -0,0 +1,255 @@
+/* PowerPC specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Adapted by Paul Mackerras <paulus@cs.anu.edu.au> from the
+ obj-sparc.c and obj-alpha.c files.
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+#include <assert.h>
+
+
+/*======================================================================*/
+
+/*
+ * Unfortunately, the bl (branch-and-link) instruction used for
+ * procedure calls on the PowerPC can only reach +/- 32MB from the
+ * current instruction. If the module is loaded far enough away from
+ * the main kernel text (or other modules) that this limit is
+ * exceeded, we have to redirect procedure calls via a procedure
+ * linkage table (PLT). Each entry in the PLT contains instructions
+ * to put the address of the procedure in a register and jump to it.
+ */
+
+typedef unsigned int instruction; /* a powerpc instruction (4 bytes) */
+
+struct ppc_plt_entry
+{
+ struct ppc_plt_entry *next;
+ ElfW(Addr) addend;
+ int offset;
+ int inited;
+};
+
+struct ppc_file
+{
+ struct obj_file file;
+ struct obj_section *plt;
+};
+
+struct ppc_symbol
+{
+ struct obj_symbol sym;
+ struct ppc_plt_entry *plt_entries;
+};
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct ppc_file *f;
+
+ f = xmalloc(sizeof(struct ppc_file));
+ f->plt = NULL;
+ return &f->file;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct ppc_symbol *p;
+
+ p = xmalloc(sizeof(struct ppc_symbol));
+ p->plt_entries = NULL;
+ return &p->sym;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ struct ppc_file *pf = (struct ppc_file *) ef;
+ struct ppc_symbol *psym = (struct ppc_symbol *) sym;
+ struct ppc_plt_entry *pe;
+ instruction *ip;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_PPC_ADDR16_HA:
+ *(unsigned short *)loc = (v + 0x8000) >> 16;
+ break;
+
+ case R_PPC_ADDR16_HI:
+ *(unsigned short *)loc = v >> 16;
+ break;
+
+ case R_PPC_ADDR16_LO:
+ *(unsigned short *)loc = v;
+ break;
+
+ case R_PPC_REL24:
+ /* find the plt entry and initialize it if necessary */
+ assert(psym != NULL);
+ for (pe = psym->plt_entries; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->inited)
+ {
+ ip = (instruction *) (pf->plt->contents + pe->offset);
+ ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
+ ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
+ ip[2] = 0x7d6903a6; /* mtctr r11 */
+ ip[3] = 0x4e800420; /* bctr */
+ pe->inited = 1;
+ }
+
+ v -= dot;
+ if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+ {
+ /* go via the plt */
+ v = pf->plt->header.sh_addr + pe->offset - dot;
+ }
+ if (v & 3)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
+ break;
+
+ case R_PPC_REL32:
+ *loc = v - dot;
+ break;
+
+ case R_PPC_ADDR32:
+ *loc = v;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct ppc_file *pf = (struct ppc_file *) f;
+ int i, offset;
+ struct obj_section *sec, *syms, *strs;
+ ElfW(Rela) *rel, *relend;
+ ElfW(Sym) *symtab, *extsym;
+ const char *strtab, *name;
+ struct ppc_symbol *intsym;
+ struct ppc_plt_entry *pe;
+
+ offset = 0;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type != SHT_RELM)
+ continue;
+ syms = f->sections[sec->header.sh_link];
+ strs = f->sections[syms->header.sh_link];
+
+ rel = (ElfW(RelM) *) sec->contents;
+ relend = rel + (sec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) syms->contents;
+ strtab = (const char *) strs->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ if (ELF32_R_TYPE(rel->r_info) != R_PPC_REL24)
+ continue;
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct ppc_symbol *) obj_find_symbol(f, name);
+
+ for (pe = intsym->plt_entries; pe != NULL; pe = pe->next)
+ if (pe->addend == rel->r_addend)
+ break;
+ if (pe == NULL)
+ {
+ pe = xmalloc(sizeof(struct ppc_plt_entry));
+ pe->next = intsym->plt_entries;
+ pe->addend = rel->r_addend;
+ pe->offset = offset;
+ pe->inited = 0;
+ intsym->plt_entries = pe;
+ offset += 16;
+ }
+ }
+ }
+
+ pf->plt = obj_create_alloced_section(f, ".plt", 16, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_reloc.c b/mdk-stage1/insmod-modutils/obj/obj_reloc.c
new file mode 100644
index 000000000..f5f2de90d
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_reloc.c
@@ -0,0 +1,435 @@
+/* Elf relocation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <alloca.h>
+
+#include <obj.h>
+#include <util.h>
+
+/*======================================================================*/
+
+int
+obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string)
+{
+ struct obj_string_patch_struct *p;
+ struct obj_section *strsec;
+ size_t len = strlen(string)+1;
+ char *loc;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->string_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ f->string_patches = p;
+
+ strsec = obj_find_section(f, ".kstrtab");
+ if (strsec == NULL)
+ {
+ strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+ p->string_offset = 0;
+ loc = strsec->contents;
+ }
+ else
+ {
+ p->string_offset = strsec->header.sh_size;
+ loc = obj_extend_section(strsec, len);
+ }
+ memcpy(loc, string, len);
+
+ return 1;
+}
+
+int
+obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym)
+{
+ struct obj_symbol_patch_struct *p;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->symbol_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ p->sym = sym;
+ f->symbol_patches = p;
+
+ return 1;
+}
+
+int
+obj_check_undefineds(struct obj_file *f, int quiet)
+{
+ unsigned long i;
+ int ret = 1;
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF)
+ {
+ if (ELFW(ST_BIND)(sym->info) == STB_WEAK)
+ {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ }
+ else if (sym->r_type) /* assumes R_arch_NONE is 0 on all arch */
+ {
+ if (!quiet)
+ error("unresolved symbol %s", sym->name);
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void
+obj_clear_undefineds(struct obj_file *f)
+{
+ unsigned long i;
+ struct obj_symbol *sym;
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF)
+ {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ }
+ }
+}
+
+void
+obj_allocate_commons(struct obj_file *f)
+{
+ struct common_entry
+ {
+ struct common_entry *next;
+ struct obj_symbol *sym;
+ } *common_head = NULL;
+
+ unsigned long i;
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_COMMON)
+ {
+ /* Collect all COMMON symbols and sort them by size so as to
+ minimize space wasted by alignment requirements. */
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p ; p = &(*p)->next)
+ if (sym->size <= (*p)->sym->size)
+ break;
+
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ }
+ }
+ }
+
+ for (i = 1; i < f->local_symtab_size; ++i)
+ {
+ struct obj_symbol *sym = f->local_symtab[i];
+ if (sym && sym->secidx == SHN_COMMON)
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p ; p = &(*p)->next)
+ if (sym == (*p)->sym)
+ break;
+ else if (sym->size < (*p)->sym->size)
+ {
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ break;
+ }
+ }
+ }
+
+ if (common_head)
+ {
+ /* Find the bss section. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ if (f->sections[i]->header.sh_type == SHT_NOBITS)
+ break;
+
+ /* If for some reason there hadn't been one, create one. */
+ if (i == f->header.e_shnum)
+ {
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (i+1) * sizeof(sec));
+ f->sections[i] = sec = arch_new_section();
+ f->header.e_shnum = i+1;
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->name = ".bss";
+ sec->idx = i;
+ }
+
+ /* Allocate the COMMONS. */
+ {
+ ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+ ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+ struct common_entry *c;
+
+ for (c = common_head; c ; c = c->next)
+ {
+ ElfW(Addr) align = c->sym->value;
+
+ if (align > max_align)
+ max_align = align;
+ if (bss_size & (align - 1))
+ bss_size = (bss_size | (align - 1)) + 1;
+
+ c->sym->secidx = i;
+ c->sym->value = bss_size;
+
+ bss_size += c->sym->size;
+ }
+
+ f->sections[i]->header.sh_size = bss_size;
+ f->sections[i]->header.sh_addralign = max_align;
+ }
+ }
+
+ /* For the sake of patch relocation and parameter initialization,
+ allocate zeroed data for NOBITS sections now. Note that after
+ this we cannot assume NOBITS are really empty. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ struct obj_section *s = f->sections[i];
+ if (s->header.sh_type == SHT_NOBITS)
+ {
+ if (s->header.sh_size)
+ s->contents = memset(xmalloc(s->header.sh_size),
+ 0, s->header.sh_size);
+ else
+ s->contents = NULL;
+ s->header.sh_type = SHT_PROGBITS;
+ }
+ }
+}
+
+unsigned long
+obj_load_size (struct obj_file *f)
+{
+ unsigned long dot = 0;
+ struct obj_section *sec;
+
+ /* Finalize the positions of the sections relative to one another. */
+
+ for (sec = f->load_order; sec ; sec = sec->load_next)
+ {
+ ElfW(Addr) align;
+
+ align = sec->header.sh_addralign;
+ if (align && (dot & (align - 1)))
+ dot = (dot | (align - 1)) + 1;
+
+ sec->header.sh_addr = dot;
+ dot += sec->header.sh_size;
+ }
+
+ return dot;
+}
+
+int
+obj_relocate (struct obj_file *f, ElfW(Addr) base)
+{
+ int i, n = f->header.e_shnum;
+ int ret = 1;
+
+ /* Finalize the addresses of the sections. */
+
+ arch_finalize_section_address(f, base);
+
+ /* And iterate over all of the relocations. */
+
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *targsec, *strsec;
+ ElfW(RelM) *rel, *relend;
+ ElfW(Sym) *symtab;
+ const char *strtab;
+
+ relsec = f->sections[i];
+ if (relsec->header.sh_type != SHT_RELM)
+ continue;
+
+ symsec = f->sections[relsec->header.sh_link];
+ targsec = f->sections[relsec->header.sh_info];
+ strsec = f->sections[symsec->header.sh_link];
+
+ rel = (ElfW(RelM) *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ ElfW(Addr) value = 0;
+ struct obj_symbol *intsym = NULL;
+ unsigned long symndx;
+ ElfW(Sym) *extsym = 0;
+ const char *errmsg;
+
+ /* Attempt to find a value to use for this relocation. */
+
+ symndx = ELFW(R_SYM)(rel->r_info);
+ if (symndx)
+ {
+ /* Note we've already checked for undefined symbols. */
+
+ extsym = &symtab[symndx];
+ if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL)
+ {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ }
+ else
+ {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+
+ value = obj_symbol_final_value(f, intsym);
+ }
+
+#if SHT_RELM == SHT_RELA
+#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+ /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
+ if (!extsym || !extsym->st_name ||
+ ELFW(ST_BIND)(extsym->st_info) != STB_LOCAL)
+#endif
+ value += rel->r_addend;
+#endif
+
+ /* Do it! */
+ switch (arch_apply_relocation(f,targsec,symsec,intsym,rel,value))
+ {
+ case obj_reloc_ok:
+ break;
+
+ case obj_reloc_overflow:
+ errmsg = "Relocation overflow";
+ goto bad_reloc;
+ case obj_reloc_dangerous:
+ errmsg = "Dangerous relocation";
+ goto bad_reloc;
+ case obj_reloc_unhandled:
+ errmsg = "Unhandled relocation";
+ goto bad_reloc;
+ case obj_reloc_constant_gp:
+ errmsg = "Modules compiled with -mconstant-gp cannot be loaded";
+ goto bad_reloc;
+ bad_reloc:
+ if (extsym)
+ {
+ error("%s of type %ld for %s", errmsg,
+ (long)ELFW(R_TYPE)(rel->r_info),
+ strtab + extsym->st_name);
+ }
+ else
+ {
+ error("%s of type %ld", errmsg,
+ (long)ELFW(R_TYPE)(rel->r_info));
+ }
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ /* Finally, take care of the patches. */
+
+ if (f->string_patches)
+ {
+ struct obj_string_patch_struct *p;
+ struct obj_section *strsec;
+ ElfW(Addr) strsec_base;
+ strsec = obj_find_section(f, ".kstrtab");
+ strsec_base = strsec->header.sh_addr;
+
+ for (p = f->string_patches; p ; p = p->next)
+ {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
+ = strsec_base + p->string_offset;
+ }
+ }
+
+ if (f->symbol_patches)
+ {
+ struct obj_symbol_patch_struct *p;
+
+ for (p = f->symbol_patches; p; p = p->next)
+ {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
+ = obj_symbol_final_value(f, p->sym);
+ }
+ }
+
+ return ret;
+}
+
+int
+obj_create_image (struct obj_file *f, char *image)
+{
+ struct obj_section *sec;
+ ElfW(Addr) base = f->baseaddr;
+
+ for (sec = f->load_order; sec ; sec = sec->load_next)
+ {
+ char *secimg;
+
+ if (sec->contents == 0)
+ continue;
+
+ secimg = image + (sec->header.sh_addr - base);
+
+ /* Note that we allocated data for NOBITS sections earlier. */
+ memcpy(secimg, sec->contents, sec->header.sh_size);
+ }
+
+ return 1;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_s390.c b/mdk-stage1/insmod-modutils/obj/obj_s390.c
new file mode 100644
index 000000000..3da72e771
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_s390.c
@@ -0,0 +1,245 @@
+/* S/390 specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct s390_got_entry
+{
+ int offset;
+ unsigned offset_done : 1;
+ unsigned reloc_done : 1;
+};
+
+struct s390_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct s390_symbol
+{
+ struct obj_symbol root;
+ struct s390_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct s390_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct s390_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ struct s390_file *ifile = (struct s390_file *)f;
+ struct s390_symbol *isym = (struct s390_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_390_NONE:
+ break;
+
+ case R_390_32:
+ *loc += v;
+ break;
+
+ case R_390_PLT32:
+ case R_390_PC32:
+ *loc += v - dot;
+ break;
+
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_390_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_390_GOTPC:
+ assert(got != 0);
+ *loc += got - dot;
+ break;
+
+ case R_390_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;
+ break;
+
+ case R_390_GOTOFF:
+ assert(got != 0);
+ *loc += v - got;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct s390_file *ifile = (struct s390_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;
+ Elf32_Rel *rel, *relend;
+ Elf32_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_REL)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rel *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ Elf32_Sym *extsym;
+ struct s390_symbol *intsym;
+ const char *name;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_390_GOTPC:
+ case R_390_GOTOFF:
+ gotneeded = 1;
+ default:
+ continue;
+
+ case R_390_GOT32:
+ break;
+ }
+
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct s390_symbol *)obj_find_symbol(&ifile->root, name);
+
+ if (!intsym->gotent.offset_done)
+ {
+ intsym->gotent.offset_done = 1;
+ intsym->gotent.offset = offset;
+ offset += 4;
+ }
+ }
+ }
+
+ if (offset > 0 || gotneeded)
+ ifile->got = obj_create_alloced_section(&ifile->root, ".got", 4, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *m)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_sparc.c b/mdk-stage1/insmod-modutils/obj/obj_sparc.c
new file mode 100644
index 000000000..1a03c9090
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_sparc.c
@@ -0,0 +1,226 @@
+/* Sparc specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_32:
+ *loc = v;
+ break;
+ case R_SPARC_DISP8:
+ v -= dot;
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_DISP16:
+ v -= dot;
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_DISP32:
+ v -= dot;
+ *loc = v;
+ break;
+ case R_SPARC_WDISP30:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffffff) | (v >> 2);
+ break;
+ case R_SPARC_WDISP22:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffff) | ((v >> 2) & 0x3fffff);
+ break;
+ case R_SPARC_HI22:
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+ case R_SPARC_22:
+ if (v > 0x3fffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3fffff) | (v & 0x3fffff);
+ break;
+ case R_SPARC_13:
+ if (v > 0x1fff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1fff) | (v & 0x1fff);
+ break;
+ case R_SPARC_LO10:
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+
+ case R_SPARC_PC10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_PC22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+
+ case R_SPARC_UA32:
+ *(((char *)loc) + 0) = (char)(v >> 24);
+ *(((char *)loc) + 1) = (char)(v >> 16);
+ *(((char *)loc) + 2) = (char)(v >> 8);
+ *(((char *)loc) + 3) = (char)v;
+ break;
+
+#ifdef R_SPARC_10
+ case R_SPARC_10:
+ if (v > 0x3ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_11:
+ if (v > 0x7ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7ff) | (v & 0x7ff);
+ break;
+ case R_SPARC_WDISP16:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x303fff) | ((v << 4) & 0x300000) | ((v >> 2) & 0x3fff);
+ break;
+ case R_SPARC_WDISP19:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x7ffff) | ((v >> 2) & 0x7ffff);
+ break;
+ case R_SPARC_7:
+ if (v > 0x7f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7f) | (v & 0x7f);
+ break;
+ case R_SPARC_5:
+ if (v > 0x1f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1f) | (v & 0x1f);
+ break;
+ case R_SPARC_6:
+ if (v > 0x3f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3f) | (v & 0x3f);
+ break;
+#endif /* R_SPARC_10 */
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_sparc64.c b/mdk-stage1/insmod-modutils/obj/obj_sparc64.c
new file mode 100644
index 000000000..84e8d18a0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_sparc64.c
@@ -0,0 +1,352 @@
+/* Sparc64 specific support for Elf loading and relocation.
+ Copyright 1997 Linux International.
+
+ Contributed by Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+#ifdef BROKEN_SPARC64_RELOCS
+
+#undef R_SPARC_PLT32
+#undef R_SPARC_HIPLT22
+#undef R_SPARC_LOPLT10
+#undef R_SPARC_PCPLT32
+#undef R_SPARC_PCPLT22
+#undef R_SPARC_PCPLT10
+#undef R_SPARC_10
+#undef R_SPARC_11
+#undef R_SPARC_64
+#undef R_SPARC_OLO10
+#undef R_SPARC_HH22
+#undef R_SPARC_HM10
+#undef R_SPARC_LM22
+#undef R_SPARC_PC_HH22
+#undef R_SPARC_PC_HM10
+#undef R_SPARC_PC_LM22
+#undef R_SPARC_WDISP16
+#undef R_SPARC_WDISP19
+#undef R_SPARC_GLOB_JMP
+#undef R_SPARC_7
+#undef R_SPARC_5
+#undef R_SPARC_6
+
+#define R_SPARC_10 24
+#define R_SPARC_11 25
+#define R_SPARC_64 26
+#define R_SPARC_OLO10 27
+#define R_SPARC_HH22 28
+#define R_SPARC_HM10 29
+#define R_SPARC_LM22 30
+#define R_SPARC_PC_HH22 31
+#define R_SPARC_PC_HM10 32
+#define R_SPARC_PC_LM22 33
+#define R_SPARC_WDISP16 34
+#define R_SPARC_WDISP19 35
+#define R_SPARC_GLOB_JMP 36
+#define R_SPARC_7 37
+#define R_SPARC_5 38
+#define R_SPARC_6 39
+
+#else
+
+#ifndef R_SPARC_64
+
+#define R_SPARC_64 32
+#define R_SPARC_OLO10 33
+#define R_SPARC_HH22 34
+#define R_SPARC_HM10 35
+#define R_SPARC_LM22 36
+#define R_SPARC_PC_HH22 37
+#define R_SPARC_PC_HM10 38
+#define R_SPARC_PC_LM22 39
+
+#endif
+
+#endif
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+#define ELF64_R_TYPE_ID(info) ((info) & 0xff)
+#define ELF64_R_TYPE_DATA(info) ((info) >> 8)
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ unsigned int *loc = (unsigned int *)(targsec->contents + rel->r_offset);
+ unsigned int dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF64_R_TYPE_ID(rel->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ if (! ((long) loc & 3)) {
+ /* Common in .eh_frame */
+ ((unsigned int *) loc) [0] = v >> 32;
+ ((unsigned int *) loc) [1] = v;
+ break;
+ }
+ ((unsigned char *) loc) [0] = v >> 56;
+ ((unsigned char *) loc) [1] = v >> 48;
+ ((unsigned char *) loc) [2] = v >> 40;
+ ((unsigned char *) loc) [3] = v >> 32;
+ ((unsigned char *) loc) [4] = v >> 24;
+ ((unsigned char *) loc) [5] = v >> 16;
+ ((unsigned char *) loc) [6] = v >> 8;
+ ((unsigned char *) loc) [7] = v;
+ break;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ if (! ((long) loc & 3)) {
+ *loc = v;
+ break;
+ }
+ ((unsigned char *) loc) [0] = v >> 24;
+ ((unsigned char *) loc) [1] = v >> 16;
+ ((unsigned char *) loc) [2] = v >> 8;
+ ((unsigned char *) loc) [3] = v;
+ break;
+ case R_SPARC_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+
+ case R_SPARC_DISP32:
+ v -= dot;
+ *loc = v;
+ break;
+ case R_SPARC_DISP16:
+ v -= dot;
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_DISP8:
+ v -= dot;
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_WDISP30:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffffff) | ((v >> 2) & 0x3fffffff);
+ break;
+
+ /* MEDLOW code model relocs */
+ case R_SPARC_LO10:
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_HI22:
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+ case R_SPARC_OLO10:
+ *loc = (*loc & ~0x1fff) | (((v & 0x3ff) + ELF64_R_TYPE_DATA (rel->r_info)) & 0x1fff);
+ break;
+
+ /* MEDMID code model relocs */
+ case R_SPARC_H44:
+ *loc = (*loc & ~0x3fffff) | (v >> 22);
+ break;
+ case R_SPARC_M44:
+ *loc = (*loc & ~0x3ff) | ((v >> 12) & 0x3ff);
+ break;
+ case R_SPARC_L44:
+ *loc = (*loc & ~0xfff) | (v & 0xfff);
+ break;
+
+ /* MEDANY code model relocs */
+ case R_SPARC_HH22:
+ *loc = (*loc & ~0x3fffff) | (v >> 42);
+ break;
+ case R_SPARC_HM10:
+ *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff);
+ break;
+ case R_SPARC_LM22:
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+
+ case R_SPARC_WDISP22:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffff) | ((v >> 2) & 0x3fffff);
+ break;
+ case R_SPARC_22:
+ if (v > 0x3fffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3fffff) | (v & 0x3fffff);
+ break;
+ case R_SPARC_13:
+ if (v > 0x1fff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1fff) | (v & 0x1fff);
+ break;
+
+ case R_SPARC_PC10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_PC22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+
+#ifdef R_SPARC_10
+ case R_SPARC_10:
+ if (v > 0x3ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_11:
+ if (v > 0x7ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7ff) | (v & 0x7ff);
+ break;
+
+#ifdef R_SPARC_64
+ case R_SPARC_PC_HH22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | (v >> 42);
+ break;
+ case R_SPARC_PC_HM10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff);
+ break;
+ case R_SPARC_PC_LM22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+#endif
+
+ case R_SPARC_WDISP16:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x303fff) | ((v << 4) & 0x300000) | ((v >> 2) & 0x3fff);
+ break;
+ case R_SPARC_WDISP19:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x7ffff) | ((v >> 2) & 0x7ffff);
+ break;
+ case R_SPARC_7:
+ if (v > 0x7f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7f) | (v & 0x7f);
+ break;
+ case R_SPARC_5:
+ if (v > 0x1f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1f) | (v & 0x1f);
+ break;
+ case R_SPARC_6:
+ if (v > 0x3f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3f) | (v & 0x3f);
+ break;
+#endif /* R_SPARC_10 */
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}