Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc - writing and executing code in the bss - setting the permission flags

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);
like image 559
auscoder Avatar asked Sep 10 '10 11:09

auscoder


1 Answers

You should probably just directly request a writeable, executable anonymous mapping with mmap() to store your generated machine code.

like image 82
caf Avatar answered Sep 21 '22 17:09

caf