#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifndef EXPORT
#define EXPORT
#endif

static char rcsid[] = "$Id: thunks.c#5 2002/08/30 14:24:46 REDMOND\\drh $";

struct thunk {
	struct thunk *link;
	void (*entrypoint)();
	unsigned char code[16];
};
static struct thunk *thunktable[237];

#define HASH(f) ((int)(((unsigned)f)>>2)%(sizeof thunktable/sizeof thunktable[0]))

static void *newthunk(void (*f)(), void *thunkcode, size_t size, size_t offset) {
	int i = HASH(f);
	struct thunk *tp = malloc(sizeof *tp);

	if (tp == NULL)
		return NULL;	/* cause an exception when dereferenced */
	tp->link = thunktable[i];
	thunktable[i] = tp;
	tp->entrypoint = f;
	memcpy(tp->code, thunkcode, size);
	*(int *)(tp->code + offset) = (char *)f - (tp->code + offset + 4);
	return tp->code;
}

#define NOP 0x90

EXPORT void *__getUMThunk(void (*f)()) {
	static struct thunkcode {		/* must be <= 16 bytes */
		unsigned char code[12];
		int offset;
	} thunkcode = {
		NOP,  NOP,  NOP,
		0x8B, 0x4C, 0x24, 0x04,		/* mov ecx,DWORD PTR [esp+4] */
		0x8B, 0x54, 0x24, 0x08,		/* mov edx,DWORD PTR [esp+8] */
		0xE9,						/* jmp rel32 */
		0
	};
	int i = HASH(f);
	struct thunk *tp = thunktable[i];

	for ( ; tp != NULL; tp = tp->link)
		if (tp->entrypoint == f)
			return tp->code;
	return newthunk(f, &thunkcode, sizeof thunkcode, offsetof(struct thunkcode,offset));
}

EXPORT void *__getMUThunk(void (*f)()) {
	static struct thunkcode {		/* must be <= 16 bytes */
		unsigned char code[4];
		int offset;
		unsigned char retcode[4];
	} thunkcode = {
		NOP,
		0x52,						/* push	edx */
		0x51,						/* push ecx */
		0xE8,						/* call rel32 */
		0,
		0x83, 0xC4, 0x08,			/* add esp,8 */
		0xC3						/* ret */
	};
	int i = HASH(f);
	struct thunk *tp = thunktable[i];

	for ( ; tp != NULL; tp = tp->link)
		if (tp->entrypoint == f)
			return tp->code;
	return newthunk(f, &thunkcode, sizeof thunkcode, offsetof(struct thunkcode,offset));
}