I am generating x86-64 code at runtime in a C program on a linux system (centos 5.4 to be exact).
I generate my bytecodes into a global array as shown below
char program[1024 * 1024] __attribute__((aligned (16)));
and then call into it via a function pointer.
My issue is, when I compile the program like this
gcc -std=gnu99 parse.c -o parse -lm
I get a SIGSEGV, which I am surmising is due to the bss section not being set as executable, as shown by pmap
0000000000601000 4K rw--- /data/work/tmp/parse
0000000000602000 1024K rw--- [ anon ]
when I compile it like this, (empty.s is a zero-length file)
gcc -std=gnu99 parse.c empty.s -o parse -lm
during runtime, the bss sections magically have the execute bit set, and everything works just great.
0000000000601000 4K rwx-- /data/work/tmp/parse
0000000000602000 1024K rwx-- [ anon ]
So, how do these flags get set up in the ELF? And is there a reliable, correct way to get a bss section with rwx permissions?
More details - software versions
gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)
Linux 2.6.18-164.15.1.el5 x86_64 GNU/Linux
Thankyou
update - at first I thought I could not use mmap to solve this problem as caf suggested, because mmap was giving me back pages that were too far away (I wanted to jump into nearby code with relative adressing). It turns out that you can ask mmap to take care of this for you, like so - the MAP_32BIT will give you back a page in the first 2GB.
char* program = mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
You should probably just directly request a writeable, executable anonymous mapping with mmap()
to store your generated machine code.
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