First Class Functions in C
First off and off topic, I hate this blogs design now. I'm really thinking of switching to some legit CMS rather than my own crap. But I just really enjoy the simplicity of my own, and knowing that after all these years, its essentially bug free and secure. So yeah...maybe expect that to change.
Anyway, the point of this post was a tad bit of interesting code i've been messing with. There was a discussion today on reddit if function pointers in C could be considered first class functions.
In the midst of that, this was developed.
#include
#include
#include
typedef int(returns_int_f)();
static returns_int_f* returns_int_lambda(char *source) {
FILE *fp = popen("gcc -Wall -Werror -c -x c - -o ./wee", "w");
const int magic_offset = 0x34;
fwrite(source, 1, strlen(source), fp);
fprintf(fp, "n");
fclose(fp);
fp = fopen("wee", "r");
long binlength;
fseek(fp, 0, SEEK_END);
binlength = ftell(fp) - magic_offset;
fseek(fp, magic_offset, SEEK_SET);
char *binbuf = malloc(binlength);
fread(binbuf, 1, binlength, fp);
fclose(fp);
return (returns_int_f *) binbuf;
}
int main() {
returns_int_f *times2 = returns_int_lambda("int f(x) { return x * 2; }");
int answer = (*times2)(55);
printf("answer is %dn", answer);
}
The result of this code:
$ ./firstclass
answer is 110
The code Is basically just creating a pipe to a new shell processing running gcc and piping the string of C code to gcc.
We then open the object file produced and skip past the header directly to the functions machine code, and read that code into a buffer. That buffer is then returned and cast as a function pointer.
This has is obviously limitations. You cannot call functions inside the original program from the generated function. As there is no relocation being done to the object file.
I did a little searching around and found this: libtcc
Its a library for access to functions internal to TinyCC, the Tiny C Compiler. Implementing this library was quite easy and I was able to write a new version that was a little less hackish (but I'd still never do this in real life).
#include
#include
#include "libtcc.h"
typedef int (*function_t)();
function_t create_function(char *name, char *code)
{
TCCState *s;
unsigned long val;
s = tcc_new();
if(!s)
exit(1);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
tcc_compile_string(s, code);
tcc_relocate(s);
tcc_get_symbol(s, &val, name);
return (function_t)val;
}
int main(int argc, char *argv[])
{
function_t square;
square = create_function("f", "int f(x) { return x * x; }");
int answer = square(atoi(argv[1]));
printf("answer is: %dn", answer);
}
Enjoy. :]