diff -Nurb linux.orig/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- linux.orig/arch/i386/kernel/Makefile Tue Sep 18 08:03:09 2001 +++ linux/arch/i386/kernel/Makefile Wed Dec 5 22:12:44 2001 @@ -18,7 +18,8 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \ + obj_i386.o ifdef CONFIG_PCI diff -Nurb linux.orig/arch/i386/kernel/obj_i386.c linux/arch/i386/kernel/obj_i386.c --- linux.orig/arch/i386/kernel/obj_i386.c Thu Jan 1 01:00:00 1970 +++ linux/arch/i386/kernel/obj_i386.c Sat Dec 8 14:16:06 2001 @@ -0,0 +1,237 @@ +/* i386 specific support for Elf loading and relocation. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + +#ident "$Id: obj_i386.c 1.3 Wed, 26 Sep 2001 14:50:45 +1000 kaos $" + +#include +#include + + +/*======================================================================*/ + +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 = kmalloc(sizeof(*f), GFP_KERNEL); + f->got = NULL; + return &f->root; +} + +struct obj_section * +arch_new_section (void) +{ + return kmalloc(sizeof(struct obj_section), GFP_KERNEL); +} + +struct obj_symbol * +arch_new_symbol (void) +{ + struct i386_symbol *sym; + sym = kmalloc(sizeof(*sym), GFP_KERNEL); + 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) + { + struct i386_symbol *intsym; + + switch (ELF32_R_TYPE(rel->r_info)) + { + case R_386_GOTPC: + case R_386_GOTOFF: + gotneeded = 1; + default: + continue; + + case R_386_GOT32: + break; + } + + obj_find_relsym(intsym, f, &ifile->root, rel, symtab, strtab); + + 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, + SHF_WRITE); + + 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 -Nurb linux.orig/include/linux/obj_load.h linux/include/linux/obj_load.h --- linux.orig/include/linux/obj_load.h Thu Jan 1 01:00:00 1970 +++ linux/include/linux/obj_load.h Sat Dec 8 14:16:39 2001 @@ -0,0 +1,299 @@ +/* Elf object file loading and relocation routines. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + obj_free() added by Björn Ekwall March 1999 + + 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + + +#ifndef MODUTILS_OBJ_H +#define MODUTILS_OBJ_H 1 + +#ident "$Id: obj.h 1.7 Tue, 02 Oct 2001 11:22:51 +1000 kaos $" + +/* The relocatable object is manipulated using elfin types. */ + +#include +#include + +//#ifndef ElfW +//# if ELF_CLASS == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +//# else +//# define ElfW(x) Elf64_ ## x +//# define ELFW(x) ELF64_ ## x +//# endif +//#endif + +#if defined(COMMON_3264) && defined(ONLY_32) +# define ObjW(x) obj32_ ## x +#else +# if defined(COMMON_3264) && defined(ONLY_64) +# define ObjW(x) obj64_ ## x +# else +# define ObjW(x) obj_ ## x +# endif +#endif + +/* For some reason this is missing from lib5. */ +#ifndef ELF32_ST_INFO +# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +#ifndef ELF64_ST_INFO +# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +struct obj_string_patch_struct; +struct obj_symbol_patch_struct; + +struct obj_section +{ + ElfW(Shdr) header; + const char *name; + char *contents; + struct obj_section *load_next; + int idx; +}; + +struct obj_symbol +{ + struct obj_symbol *next; /* hash table link */ + const char *name; + unsigned long value; + unsigned long size; + int secidx; /* the defining section index/module */ + int info; + int ksymidx; /* for export to the kernel symtab */ + int r_type; /* relocation type */ +}; + +/* Hardcode the hash table size. We shouldn't be needing so many + symbols that we begin to degrade performance, and we get a big win + by giving the compiler a constant divisor. */ + +#define HASH_BUCKETS 521 + +struct obj_file +{ + ElfW(Ehdr) header; + ElfW(Addr) baseaddr; + struct obj_section **sections; + struct obj_section *load_order; + struct obj_section **load_order_search_start; + struct obj_string_patch_struct *string_patches; + struct obj_symbol_patch_struct *symbol_patches; + int (*symbol_cmp)(const char *, const char *); + unsigned long (*symbol_hash)(const char *); + unsigned long local_symtab_size; + struct obj_symbol **local_symtab; + struct obj_symbol *symtab[HASH_BUCKETS]; + const char *filename; + char *persist; +}; + +enum obj_reloc +{ + obj_reloc_ok, + obj_reloc_overflow, + obj_reloc_dangerous, + obj_reloc_unhandled, + obj_reloc_constant_gp +}; + +struct obj_string_patch_struct +{ + struct obj_string_patch_struct *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + ElfW(Addr) string_offset; +}; + +struct obj_symbol_patch_struct +{ + struct obj_symbol_patch_struct *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + struct obj_symbol *sym; +}; + + +/* Generic object manipulation routines. */ + +#define obj_elf_hash ObjW(elf_hash) +#define obj_elf_hash_n ObjW(elf_hash_n) +#define obj_add_symbol ObjW(add_symbol) +#define obj_find_symbol ObjW(find_symbol) +#define obj_symbol_final_value ObjW(symbol_final_value) +#define obj_set_symbol_compare ObjW(set_symbol_compare) +#define obj_find_section ObjW(find_section) +#define obj_insert_section_load_order ObjW(insert_section_load_order) +#define obj_create_alloced_section ObjW(create_alloced_section) +#define obj_create_alloced_section_first \ + ObjW(create_alloced_section_first) +#define obj_extend_section ObjW(extend_section) +#define obj_string_patch ObjW(string_patch) +#define obj_symbol_patch ObjW(symbol_patch) +#define obj_check_undefineds ObjW(check_undefineds) +#define obj_clear_undefineds ObjW(clear_undefineds) +#define obj_allocate_commons ObjW(allocate_commons) +#define obj_load_size ObjW(load_size) +#define obj_relocate ObjW(relocate) +#define obj_load ObjW(load) +#define obj_free ObjW(free) +#define obj_create_image ObjW(create_image) +#define obj_addr_to_native_ptr ObjW(addr_to_native_ptr) +#define obj_native_ptr_to_addr ObjW(native_ptr_to_addr) +#define obj_kallsyms ObjW(kallsyms) +#define arch_new_file ObjW(arch_new_file) +#define arch_new_section ObjW(arch_new_section) +#define arch_new_symbol ObjW(arch_new_symbol) +#define arch_apply_relocation ObjW(arch_apply_relocation) +#define arch_create_got ObjW(arch_create_got) +#define arch_init_module ObjW(arch_init_module) +#define arch_load_proc_section ObjW(arch_load_proc_section) +#define arch_finalize_section_address ObjW(arch_finalize_section_address) +#define arch_archdata ObjW(arch_archdata) + +unsigned long obj_elf_hash (const char *); + +unsigned long obj_elf_hash_n (const char *, unsigned long len); + +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 *obj_find_symbol (struct obj_file *f, + const char *name); + +ElfW(Addr) obj_symbol_final_value (struct obj_file *f, + struct obj_symbol *sym); + +void obj_set_symbol_compare (struct obj_file *f, + int (*cmp)(const char *, const char *), + unsigned long (*hash)(const char *)); + +struct obj_section *obj_find_section (struct obj_file *f, + const char *name); + +void obj_insert_section_load_order (struct obj_file *f, + struct obj_section *sec); + +struct obj_section *obj_create_alloced_section (struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size, + unsigned long flags); + +struct obj_section *obj_create_alloced_section_first (struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size); + +void *obj_extend_section (struct obj_section *sec, unsigned long more); + +int obj_string_patch (struct obj_file *f, int secidx, ElfW(Addr) offset, + const char *string); + +int obj_symbol_patch (struct obj_file *f, int secidx, ElfW(Addr) offset, + struct obj_symbol *sym); + +int obj_check_undefineds (struct obj_file *f, int quiet); + +void obj_clear_undefineds (struct obj_file *f); + +void obj_allocate_commons (struct obj_file *f); + +unsigned long obj_load_size (struct obj_file *f); + +int obj_relocate (struct obj_file *f, ElfW(Addr) base); + +struct obj_file * +obj_load (void *modmem, unsigned int modsize, Elf32_Half e_type, const char *filename); + +void obj_free (struct obj_file *f); + +int obj_create_image (struct obj_file *f, char *image); + +int obj_kallsyms (struct obj_file *fin, struct obj_file **fout); + +/* Architecture specific manipulation routines. */ + +struct obj_file *arch_new_file (void); + +struct obj_section *arch_new_section (void); + +struct obj_symbol *arch_new_symbol (void); + +enum obj_reloc arch_apply_relocation (struct obj_file *f, + struct obj_section *targsec, + struct obj_section *symsec, + struct obj_symbol *sym, + ElfW(Rel) *rel, ElfW(Addr) value); + +int arch_create_got (struct obj_file *f); + +struct module; +int arch_init_module (struct obj_file *f, struct module *); + +int arch_load_proc_section (struct obj_section *sec, int fp); + +int arch_finalize_section_address (struct obj_file *f, ElfW(Addr) base); + +int arch_archdata (struct obj_file *fin, struct obj_section *sec); + +#define ARCHDATA_SEC_NAME "__archdata" + +/* Pointers in objects can be 32 or 64 bit */ +union obj_ptr_4 { + Elf32_Word addr; + void *ptr; +}; +union obj_ptr_8 { + u_int64_t addr; /* Should be Elf64_Xword but not all users have this yet */ + void *ptr; +}; + +void *obj_addr_to_native_ptr(ElfW(Addr)); + +ElfW(Addr) obj_native_ptr_to_addr(void *); + +/* Standard method of finding relocation symbols, sets isym */ +#define obj_find_relsym(isym, f, find, rel, symtab, strtab) \ + { \ + unsigned long symndx = ELFW(R_SYM)((rel)->r_info); \ + ElfW(Sym) *extsym = (symtab)+symndx; \ + if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL) { \ + isym = (typeof(isym)) (f)->local_symtab[symndx]; \ + } \ + else { \ + const char *name; \ + if (extsym->st_name) \ + name = (strtab) + extsym->st_name; \ + else \ + name = (f)->sections[extsym->st_shndx]->name; \ + isym = (typeof(isym)) obj_find_symbol((find), name); \ + } \ + } + +int obj_gpl_license(struct obj_file *, const char **); + +#endif /* obj.h */ diff -Nurb linux.orig/init/main.c linux/init/main.c --- linux.orig/init/main.c Fri Oct 12 19:17:15 2001 +++ linux/init/main.c Tue Dec 4 02:13:42 2001 @@ -94,6 +94,7 @@ extern void sysctl_init(void); extern void signals_init(void); extern int init_pcmcia_ds(void); +extern void init_boot_modules(void); extern void free_initmem(void); @@ -736,6 +737,7 @@ #ifdef CONFIG_PCMCIA init_pcmcia_ds(); /* Do this last */ #endif + init_boot_modules(); } extern void rd_load(void); diff -Nurb linux.orig/kernel/Makefile linux/kernel/Makefile --- linux.orig/kernel/Makefile Mon Sep 17 06:22:40 2001 +++ linux/kernel/Makefile Wed Dec 5 22:28:24 2001 @@ -14,7 +14,8 @@ obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o + signal.o sys.o kmod.o context.o boot_modules.o \ + obj_common.o obj_reloc.o obj_gpl_license.o obj_load.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o diff -Nurb linux.orig/kernel/boot_modules.c linux/kernel/boot_modules.c --- linux.orig/kernel/boot_modules.c Thu Jan 1 01:00:00 1970 +++ linux/kernel/boot_modules.c Thu Dec 6 15:11:02 2001 @@ -0,0 +1,413 @@ +/* + * linux/kernel/boot_modules.c + * + * Copyright (C) 2001 Christian König + * + * Ervery thing here is GPL'ed. + */ + +#include +#include + +#ifndef __i386__ //this file should'n be arch dependent, but I'am lazy + +void init_boot_modules(void) {} + +#else + +#include +#include +#include +#include + +#define STRVERSIONLEN 32 + +/* + * Conditionally add the symbols from the given symbol set + * to the new module. + */ +static int add_symbols_from(struct obj_file *f, int idx, + struct module_symbol *syms, size_t nsyms, int gpl) +{ + struct module_symbol *s; + size_t i; + int used = 0; + + for (i = 0, s = syms; i < nsyms; ++i, ++s) { + /* + * Only add symbols that are already marked external. + * If we override locals we may cause problems for + * argument initialization. + * We will also create a false dependency on the module. + */ + struct obj_symbol *sym; + + /* GPL licensed modules can use symbols exported with + * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the + * exported names. Non-GPL modules never see any GPLONLY_ + * symbols so they cannot fudge it by adding the prefix on + * their references. + */ + if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) { + if (gpl) + ((char *)s->name) += 8; + else + continue; + } + + sym = obj_find_symbol(f, (char *) s->name); + if (sym && ELFW(ST_BIND) (sym->info) != STB_LOCAL) { + sym = obj_add_symbol(f, (char *) s->name, -1, + ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), + idx, s->value, 0); + /* + * Did our symbol just get installed? + * If so, mark the module as "used". + */ + if (sym->secidx == idx) + used = 1; + } + } + + return used; +} + +static void add_kernel_symbols(struct obj_file *f, int gpl) +{ + struct module *mod; + size_t i; + + /* Add module symbols first. */ + for (mod=module_list, i = 0; mod; mod=mod->next, i++) + if (mod->nsyms) + add_symbols_from(f, SHN_HIRESERVE + 2 + i, mod->syms, mod->nsyms, gpl); +} + +static int create_this_module(struct obj_file *f, const char *m_name) +{ + struct obj_section *sec; + + sec = obj_create_alloced_section_first(f, ".this", sizeof(long), + sizeof(struct module)); + memset(sec->contents, 0, sizeof(struct module)); + + obj_add_symbol(f, "__this_module", -1, ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), + sec->idx, 0, sizeof(struct module)); + + obj_string_patch(f, sec->idx, offsetof(struct module, name), m_name); + + return 1; +} + +static void hide_special_symbols(struct obj_file *f) +{ + struct obj_symbol *sym; + const char *const *p; + static const char *const specials[] = + { + "cleanup_module", + "init_module", + "kernel_version", + NULL + }; + + for (p = specials; *p; ++p) + if ((sym = obj_find_symbol(f, *p)) != NULL) + sym->info = ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); +} + +static int create_module_ksymtab(struct obj_file *f) +{ + struct obj_section *sec; + int i; + + /* We must always add the module references. */ + +/* if (n_ext_modules_used) { + struct module_ref *dep; + struct obj_symbol *tm; + + sec = obj_create_alloced_section(f, ".kmodtab", + tgt_sizeof_void_p, + sizeof(struct module_ref) * n_ext_modules_used, 0); + if (!sec) + return 0; + + tm = obj_find_symbol(f, "__this_module"); + dep = (struct module_ref *) sec->contents; + for (i = 0; i < n_module_stat; ++i) + if (module_stat[i].status ) { + dep->dep = module_stat[i].addr; + obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm); + dep->next_ref = 0; + ++dep; + } + }*/ +/* if (!obj_find_section(f, "__ksymtab")) { + int *loaded; + + We don't want to export symbols residing in sections that + aren't loaded. There are a number of these created so that + we make sure certain module options don't appear twice. + + loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); + while (--i >= 0) + loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) { + if (ELFW(ST_BIND) (sym->info) != STB_LOCAL + && sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE + || loaded[sym->secidx])) { + add_ksymtab(f, sym); + } + } + } + }*/ + return 1; +} + +extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size); +extern asmlinkage long sys_delete_module(const char *name_user); +extern asmlinkage long sys_init_module(const char *name_user, struct module *mod_user); + +static int init_module(const char *m_name, struct obj_file *f, + unsigned long m_size) +{ + struct module *module; + struct obj_section *sec; + void *image; + int ret = 0; + long m_addr; + + sec = obj_find_section(f, ".this"); + module = (struct module *) sec->contents; + m_addr = sec->header.sh_addr; + + module->size_of_struct = sizeof(*module); + module->size = m_size; + module->flags = 0; //flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; + + sec = obj_find_section(f, "__ksymtab"); + if (sec && sec->header.sh_size) { + module->syms = sec->header.sh_addr; + module->nsyms = sec->header.sh_size / (2 * sizeof(char *)); + } +/* if (n_ext_modules_used) { + sec = obj_find_section(f, ".kmodtab"); + module->deps = sec->header.sh_addr; + module->ndeps = n_ext_modules_used; + }*/ + module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); + module->cleanup = obj_symbol_final_value(f, + obj_find_symbol(f, "cleanup_module")); + + sec = obj_find_section(f, "__ex_table"); + if (sec) { + module->ex_table_start = sec->header.sh_addr; + module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; + } + sec = obj_find_section(f, ".text.init"); + if (sec) { + module->runsize = sec->header.sh_addr - m_addr; + } + sec = obj_find_section(f, ".data.init"); + if (sec) { + if (!module->runsize || + module->runsize > sec->header.sh_addr - m_addr) + module->runsize = sec->header.sh_addr - m_addr; + } +/* sec = obj_find_section(f, ARCHDATA_SEC_NAME); + if (sec && sec->header.sh_size) { + module->archdata_start = sec->header.sh_addr; + module->archdata_end = module->archdata_start + sec->header.sh_size; + } + sec = obj_find_section(f, KALLSYMS_SEC_NAME); + if (sec && sec->header.sh_size) { + module->kallsyms_start = sec->header.sh_addr; + module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; + } + if (!arch_init_module(f, module)) + return 0; +*/ + /* + * Whew! All of the initialization is complete. + * Collect the final module image and give it to the kernel. + */ + image = kmalloc(m_size, GFP_KERNEL); + obj_create_image(f, image); + + if (ret == 0) { +// fflush(stdout); /* Flush any debugging output */ + ret = sys_init_module(m_name, (struct module *) image); + if (ret) { + printk(KERN_INFO "init_module: %m\n"); + printk(KERN_INFO "Hint: insmod errors can be caused by incorrect module parameters, " + "including invalid IO or IRQ parameters\n"); + } + } + + kfree(image); + + return ret == 0; +} + +static int insert_module(struct obj_file *f, const char *m_name, int argc, char **argv) +{ + int gpl; + unsigned long m_size; + unsigned long m_addr; + +/* int k_crcs; + int m_version; + char m_strversion[STRVERSIONLEN]; + int m_crcs; + + m_version = get_module_version(f, m_strversion); + if (m_version == -1) { + printk(KERN_INFO "couldn't find the kernel version the module was compiled for"); + return 0; + } + + k_crcs = is_kernel_checksummed(); + m_crcs = is_module_checksummed(f); + if ((m_crcs == 0 || k_crcs == 0) && + strncmp(m_strversion, UTS_RELEASE, STRVERSIONLEN) != 0) { + printk(KERN_INFO "kernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s.", + filename, m_strversion, UTS_RELEASE); + return 0; + } + if (m_crcs != k_crcs) + obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);*/ + + // We don't care about Versions for now + + /* Let the module know about the kernel symbols. */ + gpl = obj_gpl_license(f, NULL) == 0; + add_kernel_symbols(f, gpl); + + /* Allocate common symbols, symbol tables, and string tables. + * + * The calls marked DEPMOD indicate the bits of code that depmod + * uses to do a pseudo relocation, ignoring undefined symbols. + * Any changes made to the relocation sequence here should be + * checked against depmod. + */ + if (!create_this_module(f, m_name)) + return 0; + + arch_create_got(f); /* DEPMOD */ + if (!obj_check_undefineds(f, 0)) { /* DEPMOD, obj_clear_undefineds */ + if (!gpl) + printk(KERN_INFO "Note: modules without a GPL compatible license cannot use GPLONLY_ symbols\n"); + return 0; + } + obj_allocate_commons(f); /* DEPMOD */ + +// check_module_parameters(f, &persist_parms); +// check_tainted_module(f, noload); + +/* if (argc) { + if (!process_module_arguments(f, argc, argv, 1)) + return 0; + }*/ + hide_special_symbols(f); + +/* if (flag_ksymoops) + add_ksymoops_symbols(f, filename, m_name);*/ + +// if (k_new_syscalls) + create_module_ksymtab(f); + + /* archdata based on relocatable addresses */ +// if (add_archdata(f, &archdata)) +// return 0; + + /* kallsyms based on relocatable addresses */ +// if (add_kallsyms(f, &kallsyms, force_kallsyms)) +// return 0; + /**** No symbols or sections to be changed after kallsyms above ***/ + +// if (errors) +// return 0; + + /* Module has now finished growing; find its size and install it. */ + m_size = obj_load_size(f); /* DEPMOD */ + +// errno = 0; + m_addr = sys_create_module(m_name, m_size); + + switch (-m_addr) { + case 0: + break; + case EEXIST: + printk(KERN_INFO "a module named %s already exists\n", m_name); + return 0; + case ENOMEM: + printk(KERN_INFO "can't allocate kernel memory for module; needed %lu bytes\n", + m_size); + return 0; + default: + if(m_addr > 127) + break; + printk(KERN_INFO "create_module: %m\n"); + return 0; + } + + printk(KERN_INFO "Trying to relocate module @ 0x%x\n",m_addr); + if (!obj_relocate(f, m_addr)) { /* DEPMOD */ + sys_delete_module(m_name); + return 0; + } + + /* Do archdata again, this time we have the final addresses */ +// if (add_archdata(f, &archdata)) +// return 0; + + /* Do kallsyms again, this time we have the final addresses */ +// if (add_kallsyms(f, &kallsyms, force_kallsyms)) +// return 0; + + init_module(m_name, f, m_size); +/* if (errors) { + delete_module(m_name); + return 0; + }*/ + return 1; +} + +void init_boot_modules(void) +{ + int i; + struct obj_file *f; + + if(!mbootinfo) + return; + if(!(mbootinfo->flags & 8)) + return; + + for(i=0;imods_count;i++) { + char *m_name; + struct multiboot_module *mod = &mbootinfo->mods_addr[i]; + + for(m_name = mod->string; + (*m_name != 0) && (*m_name != ' ') && (strncmp(m_name,".o",2) != 0); + m_name++); + *m_name = 0; + for(;(m_name > mod->string) && (*m_name != '/');m_name--); + m_name++; + + printk(KERN_INFO "Ok Starting to load Module %s from addr 0x%x - 0x%x\n", m_name, mod->mod_start, mod->mod_end); + f = obj_load ((void *)mod->mod_start, mod->mod_end - mod->mod_start, ET_REL, mod->string); + if (!f) continue; + + insert_module(f,m_name,0,0); + obj_free(f); + } +} + +#endif diff -Nurb linux.orig/kernel/obj_common.c linux/kernel/obj_common.c --- linux.orig/kernel/obj_common.c Thu Jan 1 01:00:00 1970 +++ linux/kernel/obj_common.c Wed Dec 5 23:24:38 2001 @@ -0,0 +1,424 @@ +/* Elf file, section, and symbol manipulation routines. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + +#ident "$Id: obj_common.c 1.4 Wed, 26 Sep 2001 11:58:34 +1000 kaos $" + +#include + +#include + +/*======================================================================*/ + +/* 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) + printk(KERN_INFO "%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) + printk(KERN_INFO "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; +} + +#if defined (ARCH_alpha) +#define ARCH_SHF_SHORT SHF_ALPHA_GPREL +#elif defined (ARCH_ia64) +#define ARCH_SHF_SHORT SHF_IA_64_SHORT +#else +#define ARCH_SHF_SHORT 0 +#endif + +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 |= 64; + if (af & SHF_ALLOC) ac |= 32; + if (af & SHF_EXECINSTR) ac |= 16; + if (!(af & SHF_WRITE)) ac |= 8; + if (a->header.sh_type != SHT_NOBITS) ac |= 4; + /* Desired order is + P S AC & 7 + .data 1 0 4 + .got 1 1 3 + .sdata 1 1 1 + .sbss 0 1 1 + .bss 0 0 0 */ + if (strcmp (a->name, ".got") == 0) ac |= 2; + if (af & ARCH_SHF_SHORT) + ac = (ac & ~4) | 1; + + 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; +} + +static void *realloc(void *ptr, unsigned int size, unsigned int oldsize) +{ + void *new; + new = kmalloc(size, GFP_KERNEL); + memcpy(new, ptr, oldsize); + kfree(ptr); + return new; +} + +struct obj_section * +obj_create_alloced_section (struct obj_file *f, const char *name, + unsigned long align, unsigned long size, + unsigned long flags) +{ + int newidx = f->header.e_shnum++; + struct obj_section *sec; + + f->sections = realloc(f->sections, (newidx+1) * sizeof(sec), newidx * sizeof(sec)); + f->sections[newidx] = sec = arch_new_section(); + + memset(sec, 0, sizeof(*sec)); + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = flags | SHF_ALLOC; + sec->header.sh_size = size; + sec->header.sh_addralign = align; + sec->name = name; + sec->idx = newidx; + if (size) + sec->contents = kmalloc(size, GFP_KERNEL); + + 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 = realloc(f->sections, (newidx+1) * sizeof(sec), newidx * 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 = kmalloc(size, GFP_KERNEL); + + 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 = realloc(sec->contents, sec->header.sh_size += more, oldsize); + 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) { + printk(KERN_INFO "obj_addr_to_native_ptr truncation %lx", + (unsigned long) addr); + return NULL; + } + return(p4.ptr); + break; + case 0x0804: + p8.addr = addr; + return(p8.ptr); + break; + case 0x0808: + p8.addr = addr; + return(p8.ptr); + break; + default: + printk(KERN_INFO "obj_addr_to_native_ptr unknown conversion 0x%04x", convert); + return NULL; + } +} + +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) { + printk(KERN_INFO "obj_native_ptr_to_addr truncation %x", + p8.addr); + return 0; + } + 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: + printk(KERN_INFO "obj_native_ptr_to_addr unknown conversion 0x%04x", convert); + return 0; + } +} diff -Nurb linux.orig/kernel/obj_gpl_license.c linux/kernel/obj_gpl_license.c --- linux.orig/kernel/obj_gpl_license.c Thu Jan 1 01:00:00 1970 +++ linux/kernel/obj_gpl_license.c Sat Dec 8 14:15:16 2001 @@ -0,0 +1,65 @@ +/* Return the type of license for a module. 0 for GPL, 1 for no license, 2 for + non-GPL. The license parameter is set to the license string or NULL. + + 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + + +#include +#include +#include + +#include + +/* This list must match *exactly* the list of allowable licenses in + * linux/include/linux/module.h. Checking for leading "GPL" will not + * work, somebody will use "GPL sucks, this is proprietary". + */ +static const char *gpl_licenses[] = { + "GPL", + "GPL and additional rights", + "Dual BSD/GPL", + "Dual MPL/GPL", +}; + +int obj_gpl_license(struct obj_file *f, const char **license) +{ + struct obj_section *sec; + if ((sec = obj_find_section(f, ".modinfo"))) { + const char *value, *ptr, *endptr; + ptr = sec->contents; + endptr = ptr + sec->header.sh_size; + while (ptr < endptr) { + if ((value = strchr(ptr, '=')) && strncmp(ptr, "license", value-ptr) == 0) { + int i; + if (license) + *license = value+1; + for (i = 0; i < sizeof(gpl_licenses)/sizeof(gpl_licenses[0]); ++i) { + if (strcmp(value+1, gpl_licenses[i]) == 0) + return(0); + } + return(2); + } + if (strchr(ptr, '\0')) + ptr = strchr(ptr, '\0') + 1; + else + ptr = endptr; + } + } + return(1); +} diff -Nurb linux.orig/kernel/obj_load.c linux/kernel/obj_load.c --- linux.orig/kernel/obj_load.c Thu Jan 1 01:00:00 1970 +++ linux/kernel/obj_load.c Wed Dec 5 23:24:53 2001 @@ -0,0 +1,366 @@ +/* Elf file reader. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + obj_free() added by Björn Ekwall March 1999 + Support for kallsyms Keith Owens 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + +#ident "$Id: obj_load.c 1.4 Wed, 26 Sep 2001 14:50:45 +1000 kaos $" + +#include +#include +#include + +#include +//#include "util.h" + +/*======================================================================*/ + +int memcpy_chk(void *src, unsigned int size, int index, void *dst, int dstsize) +{ + if((size-index) < dstsize) + return 0; + memcpy(dst, src + index, dstsize); + return dstsize; +} + +struct obj_file * +obj_load (void *modmem, unsigned int modsize, 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; + + if (memcpy_chk(modmem, modsize, 0, &f->header, sizeof(f->header)) != sizeof(f->header)) + { + printk(KERN_INFO "cannot read ELF header from %s\n", filename); + obj_free(f); + 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) + { + printk(KERN_INFO "%s is not an ELF file\n", filename); + obj_free(f); + return NULL; + } + if (f->header.e_ident[EI_CLASS] != ELF_CLASS + || f->header.e_ident[EI_DATA] != ELF_DATA + || f->header.e_ident[EI_VERSION] != EV_CURRENT + || f->header.e_machine != ELF_ARCH) + { + printk(KERN_INFO "ELF file %s not for this architecture\n", filename); + obj_free(f); + return NULL; + } + if (f->header.e_type != e_type && e_type != ET_NONE) + { + switch (e_type) { + case ET_REL: + printk(KERN_INFO "ELF file %s not a relocatable object\n", filename); + break; + case ET_EXEC: + printk(KERN_INFO "ELF file %s not an executable object\n", filename); + break; + default: + printk(KERN_INFO "ELF file %s has wrong type, expecting %d got %d\n", + filename, e_type, f->header.e_type); + break; + } + obj_free(f); + return NULL; + } + + /* Read the section headers. */ + + if (f->header.e_shentsize != sizeof(ElfW(Shdr))) + { + printk(KERN_INFO "section header size mismatch %s: %lu != %lu\n", + filename, + (unsigned long)f->header.e_shentsize, + (unsigned long)sizeof(ElfW(Shdr))); + obj_free(f); + return NULL; + } + + shnum = f->header.e_shnum; + f->sections = kmalloc(sizeof(struct obj_section *) * shnum, GFP_KERNEL); + memset(f->sections, 0, sizeof(struct obj_section *) * shnum); + + section_headers = kmalloc(sizeof(ElfW(Shdr)) * shnum, GFP_KERNEL); + if (memcpy_chk(modmem, modsize, f->header.e_shoff, section_headers, sizeof(ElfW(Shdr))*shnum) != sizeof(ElfW(Shdr))*shnum) + { + printk(KERN_INFO "reading ELF section headers %s: %m\n", filename); + obj_free(f); + 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_REL: + case SHT_RELA: + if (sec->header.sh_size > 0) + { + sec->contents = kmalloc(sec->header.sh_size, GFP_KERNEL); + if (memcpy_chk(modmem, modsize, sec->header.sh_offset, sec->contents, sec->header.sh_size) != sec->header.sh_size) + { + printk(KERN_INFO "reading ELF section data %s: %m\n", filename); + obj_free(f); + return NULL; + } + } + else + sec->contents = NULL; + break; + +/*#if SHT_RELM == SHT_REL + case SHT_RELA: + if (sec->header.sh_size) { + printk(KERN_INFO "RELA relocations not supported on this architecture %s", filename); + obj_free(f); + return NULL; + } + break; +#else + case SHT_REL: + if (sec->header.sh_size) { + printk(KERN_INFO "REL relocations not supported on this architecture %s", filename); + obj_free(f); + return NULL; + } + break; +#endif*/ + + default: +/* if (sec->header.sh_type >= SHT_LOPROC) + { + if (arch_load_proc_section(sec, fp) < 0) + return NULL; + break; + }*/ + + printk(KERN_INFO "can't handle sections of type %ld %s %d\n", + (long)sec->header.sh_type, filename,i); + obj_free(f); + 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))) + { + printk(KERN_INFO "symbol size mismatch %s: %lu != %lu\n", + filename, + (unsigned long)sec->header.sh_entsize, + (unsigned long)sizeof(ElfW(Sym))); + obj_free(f); + 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 = kmalloc(j *= sizeof(struct obj_symbol *), GFP_KERNEL); + 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_REL: + case SHT_RELA: + { + unsigned long nrel, j, nsyms; + ElfW(Rel) *rel; + struct obj_section *symtab; + char *strtab; + if (sec->header.sh_entsize != sizeof(ElfW(Rel))) + { + printk(KERN_INFO "relocation entry size mismatch %s: %lu != %lu\n", + filename, + (unsigned long)sec->header.sh_entsize, + (unsigned long)sizeof(ElfW(Rel))); + obj_free(f); + return NULL; + } + + nrel = sec->header.sh_size / sizeof(ElfW(Rel)); + rel = (ElfW(Rel) *) sec->contents; + symtab = f->sections[sec->header.sh_link]; + nsyms = symtab->header.sh_size / symtab->header.sh_entsize; + strtab = f->sections[symtab->header.sh_link]->contents; + + /* Save the relocate type in each symbol entry. */ + for (j = 0; j < nrel; ++j, ++rel) + { + struct obj_symbol *intsym; + unsigned long symndx; + symndx = ELFW(R_SYM)(rel->r_info); + if (symndx) + { + if (symndx >= nsyms) + { + printk(KERN_INFO "%s: Bad symbol index: %08lx >= %08lx\n", + filename, symndx, nsyms); + continue; + } + + obj_find_relsym(intsym, f, f, rel, (ElfW(Sym) *)(symtab->contents), strtab); + intsym->r_type = ELFW(R_TYPE)(rel->r_info); + } + } + } + break; + } + } + + f->filename = kmalloc(strlen(filename), GFP_KERNEL); + strcpy((char *)f->filename,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) + kfree(sec->contents); + kfree(sec); + } + } + kfree(f->sections); + } + + for (i = 0; i < HASH_BUCKETS; ++i) { + for (sym = f->symtab[i]; sym; sym = next) { + next = sym->next; + kfree(sym); + } + } + + if (f->local_symtab) + kfree(f->local_symtab); + + if (f->filename) + kfree((char *)(f->filename)); + + if (f->persist) + kfree((char *)(f->persist)); + + kfree(f); +} diff -Nurb linux.orig/kernel/obj_reloc.c linux/kernel/obj_reloc.c --- linux.orig/kernel/obj_reloc.c Thu Jan 1 01:00:00 1970 +++ linux/kernel/obj_reloc.c Sat Dec 8 14:15:27 2001 @@ -0,0 +1,425 @@ +/* Elf relocation routines. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + 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. + + Modified by Christian König (ChristianK.@t-online.de) to work inside the kernel*/ + +#ident "$Id: obj_reloc.c 1.4 Wed, 26 Sep 2001 14:50:45 +1000 kaos $" + +#include +#include +#include + +#include + +/*======================================================================*/ + +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 = kmalloc(sizeof(*p), GFP_KERNEL); + 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, 0); + 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 = kmalloc(sizeof(*p), GFP_KERNEL); + 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) + printk(KERN_INFO "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; + } + } +} + +static void *realloc(void *ptr, unsigned int size, unsigned int oldsize) +{ + void *new; + new = kmalloc(size, GFP_KERNEL); + memcpy(new, ptr, oldsize); + kfree(ptr); + return new; +} + +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 = realloc(f->sections, (i+1) * sizeof(sec), i * 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(kmalloc(s->header.sh_size, GFP_KERNEL), + 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(Rel) *rel, *relend; + ElfW(Sym) *symtab; + const char *strtab; + unsigned long nsyms; + + relsec = f->sections[i]; + if (relsec->header.sh_type != SHT_REL) + continue; + + symsec = f->sections[relsec->header.sh_link]; + targsec = f->sections[relsec->header.sh_info]; + strsec = f->sections[symsec->header.sh_link]; + + if (!(targsec->header.sh_flags & SHF_ALLOC)) + continue; + + rel = (ElfW(Rel) *)relsec->contents; + relend = rel + (relsec->header.sh_size / sizeof(ElfW(Rel))); + symtab = (ElfW(Sym) *)symsec->contents; + nsyms = symsec->header.sh_size / symsec->header.sh_entsize; + strtab = (const char *)strsec->contents; + + for (; rel < relend; ++rel) + { + ElfW(Addr) value = 0; + struct obj_symbol *intsym = NULL; + unsigned long symndx; + 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. */ + + if (symndx >= nsyms) + { + printk(KERN_INFO "Bad symbol index: %08lx >= %08lx", + symndx, nsyms); + continue; + } + + obj_find_relsym(intsym, f, f, rel, symtab, strtab); + value = obj_symbol_final_value(f, intsym); + } + +#if SHT_RELM == SHT_RELA + 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: + printk(KERN_INFO "%s of type %ld for %s", errmsg, + (long)ELFW(R_TYPE)(rel->r_info), intsym->name); + 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; +}