4

I just have an interesting idea. I was using objdump to dump a simple binary and I see many functions in the binary. Is it possible to create another C program that link with these functions? Assuming I know the parameters for input and output.

Some more information: file1:test.c

#include <stdio.h>

int add(int x,int y)
{
    return x+y;
}

int main(int argc, const char *argv[])
{
    printf("%d\n",add(3,4));
    return 0;
}

file2: test1.c

#include <stdio.h>

int main(int argc, const char *argv[]) 
{
    printf("%d\n",add(8,8));
    return 0; 
}

gcc test.c -o test.exe
gcc test1.c test.exe -o test1.exe

Output:

ld: in test.exe, can't link with a main executable
collect2: ld returned 1 exit status
Patrick
  • 4,186
  • 9
  • 32
  • 45

3 Answers3

2

I'm afraid not.

The compiled binary file has been processed through relocation phase by the linker, which associate each symbol reference in the code with a run-time address.

You can do a simple experiment to find out the differences, here is a program which output 'Hello World':

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

int main()
{
    printf("Hello World!");
    return 0;
}

Using gcc -c you can compile the source code into a relocatable object:

$ gcc -c main.o

$ readelf -s main.o

Symbol table '.symtab' contains 10 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000     0 SECTION LOCAL  DEFAULT    7 
     7: 00000000     0 SECTION LOCAL  DEFAULT    6 
     8: 00000000    29 FUNC    GLOBAL DEFAULT    1 main
     9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf

You can see from here the value of function main is 0x0, which means it has not yet been relocated and can be linked with others.

But when you compile the file with gcc command, to generated an executable one:

$ gcc main.c
$ readelf -s a.out | grep main
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
    39: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    51: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    62: 080483c4    29 FUNC    GLOBAL DEFAULT   13 main

Now you can see the address of function main has been relocated to 0x80483c4, which is the runtime address of the function code. The generate a.out can no longer get linked with others, since there may be runtime address violation to do so.

Generally speaking the relocation phase cannot be reverted, because some symbol information get lost after the phase.

For more details I suggest you to read the Linking chapter in the book Computer System: A Programmer's Prospective, which covers a lot in linking and relocation.

ZelluX
  • 69,107
  • 19
  • 71
  • 104
1

Sure, simply write a header file that provides declarations for the functions you want to use with the correct function signatures, and then include that header file in your C code-module where you call the functions. Then compile and link with the other object file to create a final executable.

The assumption though is that the functions in the object file you've dumped follow the ABI and calling-conventions for the platform/compiler you're working with (I know that one seems obvious), and it can't include its own entry-point (i.e., a main() function). With regards to the second point, the object file must basically be a "library" of stand-alone functions. This means you can't link against an executable.

Jason
  • 31,834
  • 7
  • 59
  • 78
  • I know I can link with .o file easily. Though, I was wondering if I can do this with an executable. – Patrick Jan 15 '12 at 06:52
  • 1
    Ah, you didn't mention that your object file has `main()` included ... that won't work, it must be an object file for a library of functions – Jason Jan 15 '12 at 06:53
  • Somebody should mention differences between compilers. – Mikhail Jan 15 '12 at 06:55
  • So is there a way to convert executable (with main function) back to series of object files? – Patrick Jan 15 '12 at 06:57
1

From a practical standpoint, there is little difference between an object (.o) file and an executable. The object file can contain unbound symbols, where the executable cannot. The executable must contain an entry point, where the object file has no such restriction. The executable has a more complete header. The executable also has all its jump offsets resolved, as it has been through the linking resolution phase. Some functions may have been permanently inlined away.

So yes, in theory you can create an executable which calls the functions from another executable, but not just with a normal link line. Your primary issue is that the second executable can't have an entry point - a main function - and still be linked with the original (since the names would collide).

If your goal is just to call the original functions, I suggest using a different method from the direct linking you seem to be suggesting. If you craft a shared library and put it in the LD_PRELOAD environment variable, and then invoke the original executable, you may use your library to effectively hook the program entry (possibly via the _main symbol) and then call an alternate program routine. Because this library is loaded along with the original binary, you may call all the original functions...

But the easiest way by far to call the functions from the binary is just to link with the object files instead of the executable.

Borealid
  • 95,191
  • 9
  • 106
  • 122