2222 * Portions created by Joachim Bauch are Copyright (C) 2004-2015
2323 * Joachim Bauch. All Rights Reserved.
2424 *
25+ *
26+ * THeller: Added binary search in MemoryGetProcAddress function
27+ * (#define USE_BINARY_SEARCH to enable it). This gives a very large
28+ * speedup for libraries that exports lots of functions.
29+ *
30+ * These portions are Copyright (C) 2013 Thomas Heller.
2531 */
2632
2733#include <windows.h>
5662
5763#include "MemoryModule.h"
5864
65+ struct ExportNameEntry {
66+ LPCSTR name ;
67+ WORD idx ;
68+ };
69+
5970typedef BOOL (WINAPI * DllEntryProc )(HINSTANCE hinstDLL , DWORD fdwReason , LPVOID lpReserved );
6071typedef int (WINAPI * ExeEntryProc )(void );
6172
@@ -72,6 +83,7 @@ typedef struct {
7283 CustomLoadLibraryFunc loadLibrary ;
7384 CustomGetProcAddressFunc getProcAddress ;
7485 CustomFreeLibraryFunc freeLibrary ;
86+ struct ExportNameEntry * nameExportsTable ;
7587 void * userdata ;
7688 ExeEntryProc exeEntry ;
7789 DWORD pageSize ;
@@ -688,12 +700,27 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
688700 return NULL ;
689701}
690702
691- FARPROC MemoryGetProcAddress (HMEMORYMODULE module , LPCSTR name )
703+ static int _compare (const void * a , const void * b )
704+ {
705+ const struct ExportNameEntry * p1 = (const struct ExportNameEntry * ) a ;
706+ const struct ExportNameEntry * p2 = (const struct ExportNameEntry * ) b ;
707+ return _stricmp (p1 -> name , p2 -> name );
708+ }
709+
710+ static int _find (const void * a , const void * b )
711+ {
712+ LPCSTR * name = (LPCSTR * ) a ;
713+ const struct ExportNameEntry * p = (const struct ExportNameEntry * ) b ;
714+ return _stricmp (* name , p -> name );
715+ }
716+
717+ FARPROC MemoryGetProcAddress (HMEMORYMODULE mod , LPCSTR name )
692718{
693- unsigned char * codeBase = ((PMEMORYMODULE )module )-> codeBase ;
719+ PMEMORYMODULE module = (PMEMORYMODULE )mod ;
720+ unsigned char * codeBase = module -> codeBase ;
694721 DWORD idx = 0 ;
695722 PIMAGE_EXPORT_DIRECTORY exports ;
696- PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY (( PMEMORYMODULE ) module , IMAGE_DIRECTORY_ENTRY_EXPORT );
723+ PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY (module , IMAGE_DIRECTORY_ENTRY_EXPORT );
697724 if (directory -> Size == 0 ) {
698725 // no export table found
699726 SetLastError (ERROR_PROC_NOT_FOUND );
@@ -715,25 +742,44 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name)
715742 }
716743
717744 idx = LOWORD (name ) - exports -> Base ;
745+ } else if (!exports -> NumberOfNames ) {
746+ SetLastError (ERROR_PROC_NOT_FOUND );
747+ return NULL ;
718748 } else {
719- // search function name in list of exported names
720- DWORD i ;
721- DWORD * nameRef = (DWORD * ) (codeBase + exports -> AddressOfNames );
722- WORD * ordinal = (WORD * ) (codeBase + exports -> AddressOfNameOrdinals );
723- BOOL found = FALSE;
724- for (i = 0 ; i < exports -> NumberOfNames ; i ++ , nameRef ++ , ordinal ++ ) {
725- if (_stricmp (name , (const char * ) (codeBase + (* nameRef ))) == 0 ) {
726- idx = * ordinal ;
727- found = TRUE;
728- break ;
749+ const struct ExportNameEntry * found ;
750+
751+ // Lazily build name table and sort it by names
752+ if (!module -> nameExportsTable ) {
753+ DWORD i ;
754+ DWORD * nameRef = (DWORD * ) (codeBase + exports -> AddressOfNames );
755+ WORD * ordinal = (WORD * ) (codeBase + exports -> AddressOfNameOrdinals );
756+ struct ExportNameEntry * entry = (struct ExportNameEntry * ) malloc (exports -> NumberOfNames * sizeof (struct ExportNameEntry ));
757+ module -> nameExportsTable = entry ;
758+ if (!entry ) {
759+ SetLastError (ERROR_OUTOFMEMORY );
760+ return NULL ;
729761 }
762+ for (i = 0 ; i < exports -> NumberOfNames ; i ++ , nameRef ++ , ordinal ++ , entry ++ ) {
763+ entry -> name = (const char * ) (codeBase + (* nameRef ));
764+ entry -> idx = * ordinal ;
765+ }
766+ qsort (module -> nameExportsTable ,
767+ exports -> NumberOfNames ,
768+ sizeof (struct ExportNameEntry ), _compare );
730769 }
731770
771+ // search function name in list of exported names with binary search
772+ found = (const struct ExportNameEntry * ) bsearch (& name ,
773+ module -> nameExportsTable ,
774+ exports -> NumberOfNames ,
775+ sizeof (struct ExportNameEntry ), _find );
732776 if (!found ) {
733777 // exported symbol not found
734778 SetLastError (ERROR_PROC_NOT_FOUND );
735779 return NULL ;
736780 }
781+
782+ idx = found -> idx ;
737783 }
738784
739785 if (idx > exports -> NumberOfFunctions ) {
@@ -759,6 +805,7 @@ void MemoryFreeLibrary(HMEMORYMODULE mod)
759805 (* DllEntry )((HINSTANCE )module -> codeBase , DLL_PROCESS_DETACH , 0 );
760806 }
761807
808+ free (module -> nameExportsTable );
762809 if (module -> modules != NULL ) {
763810 // free previously opened libraries
764811 int i ;
0 commit comments