Invoking a function (main()) from a binary file in

2019-05-06 17:21发布

I have simple c program like, my_bin.c:

#include <stdio.h>

int main()
{
    printf("Success!\n");
    return 0;
}

I compile it with gcc and got executable: my_bin.

Now I want to invoke main (or run this my_bin) using another C program. That I did with mmap and function pointer like this:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
int main()
{
   void (*fun)();
   int fd;
   int *map;
   fd = open("./my_bin", O_RDONLY);
   map = mmap(0, 8378, PROT_READ, MAP_SHARED, fd, 0);
   fun = map;
   fun();
   return 0;
}

EDIT 1: added PROT_EXEC Making it more clear from responses ... I want to call an external binary program within second program.

I don't know how to initialize function pointer with the address of main(other program's). any idea?

EDIT 2:

Why seg fault, after googling, figured out, its because of my size and offset argument of mmap. It should be multiple of pagesize. [Reference: Segfault while using mmap in C for reading binary files

Now the code looks like:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
int main()
{
   void (*fun)();
   int fd;
   int *map;
   int offset = 8378;
   int pageoffset = offset % getpagesize();
   fd = open("./my_bin", O_RDONLY);
   if(fd == -1) {
        printf("Err opening file\n");
        return -1;
   }
   map = mmap(0, 8378 + pageoffset, PROT_READ|PROT_EXEC,
                        MAP_SHARED, fd, offset - pageoffset);
   perror("Err\n"); //This is printing err and Success!
   //fun = map; // If I uncomment this and 
   //fun();     // this line then, still it 
                // print err and Success! from perror
                // but later it says Illegal instruction. 
   return 0;
}

Still with fun() or without that its not printing ... not sure how to give main() address.

Edit 2[Solved]:

First thing: I didn't read definition properly, I have already given address from which I should read binary file. Second: mmap: size and offset should be multiple of pagesize.

3条回答
虎瘦雄心在
2楼-- · 2019-05-06 17:30

The "correct" solution IMHO if linking the functionality in one executable, is to not call main() from another function. Rather, create a function that wraps up what main() does and call it from both main()s.

int success()
{   
  printf("Success!\n");
  return 0;
}

int main()
{
  return success();
}

For calling external system call, use system

查看更多
仙女界的扛把子
3楼-- · 2019-05-06 17:31

main() usually isn't the first function in a C program. The linker will put some setup/init code before that which, among other things, will set up the environment, get the command line arguments, parse them into a string array, stuff like that.

It gets problematic when the new main() function starts to set up the memory allocation routines - basically, this will ruin all the important data structures of your main application.

If you want to execute a function (i.e. without main()), then compile your C code into a shared library and load that with dlopen() or your OS's equivalent.

If you really need main(), use fork() and exec().

查看更多
一纸荒年 Trace。
4楼-- · 2019-05-06 17:34

Generally, the executable file produced by compiling and linking is not a simple binary image that you can load into memory and execute. (There are certain computing platform targets where it is.) Usually, a special program called a loader has to read the executable file, prepare memory using the contents of and instructions in the file, and use special system calls to initiate execution of the program as a new process.

For example, executable files usually contain some data that must be copied to memory and then marked read-only, some data that must be copied to memory and then marked readable and writeable, and some data (called “text” or program instructions) that must be copied to memory and marked executable. The executable file usually also contains some other information about preparing memory, such as setting aside some amount of initially cleared memory, setting aside a certain amount for stack space, which address to start executing at (which is usually not main), and so on.

One complicated aspect is that the executable file contains information about what parts of the program text and the data have to be changed according to what memory addresses are used. The addresses where data and text are put in memory may not be known at compile time, so the compiler writes some prototype code, and the loader has to adjust the code after it decides upon the addresses.

Another complication is that an executable file may contain references to symbols in dynamic libraries. The loader has to examine those references and load the necessary dynamic libraries.

As you can see, loading is not a simple process. You cannot simply memory map an executable file and jump to it, even if you can figure out where in it main starts.

Some systems provide an interface to the loader. These are typically used with dynamic libraries. Instead of building a stand-alone executable program, you would build a dynamic library. Then you could use calls to the dynamic library interface to load the library, find the addresses of routines in it, and call those routines.

Generally, a programming environment does not provide a convenient way to load an executable file and call its main routine. It may be easier to create a dynamic library instead of creating an executable file and then to load the dynamic library and call a routine inside of it. Alternatively, there are ways to invoke an executable file as a separate process, so that it essentially runs separately, like a command typed at the command line, without sharing memory with the calling process.

查看更多
登录 后发表回答