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;
}
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
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
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
You first compile it using -c to generate a relocatable object file:
$ gcc -c program.c -o program.o
Then you redefine entry to be main:
$ objcopy --redefine-sym entry=main program.o
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
Minimal runnable example and notes on other answers
main.c
#include <stdio.h>
#include <stdlib.h>
int mymain(void) {
puts("hello");
exit(0);
}
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.
Tested in Ubuntu 20.10.
Related
I'm trying to write my own shared library to link to an executable, but can't get the .so to link.
I'm using a very basic example to try and get it working. The shared library (test_lib.c):
#include "test_lib.h" //stdlib includes and function prototype
char *hello(void) {
char *c = malloc(100);
memcpy(c, "hello\n", 7);
return c;
}
The executable (test.c):
#include "test_lib.h"
int main() {
printf("%s", hello());
return 0;
}
Following all the guides I can find, I compile the .so with gcc -I . -fPIC -shared -o test_lib.so test_lib.c, and then the executable (in the same directory) with gcc -I . -L . test.c -ltest_lib
This gives the error:
/usr/bin/ld: cannot find -ltest_lib
collect2: error: ld returned 1 exit status
As I understand including the path through the -L flag should tell gcc where to find the .so, but this isn't working. What am I missing here?
When linking a library, the library usually has to be named libxxx.a|so for the linker to find it.
Compiling the library:
gcc -I . -fPIC -shared -o libtest.so test_lib.c
Then you can link with:
gcc -I . -L . test.c -ltest
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;
}
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
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
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
You first compile it using -c to generate a relocatable object file:
$ gcc -c program.c -o program.o
Then you redefine entry to be main:
$ objcopy --redefine-sym entry=main program.o
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
Minimal runnable example and notes on other answers
main.c
#include <stdio.h>
#include <stdlib.h>
int mymain(void) {
puts("hello");
exit(0);
}
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.
Tested in Ubuntu 20.10.
I have source files written in C programming using notepad++ and I am running them from command lines and later i need to link them inorder to generate the .exe file.
Here are the following commands I want to use while generating .exe file
gcc logc.c -o logc
gcc mainc.c -o mainc
gcc -o output logc.o mainc.o
But when i run the following command my compiler is returning with the following error status.
gcc logc.c -o logc
(x86)/mingw-w64/i686-8.1.0-win32-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain#16'
when i run the following command to compile my mainc file
C:\Users\user\AppData\Local\Temp\ccskY3nf.o:mainc.c:(.text+0x31): undefined reference to `Log'
collect2.exe: error: ld returned 1 exit status
And here are my mainc.c and logc.c and logc.h files for your reference
logc.c file is here
#include <stdio.h>
#include "logc.h"
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
printf(" %s",message);
}
mainc.c file is here
#include <stdio.h>
#include <conio.h>
#include <stdbool.h>
#include "logc.h"
int main()
{
int x = 5;
bool comparisonResult = x == 5;
if(comparisonResult == 1)
Log("Hello World");
return 0;
}
and logc.h file is here
#ifndef _LOG_H
#define _LOG_H
void InitLog();
void Log(const char* message);
#endif
How can i compile individual source files and then link them and generate an executable file.
Thanks in advance.
You don't create object files, for that you need the -c argument:
gcc logc.c -c
gcc mainc.c -c
gcc -o output logc.o mainc.o
By default gcc will generate an executable file, not an object file. So when you compile logc.c, it tries to make an executable but it can't find the main function so it fails. Similarly with main.c, it tries to make an executable but can't find Log
You need to add the -c option to create object files:
gcc logc.c -c -o logc.o
gcc mainc.c -c -o mainc.o
So I'm trying trying to use a function defined in another C (file1.c) file in my file (file2.c). I'm including the header of file1 (file1.h) in order to do this.
However, I keep getting the following error whenever I try to compile my file using gcc:
Undefined symbols for architecture x86_64:
"_init_filenames", referenced from:
_run_worker in cc8hoqCM.o
"_read_list", referenced from:
_run_worker in cc8hoqCM.o
ld: symbol(s) not found for architecture x86_64
I've been told I need to "link the object files together" in order to use the functions from file1 in file2, but I have no clue what that means :(
I assume you are using gcc, to simply link object files do:
$ gcc -o output file1.o file2.o
To get the object-files simply compile using
$ gcc -c file1.c
this yields file1.o and so on.
If you want to link your files to an executable do
$ gcc -o output file1.c file2.c
The existing answers already cover the "how", but I just wanted to elaborate on the "what" and "why" for others who might be wondering.
What a compiler (gcc) does: The term "compile" is a bit of an overloaded term because it is used at a high-level to mean "convert source code to a program", but more technically means to "convert source code to object code". A compiler like gcc actually performs two related, but arguably distinct functions to turn your source code into a program: compiling (as in the latter definition of turning source to object code) and linking (the process of combining the necessary object code files together into one complete executable).
The original error that you saw is technically a "linking error", and is thrown by "ld", the linker. Unlike (strict) compile-time errors, there is no reference to source code lines, as the linker is already in object space.
By default, when gcc is given source code as input, it attempts to compile each and then link them all together. As noted in the other responses, it's possible to use flags to instruct gcc to just compile first, then use the object files later to link in a separate step. This two-step process may seem unnecessary (and probably is for very small programs) but it is very important when managing a very large program, where compiling the entire project each time you make a small change would waste a considerable amount of time.
You could compile and link in one command:
gcc file1.c file2.c -o myprogram
And run with:
./myprogram
But to answer the question as asked, simply pass the object files to gcc:
gcc file1.o file2.o -o myprogram
Add foo1.c , foo2.c , foo3.c and makefile in one folder
the type make in bash
if you do not want to use the makefile, you can run the command
gcc -c foo1.c foo2.c foo3.c
then
gcc -o output foo1.o foo2.o foo3.o
foo1.c
#include <stdio.h>
#include <string.h>
void funk1();
void funk1() {
printf ("\nfunk1\n");
}
int main(void) {
char *arg2;
size_t nbytes = 100;
while ( 1 ) {
printf ("\nargv2 = %s\n" , arg2);
printf ("\n:> ");
getline (&arg2 , &nbytes , stdin);
if( strcmp (arg2 , "1\n") == 0 ) {
funk1 ();
} else if( strcmp (arg2 , "2\n") == 0 ) {
funk2 ();
} else if( strcmp (arg2 , "3\n") == 0 ) {
funk3 ();
} else if( strcmp (arg2 , "4\n") == 0 ) {
funk4 ();
} else {
funk5 ();
}
}
}
foo2.c
#include <stdio.h>
void funk2(){
printf("\nfunk2\n");
}
void funk3(){
printf("\nfunk3\n");
}
foo3.c
#include <stdio.h>
void funk4(){
printf("\nfunk4\n");
}
void funk5(){
printf("\nfunk5\n");
}
makefile
outputTest: foo1.o foo2.o foo3.o
gcc -o output foo1.o foo2.o foo3.o
make removeO
outputTest.o: foo1.c foo2.c foo3.c
gcc -c foo1.c foo2.c foo3.c
clean:
rm -f *.o output
removeO:
rm -f *.o
Since there's no mention of how to compile a .c file together with a bunch of .o files, and this comment asks for it:
where's the main.c in this answer? :/ if file1.c is the main, how do
you link it with other already compiled .o files? – Tom Brito Oct 12
'14 at 19:45
$ gcc main.c lib_obj1.o lib_obj2.o lib_objN.o -o x0rbin
Here, main.c is the C file with the main() function and the object files (*.o) are precompiled. GCC knows how to handle these together, and invokes the linker accordingly and results in a final executable, which in our case is x0rbin.
You will be able to use functions not defined in the main.c but using an extern reference to functions defined in the object files (*.o).
You can also link with .obj or other extensions if the object files have the correct format (such as COFF).
I try to write simple mongo c client. Source file (a.c):
#include <stdio.h>
#define MONGO_HAVE_STDINT
#include <mongo.h>
void mongo_init_c(mongo *con)
{
mongo_init(con);
}
int main() {
return 0;
}
And i try to compile it with:
gcc -I/usr/local/include -L/usr/local/lib -lmongoc a.c
But get an error:
a.c:(.text+0xd): undefined reference to `mongo_init'
Files /usr/local/include/mongo.h and /usr/local/lib/libmongoc.so exists
How can I correctly compile a.c?
p.s. mongo-2.0.4, gcc-4.6, mongo-c-driver - pulled from github
update
$ nm /usr/local/lib/libmongoc.so | grep init
000034e0 T _init
0000dd10 T bson_init
0000c740 T bson_init_data
0000c7b0 T bson_init_finished_data
0000dc10 T bson_init_size
0000d060 T bson_iterator_init
0000a5e0 T gridfile_init
00009af0 T gridfile_writer_init
000095e0 T gridfs_init
00010a18 R initialBufferSize
00005f40 T mongo_cursor_init
00008da0 T mongo_env_sock_init
00005d90 T mongo_init
000057b0 T mongo_init_sockets
00004800 T mongo_md5_init
00005e40 T mongo_replica_set_init
00005f00 T mongo_replset_init
00005b80 T mongo_write_concern_init
$ gcc -I/usr/local/include -L/usr/local/lib -Wall -Werror -lmongoc a.c
/tmp/cccuNEp1.o: In function `mongo_init_c':
a.c:(.text+0xd): undefined reference to `mongo_init'
Try linking the library after the source file, like gcc a.c -lmongoc. This is because you're using a traditional single-pass linker, which expects to satisfy dependencies with subsequent, not previous, objects specified on the command line.