JIT 64 bits chamada dinâmica !

1. JIT 64 bits chamada dinâmica !

???
gokernel

(usa Linux Mint)

Enviado em 06/10/2018 - 11:51h

Olá Pessoal !!!

Estava tentando resolver um BUG de como carregar bibliotecas dinâmicas ( .so ) no Linux 64 BIts ...

Então pesquisando na net, encontrei esse projeto:
https://github.com/skeeto/dynamic-function-benchmark

Para quem é curioso sobre JIT, resolvi compartilhar um pequeno JIT que chama função dinâmica ( SDL1 ) em Linux 64 BITS:

Para entender melhor, pular direto para função ( execute ) ... Codigo:


//-------------------------------------------------------------------
//
// Jit com chamada dinamica ( .so ) ... usa SDL1.x como exemplo.
//
// Testado somente em 64 BITS.
//
// A Funcao ( emit_call_direct(ASM *a)) eh baseado neste projeto:
//
// https://github.com/skeeto/dynamic-function-benchmark
//
// ARQUIVO:
// jit64.c
//
// COMPILE:
// gcc jit64.c -o jit64 -ldl -Wall
//
// BY: Francisco - gokernel@hotmail.com
//
//-------------------------------------------------------------------
#ifdef WIN32
#include <windows.h>
#endif
#ifdef __linux__
#include <unistd.h>
#include <sys/mman.h> // to: mprotect()
#include <dlfcn.h> // to: dlopen(), dlsym(), ... in file: cs_library.c
#endif

#include <stdio.h>
#include <stdlib.h>

#define MMAP_ANON 0x20

#define UCHAR unsigned char

typedef struct {
UCHAR *p;
UCHAR *code;
}ASM;

void *init = NULL;
void *delay = NULL;
void *quit = NULL;

void libopen (void) {
#ifdef __linux__
void *lib = dlopen ("libSDL.so", RTLD_NOW);

if (lib) {
printf ("Library SDL Loaded\n");
init = dlsym (lib, "SDL_Init");
delay = dlsym (lib, "SDL_Delay");
quit = dlsym (lib, "SDL_Quit");
if (init) {
printf ("SDL_Init loaded ...\n");
}
if (delay) {
printf ("SDL_Delay loaded ...\n");
}
if (quit) {
printf ("SDL_Quit loaded ...\n");
}
}
else printf ("libSDL.so Not Found\n");
#endif
}

ASM * asm_new (unsigned int size) {
ASM *a = (ASM*)malloc(sizeof(ASM));

#ifdef WIN32
if (a && (a->code=(UCHAR*)malloc(size)) != NULL) {
a->p = a->code;
return a;
}
#endif
#ifdef __linux__
if (a && (a->code = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MMAP_ANON, -1, 0)) != MAP_FAILED) {
a->p = a->code;
return a;
}
#endif
return NULL;
}

int set_executable (void *ptr, unsigned int size) {

#ifdef WIN32
unsigned long old_protect;

if (!VirtualProtect(ptr, size, PAGE_EXECUTE_READWRITE, &old_protect)) {
printf ("ERROR: asm_set_executable() ... NOT FOUND - VirtualProtect()\n");
return 1; // erro
}
#endif

#ifdef __linux__
unsigned long start, end, PageSize;

PageSize = sysconf (_SC_PAGESIZE);
start = (unsigned long)ptr & ~(PageSize - 1);
end = (unsigned long)ptr + size;
end = (end + PageSize - 1) & ~(PageSize - 1);
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
printf ("ERROR: asm_set_executable() ... NOT FOUND - mprotec()\n");
return 1; // erro
}
#endif

return 0; // no erro
}
void asm_get_addr (ASM *a, void *ptr) { ///: 32/64 BITS OK
*(void**)a->p = ptr;
a->p += 4; // ! OK
}

void g2 (ASM *a, UCHAR c1, UCHAR c2) {
a->p[0] = c1;
a->p[1] = c2;
a->p += 2;
}
void g3 (ASM *a, UCHAR c1, UCHAR c2, UCHAR c3) {
a->p[0] = c1;
a->p[1] = c2;
a->p[2] = c3;
a->p += 3;
}
void g4 (ASM *a, UCHAR c1, UCHAR c2, UCHAR c3, UCHAR c4) {
a->p[0] = c1;
a->p[1] = c2;
a->p[2] = c3;
a->p[3] = c4;
a->p += 4;
}

void emit_sub_esp (ASM *a, char c) { // 32/64 BITS OK
#if defined(__x86_64__)
g4(a,0x48,0x83,0xec,(char)c); // 48 83 ec 08 sub $0x8,%rsp
#else
g3(a,0x83,0xec,(char)c); // 83 ec 08 sub $0x8,%esp
#endif
}
void emit_begin (ASM *a) { //: 32/64 BITS OK
#if defined(__x86_64__)
// 55 : push %rbp
// 48 89 e5 : mov %rsp,%rbp
//-----------------------------
a->p[0] = 0x55;
a->p[1] = 0x48;
a->p[2] = 0x89;
a->p[3] = 0xe5;
a->p += 4;
emit_sub_esp (a,16);
#else
// 55 : push %ebp
// 89 e5 : mov %esp,%ebp
//-----------------------------
a->p[0] = 0x55;
a->p[1] = 0x89;
a->p[2] = 0xe5;
a->p += 3;
emit_sub_esp (a,100);
#endif
}
void emit_end (ASM *a) { ///: 32/64 BITS OK
#if defined(__x86_64__)
a->p[0] = 0xc9; // c9 : leaveq
a->p[1] = 0xc3; // c3 : retq
a->p += 2;
#else
a->p[0] = 0xc9; // c9 : leave
a->p[1] = 0xc3; // c3 : ret
a->p += 2;
#endif
}

void emit_call (ASM *a, void *func) {
//
// b8 7a 13 40 00 mov $0x40137a,%eax
// ff d0 call *%eax
//
*a->p++ = 0xb8; asm_get_addr(a, func); // %eax
g2(a,0xff,0xd0); // %eax

}
void emit_call_direct (ASM *a, void *func) {
#ifdef __linux__
#if defined(__x86_64__)
//
// Codigo baseado neste projeto:
//
// https://github.com/skeeto/dynamic-function-benchmark
//
//uintptr_t rel = (uintptr_t)func - (uintptr_t)a->p - 5;
*a->p++ = 0xe8;
*(long*)a->p = (void*)func - (void*)a->p - 4;
a->p += 4;
#endif
#endif
}

void hello (int i) {
printf ("\nFunction Hello World: %d\n\n", i);
}

void execute (void) {
ASM *a;
if ((a = asm_new (1000)) != NULL) {

libopen ();

if (init && delay && quit) {

emit_begin(a);

// funcao argumento 1:
// mov $32 %edi
g2(a,0xbf,0x20); g3(a,0x00,0x00,0x00);
emit_call_direct (a, init);

// funcao argumento 1:
// mov $32 %edi
g2 (a,0xbf,0x20); g3(a,0x00,0x00,0x00);
emit_call (a, hello);

// funcao argumento 1:
// bf b8 0b 00 00 mov $3000,%edi
g2(a,0xbf,0xb8); g3(a,0x0b,0x00,0x00);
emit_call_direct (a, delay);

emit_call_direct (a, quit);

emit_end(a);

if (set_executable(a, (a->p - a->code))==0) {
( (void(*)(void)) a->code ) ();
printf ("\nExiting Whith Sucess !!!\n");
}

}
}
}

int main (void) {
execute ();
return 0;
}


Obrigado ao Chris !!!.



  






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts