Jump to content

Creating an eval() in C


Jonnycake

Recommended Posts

So, I'm trying to write an eval function in C because it sounds like a fun and challenging idea. So, I have this so far:

#include <stdio.h>

int eval(int* funaddr)
{
        asm(
                "calll %0\n"
                :
                : "r" (funaddr)
        );
        return 0;
}

int whatever()
{
        printf("Hi, whatever() was executed :D :D :D.\n");
        return 0;
}

int main()
{
        eval((int*) &whatever);
        return 0;
}

What I'm trying to figure out how is how I would make it so that a user could input the name of the function and it would execute it. This would require me translating their input into an address of the function which is named that and since the functions don't have names after it's compiled, I'm running into a problem. The only way I can think about doing it is if I were to look at the function table in the file like what gdb does when it translates the function addresses to names. Does anyone else have a better idea?

Edit:

Also, when I compile I get this warning:

/tmp/ccxrgb26.s: Assembler messages:

/tmp/ccxrgb26.s:10: Warning: indirect call without `*'

When it's run, it still works, but I was wondering if this is necessary to fix (as it doesn't appear to be) and if it is, how could I fix it?

Link to comment
Share on other sites

  • 4 weeks later...

I'm not sure if I completely understand you but if i am thinking what you are thinking :P you can use function pointers! :P (as long as the functions have the same return type)

So I am going to use these functions:

int first_function()
{
  printf("Hey I am the First Function \n");
  return 0;
}

int second_function()
{
  printf("Hey I am the Second Function \n");
  return 0;
}

now lets go ahead and make the main code:

//main.c
#include <stdio.h>
#include <string.h>

// Declare Function prototypes
int first_function(void);
int second_function(void);


int main(int argc, char **argv)
{
  //our generic function will be generi_func which will
  // be assigned one of the two 
  int (*generic_func) (void) = NULL;

  //just some input parsing that is only used to select
  //either function and set the address of our temp
  //function to that needed.

  if(strcmp(argv[1], "first") == 0)
  {
    generic_func = &first_function;
    return generic_func();
  } else  if(strcmp(argv[1], "second") == 0)
  {
    generic_func = &second_function;
     return generic_func();
  }
}

//Declare Functions

int first_function()
{
  printf("Hey I am the First Function \n");
  return 0;
}

int second_function()
{
  printf("Hey I am the Second Function \n");
  return 0;
}

Now if i run:

>gnuc main.c

>a.out first

this will run the first_function and if i run

>gnuc main.c

>a.out second

it will run the second function

(also if you run just >a.out the program will segfault as i made this in a few minutes and didn't put any error checking in)

If this is what you were looking for..GREAT!!...if not well sorry but someone else may learn something from it.

If it is what you wanted and don't understand some parts just drop me a line!

Link to comment
Share on other sites

Hey, thanks for replying. That's sort of what I wanted, but not exactly. I know about function pointers and stuff like that. My problem is that I want to not have to explicitly define names. For example, I want to be able to run a program which accepts input which will be run like it would be if it were in a compiled program. Like, an input of printf("Hi\n"); should print Hi to the screen. I've been trying to look into the ELF file structure and getting the memory address from there, atm, this is my eval function:

// Call the function located at funaddr using the arguments in argv[]
int eval(int* funaddr,int argc,char* argv[])
{
        int x;

        // Set up the stack to run the function
        for(x=argc-1;x>=0;x--)
                asm(
                        "pushl %0\n"
                        :
                        : "r" (argv[x])
                );

        // Call the function
        asm(
                "call *%0\n"
                :
                : "r" (funaddr)
        );

        // %eax has not been reset so it will return the return value of the function called
        return;
}

My problem is getting the function address so that I can run it (which I assume I can do since gdb does). Anyway, hope I made what I wanted a little clearer.

Edit:

BTW, example of the use of the function: eval((int*) &printf,1,"Hi\n");.

Link to comment
Share on other sites

The problem with an eval() in C is that C is a compiled language, so by the time the user enters the string to evaluate, function names and other higher level language features have been reduced to machine code. This is why C doesn't have a built-in eval function, but an interpreted language like javascript does: in js, when eval() is called, it is translated into machine code on-the-fly, so interpreting the string you want to evaluate is just a matter of sending it to the interpreter.

So, there are two ways to do an eval-like function in C that I can think of:

1) If you only need a limited number of commands, you could build a small interpreter that would parse the supplied string and execute the appropriate function calls, etc. Theoretically, you could write something universal, but then you'd have a full C interpreter, and I doubt you want to embark on a project that ambitious...

2) You could:

i) wrap the input string in a "main(){...}",

ii) write this to a file (with appropriate #includes, etc),

iii) compile the file with gcc,

iv) execute the generated binary as a child process, and

v) after execution, return control to the main program and delete the files from ii) and iii)...

Solution 1) would give you access to only as many features as you code for, but it would give you access to other parts of your program. Solution 2) would allow you to enter any C code, but you wouldn't be able to access other parts of your program directly.

Edit: Info on how GDB gets it's symbolic information (e.g. function and variable names, etc) here: http://sourceware.org/gdb/current/onlinedo...nt_8.html#SEC49

Link to comment
Share on other sites

Theoretically, you could write something universal, but then you'd have a full C interpreter, and I doubt you want to embark on a project that ambitious...

Haha...I actually thought about that >_>...don't make a C interpreter :P

Link to comment
Share on other sites

@OneTimePad: Thanks for the link, I'll look at it a little bit later today. I think I'm probably just gonna make it able to run functions and have variables. Of course, writing it so that it can do while and for loops would be fun too *thinks*. Would take lots of code, but would be totally worth it lol.

@Gyf: Well, it would be fun :P

Link to comment
Share on other sites

Haha I would totally be up for making a C interpreter, however I don't see myself making a useful one in the near or distant future :P

Was this just an experiment you were conducting Jonnycake? Or do you actually need it done?

If you need it done and are not restricted to a language check out C# (looking at the internet it looks like it lets you do what you are trying to achieve a lot easier than C but that is ually the case with C# and C lol) or err BAH i forgot the other language :P I wrote it down at home (YES WITH A PENCIL AND ACTUAL PAPER) but yeah :P

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...