1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
#ifndef ___SYSTEM__H___
#define ___SYSTEM__H___
// This should probably be moved to platform.h at some point
#if defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__)
# define SYSTEM_AMD64
#elif defined(_M_IX86) || defined(__i386__) || defined(_X86_)
# define SYSTEM_X86
#elif defined(_M_ARM64)
# define SYSTEM_ARM64
#else
# error "Unknown architecture!"
#endif
#ifdef _WIN64
# define SYSFMT_HEXPTR _T("0x%016IX")
#else
# define SYSFMT_HEXPTR _T("0x%08X")
#endif
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the SYSTEM_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// SYSTEM_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef SYSTEM_EXPORTS
# define SYSTEM_API __declspec(dllexport)
#else
# define SYSTEM_API __declspec(dllimport) // BUGBUG: This is a plugin, who is going to import the functions directly?
#endif
#define SYS_ALIGNUP(num, al) ( ((num)+((al)-1)) & ~((al)-1) )
#define SYS_UNSAFEALIGNON(num, al) ( (num) % (al) == 0 ? (num) : SYS_ALIGNUP((num), (al)) ) // al CANNOT be 0!
#define SYS_ALIGNON(num, al) ( (al) ? SYS_UNSAFEALIGNON((num), (al)) : (num) )
#define NEW_STACK_SIZE 256*256
// Proc types:
#define PT_NOTHING 0
#define PT_PROC 1
#define PT_STRUCT 2
#define PT_VTABLEPROC 3
// Proc results:
#define PR_OK 0
#define PR_ERROR -1
#define PR_CALLBACK 1
// Real world argument types
#define PAT_VOID 0
#define PAT_INT 1
#define PAT_LONG 2
#define PAT_STRING 3
#define PAT_WSTRING 4
#define PAT_GUID 5
#define PAT_CALLBACK 6
#define PAT_REGMEM 7
#ifdef _UNICODE
#define PAT_TSTRING PAT_WSTRING
#else
#define PAT_TSTRING PAT_STRING
#endif
#define PAT_PTR ( (4==sizeof(void*)) ? PAT_INT : PAT_LONG )
#define PAT_ALIGNFLAG 0x8000 // Type is aligned to its natural alignment
// Input/Output Source/Destination
#define IOT_NONE 0
#define IOT_STACK -1
#define IOT_REG 1
#define IOT_INLINE (__INST_LAST+1) // should replace pointer to inline input
// #define INLINE_INPUT -> any other value, will contain pointer to input string
// Options
#define POPT_CDECL 0x1 // (Option & 0x1) == 0x1 -> cdecl, otherwise stdcall
#define POPT_PERMANENT 0x2 // Permanent proc, will not be destroyed after calling
#define POPT_ALWRETURN 0x4 // Always return
#define POPT_NEVERREDEF 0x8 // Never redefine
#define POPT_GENSTACK 0x10 // Use general stack (non temporary for callback)
#define POPT_ERROR 0x20 // Call GetLastError after proc and push it to stack
#define POPT_UNLOAD 0x40 // unload dll after call
#define POPT_CLONE 0x80 // Callback clone
#define POPT_SYNTAX2 0x100 // "?2" syntax mode (direct callback ids and aligned uppercased types)
// Proc argument (ProcParameter) options
#define PAO_PTRFLAG -1 // Could be changed to 0x80000000 if we need to support "*&iN"
#define PAO_ARRBASE 1
#define ParamOptionIsPointer(opt) ( (opt) < 0 )
typedef struct
{
int Type; // Can be ORed with PAT_ALIGNFLAG to request alignment in structs
int Option; // PAO_PTRFLAG -> Pointer, PAO_ARRBASE-... -> Special+PAO_ARRBASE
INT_PTR Value; // it can hold any pointer sized value
#ifndef _WIN64
int _value; // Upper 32 bits of Value when type is 64 bit (2 pushes)
#endif
int Size; // Value real size (should be either 1 or 2 (the number of pushes))
int Output;
INT_PTR Input;
HGLOBAL allocatedBlock; // block allocated for passing string, wstring or guid param
} ProcParameter;
#define ParamIsSimple(par) ( (par).Option == 0 )
#define ParamIsPointer(par) ParamOptionIsPointer((par).Option)
#define ParamIsArray(par) ( (par).Option > 0 ) // AKA special
#define GetParamArrayTypeSize GetSpecialParamTypeSize
#ifdef POPT_SYNTAX2
#define GetParamType(par) ( (BYTE) (par).Type )
#else
#define GetParamType(par) ( (par).Type )
#endif
// Our single proc (Since the user will free proc with GlobalFree,
// I've declared all variables as statics)
typedef struct tag_SystemProc SystemProc;
struct tag_SystemProc
{
int ProcType;
int ProcResult;
TCHAR DllName[1024];
TCHAR ProcName[1024];
HMODULE Dll;
HANDLE Proc;
int Options;
int ParamCount;
ProcParameter Params[100]; // I hope nobody will use more than 100 params
// Callback specific
int CallbackIndex;
int ArgsSize;
// Clone of current element (used for multi-level callbacks)
SystemProc *Clone;
};
typedef struct tag_CallbackThunk CallbackThunk;
struct tag_CallbackThunk
{
#ifdef SYSTEM_X86
/*
#pragma pack(push,1)
char mov_eax_imm;
int sysprocptr;
char reljmp_imm;
int realprocaddr;
#pragma pack(pop)
*/
char asm_code[10];
#elif defined(SYSTEM_AMD64) || defined(SYSTEM_ARM64)
char asm_code[BUGBUG64(1)]; // TODO: BUGBUG64
#else
#error "Asm thunk not implemeted for this architecture!"
#endif
CallbackThunk* pNext;
};
// Free() only knows about pNext in CallbackThunk, it does not know anything about the assembly, that is where this helper comes in...
#ifdef SYSTEM_X86
# define GetAssociatedSysProcFromCallbackThunkPtr(pCbT) ( (SystemProc*) *(unsigned int*) (((char*)(pCbT))+1) )
#elif defined(SYSTEM_AMD64) || defined(SYSTEM_ARM64)
# define GetAssociatedSysProcFromCallbackThunkPtr(pCbT) BUGBUG64(NULL)
#else
# error "GetAssociatedSysProcFromCallbackThunkPtr not defined for the current architecture!"
#endif
extern const int ParamSizeByType[]; // Size of every parameter type (*4 bytes)
extern HANDLE CreateCallback(SystemProc *cbproc);
extern SystemProc* PrepareProc(BOOL NeedForCall);
extern void ParamAllocate(SystemProc *proc);
extern void ParamsDeAllocate(SystemProc *proc);
extern void ParamsIn(SystemProc *proc);
extern void ParamsOut(SystemProc *proc);
#ifdef SYSTEM_AMD64
extern SystemProc* CallProc2(SystemProc *proc, UINT_PTR ParamCount);
#define CallProc(p) CallProc2((p), (p)->ParamCount) // ParamCount is passed as a parameter so CallProc2 can determine the required stack size without a function call
#else //! SYSTEM_AMD64
extern SystemProc* CallProc(SystemProc *proc);
#endif //~ SYSTEM_AMD64
#ifndef SYSTEM_NOCALLBACKS
extern SystemProc* CallBack(SystemProc *proc);
extern SystemProc* RealCallBack();
#endif
extern void CallStruct(SystemProc *proc);
#ifdef _UNICODE
# define STRSET2CH(str, c1, c2) ( *(DWORD*)(str) = ((c1)|(c2)<<16) )
#else
# define STRSET2CH(str, c1, c2) ( *(WORD*)(str) = ((c1)|(c2)<<8) )
#endif
#endif
|