summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/insmod-modutils/obj/obj_load.c
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/obj_load.c
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/obj_load.c')
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_load.c354
1 files changed, 354 insertions, 0 deletions
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);
+}