I'm just playing at this point and I'm pretty sure these hacks
won't quite work or might even be kinda useless... but one way to
avoid the hassle of making the machine code yourself is to get
the compiler to do it.
So we'll write our function (just 32 bit here, the 64 bit didn't
work and I'm not sure why, could be because of this
http://stackoverflow.com/a/6313264/1457000 ) in D then copy it
into the magic memory:
void sayHello() {
asm {
naked;
}
static immutable hello = "hello!\n";
auto sptr = hello.ptr;
auto slen = hello.length;
version(D_InlineAsm_X86)
asm { // 32 bit
mov ECX, sptr;
mov EDX, slen;
mov EBX, 1; // stdout
mov EAX, 4; // sys_write
int 0x80;
}
asm {
ret;
}
}
void sayHelloEnd(){} // I'm using this with the assumption that
the two functions will be right next to each other in memory,
thus sayHello's code goes from &sayHello .. &sayHelloEnd. idk if
that is really true but it seems to work for me
import core.sys.posix.sys.mman;
void main()
{
// NOTE: you did uint* before, now i'm doing ubyte* since
we're really working in bytes, not ints
ubyte[] opcodes = (cast(ubyte*) mmap(null, 4096,
PROT_EXEC | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0))[0 .. 4096];
assert(opcodes !is null);
scope(exit)
munmap(opcodes.ptr, 4096);
// copy the code from our sayHello function that dmd
compiled for us into the executable memory area
auto f = cast(ubyte*) &sayHello;
auto fe = cast(ubyte*) &sayHelloEnd;
auto len = fe - f;
import std.stdio;
writeln("length: ", len); // shouldn't be very large
opcodes[0 .. len] = f[0 .. len]; // copy it over
void* function() func = cast(void* function()) opcodes;
func(); // and run it
writeln("ending function normally!");
// then write over it to prove we still can...
opcodes[0] = 0xcc;
func(); // this should trap
}
Perhaps you could string together a bunch of little functions
written in D and inline asm to build your executable code most
easily using tricks like this. Assuming it continues to work in
more complex situations!