]> git.hungrycats.org Git - linux/commitdiff
[PATCH] sort exception tables
authorPaul Mackerras <paulus@samba.org>
Mon, 19 Jan 2004 13:49:29 +0000 (05:49 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Mon, 19 Jan 2004 13:49:29 +0000 (05:49 -0800)
This patch arranges for the exception tables to be sorted on most
architectures.  It sorts the main kernel exception table on startup
and the module exception tables when they get loaded.  The main table
is sorted reasonably early - just after kmem_cache_init - but that
could be moved even earlier if necessary.

There is now a lib/extable.c which includes the sort_extable()
function from arch/ppc/mm/extable.c and the search_extable() function
from arch/i386/mm/extable.c, which had been copied to many
architectures.  On many architectures, arch/$(ARCH)/mm/extable.c
became empty and so I have removed it.

There are four architectures which do things differently from i386:
alpha, ia64, sparc and sparc64.  Alpha and ia64 store the offset from
the offset from the exception table entry to the instruction, and
sparc and sparc64 have range entries in the table.  For those
architectures I have added empty sort_extable functions.  The
maintainers for those architectures can implement something better if
they care to.  As it is they are no worse off than before.

Although it is a moderately sizable patch, it ends up with a net
reduction of 377 lines in the size of the kernel source. :)

I have tested this on x86 and ppc with a module that uses __get_user
in an init function, deliberately laid out to get the exception table
out of order, and it works (whereas it oopsed without this patch).

38 files changed:
arch/alpha/mm/extable.c
arch/arm/mm/extable.c
arch/arm26/mm/extable.c
arch/cris/mm/Makefile
arch/cris/mm/extable.c [deleted file]
arch/h8300/mm/Makefile
arch/h8300/mm/extable.c [deleted file]
arch/i386/mm/extable.c
arch/ia64/mm/extable.c
arch/m68k/mm/Makefile
arch/m68k/mm/extable.c [deleted file]
arch/m68knommu/mm/Makefile
arch/m68knommu/mm/extable.c [deleted file]
arch/mips/mm/Makefile
arch/mips/mm/extable.c [deleted file]
arch/parisc/mm/Makefile
arch/parisc/mm/extable.c [deleted file]
arch/ppc/kernel/module.c
arch/ppc/mm/Makefile
arch/ppc/mm/extable.c [deleted file]
arch/ppc64/kernel/module.c
arch/ppc64/kernel/setup.c
arch/ppc64/mm/Makefile
arch/ppc64/mm/extable.c [deleted file]
arch/s390/mm/Makefile
arch/s390/mm/extable.c [deleted file]
arch/sh/mm/extable.c
arch/sparc/mm/extable.c
arch/sparc64/mm/extable.c
arch/x86_64/mm/extable.c
include/asm-ppc/uaccess.h
include/asm-ppc64/uaccess.h
include/linux/module.h
init/main.c
kernel/extable.c
kernel/module.c
lib/Makefile
lib/extable.c [new file with mode: 0644]

