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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy