C 从内存执行代码

C 从内存执行代码,c,memory,jit,C,Memory,Jit,假设我想在C中进行某种JIT编译。我反汇编函数并将其代码插入程序的内存中: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> void* alloc_executable_memory(size_t size) { void *ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRI

假设我想在C中进行某种JIT编译。我反汇编函数并将其代码插入程序的内存中:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>


void* alloc_executable_memory(size_t size) {

  void *ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);

  if (ptr == MAP_FAILED) {
      fprintf(stderr, "%s\n", "mmap failed");
      return NULL;
  }

  return ptr;
}

void push_code_into_memory(unsigned char *memory) {
  unsigned char code[] = {
    0x48, 0x89, 0xf8,       // mov %rdi, %rax
    0,48, 0x83, 0xc0, 0x04, // add $4, %rax
    0xc3                    // ret
  };

  memcpy(memory, code, sizeof(code));
}

int make_memory_executable(void* memory, size_t size) {

  if (mprotect(memory, size, PROT_READ | PROT_EXEC) == -1) {
      fprintf(stderr, "%s\n", "mprotect failed");
      return -1;
  }
  return 0;
}

const size_t SIZE = 512;
typedef long (*jitFunc)(long);

int main(int argc, char const *argv[]) {

  void *mem = alloc_executable_memory(SIZE);
  push_code_into_memory((unsigned char *)mem);
  make_memory_executable(mem, SIZE);

  jitFunc foo = (jitFunc)mem;
  int res = foo(2);
  printf("%d\n", res);

  return 0;
}
#包括
#包括
#包括
#包括
void*alloc\u可执行内存(大小\u t大小){
void*ptr=mmap(0,大小,保护读取,保护写入,映射私有,映射匿名,0,0);
如果(ptr==MAP_失败){
fprintf(标准指令,“%s\n”,“mmap失败”);
返回NULL;
}
返回ptr;
}
无效将\u代码\u推入\u内存(无符号字符*内存){
无符号字符代码[]={
0x48,0x89,0xf8,//mov%rdi,%rax
0,48,0x83,0xc0,0x04,//添加$4,%rax
0xc3//ret
};
memcpy(内存、代码、sizeof(代码));
}
int make_memory_executable(无效*内存,大小\u t大小){
如果(mprotect(内存、大小、保护读取|保护执行)=-1){
fprintf(标准指令,“%s\n”,“mprotect失败”);
返回-1;
}
返回0;
}
常数大小=512;
typedef long(*jitFunc)(long);
int main(int argc,char const*argv[]{
void*mem=所有可执行内存(大小);
将代码推入内存((无符号字符*)mem);
使_memory_可执行(mem,SIZE);
jitFunc foo=(jitFunc)mem;
int res=foo(2);
printf(“%d\n”,res);
返回0;
}
然而,在给foo打电话后,我总是收到SEGFULT 11(macOS)。这个代码有什么问题?首先,我认为问题出在访问权限上,但标志似乎设置正确。

我想我找到了:

0,48, 0x83, 0xc0, 0x04
应该是

0x48, 0x83, 0xc0, 0x04

调试器在这里可能会有所帮助。此外,您必须确保编译器遵守jitted函数所需的调用约定,即参数
2
必须在
rdi
中,而不是在堆栈上。@BlagovestBuyukliev Yes。。。我还将明确调用约定,检查您是否真的在x64(而不是x86)上运行,然后开始真正可怕的构建自己的JIT。。。“过去我构建了几个JIT,但现在我只建议使用LLVM。@Jean-Françoisfare debugger在调用foo时抛出异常:EXC_BAD_ACCESS。我已经发现了问题-它是错误的汇编列表。@NikitaRock:这当然是有问题的,但为了确保代码不会在其他ABI/编译器下中断,您必须使用指定调用约定的特殊属性限定
jitFunc
类型。非常感谢,这是一个愚蠢的错误,浪费了很多时间。现在它工作正常了