index 310c9fd5604f880ce4e0333952d3129d57471e13..c3849baebd575e06683e706c2710dbf13f596480 100644 (file)
@@ -6,6 +6,11 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+}
+
 const struct exception_table_entry *
 search_extable(const struct exception_table_entry *first,
               const struct exception_table_entry *last,
index 8c4840f5b4a3e8e2af12be906f38b6502c4c5e9d..9592c3ee4cb2543002eef58f3a3298fc3606dca6 100644 (file)
@@ -4,27 +4,6 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
-
 int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fixup;
index ab012b131edc080b14b5a2a6a5c43138bfe5aa65..72644dd07201958e051fdb0073e42092572eedea 100644 (file)
@@ -6,27 +6,6 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-               const struct exception_table_entry *last,
-               unsigned long value)
-{
-        while (first <= last) {
-                const struct exception_table_entry *mid;
-                long diff;
-
-                mid = (last - first) / 2 + first;
-                diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
-
 int fixup_exception(struct pt_regs *regs)
 {
         const struct exception_table_entry *fixup;
index f3790c7e41ae4734582f08f061710fdc63358827..d3ae08c90b4e8bb0d54110a104c613fb995420e6 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the linux cris-specific parts of the memory manager.
 #
 
-obj-y   := init.o fault.o tlb.o extable.o ioremap.o
+obj-y   := init.o fault.o tlb.o ioremap.o
 
diff --git a/arch/cris/mm/extable.c b/arch/cris/mm/extable.c
deleted file mode 100644 (file)
index 7992bdb..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * linux/arch/cris/mm/extable.c
- *
- * $Log: extable.c,v $
- * Revision 1.4  2003/01/09 14:42:52  starvik
- * Merge of Linux 2.5.55
- *
- * Revision 1.3  2002/11/21 07:24:54  starvik
- * Made search_exception_table similar to implementation for other archs
- * (now compiles with CONFIG_MODULES)
- *
- * Revision 1.2  2002/11/18 07:36:55  starvik
- * Removed warning
- *
- * Revision 1.1  2001/12/17 13:59:27  bjornw
- * Initial revision
- *
- * Revision 1.3  2001/09/27 13:52:40  bjornw
- * Harmonize underscore-ness with other parts
- *
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
index 79c34b1c9872f71663ba86e5926fb1fa16f0e5cc..05d4fea86c1e2c1e035c2785b71922c60f9a70bf 100644 (file)
@@ -7,4 +7,4 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-obj-y   := init.o fault.o memory.o kmap.o extable.o
+obj-y   := init.o fault.o memory.o kmap.o
diff --git a/arch/h8300/mm/extable.c b/arch/h8300/mm/extable.c
deleted file mode 100644 (file)
index 4f4f885..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/arch/h8300/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
index 1526546b5c3eb650b923cf07af4c85bb8d716f61..d9b0e43343f4d177a0f231e31d2f6d218bf9dc3a 100644 (file)
@@ -7,28 +7,6 @@
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
-
 int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fixup;
index 898824e69a1a02c8db4c0b79031bc31e841a1347..7f7955395173d5ec446699e4ca5efc40001c6bac 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/module.h>
 
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+}
+
 const struct exception_table_entry *
 search_extable (const struct exception_table_entry *first,
                const struct exception_table_entry *last,
index 7fabdff3c2d36e6af445ba7ebb6e727293e40227..f3fe7dd6abb8412dd5f84f47f74aa487b978d82a 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux m68k-specific parts of the memory manager.
 #
 
-obj-y          := init.o fault.o extable.o hwtest.o
+obj-y          := init.o fault.o hwtest.o
 
 ifndef CONFIG_SUN3
 obj-y          += kmap.o memory.o motorola.o
diff --git a/arch/m68k/mm/extable.c b/arch/m68k/mm/extable.c
deleted file mode 100644 (file)
index ca4c8ef..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * linux/arch/m68k/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = value - mid->insn;
-               if (diff >= 0 && diff <= 2)
-                       return mid;
-               else if (diff > 0)
-                       first = mid+1;
-               else
-                       last = mid-1;
-       }
-       return NULL;
-}
-
index 8bc60abd53f3593ce5bbbbb681b12245439cc8cb..fc91f254f51b35555375a64ccf9b1db0917a86cc 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the linux m68knommu specific parts of the memory manager.
 #
 
-obj-y += init.o fault.o memory.o kmap.o extable.o
+obj-y += init.o fault.o memory.o kmap.o
diff --git a/arch/m68knommu/mm/extable.c b/arch/m68knommu/mm/extable.c
deleted file mode 100644 (file)
index 888202c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/arch/m68knommu/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
index b0ef91adf96ec0116a72550ee21ab65e1ddc52c3..62439685503107042bb748c5eab856b02d56dcea 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Linux/MIPS-specific parts of the memory manager.
 #
 
-obj-y                          += cache.o extable.o fault.o loadmmu.o pgtable.o
+obj-y                          += cache.o fault.o loadmmu.o pgtable.o
 
 obj-$(CONFIG_MIPS32)           += ioremap.o pgtable-32.o
 obj-$(CONFIG_MIPS64)           += pgtable-64.o
diff --git a/arch/mips/mm/extable.c b/arch/mips/mm/extable.c
deleted file mode 100644 (file)
index 946e7ad..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/arch/i386/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return NULL;
-}
index 7d071aac8c17e3974d9ad304b01ca4f9a7557078..758ceefb373aedaa0aaa86d57bccfe8fc6390887 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for arch/parisc/mm
 #
 
