2005-04-17 02:20:36 +04:00
/*
* 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/module.h>
# include <linux/init.h>
# include <linux/sort.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
2016-01-01 14:39:09 +03:00
# ifndef ARCH_HAS_RELATIVE_EXTABLE
# define ex_to_insn(x) ((x)->insn)
# else
static inline unsigned long ex_to_insn ( const struct exception_table_entry * x )
{
return ( unsigned long ) & x - > insn + x - > insn ;
}
# endif
2005-04-17 02:20:36 +04:00
# ifndef ARCH_HAS_SORT_EXTABLE
2016-01-01 14:39:09 +03:00
# ifndef ARCH_HAS_RELATIVE_EXTABLE
# define swap_ex NULL
# else
static void swap_ex ( void * a , void * b , int size )
{
struct exception_table_entry * x = a , * y = b , tmp ;
int delta = b - a ;
tmp = * x ;
x - > insn = y - > insn + delta ;
y - > insn = tmp . insn - delta ;
# ifdef swap_ex_entry_fixup
swap_ex_entry_fixup ( x , y , tmp , delta ) ;
# else
x - > fixup = y - > fixup + delta ;
y - > fixup = tmp . fixup - delta ;
# endif
}
# endif /* ARCH_HAS_RELATIVE_EXTABLE */
2005-04-17 02:20:36 +04:00
/*
* 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 .
*/
static int cmp_ex ( const void * a , const void * b )
{
const struct exception_table_entry * x = a , * y = b ;
/* avoid overflow */
2016-01-01 14:39:09 +03:00
if ( ex_to_insn ( x ) > ex_to_insn ( y ) )
2005-04-17 02:20:36 +04:00
return 1 ;
2016-01-01 14:39:09 +03:00
if ( ex_to_insn ( x ) < ex_to_insn ( y ) )
2005-04-17 02:20:36 +04:00
return - 1 ;
return 0 ;
}
void sort_extable ( struct exception_table_entry * start ,
struct exception_table_entry * finish )
{
sort ( start , finish - start , sizeof ( struct exception_table_entry ) ,
2016-01-01 14:39:09 +03:00
cmp_ex , swap_ex ) ;
2005-04-17 02:20:36 +04:00
}
2009-06-13 07:47:03 +04:00
# ifdef CONFIG_MODULES
/*
* If the exception table is sorted , any referring to the module init
* will be at the beginning or the end .
*/
void trim_init_extable ( struct module * m )
{
/*trim the beginning*/
2016-01-01 14:39:09 +03:00
while ( m - > num_exentries & &
within_module_init ( ex_to_insn ( & m - > extable [ 0 ] ) , m ) ) {
2009-06-13 07:47:03 +04:00
m - > extable + + ;
m - > num_exentries - - ;
}
/*trim the end*/
while ( m - > num_exentries & &
2016-01-01 14:39:09 +03:00
within_module_init ( ex_to_insn ( & m - > extable [ m - > num_exentries - 1 ] ) ,
m ) )
2009-06-13 07:47:03 +04:00
m - > num_exentries - - ;
}
# endif /* CONFIG_MODULES */
# endif /* !ARCH_HAS_SORT_EXTABLE */
2005-04-17 02:20:36 +04:00
# ifndef ARCH_HAS_SEARCH_EXTABLE
/*
* 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 ;
lib/extable.c: remove an expensive integer divide in search_extable()
Actual code let compiler generates idiv instruction on x86.
Using a right shift is OK here and readable as well.
Before patch
10: 57 push %edi
11: 56 push %esi
12: 89 d6 mov %edx,%esi
14: 53 push %ebx
15: 89 c3 mov %eax,%ebx
17: eb 22 jmp 3b <search_extable+0x2b>
19: 89 f0 mov %esi,%eax
1b: ba 02 00 00 00 mov $0x2,%edx
20: 29 d8 sub %ebx,%eax
22: 89 d7 mov %edx,%edi
24: c1 f8 03 sar $0x3,%eax
27: 99 cltd
28: f7 ff idiv %edi
2a: 8d 04 c3 lea (%ebx,%eax,8),%eax
2d: 39 08 cmp %ecx,(%eax)
...
After patch
00000010 <search_extable>:
10: 53 push %ebx
11: 89 c3 mov %eax,%ebx
13: eb 18 jmp 2d <search_extable+0x1d>
15: 89 d0 mov %edx,%eax
17: 29 d8 sub %ebx,%eax
19: c1 f8 04 sar $0x4,%eax
1c: 8d 04 c3 lea (%ebx,%eax,8),%eax
1f: 39 08 cmp %ecx,(%eax)
...
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:37:49 +03:00
mid = ( ( last - first ) > > 1 ) + first ;
2005-04-17 02:20:36 +04:00
/*
lib/extable.c: remove an expensive integer divide in search_extable()
Actual code let compiler generates idiv instruction on x86.
Using a right shift is OK here and readable as well.
Before patch
10: 57 push %edi
11: 56 push %esi
12: 89 d6 mov %edx,%esi
14: 53 push %ebx
15: 89 c3 mov %eax,%ebx
17: eb 22 jmp 3b <search_extable+0x2b>
19: 89 f0 mov %esi,%eax
1b: ba 02 00 00 00 mov $0x2,%edx
20: 29 d8 sub %ebx,%eax
22: 89 d7 mov %edx,%edi
24: c1 f8 03 sar $0x3,%eax
27: 99 cltd
28: f7 ff idiv %edi
2a: 8d 04 c3 lea (%ebx,%eax,8),%eax
2d: 39 08 cmp %ecx,(%eax)
...
After patch
00000010 <search_extable>:
10: 53 push %ebx
11: 89 c3 mov %eax,%ebx
13: eb 18 jmp 2d <search_extable+0x1d>
15: 89 d0 mov %edx,%eax
17: 29 d8 sub %ebx,%eax
19: c1 f8 04 sar $0x4,%eax
1c: 8d 04 c3 lea (%ebx,%eax,8),%eax
1f: 39 08 cmp %ecx,(%eax)
...
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-02-06 12:37:49 +03:00
* careful , the distance between value and insn
* can be larger than MAX_LONG :
2005-04-17 02:20:36 +04:00
*/
2016-01-01 14:39:09 +03:00
if ( ex_to_insn ( mid ) < value )
2005-04-17 02:20:36 +04:00
first = mid + 1 ;
2016-01-01 14:39:09 +03:00
else if ( ex_to_insn ( mid ) > value )
2005-04-17 02:20:36 +04:00
last = mid - 1 ;
else
return mid ;
2016-01-01 14:39:09 +03:00
}
return NULL ;
2005-04-17 02:20:36 +04:00
}
# endif