diff -Nur linux-2.6.0-test11/arch/i386/kernel/module.c linux-2.6.0-test11-modified/arch/i386/kernel/module.c --- linux-2.6.0-test11/arch/i386/kernel/module.c 2003-11-26 18:44:07.000000000 -0200 +++ linux-2.6.0-test11-modified/arch/i386/kernel/module.c 2003-12-02 15:17:46.000000000 -0200 @@ -35,13 +35,10 @@ return vmalloc(size); } - /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) -{ +{ vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ } /* We don't need anything special. */ diff -Nur linux-2.6.0-test11/include/asm-i386/uaccess.h linux-2.6.0-test11-modified/include/asm-i386/uaccess.h --- linux-2.6.0-test11/include/asm-i386/uaccess.h 2003-11-26 18:43:07.000000000 -0200 +++ linux-2.6.0-test11-modified/include/asm-i386/uaccess.h 2003-12-02 15:10:52.000000000 -0200 @@ -123,6 +123,15 @@ unsigned long insn, fixup; }; +/* Compare two exception table entries: < 0 if ex1 comes before ex2 */ +static inline int extable_cmp(const struct exception_table_entry ex1, + const struct exception_table_entry ex2) +{ + return (long)ex1.insn - ex2.insn; +} + + + extern int fixup_exception(struct pt_regs *regs); /* diff -Nur linux-2.6.0-test11/include/linux/moduleloader.h linux-2.6.0-test11-modified/include/linux/moduleloader.h --- linux-2.6.0-test11/include/linux/moduleloader.h 2003-11-26 18:43:40.000000000 -0200 +++ linux-2.6.0-test11-modified/include/linux/moduleloader.h 2003-12-02 15:10:52.000000000 -0200 @@ -44,4 +44,8 @@ /* Any cleanup needed when module leaves. */ void module_arch_cleanup(struct module *mod); +/* This code sorts an exception table. It is very used with modules code */ +void sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish); + #endif diff -Nur linux-2.6.0-test11/kernel/extable.c linux-2.6.0-test11-modified/kernel/extable.c --- linux-2.6.0-test11/kernel/extable.c 2003-11-26 18:43:32.000000000 -0200 +++ linux-2.6.0-test11-modified/kernel/extable.c 2003-12-02 15:10:52.000000000 -0200 @@ -19,6 +19,8 @@ #include #include +#include + extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; @@ -45,3 +47,26 @@ return module_text_address(addr) != NULL; } + + +void sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (extable_cmp(p[0], p[-1]) == -1) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && extable_cmp(el, q[-1]) == -1); + *q = el; + } + } +} + diff -Nur linux-2.6.0-test11/kernel/module.c linux-2.6.0-test11-modified/kernel/module.c --- linux-2.6.0-test11/kernel/module.c 2003-11-26 18:44:57.000000000 -0200 +++ linux-2.6.0-test11-modified/kernel/module.c 2003-12-02 15:10:52.000000000 -0200 @@ -1076,6 +1076,42 @@ return ret; } +static inline int within(unsigned long addr, void *start, unsigned long size) +{ + return ((void *)addr >= start && (void *)addr < start + size); +} + +/* Remove exception table entries which belongs to this module's init area */ +void remove_init_exceptions(struct module *mod) +{ + const struct exception_table_entry *local; + unsigned int i; + int num_init_ex=0; + + if (!mod->module_init) + return; + + local = mod->extable; + i = 1; + while (i <= mod->num_exentries) { + if (within((unsigned long) local->insn, mod->module_init, + mod->init_size)) { + num_init_ex++; + } + else break; + local = local+1; + i++; + } + + /* Move the pointer to remove the init exceptions */ + spin_lock(&modlist_lock); + mod->extable += num_init_ex; + mod->num_exentries -= num_init_ex; + spin_unlock(&modlist_lock); +} + + + /* Free a module, remove from lists, etc (must hold module mutex). */ static void free_module(struct module *mod) { @@ -1615,6 +1651,11 @@ mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); mod->extable = (void *)sechdrs[exindex].sh_addr; + /* Classifying the exception table */ + sort_ex_table((struct exception_table_entry *)mod->extable, + (struct exception_table_entry *)mod->extable + + mod->num_exentries); + /* Now do relocations. */ for (i = 1; i < hdr->e_shnum; i++) { const char *strtab = (char *)sechdrs[strindex].sh_addr; @@ -1753,6 +1794,7 @@ mod->state = MODULE_STATE_LIVE; /* Drop initial reference. */ module_put(mod); + remove_init_exceptions(mod); module_free(mod, mod->module_init); mod->module_init = NULL; mod->init_size = 0; @@ -1762,11 +1804,6 @@ return 0; } -static inline int within(unsigned long addr, void *start, unsigned long size) -{ - return ((void *)addr >= start && (void *)addr < start + size); -} - #ifdef CONFIG_KALLSYMS static const char *get_ksymbol(struct module *mod, unsigned long addr,