Is it possible to create a dynamic function by allocating dynamic memory, writing some assembler opcodes to it (like 0x90 0xC2 for NOP RET), creating a function pointer which points to that dynamic memory and execute it like a regular function from within a C program?
Target should be a regular x86 Linux system.
So in a worst case scenario, a function pointer call is arbitrarily slower than a direct function call, but this is misleading. It turns out that if foo_ptr had been const , then call_foo() and call_foo_ptr() would have generated the same code.
No, they're not evil. They're absolute necessary in order to implement various features such as callback functions in C. Without function pointers, you could not implement: qsort(3)
A function pointer, also called a subroutine pointer or procedure pointer, is a pointer that points to a function. As opposed to referencing a data value, a function pointer points to executable code within memory.
In C, we can use function pointers to avoid code redundancy. For example a simple qsort() function can be used to sort arrays in ascending order or descending or by any other order in case of array of structures. Not only this, with function pointers and void pointers, it is possible to use qsort for any data type.
In general yes, but you need to go into system-specific things to do so. That's not very surprising I guess, since the fact that you're going to use binary assembly instructions is making it pretty clear.
You need to be aware that you can't assume that heap memory on modern operating systems is executable, so you might need to jump through some hoops to make it so. You can't just call malloc()
and assume the returned pointer points to memory where you can execute code.
In Linux, you can use mmap()
to ask the kernel to map you some memory, and by specifying the PROT_EXEC
flag in the call you can ask it to make the memory executable too.
This memory doesn't have be heap memory (see note below). Moreover, I'd think that you can't change execution permission of heap memory.
On Linux, You can use the following:
#include <sys/mman.h>
size_t size = 0x1000; // 1 page
// this will be mapped somewhere between /lib/x86_64-linux-gnu/ld-2.15.so
// and stack (see note and memory map below)
void *code = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
// use `code` to write your instructions
// then store location at which you want to jump to in `fp`
void *fp = ...;
mprotect(code, size, PROT_READ | PROT_EXEC);
// use some inline assembly to jump to fp
Note: On Linux, memory mapped by user is located in separate region (something like from 400000000000
and up to stack on x86 Linux, and probably 7f0000000000
on x64 one). Heap is located after ELF segments of the program and before region, available for mmap
. Heap itself can be allocated directly using brk
system call (superseded by malloc
by now). See this example (got on my Ubuntu 12.10 x64):
➜ ~ ps
PID TTY TIME CMD
9429 pts/3 00:00:07 zsh
20069 pts/3 00:00:00 git-credential-
22626 pts/3 00:00:00 ps
➜ ~ cat /proc/9429/maps
00400000-004a2000 r-xp 00000000 08:01 6291468 /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 6291468 /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 6291468 /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0
01a51000-01fd8000 rw-p 00000000 00:00 0 [heap]
...
7f6529d61000-7f6529d91000 rw-p 00000000 00:00 0
...
7f652d0d3000-7f652d0d5000 rw-p 00023000 08:01 44833271 /lib/x86_64-linux-gnu/ld-2.15.so
7fffd7c7f000-7fffd7cae000 rw-p 00000000 00:00 0 [stack]
7fffd7dff000-7fffd7e00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
As you can see, heap
is not executable (and is rightly so), so you can't use malloc
to get executable memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With