Generate foreign procedures dynamically

Hello,

It just struck me recently that since procedures can be locked in memory and viewed as pointers, are they arrays of instructions? Can I allocate memory and directly set each byte such that I can invoke the array as a foreign function?

I'm assuming the bytes would be assembly instructions. I heard something about operating systems or even processors themselves preventing dynamically generating instructions at runtime which doesn't make any sense because then how can JITs or lambda procedures work?

I'm really curious about this because it would be fun to experiment with in a Lisp environment.

1 Like

Yes, it works in principle to write machine-code bytes into allocated memory and jump to those instructions. And, yes, the OS will probably thwart your attempt.

To generate code at runt time, Racket has to allocate memory in a particular way to cooperate with the OS, and it may have to toggle code memory between "write" mode and "execute" mode to avoid designating memory as both writable and executable at the same time. You can access those facilities from Racket via ffi/unsafe, but the details will be OS-specific, and you'll need to first learn more about what your OS allows and requires.

1 Like

Wow! Cool! Your response gave me what I needed to get unblocked; by googling "malloc executable memory" I found VirtualAlloc which looks exactly like what I'm after.

I'm so excited to look more into this! Thanks for your response!

FWIW the package asm contains a alloc/exe.

https://docs.racket-lang.org/asm/FFI_Utilities.html

1 Like

https://corsix.github.io/dynasm-doc/tutorial.html
This tutorial about DynASM could be helpful. The link_and_encode procedure allocates the memory and sets proper permissions for the DynASM library to fill in machine code.

DynASM (https://luajit.org/dynasm_examples.html) is a library that is used in LuaJIT. It preprocesses C code and turns assembly instructions into C code that fills in machine code in a buffer for run-time execution. It could be interesting to compare the source code and the preprocessed output to see how functions can be dynamically created.