Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you mark a segment of memory as executable in C?

Tags:

c

executable

jit

I am recently studying some JIT compiler. As far as I know, JIT is a technique to compile some scripting language code to native code on the fly (right before execution). As I imagined the internal of such a compiler, I figured out there must be a segment of dynamic-allocated buffer where the generated native code resides. But then we need a way to start running the code from within the buffer, which is holding data. I mean, you can't just put some code into a char[] and then jump into execution since the security implication, for which the OS must prevent you from doing so. There must be some way to mark the buffer as executable. Consider the following naive approach:

#include <stdlib.h>

void *jit_some_native_code(void) {
  void *code_segment = malloc(1024);
  /*
   * bla bla bla...
   * Generate code into this code_segment.
   */

  return code_segment;
}

int main(void) {
  void *code = jit_some_native_code();
  /*
   * How can I start executing instruction in code?
   */

  typedef void (*func_ptr_t)(void);

  /*
   * This won't work. OS bans you doing so.
   */
  ((func_ptr_t)code)();

}

On Ubuntu the code will run but will exit with status code 26. Given the type unsafe nature of C, the code can compile, but for C++, the compiler simply stops you. Does it means the JIT has to bypass compiler, along with setting the executable flag?

Edit: Besides mprotect, if you use mmap, you can also specify a permission to the page to map:

   PROT_EXEC  Pages may be executed.
   PROT_READ  Pages may be read.
   PROT_WRITE Pages may be written.
   PROT_NONE  Pages may not be accessed.

As such the page will have executable permission.

like image 870
cgsdfc Avatar asked Sep 03 '25 14:09

cgsdfc


1 Answers

If you want to make a region in the heap executable you can use mprotect.

int main() {
  typedef void (*func_t)(void);
  void *code = &some_jit_func;
  int pagesize = getpagesize();
  mprotect(code, pagesize,PROT_EXEC);
  ((func_t)code)();
}

You can also OR the flags with PROT_READ/PROT_WRITE

like image 145
Irelia Avatar answered Sep 05 '25 08:09

Irelia