Skip to content

Instantly share code, notes, and snippets.

@vanaur
Created June 6, 2020 18:34
Show Gist options
  • Save vanaur/40a2330300500d709a785c83e3fc83c5 to your computer and use it in GitHub Desktop.
Save vanaur/40a2330300500d709a785c83e3fc83c5 to your computer and use it in GitHub Desktop.
Very small JIT with constant program
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include "mman.h"
#else
#include <sys\mman>
#endif
// This simple JIT program just returns the user input number
int dyn_program1(const char *user_input)
{
// mov eax, 0x0
// ret
unsigned char program[]
= { 0xb8 // - mov eax
, 0x00 //
, 0x00 //
, 0x00 //
, 0x00 // - 0x0 // We will change this value by the input value: program[4] = user value
, 0xc3 }; // - ret
// Assign the user value to the program
const int input_num = atoi(user_input);
memcpy(&program[1], &input_num, 4);
// Defining the dynamic memory that our mini JIT program will take up
void *lptr = mmap(NULL, sizeof(program)
, PROT_WRITE
| PROT_EXEC
, MAP_ANON
| MAP_PRIVATE, -1, 0);
// Injecting our mini program dynamically into the memory
memcpy(lptr, program, sizeof(program));
// This define the pointer to call the mini program
const int (*dyn_func)() = lptr;
// Calling this function pointer will make execute our mini program
// `call_res` will handle the return value, in this case, this will be
// the value entered by the user.
const int call_res = dyn_func();
// We no longer need our mini dynamic JIT program
// Se we free the memory used
munmap(lptr, sizeof(program));
// Display some info
printf("You entered '%s' and the JIT function returned '%d'.\n", user_input, call_res);
return call_res;
}
// This simple JIT program just returns the user input number multiplied by 10
int dyn_program2(const char *user_input)
{
// mov eax, 0
// imul eax, 10
// ret
unsigned char program[]
= { 0xb8 // - mov eax
, 0x00
, 0x00
, 0x00
, 0x00 // - 0x0 // We will change this value by the input value: program[4] = user value
, 0x6b // - imul eax, eax, 0xa
, 0xc0
, 0x0a
, 0xc3 }; // - ret
// Assign the user value to the program
const int input_num = atoi(user_input);
memcpy(&program[1], &input_num, 4);
// Defining the dynamic memory that our mini JIT program will take up
void *lptr = mmap(NULL, sizeof(program)
, PROT_WRITE
| PROT_EXEC
, MAP_ANON
| MAP_PRIVATE, -1, 0);
// Injecting our mini program dynamically into the memory
memcpy(lptr, program, sizeof(program));
// This define the pointer to call the mini program
const int (*dyn_func)() = lptr;
// Calling this function pointer will make execute our mini program
// `call_res` will handle the return value, in this case, this will be
// the value entered by the user.
const int call_res = dyn_func();
// We no longer need our mini dynamic JIT program
// Se we free the memory used
munmap(lptr, sizeof(program));
// Display some info
printf("You entered '%s' and the JIT function returned '%d'.\n", user_input, call_res);
return call_res;
}
int main(int argc, char *argv[])
{
// The usage of this mini program
if (argc < 2)
return fprintf(stderr, "Usage: main <number>\n"), EXIT_FAILURE;
const int res0 = dyn_program1(argv[1]);
const int res1 = dyn_program2(argv[1]);
return EXIT_SUCCESS;
}
/*
* sys/mman.h
* mman-win32
*/
#pragma once
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
/* All the headers include this file. */
#ifndef _MSC_VER
#include <_mingw.h>
#endif
#include <sys/types.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xf
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
/* Flags for msync. */
#define MS_ASYNC 1
#define MS_SYNC 2
#define MS_INVALIDATE 4
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
int munmap(void *addr, size_t len);
int mprotect(void *addr, size_t len, int prot);
int msync(void *addr, size_t len, int flags);
int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
#ifdef __cplusplus
};
#endif
#include <windows.h>
#include <errno.h>
#include <io.h>
#ifndef FILE_MAP_EXECUTE
#define FILE_MAP_EXECUTE 0x0020
#endif /* FILE_MAP_EXECUTE */
static int __map_mman_error(const DWORD err, const int deferr)
{
if (err == 0)
return 0;
//TODO: implement
return err;
}
static DWORD __map_mmap_prot_page(const int prot)
{
DWORD protect = 0;
if (prot == PROT_NONE)
return protect;
if ((prot & PROT_EXEC) != 0)
{
protect = ((prot & PROT_WRITE) != 0) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
else
{
protect = ((prot & PROT_WRITE) != 0) ? PAGE_READWRITE : PAGE_READONLY;
}
return protect;
}
static DWORD __map_mmap_prot_file(const int prot)
{
DWORD desiredAccess = 0;
if (prot == PROT_NONE)
return desiredAccess;
if ((prot & PROT_READ) != 0)
desiredAccess |= FILE_MAP_READ;
if ((prot & PROT_WRITE) != 0)
desiredAccess |= FILE_MAP_WRITE;
if ((prot & PROT_EXEC) != 0)
desiredAccess |= FILE_MAP_EXECUTE;
return desiredAccess;
}
inline void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
{
HANDLE fm, h;
void *map = MAP_FAILED;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4293)
#endif
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
const DWORD protect = __map_mmap_prot_page(prot);
const DWORD desiredAccess = __map_mmap_prot_file(prot);
const off_t maxSize = off + (off_t)len;
const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ? (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
errno = 0;
if (len == 0
/* Unsupported flag combinations */
|| (flags & MAP_FIXED) != 0
/* Usupported protection combinations */
|| prot == PROT_EXEC)
{
errno = EINVAL;
return MAP_FAILED;
}
h = ((flags & MAP_ANONYMOUS) == 0) ? (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return MAP_FAILED;
}
fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
if (fm == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
CloseHandle(fm);
if (map == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
return map;
}
inline int munmap(void *addr, size_t len)
{
if (UnmapViewOfFile(addr))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
inline int mprotect(void *addr, size_t len, int prot)
{
DWORD newProtect = __map_mmap_prot_page(prot);
DWORD oldProtect = 0;
if (VirtualProtect(addr, len, newProtect, &oldProtect))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
inline int msync(void *addr, size_t len, int flags)
{
if (FlushViewOfFile(addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
inline int mlock(const void *addr, size_t len)
{
if (VirtualLock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
inline int munlock(const void *addr, size_t len)
{
if (VirtualUnlock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
@vanaur
Copy link
Author

vanaur commented Jun 6, 2020

Example of result:

./main 6
You entered '6' and the JIT function returned '6'.
You entered '6' and the JIT function returned '60'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment