| 
									
										
										
										
											2005-04-16 15:20:36 -07: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); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-06-12 21:47:03 -06: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*/ | 
					
						
							|  |  |  | 	while (m->num_exentries && within_module_init(m->extable[0].insn, m)) { | 
					
						
							|  |  |  | 		m->extable++; | 
					
						
							|  |  |  | 		m->num_exentries--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/*trim the end*/ | 
					
						
							|  |  |  | 	while (m->num_exentries && | 
					
						
							|  |  |  | 		within_module_init(m->extable[m->num_exentries-1].insn, m)) | 
					
						
							|  |  |  | 		m->num_exentries--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* CONFIG_MODULES */
 | 
					
						
							|  |  |  | #endif /* !ARCH_HAS_SORT_EXTABLE */
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07: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 01:37:49 -08:00
										 |  |  | 		mid = ((last - first) >> 1) + first; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07: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 01:37:49 -08:00
										 |  |  | 		 * careful, the distance between value and insn | 
					
						
							|  |  |  | 		 * can be larger than MAX_LONG: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		 */ | 
					
						
							|  |  |  | 		if (mid->insn < value) | 
					
						
							|  |  |  | 			first = mid + 1; | 
					
						
							|  |  |  | 		else if (mid->insn > value) | 
					
						
							|  |  |  | 			last = mid - 1; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return mid; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 |