mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 19:15:36 +00:00
Added MSVC++ support for unicorn
This lets you import the pre-built unicorn.dll files with Microsoft Visual C++ projects. There is support for static and dynamic linking of dlls. This has been tested as working for both 32bit and 64bit versions. The dynamic linking code should also work in Linux, though I have not tested it.
This commit is contained in:
parent
032eb66908
commit
77f946f2fc
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -77,6 +77,7 @@ unicorn.pc
|
|||
unicorn.lib
|
||||
unicorn.dll
|
||||
unicorn_*.lib
|
||||
unicorn_*.exp
|
||||
unicorn_*.dll
|
||||
|
||||
|
||||
|
|
77
bindings/msvc/README.TXT
Normal file
77
bindings/msvc/README.TXT
Normal file
|
@ -0,0 +1,77 @@
|
|||
This documentation explains how to use Unicorn with Microsoft Visual C++ (MSVC).
|
||||
This will not build the Unicorn Engine itself, it just allows you to use the
|
||||
prebuilt Windows binaries when writing projects in Microsoft Visual C++.
|
||||
|
||||
The prebuilt windows binaries can be found under the "Windows Core engine"
|
||||
heading on the following page. Be sure to use the 32bit package when making
|
||||
32bit applications (even in 64bit windows). And use the 64bit package to
|
||||
build 64bit applications.
|
||||
http://www.unicorn-engine.org/download/
|
||||
|
||||
|
||||
|
||||
It is not possible to use the prebuilt static Unicorn library, unicorn.lib,
|
||||
with Microsoft Visual C++ because it will complain about a bunch of missing
|
||||
functions, variables etc.
|
||||
|
||||
We therefore use the prebuilt dynamic Unicorn library, unicorn.dll.
|
||||
There are two ways to use this with your Microsoft Visual C++ project:
|
||||
1) By dynamically linking the dll into your project.
|
||||
2) By statically linking the dll into your project.
|
||||
|
||||
|
||||
|
||||
:: 1) Dynamic Linking
|
||||
|
||||
The files unicorn_dynload.c and unicorn_dynload.h are used for dynamic linking.
|
||||
Ensure that unicorn_dynload.h is in the main unicorn includes directory.
|
||||
(It should be in the same directory as "unicorn.h".)
|
||||
Then include unicorn_dynload.c in your project so that it gets build along
|
||||
with your other project files. You could alternatively compile it first into a
|
||||
static library and then link that library into your project.
|
||||
|
||||
Now where you would normally include "unicorn.h" in your project you instead
|
||||
include "unicorn_dynload.h". You should also define DYNLOAD above the include
|
||||
of "unicorn_dynload.h", or instead add DYNLOAD to your project settings in:
|
||||
Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions.
|
||||
|
||||
Some example code for including this header is as follows:
|
||||
|
||||
#define DYNLOAD 1
|
||||
|
||||
#ifdef DYNLOAD
|
||||
#include <unicorn/unicorn_dynload.h>
|
||||
#else
|
||||
#include <unicorn/unicorn.h>
|
||||
#endif
|
||||
|
||||
Now build your application as normal.
|
||||
|
||||
|
||||
|
||||
:: 2) Static Linking
|
||||
|
||||
To perform static linking of unicorn.dll, you need to first generate some
|
||||
static import libraries. To do this run "make_staload.bat".
|
||||
You may need to edit the first line in "make_staload.bat" to point to the
|
||||
location of your "vcvars32.bat" file. This will build separate import libraries
|
||||
for importing the 32bit or 64bit version of the dlls.
|
||||
unicorn_staload.lib is used to link to the 32bit version of unicorn.dll.
|
||||
unicorn_staload64.lib is used to link to the 64bit version of unicorn.dll.
|
||||
|
||||
Now you make a unicorn project like usual, including "unicorn.h", and
|
||||
then you need to also link in "unicorn_staload.lib" or "unicorn_staload64.lib".
|
||||
|
||||
The first step to doing this is to make sure the directory that contains
|
||||
"unicorn_staload.lib" is added to your project by adding it in:
|
||||
Configuration Properties -> C/C++ -> Linker -> General -> Additional Library Directories
|
||||
(So for example add here "C:\unicorn\bindings\msvc" if that is where they are)
|
||||
|
||||
The second step is to link in the library. You can do this by either adding
|
||||
this line to your C sourcecode:
|
||||
#pragma comment(lib, "unicorn_staload.lib")
|
||||
|
||||
Or by adding "unicorn_staload.lib" to your project in:
|
||||
Configuration Properties -> C/C++ -> Linker -> Input -> Additional Dependencies
|
||||
|
||||
|
3
bindings/msvc/make_staload.bat
Normal file
3
bindings/msvc/make_staload.bat
Normal file
|
@ -0,0 +1,3 @@
|
|||
call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\vcvars32.bat"
|
||||
lib /DEF:unicorn.def /OUT:unicorn_staload.lib /MACHINE:X86
|
||||
lib /DEF:unicorn.def /OUT:unicorn_staload64.lib /MACHINE:X64
|
18
bindings/msvc/unicorn.def
Normal file
18
bindings/msvc/unicorn.def
Normal file
|
@ -0,0 +1,18 @@
|
|||
EXPORTS
|
||||
uc_version
|
||||
uc_arch_supported
|
||||
uc_open
|
||||
uc_close
|
||||
uc_errno
|
||||
uc_strerror
|
||||
uc_reg_write
|
||||
uc_reg_read
|
||||
uc_mem_write
|
||||
uc_mem_read
|
||||
uc_emu_start
|
||||
uc_emu_stop
|
||||
uc_hook_add
|
||||
uc_hook_del
|
||||
uc_mem_map
|
||||
uc_mem_unmap
|
||||
uc_mem_protect
|
249
bindings/msvc/unicorn_dynload.c
Normal file
249
bindings/msvc/unicorn_dynload.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will
|
||||
// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc)
|
||||
// from standard dll paths. This is usually the directory that the main
|
||||
// exe file, that loaded unicorn.dll, is in. This is standard behaviour for
|
||||
// Windows dll files, and not specific to unicorn dlls.
|
||||
//
|
||||
// So putting all dlls in their own directory and then attempting to load
|
||||
// unicorn.dll from that directory via an absolute path will cause
|
||||
// uc_dyn_load() to fail.
|
||||
//
|
||||
// The easiest way around this is to place all dlls in the same directory
|
||||
// as your main exe file. Other ways around this are using various flags
|
||||
// for LoadLibraryEx() or by calling SetDllDirectory().
|
||||
//
|
||||
// LoadLibraryEx info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||
// SetDllDirectory() info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx
|
||||
//
|
||||
// Zak Escano - November 2015
|
||||
//
|
||||
|
||||
// This is to detect whether we are loading a dll in windows or a so in linux.
|
||||
#ifdef _MSC_VER
|
||||
#define WINDOWS_DLL 1
|
||||
#endif
|
||||
|
||||
#include <unicorn/unicorn_dynload.h>
|
||||
|
||||
#ifdef WINDOWS_DLL
|
||||
#include <Windows.h>
|
||||
#define DYNLOAD_DEFPATH "unicorn.dll"
|
||||
#define DYNLOAD_HANDLE HMODULE
|
||||
#define DYNLOAD_LOADLIB(path, f)LoadLibraryEx(path, NULL, f)
|
||||
#define DYNLOAD_FREELIB(handle) FreeLibrary(handle)
|
||||
#define DYNLOAD_GETFUNC(h, n) GetProcAddress(h, n)
|
||||
#define DYNLOAD_GETERROR() GetLastError()
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define DYNLOAD_DEFPATH "unicorn.so"
|
||||
#define DYNLOAD_HANDLE void*
|
||||
#define DYNLOAD_LOADLIB(path, f)dlopen(path, f)
|
||||
#define DYNLOAD_FREELIB(handle) dlclose(handle)
|
||||
#define DYNLOAD_GETFUNC(h, n) dlsym(h, n)
|
||||
#define DYNLOAD_GETERROR() dlerror()
|
||||
#endif
|
||||
|
||||
|
||||
static DYNLOAD_HANDLE g_dyn_handle = NULL;
|
||||
|
||||
|
||||
typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor);
|
||||
typedef bool (*uc_arch_supported_t)(uc_arch arch);
|
||||
typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc);
|
||||
typedef uc_err (*uc_close_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_errno_t)(uc_engine *uc);
|
||||
typedef const char* (*uc_strerror_t)(uc_err code);
|
||||
typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value);
|
||||
typedef uc_err (*uc_reg_read_t)(uc_engine *uc, int regid, void *value);
|
||||
typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *bytes, size_t size);
|
||||
typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
typedef uc_err (*uc_emu_stop_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
|
||||
typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh);
|
||||
typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size);
|
||||
typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
|
||||
|
||||
static uc_version_t gp_uc_version = NULL;
|
||||
static uc_arch_supported_t gp_uc_arch_supported = NULL;
|
||||
static uc_open_t gp_uc_open = NULL;
|
||||
static uc_close_t gp_uc_close = NULL;
|
||||
static uc_errno_t gp_uc_errno = NULL;
|
||||
static uc_strerror_t gp_uc_strerror = NULL;
|
||||
static uc_reg_write_t gp_uc_reg_write = NULL;
|
||||
static uc_reg_read_t gp_uc_reg_read = NULL;
|
||||
static uc_mem_write_t gp_uc_mem_write = NULL;
|
||||
static uc_mem_read_t gp_uc_mem_read = NULL;
|
||||
static uc_emu_start_t gp_uc_emu_start = NULL;
|
||||
static uc_emu_stop_t gp_uc_emu_stop = NULL;
|
||||
static uc_hook_add_t gp_uc_hook_add = NULL;
|
||||
static uc_hook_del_t gp_uc_hook_del = NULL;
|
||||
static uc_mem_map_t gp_uc_mem_map = NULL;
|
||||
static uc_mem_unmap_t gp_uc_mem_unmap = NULL;
|
||||
static uc_mem_protect_t gp_uc_mem_protect = NULL;
|
||||
|
||||
|
||||
bool uc_dyn_load(const char* path, int flags)
|
||||
{
|
||||
if( path == NULL )
|
||||
{
|
||||
path = DYNLOAD_DEFPATH;
|
||||
}
|
||||
|
||||
if( g_dyn_handle )
|
||||
{
|
||||
if( !uc_dyn_free() )
|
||||
return false;
|
||||
}
|
||||
|
||||
g_dyn_handle = DYNLOAD_LOADLIB(path, flags);
|
||||
if( g_dyn_handle == NULL )
|
||||
{
|
||||
//int err = DYNLOAD_GETERROR();
|
||||
//printf("Error loading %s: Last error is %X\n", path, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_uc_version = (uc_version_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_version");
|
||||
gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported");
|
||||
gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open");
|
||||
gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close");
|
||||
gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno");
|
||||
gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror");
|
||||
gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write");
|
||||
gp_uc_reg_read = (uc_reg_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_read");
|
||||
gp_uc_mem_write = (uc_mem_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_write");
|
||||
gp_uc_mem_read = (uc_mem_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_read");
|
||||
gp_uc_emu_start = (uc_emu_start_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_start");
|
||||
gp_uc_emu_stop = (uc_emu_stop_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_stop");
|
||||
gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add");
|
||||
gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del");
|
||||
gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map");
|
||||
gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap");
|
||||
gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uc_dyn_free(void)
|
||||
{
|
||||
if( g_dyn_handle==NULL )
|
||||
return true;
|
||||
|
||||
DYNLOAD_FREELIB(g_dyn_handle);
|
||||
g_dyn_handle = NULL;
|
||||
|
||||
gp_uc_version = NULL;
|
||||
gp_uc_arch_supported = NULL;
|
||||
gp_uc_open = NULL;
|
||||
gp_uc_close = NULL;
|
||||
gp_uc_errno = NULL;
|
||||
gp_uc_strerror = NULL;
|
||||
gp_uc_reg_write = NULL;
|
||||
gp_uc_reg_read = NULL;
|
||||
gp_uc_mem_write = NULL;
|
||||
gp_uc_mem_read = NULL;
|
||||
gp_uc_emu_start = NULL;
|
||||
gp_uc_emu_stop = NULL;
|
||||
gp_uc_hook_add = NULL;
|
||||
gp_uc_hook_del = NULL;
|
||||
gp_uc_mem_map = NULL;
|
||||
gp_uc_mem_unmap = NULL;
|
||||
gp_uc_mem_protect = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
||||
{ return gp_uc_version(major, minor); }
|
||||
|
||||
bool uc_arch_supported(uc_arch arch)
|
||||
{ return gp_uc_arch_supported(arch); }
|
||||
|
||||
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc)
|
||||
{ return gp_uc_open(arch, mode, uc); }
|
||||
|
||||
uc_err uc_close(uc_engine *uc)
|
||||
{ return gp_uc_close(uc); }
|
||||
|
||||
uc_err uc_errno(uc_engine *uc)
|
||||
{ return gp_uc_errno(uc); }
|
||||
|
||||
const char *uc_strerror(uc_err code)
|
||||
{ return gp_uc_strerror(code); }
|
||||
|
||||
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
|
||||
{ return gp_uc_reg_write(uc, regid, value); }
|
||||
|
||||
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
|
||||
{ return gp_uc_reg_read(uc, regid, value); }
|
||||
|
||||
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size)
|
||||
{ return gp_uc_mem_write(uc, address, bytes, size); }
|
||||
|
||||
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size)
|
||||
{ return gp_uc_mem_read(uc, address, bytes, size); }
|
||||
|
||||
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
||||
{ return gp_uc_emu_start(uc, begin, until, timeout, count); }
|
||||
|
||||
uc_err uc_emu_stop(uc_engine *uc)
|
||||
{ return gp_uc_emu_stop(uc); }
|
||||
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
||||
{
|
||||
va_list valist;
|
||||
uc_err ret = UC_ERR_OK;
|
||||
int id;
|
||||
uint64_t begin, end;
|
||||
va_start(valist, user_data);
|
||||
|
||||
switch(type) {
|
||||
default:
|
||||
break;
|
||||
case UC_HOOK_INTR:
|
||||
// 0 extra args
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data);
|
||||
break;
|
||||
case UC_HOOK_INSN:
|
||||
// 1 extra arg
|
||||
id = va_arg(valist, int);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id);
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
case UC_HOOK_BLOCK:
|
||||
case UC_HOOK_MEM_READ:
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
||||
// 2 extra arg
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||
{ return gp_uc_hook_del(uc, hh); }
|
||||
|
||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{ return gp_uc_mem_map(uc, address, size, perms); }
|
||||
|
||||
uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size)
|
||||
{ return gp_uc_mem_unmap(uc, address, size); }
|
||||
|
||||
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{ return gp_uc_mem_protect(uc, address, size, perms); }
|
||||
|
67
include/unicorn/unicorn_dynload.h
Normal file
67
include/unicorn/unicorn_dynload.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will
|
||||
// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc)
|
||||
// from standard dll paths. This is usually the directory that the main
|
||||
// exe file, that loaded unicorn.dll, is in. This is standard behaviour for
|
||||
// Windows dll files, and not specific to unicorn dlls.
|
||||
//
|
||||
// So putting all dlls in their own directory and then attempting to load
|
||||
// unicorn.dll from that directory via an absolute path will cause
|
||||
// uc_dyn_load() to fail.
|
||||
//
|
||||
// The easiest way around this is to place all dlls in the same directory
|
||||
// as your main exe file. Other ways around this are using various flags
|
||||
// for LoadLibraryEx() or by calling SetDllDirectory().
|
||||
//
|
||||
// LoadLibraryEx info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||
// SetDllDirectory() info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx
|
||||
//
|
||||
// Zak Escano - November 2015
|
||||
//
|
||||
|
||||
#ifndef _UNICORN_DYNLOAD_H_
|
||||
#define _UNICORN_DYNLOAD_H_
|
||||
|
||||
// Undefine shared here so that functions aren't defined as: "__declspec(dllexport)"
|
||||
#ifdef UNICORN_SHARED
|
||||
#undef UNICORN_SHARED
|
||||
#endif
|
||||
#include "unicorn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Dynamically load shared library.
|
||||
Check the notes at the top for info regarding dll file locations in windows.
|
||||
|
||||
@path: path to shared library file. (NULL to use default path)
|
||||
@flags: system specific flags for loading shared library file. (0 for default)
|
||||
|
||||
@return true on success, false if failed.
|
||||
*/
|
||||
bool uc_dyn_load(const char* path, int flags);
|
||||
|
||||
/*
|
||||
Free resources when done using shared library.
|
||||
|
||||
@return true on success, false if failed.
|
||||
*/
|
||||
bool uc_dyn_free(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _UNICORN_DYNLOAD_H_
|
||||
|
Loading…
Reference in a new issue