Skip to content

Instantly share code, notes, and snippets.

@jaxFF
Created May 23, 2023 19:29
Show Gist options
  • Save jaxFF/1cfce693fb420c38384ba30882e2ce85 to your computer and use it in GitHub Desktop.
Save jaxFF/1cfce693fb420c38384ba30882e2ce85 to your computer and use it in GitHub Desktop.
shared interfacing
#include "shared.h"
global string DllInterfaceName = {"dll_001", 7};
#ifndef DLL_C
#define DLL_C
// Start compilation unit
#define MAIN_C
#include "main.c"
typedef struct interface_module interface_module;
struct interface_module {
uint64_t Hash;
HANDLE TheModuleHandle;
};
global interface_module* InterfacesForThisModule = {0};
void* LoadAndPresentInterface(string, size_t);
global dll_struct* DLL01Interface = (dll_struct*)LoadAndPresentInterface(
string({"dll_001", 7}), sizeof(dll_struct));
///
#if 0
void GetModuleInterface(string a, void* b) {
// Query InterfacesForThisModule
// Hash must match module+funcname, or return
// Call and return function result through void*
}
#endif
interface_hash GetInterfaceHash(string Name) {
u64 HashValue = MurmurHash3UpdateString(0x101, Name);
HashValue = MurmurHash3Finalize(HashValue);
u64 HashBucket = HashValue % (ArrayCount(TheInterfaces) - 1);
Assert(HashBucket < ArrayCount(TheInterfaces));
#ifdef __cplusplus
return interface_hash{HashValue, HashBucket};
#else
return (interface_hash){HashValue, HashBucket};
#endif
}
void* LoadAndPresentInterface(string Name, size_t Size) {
printf("0x%02x\n", &TheInterfaces);
// Add to InterfacesForThisModule
interface_hash Hash = GetInterfaceHash(Name);
interfaces* Entry = TheInterfaces[Hash.Bucket];
interfaces* TheInterface = Entry;
if (!TheInterfaces[Hash.Bucket]) {
TheInterface = (interfaces*)VirtualAlloc(0, sizeof(interfaces), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
TheInterface->NextInHash = TheInterfaces[Hash.Bucket];
TheInterface->Name = Name; // copy !!!
TheInterface->Hash = Hash.Value;
TheInterfaces[Hash.Bucket] = TheInterface;
Breakpoint;
}
if (TheInterface->InterfacePtr == 0) {
TheInterface->InterfacePtr = VirtualAlloc(0, Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
}
return 0;
}
#endif
#include "shared.h"
#ifndef MAIN_C
#define MAIN_C
// Start compilation unit
#define DLL_C
#include "dll.cpp"
__declspec(dllexport) interfaces* TheInterfaces[4096] = { 0 };
interface_hash GetInterfaceHash(string Name) {
u64 HashValue = MurmurHash3UpdateString(0x101, Name);
HashValue = MurmurHash3Finalize(HashValue);
u64 HashBucket = HashValue % (ArrayCount(TheInterfaces) - 1);
Assert(HashBucket < ArrayCount(TheInterfaces));
#ifdef __cplusplus
return interface_hash{HashValue, HashBucket};
#else
return (interface_hash){HashValue, HashBucket};
#endif
}
__declspec(dllexport) void GetModuleInterface(string Name, void* InterfacePtr) {
// NOTE, TODO: Assumes only one underscore. It also must be on the right.
// TODO: We need a better way of getting the module name for the interface.
char* ModuleName[256] = {0};
Assert(Name.Count < ArrayCount(ModuleName));
strcpy(ModuleName, Name.Data);
{
char* tmp = 0;
tmp = strchr(ModuleName, '_');
*tmp = '\0';
}
sprintf(ModuleName, "%s%s", ModuleName, ".dll");
printf(ModuleName);
printf("\n");
printf("%llu = ", GetInterfaceHash(Name).Value);
printf("%d\n", GetInterfaceHash(Name).Bucket);
// TODO: Start at the bucket
interface_hash Hash = GetInterfaceHash(Name);
interfaces* Entry = &TheInterfaces[Hash.Bucket];
interfaces* TheInterface = Entry;
for (int Index = 0; Index < ArrayCount(TheInterfaces); ++Index) {
for (interfaces* At = TheInterfaces[Index]; At; At = At->NextInHash) {
if (strcmp(At->Name.Data, Name.Data) == 0) {
TheInterface = At;
break;
}
}
}
Breakpoint;
Assert(TheInterface);
}
int main(int argc, char* argv[]) {
string Name = {"dll_001", strlen("dll_001")};
u64 Hash = MurmurHash3UpdateString(1234, Name);
Hash = MurmurHash3Finalize(Hash);
printf("%d\n", ArrayCount(TheInterfaces));
printf("0x%02x\n", &TheInterfaces);
dll_struct* TheDLLInterface = 0;
GetModuleInterface((string){"dll_001", strlen("dll_001")},
(void*)&TheDLLInterface);
return 0;
}
#endif
#ifndef SHARED_H
#define SHARED_H
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
typedef uint64_t u64;
#define global static
#define ArrayCount(arr) (sizeof arr / sizeof *arr)
#define Breakpoint __debugbreak()
#define Assert(Expr) do { if (!(Expr)) { *(volatile int*)(0) = (0); } } while (0)
#ifdef MAIN_EXPORTS
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
typedef struct string string;
struct string {
char* Data;
uint32_t Count;
};
// Exposed by a dll. Function pointers would exist inside.
typedef struct dll_struct dll_struct;
struct dll_struct {
uint32_t A;
};
typedef struct interfaces interfaces;
struct interfaces {
string Name;
uint64_t Hash;
void* InterfacePtr;
struct interfaces* NextInHash;
};
typedef struct interface_hash interface_hash;
struct interface_hash {
u64 Value;
u64 Bucket;
};
#ifdef __cplusplus
extern "C" void GetModuleInterface(string, void*);
extern "C" interfaces* TheInterfaces[4096];
#endif
global u64 MurmurHash3UpdateString(u64 Hash, string Data);
global inline u64 MurmurHash3Finalize(u64 Hash);
// MurmurHash3 based on 128-bit version
global inline u64 MurmurHash3Update(u64 Hash, u64 Data) {
u64 c1 = 0x87c37b91114253d5;
u64 c2 = 0x4cf5ad432745937f;
Data *= c1;
Data = _rotl(Data, 31);
Data *= c2;
Hash ^= Data;
Hash = _rotr(Data, 27);
Hash = Hash * 5 + 0x52dce729;
return Hash;
}
global inline u64 MurmurHash3UpdateString(u64 Hash, string Data) {
u64 Result = MurmurHash3Update(Hash, Data.Data[0]);
for (uint32_t Index = 1; Index < Data.Count; ++Index) {
Result = MurmurHash3Update(Result, Data.Data[Index]);
}
return Result;
}
global inline u64 MurmurHash3Finalize(u64 Hash) {
Hash ^= Hash >> 33;
Hash *= 0xff51afd7ed558ccd;
Hash ^= Hash >> 33;
Hash *= 0xc4ceb9fe1a85ec53;
Hash ^= Hash >> 33;
return Hash;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment