diff -Nur linux-2.6.0-test11/Makefile linux-2.6.0-test11-modified/Makefile --- linux-2.6.0-test11/Makefile 2003-11-26 18:44:43.000000000 -0200 +++ linux-2.6.0-test11-modified/Makefile 2003-12-02 15:12:34.000000000 -0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -test11 +EXTRAVERSION = -test11-so3 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/drivers/base/Kconfig linux-2.6.0-test11-modified/drivers/base/Kconfig --- linux-2.6.0-test11/drivers/base/Kconfig 2003-11-26 18:43:09.000000000 -0200 +++ linux-2.6.0-test11-modified/drivers/base/Kconfig 2003-12-02 15:10:51.000000000 -0200 @@ -8,4 +8,7 @@ require hotplug firmware loading support, but a module built outside the kernel tree does. +config SISOP3 + tristate "Modulo de SO3" + endmenu diff -Nur linux-2.6.0-test11/drivers/base/Makefile linux-2.6.0-test11-modified/drivers/base/Makefile --- linux-2.6.0-test11/drivers/base/Makefile 2003-11-26 18:45:22.000000000 -0200 +++ linux-2.6.0-test11-modified/drivers/base/Makefile 2003-12-02 15:10:51.000000000 -0200 @@ -6,3 +6,4 @@ obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o memblk.o +obj-$(CONFIG_SISOP3) += sisop3.o diff -Nur linux-2.6.0-test11/drivers/base/sisop3.c linux-2.6.0-test11-modified/drivers/base/sisop3.c --- linux-2.6.0-test11/drivers/base/sisop3.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6.0-test11-modified/drivers/base/sisop3.c 2003-12-02 15:10:51.000000000 -0200 @@ -0,0 +1,11 @@ +#include +#include +#include + +/* Dummy function in the init section which causes an extable entry */ +int __init function_with_exception_init(void *uaddr, void *addr) +{ + return copy_from_user(addr, uaddr, 4); +} + +MODULE_LICENSE("GPL"); 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,