8000 Implement binary search for looking up exports by name. · fancycode/MemoryModule@98b95ec · GitHub
[go: up one dir, main page]

Skip to content

Commit 98b95ec

Browse files
committed
Implement binary search for looking up exports by name.
Code based on #74 which contained code from py2exe.
1 parent 0884dcc commit 98b95ec

File tree

1 file changed

+60
-13
lines changed

1 file changed

+60
-13
lines changed

MemoryModule.c

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
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>
@@ -56,6 +62,11 @@
5662

5763
#include "MemoryModule.h"
5864

65+
struct ExportNameEntry {
66+
LPCSTR name;
67+
WORD idx;
68+
};
69+
5970
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
6071
typedef 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

Comments
 (0)
0