How to change entry point of C program with gcc?
Asked Answered
C

5

44

How to change the entry point of a C program compiled with gcc ?
Just like in the following code

#include<stdio.h>
int entry()  //entry is the entry point instead of main
 {
   return 0;
 }
Careen answered 21/9, 2011 at 3:26 Comment(2)
@iandotkelly Not OP but I needed to use a checkpointing library which required me to change main() to something else ;)Cheshire
@Cheshire Do you know the linker's option --wrap=xxx? It replaces all references of xxx by __wrap_xxx and all definitions of xxx by __real_xxx. I used it successfully for testing a main().Waxler
T
56

It's a linker setting:

-Wl,-eentry

the -Wl,... thing passes arguments to the linker, and the linker takes a -e argument to set the entry function

Tapster answered 21/9, 2011 at 3:31 Comment(6)
This is what I got when I compiled a hello world C program with this option: $ gcc -Wl,-emymain t27.c /usr/lib/gcc/i686-redhat-linux/4.8.2/../../../crt1.o: In function '_start': (.text+0x18): undefined reference to 'main'Challis
@LeeDuhem, this is because you link your program with a standard c runtime library. An entry point in a program linked with c runtime library is _start. Start has a reference to main() of your program (it expects your program to have main() func instead of your custom func). Try not to link to a crt and specify an entry point as your_main and see what happens.Fastening
@LeeDuhem, -nostdlibs that flag is.Fastening
-nostartfiles is the actual flag you want, this omits the crt*.o files containing _start, but still allows you to use a libc (unless you also use -nostdlib or -nodefaultlibs, in which case you can still manually specify them using -lc -lgcc etc...)Varga
I believe there is a typo: should be -Wl,--entry="MyCutomEntryFunction" or -Wl,-e="MyCutomEntryFunction"Mcmullen
@RomainVIOLLETTE it works fine for me: https://mcmap.net/q/371226/-how-to-change-entry-point-of-c-program-with-gcc on Ubuntu 20.10.Stomatology
P
11

If you are on a system that provides GNU Binutils (like Linux), you can use the objcopy command to make an arbitrary function the new entry point.

Suppose a file called program.c containing the entry function:

$ cat > program.c
#include <stdio.h>
int entry()
{
    return 0;
}
^D
  1. You first compile it using -c to generate a relocatable object file:

    $ gcc -c program.c -o program.o
    
  2. Then you redefine entry to be main:

    $ objcopy --redefine-sym entry=main program.o
    
  3. Now use gcc to compile the new object file:

    $ gcc program.o -o program
    

NOTE: If your program already has a function called main, before step 2, you can perform a separate objcopy invocation:

objcopy --redefine-sym oldmain=main program.o
Papuan answered 14/12, 2015 at 22:26 Comment(0)
H
10

You can modify your source code as:

#include<stdio.h>

const char my_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";

int entry()  //entry is the entry point instead of main
{
   exit(0);
}

The ".interp" section will let your program able to call external shared library. The exit call will make your entry function to exit program instead of return.

Then build the program as a shared library which is executable:

$ gcc -shared -fPIC -e entry test_main.c -o test_main.so
$ ./test_main
Handgun answered 10/8, 2014 at 4:18 Comment(4)
What is the calling convention of the entry function? Is the C-runtime initialized in this way?Ruthy
could you please explain what this mean "build the program as a shared library which is executable" How can it be both?Laconia
@harper: It's not a C compatible calling convention. The ELF entry point ABI has its primary argument in the stack pointer, pointing to an "array" consisting of argc, argv pointers, null, env pointers, null, aux vector table. Some archs have additional args in specific registers.Inutility
doesn't work.. I get: cannot execute binary file: Exec format errorHosier
S
4

Minimal runnable example and notes on other answers

main.c

#include <stdio.h>
#include <stdlib.h>

int mymain(void) {
    puts("hello");
}

compile and run:

gcc -nostartfiles -Wl,--entry=mymain -o main.out main.c
# or -Wl,-emymain
./main.out 1 2 3

The notes:

  • without -nostartfiles, the link fails with:

    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
    (.text+0x20): undefined reference to `main'
    collect2: error: ld returned 1 exit status
    

    presumably because the glibc setup code that runs before main in _start normally calls main.

  • command line arguments are not setup for you, presumably because they would be setup by the glibc code that runs before main, so trying to use them prints undefined values. I haven't found a method that works for them.

Another option is to remove -nostartfiles is to just define a dummy main:

#include <stdio.h>
#include <stdlib.h>

int main(void) {}

int mymain(int argc, char **argv) {
    (void)argv;
    printf("%d\n", argc);
    exit(0);
}

which then compile and runs fine with:

gcc -nostartfiles -Wl,--entry=mymain -o main.out main.c
# or -Wl,-emymain
./main.out 1 2 3

CLI args are still broken, but perhaps more things stdlib things will work like this.

Tested in Ubuntu 23.10.

Stomatology answered 29/10, 2019 at 18:56 Comment(8)
Does not work, apparently the warning is serious.Loreeloreen
@ScottFranco what's your GCC version/OS version BTW?Stomatology
C:\projects\petit_ami>gcc -v ... gcc version 9.2.0 (MinGW.org GCC Build-2)Loreeloreen
@ScottFranco the warning was caused by small typo -eentry= should have been --entry= ; I've edited the answer accordingly.Record
@Record nice catch! I wonder how it worked with the typo at all on my test!Stomatology
@Self: it worked before by coincidence because it was the first thing in the text sectionStomatology
this causes a segfault for me, unless i redirect stdout to a file (gcc 12.2.0)Kusin
@Kusin still worked on Ubuntu 23.10 amd64 for me. But yeah, I'm not surprised, using any stdlib functionality with -nostartfiles is not guaranteed to work I think.Stomatology
H
0

If you're doing this on a hosted environment (i.e. Linux, Windows etc.) it's probably a much better idea to use the linker to redefine which function becomes main() with this:

-Wl,--defsym=main=some_other_entry_point

This way, the function being called at startup is still main(), so your operating system's _start() code will still work as normal. If you try to actually change the entry point name with --entry, you'll probably run into a lot of issues because the OS's _start won't be called.

Example:

#include <stdio.h>

int main(void) {
    printf("wrong\n");
}

int some_other_entry_point(void) {
    printf("right\n");
}
gcc -Wl,--defsym=main=some_other_entry_point -o test test.c
$ ./test
right

https://godbolt.org/z/aWGYEMhaE

Hairdo answered 1/5 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.