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>
# include <asm/uaccess.h>
# ifndef ARCH_HAS_SORT_EXTABLE
/*
* 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 */
if ( x - > insn > y - > insn )
return 1 ;
if ( x - > insn < y - > insn )
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 ) ,
cmp_ex , NULL ) ;
}
# endif
# 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
*/
if ( mid - > insn < value )
first = mid + 1 ;
else if ( mid - > insn > value )
last = mid - 1 ;
else
return mid ;
}
return NULL ;
}
# endif