Luke is super friendly, and just listening to him talk with Dave Herman and Alon Zakai is a treat. I asked Luke the basics of JIT’ing at tonight’s Mozilla Research Party and he explained clearly. Compile a simple object file, use objdump to get the resulting platform specific assembly, use the mmap system call to allocate some memory that you can write to AND execute, copy the instructions into that buffer, typecast it to a function pointer and finally call that.
So my goal was to at runtime, create a function that for simplicity’s sake multiplied two integers. The first thing I did was write up a simple .c file, then compile that to an object file with the -c flag.
1 2 3 4
As a heads up, I’m on 64bit OSX. So the generated assembly may differ on your
platform. Obviously, the production JIT maintainers have abstracted away the
platform dependency, taking into account what platform you’re on. My example
doesn’t, but that why I’m walking you through the steps I took to find out the
x86_64 instructions. The next step is to grab binutils, which is not installed
by default in OSX. I used homebrew to install it:
brew install binutils.
Homebrew installs gobjdump but it works with the same flags.
Once you have binutils and [g]objdump, the next step is to read out the machine
code from your object file, which is represented in hexadecimal. By running
gobjdump -j .text -d mul.o -M intel you should get something similar
(remember, architecture dependent).
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Voila! How neat is that! It works! Luke’s directions, an hour of working on this, and this article in particular, and we have a simple JIT working. Again, this simple example is super non-portable and dealing with memory in this fashion is generally unsafe. But now I know the basics of JIT’ing code, and now so do you!