-obj-y   := init.o fault.o extable.o ioremap.o
+obj-y   := init.o fault.o ioremap.o
diff --git a/arch/parisc/mm/extable.c b/arch/parisc/mm/extable.c
deleted file mode 100644 (file)
index f969b6e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Kernel exception handling table support.  Derived from arch/i386/mm/extable.c.
- *
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 John Marvin (jsm@fc.hp.com)
- */
-
-#include <asm/uaccess.h>
-
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long addr)
-{
-       /* Abort early if the search value is out of range.  */
-
-       if ((addr < first->addr) || (addr > last->addr))
-               return 0;
-
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = first + ((last - first)/2);
-               diff = mid->addr - addr;
-
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-
-        return 0;
-}
-
index a7a8158b211f521941f6ccdf1b00339bb7dcfb9d..92f4e5f64f02c3e30c07fb34822a1e2a78318400 100644 (file)
@@ -269,7 +269,6 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
        return 0;
 }
 
-/* FIXME: Sort exception table --RR */
 int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
index 0ed5eb8aad03a41bfe69c984ac9c3ede21c04b4c..6c1dd3974adb035271f85da3efcced43fdf1548e 100644 (file)
@@ -6,7 +6,7 @@ ifdef CONFIG_PPC64BRIDGE
 EXTRA_AFLAGS           := -Wa,-mppc64bridge
 endif
 
-obj-y                          := fault.o init.o mem_pieces.o extable.o \
+obj-y                          := fault.o init.o mem_pieces.o \
                                        mmu_context.o pgtable.o
 
 obj-$(CONFIG_PPC_STD_MMU)      += hashtable.o ppc_mmu.o tlb.o
diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c
deleted file mode 100644 (file)
index 3b8f08b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * arch/ppc/mm/extable.c
- *
- * from arch/i386/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-extern struct exception_table_entry __start___ex_table[];
-extern struct exception_table_entry __stop___ex_table[];
-
-/*
- * The exception table needs to be sorted because we use the macros
- * which put things into the exception table in a variety of segments
- * such as the prep, pmac, chrp, etc. segments as well as the init
- * segment and the main kernel text segment.
- */
-static inline 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 (p[0].insn < p[-1].insn) {
-                       /* 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 && el.insn < q[-1].insn);
-                       *q = el;
-               }
-       }
-}
-
-void __init
-sort_exception_table(void)
-{
-       sort_ex_table(__start___ex_table, __stop___ex_table);
-}
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-       return NULL;
-}
index 978211ac0e07450fe9e6f13c8830ae5999892422..7a624639454052c9ce654912aa058ad5f87cf736 100644 (file)
@@ -404,10 +404,6 @@ int module_finalize(const Elf_Ehdr *hdr,
         */
        list_add(&me->arch.bug_list, &module_bug_list);
 
-       sort_ex_table((struct exception_table_entry *)me->extable,
-                     (struct exception_table_entry *)me->extable +
-                               me->num_exentries);
-
        return 0;
 }
 
index 95252b3a9a847c5f6d490cc5f0a4988e4d4f2787..9f4d27328b16bdff11927e5e6fa48ceae60f63ed 100644 (file)
@@ -490,7 +490,6 @@ void __init ppc64_calibrate_delay(void)
 }      
 
 extern void (*calibrate_delay)(void);
-extern void sort_exception_table(void);
 
 /*
  * Called into from start_kernel, after lock_kernel has been called.
@@ -538,7 +537,6 @@ void __init setup_arch(char **cmdline_p)
        ppc_md.setup_arch();
 
        paging_init();
-       sort_exception_table();
        ppc64_boot_msg(0x15, "Setup Done");
 }
 
index 94b182fd110f5be1b69861164bb35f8cc2d6cc6d..ec0a2463cad15f1b050dcbf80fa13f56aee0aa6c 100644 (file)
@@ -4,6 +4,6 @@
 
 EXTRA_CFLAGS += -mno-minimal-toc
 
-obj-y := fault.o init.o extable.o imalloc.o hash_utils.o hash_low.o
+obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/ppc64/mm/extable.c b/arch/ppc64/mm/extable.c
deleted file mode 100644 (file)
index af24a68..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * arch/ppc64/mm/extable.c
- *
- * from arch/i386/mm/extable.c
- *
- *      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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-extern struct exception_table_entry __start___ex_table[];
-extern struct exception_table_entry __stop___ex_table[];
-
-/*
- * The exception table needs to be sorted because we use the macros
- * which put things into the exception table in a variety of segments
- * as well as the init segment and the main kernel text segment.
- *
- * Also used for modules.
- */
-void __init_or_module 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 (p[0].insn < p[-1].insn) {
-                       /* 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 && el.insn < q[-1].insn);
-                       *q = el;
-               }
-       }
-}
-
-void __init
-sort_exception_table(void)
-{
-       sort_ex_table(__start___ex_table, __stop___ex_table);
-}
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-       while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-               if (diff == 0)
-                       return mid;
-               else if (diff < 0)
-                       first = mid+1;
-               else
-                       last = mid-1;
-       }
-       return NULL;
-}
index 2e0c10b51d84d2577929c19203a2b2e441471014..3360e50a2559cc2860c37738d338db542a7728bb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the linux s390-specific parts of the memory manager.
 #
 
-obj-y   := init.o fault.o ioremap.o extable.o
+obj-y   := init.o fault.o ioremap.o
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c
deleted file mode 100644 (file)
index 8d13d71..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  arch/s390/mm/extable.c
- *
- *  S390 version
- *
- *  identical to arch/i386/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value)
-{
-       while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-               if (diff == 0)
-                       return mid;
-               else if (diff < 0)
-                       first = mid+1;
-               else
-                       last = mid-1;
-       }
-       return NULL;
-}
index f1704b25f7657a6d1efc52e8c5c063f0dbb53a6b..994d9280d72f07f3a116ed4f8aa0f64cabc2c590 100644 (file)
@@ -9,29 +9,6 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-                const struct exception_table_entry *last,
-                unsigned long value)
-{
-        while (first <= last) {
-               const struct exception_table_entry *mid;
-               long diff;
-
-               mid = (last - first) / 2 + first;
-               diff = mid->insn - value;
-                if (diff == 0)
-                        return mid;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-
-        return NULL;
-}
-
 int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fixup;
index 3d435860b5aa1cd014b1148455ea6ad12670b795..c9845c71f42666c98f91eb630083ff3d01b19b55 100644 (file)
@@ -6,6 +6,11 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+}
+
 /* Caller knows they are in a range if ret->fixup == 0 */
 const struct exception_table_entry *
 search_extable(const struct exception_table_entry *start,
index 54a17bc63324da80811f16e1e5cb84c33f656be7..ec334297ff4f232f7e19dd7c5b4c10041fd853b3 100644 (file)
@@ -9,6 +9,11 @@
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
+{
+}
+
 /* Caller knows they are in a range if ret->fixup == 0 */
 const struct exception_table_entry *
 search_extable(const struct exception_table_entry *start,
index 8b62676f3e73966b276ddef5f94f55c07a1408b3..39f7d6df69785ee515c8b551865bc6d2e2ec876c 100644 (file)
@@ -36,10 +36,9 @@ search_extable(const struct exception_table_entry *first,
 
 /* When an exception handler is in an non standard section (like __init)
    the fixup table can end up unordered. Fix that here. */
-static __init int check_extable(void)
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish)
 {
-       extern struct exception_table_entry __start___ex_table[];
-       extern struct exception_table_entry  __stop___ex_table[];
        struct exception_table_entry *e;
        int change;
 
@@ -47,7 +46,7 @@ static __init int check_extable(void)
           best (and simplest) sort algorithm. */
        do {
                change = 0;
-               for (e = __start___ex_table+1; e < __stop___ex_table; e++) {
+               for (e = start+1; e < finish; e++) {
                        if (e->insn < e[-1].insn) {
                                struct exception_table_entry tmp = e[-1];
                                e[-1] = e[0];
@@ -58,4 +57,3 @@ static __init int check_extable(void)
        } while (change != 0);
        return 0;
 }
-core_initcall(check_extable);
index 9c0bf29a424c4402b97f31d3f172da8e4ca16606..0a1a1a86a1de8a25fcdc7f751e4e06cb78322a72 100644 (file)
@@ -60,8 +60,6 @@ struct exception_table_entry
        unsigned long insn, fixup;
 };
 
-extern void sort_exception_table(void);
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
index 2c18c8ada2c9062be71e10a595955559b3cc64dc..8c673fd008da34cf163805a1135cb082ec64646a 100644 (file)
@@ -82,7 +82,6 @@ struct exception_table_entry
 
 /* Returns 0 if exception not found and fixup otherwise.  */
 extern unsigned long search_exception_table(unsigned long);
-extern void sort_exception_table(void);
 
 /*
  * These are the main single-value transfer routines.  They automatically
index c0418e47a296891a19f7855e91b92a8d427d9de2..95cbc9b4936f0dae7e5202e19804eab045557da4 100644 (file)
@@ -54,6 +54,9 @@ const struct exception_table_entry *
 search_extable(const struct exception_table_entry *first,
               const struct exception_table_entry *last,
               unsigned long value);
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish);
+void sort_main_extable(void);
 
 #ifdef MODULE
 #define ___module_cat(a,b) __mod_ ## a ## b
index 4c26b3769e8077af786217de3a818a90549c7fa5..a02aa14fdcd533576c785a2ab1a664c744bcc3a5 100644 (file)
@@ -435,6 +435,7 @@ asmlinkage void __init start_kernel(void)
        page_address_init();
        mem_init();
        kmem_cache_init();
+       sort_main_extable();
        if (late_time_init)
                late_time_init();
        calibrate_delay();
index 6f1fb8c6b75b4f6f5eb5eb8716e149f926861c92..fbbfbf4fd367c4d4edc6c3500626455d005cc51f 100644 (file)
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 #include <linux/module.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/sections.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/* Sort the kernel's built-in exception table */
+void __init sort_main_extable(void)
+{
+       sort_extable(__start___ex_table, __stop___ex_table);
+}
 
 /* Given an address, look for it in the exception tables. */
 const struct exception_table_entry *search_exception_tables(unsigned long addr)
index f3113ff198187d545ac9cb3ef7fa74fabb3fb456..28c3e2cbc760feea5c5c3e90dc1eb1a10d86ef44 100644 (file)
@@ -1395,6 +1395,7 @@ static struct module *load_module(void __user *umod,
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+       struct exception_table_entry *extable;
 
        DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
               umod, len, uargs);
@@ -1611,10 +1612,6 @@ static struct module *load_module(void __user *umod,
        }
 #endif
 
-       /* Set up exception table */
-       mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
-       mod->extable = (void *)sechdrs[exindex].sh_addr;
-
        /* Now do relocations. */
        for (i = 1; i < hdr->e_shnum; i++) {
                const char *strtab = (char *)sechdrs[strindex].sh_addr;
@@ -1637,6 +1634,11 @@ static struct module *load_module(void __user *umod,
                        goto cleanup;
        }
 
+       /* Set up and sort exception table */
+       mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);
+       mod->extable = extable = (void *)sechdrs[exindex].sh_addr;
+       sort_extable(extable, extable + mod->num_exentries);
+
        /* Finally, copy percpu area over. */
        percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
                       sechdrs[pcpuindex].sh_size);
index 15f8ca078332982819c6e55ec550409cb1ffc07e..3f1c4af35166b8c0febb561646df70fa90e7df0e 100644 (file)
@@ -6,7 +6,7 @@
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
         bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
         kobject.o idr.o div64.o parser.o int_sqrt.o mask.o \
-        bitmap.o
+        bitmap.o extable.o
 
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff --git a/lib/extable.c b/lib/extable.c
new file mode 100644 (file)
index 0000000..a4b26ce
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * lib/extable.c
+ * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.
+ *
+ * Copyright (C) 2004 Paul Mackerras, IBM Corp.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ */
+void sort_extable(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 (p[0].insn < p[-1].insn) {
+                       /* 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 && el.insn < q[-1].insn);
+                       *q = el;
+               }
+       }
+}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+              const struct exception_table_entry *last,
+              unsigned long value)
+{
+       while (first <= last) {
+               const struct exception_table_entry *mid;
+               long diff;
+
+               mid = (last - first) / 2 + first;
+               diff = mid->insn - value;
+               if (diff == 0)
+                       return mid;
+               if (diff < 0)
+                       first = mid+1;
+               else
+                       last = mid-1;
+        }
+        return NULL;
+}